From 19366220aabeeb6fcdac6fa056b9b0e9585e8e6b Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 1 Apr 2022 10:34:09 -0400
Subject: fixed up document focus to take a collectkon so that the treeView can
 focus on the matching alias when multiple aliases are shown in different
 collections.

---
 src/client/views/collections/TreeView.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index eedb353e3..ff5c4bab1 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -669,7 +669,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 ContentScaling={returnOne}
             />;
 
-        const buttons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ":afterHeader" : ""));
+        const buttons = this.props.styleProvider?.(this.doc, { ...this.props.treeView.props, ContainingCollectionDoc: this.props.parentTreeView?.doc }, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ":afterHeader" : ""));
         return <>
             <div className={`docContainer${Doc.IsSystem(this.props.document) || this.props.document.isFolder ? "-system" : ""}`} ref={this._tref} title="click to edit title. Double Click or Drag to Open"
                 style={{
-- 
cgit v1.2.3-70-g09d2


From 98567999b9882ed093bb0d750504a1bd10aa9a94 Mon Sep 17 00:00:00 2001
From: Aubrey Li <Aubrey-Li>
Date: Tue, 12 Apr 2022 19:21:53 -0400
Subject: revert presbox & treeview onclick focus

---
 package-lock.json                             | 399 +-------------------------
 src/client/util/CurrentUserUtils.ts           |   2 +-
 src/client/util/DocumentManager.ts            |   4 +-
 src/client/views/MainView.tsx                 |   2 +-
 src/client/views/collections/TreeView.tsx     |  94 +++++-
 src/client/views/nodes/button/FontIconBox.tsx |   1 +
 6 files changed, 99 insertions(+), 403 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/package-lock.json b/package-lock.json
index 0bfe79f5a..63d1b9d1e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -158,15 +158,9 @@
             }
         },
         "@babel/runtime-corejs3": {
-<<<<<<< HEAD
             "version": "7.17.7",
             "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.7.tgz",
             "integrity": "sha512-TvliGJjhxis5m7xIMvlXH/xG8Oa/LK0SCUCyfKD6nLi42n5fB4WibDJ0g9trmmBB6hwpMNx+Lzbxy9/4gpMaVw==",
-=======
-            "version": "7.17.2",
-            "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz",
-            "integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==",
->>>>>>> master
             "requires": {
                 "core-js-pure": "^3.20.2",
                 "regenerator-runtime": "^0.13.4"
@@ -229,15 +223,9 @@
             }
         },
         "@discoveryjs/json-ext": {
-<<<<<<< HEAD
             "version": "0.5.7",
             "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
             "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw=="
-=======
-            "version": "0.5.6",
-            "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz",
-            "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA=="
->>>>>>> master
         },
         "@emotion/babel-plugin": {
             "version": "11.7.2",
@@ -272,15 +260,9 @@
                     "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
                 },
                 "@babel/runtime": {
-<<<<<<< HEAD
                     "version": "7.17.7",
                     "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.7.tgz",
                     "integrity": "sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA==",
-=======
-                    "version": "7.17.2",
-                    "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
-                    "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
->>>>>>> master
                     "requires": {
                         "regenerator-runtime": "^0.13.4"
                     }
@@ -317,15 +299,9 @@
                     "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ=="
                 },
                 "csstype": {
-<<<<<<< HEAD
                     "version": "3.0.11",
                     "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
                     "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
-=======
-                    "version": "3.0.10",
-                    "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
-                    "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
->>>>>>> master
                 },
                 "escape-string-regexp": {
                     "version": "4.0.0",
@@ -422,15 +398,9 @@
                     "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ=="
                 },
                 "csstype": {
-<<<<<<< HEAD
                     "version": "3.0.11",
                     "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
                     "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
-=======
-                    "version": "3.0.10",
-                    "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
-                    "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
->>>>>>> master
                 },
                 "stylis": {
                     "version": "4.0.13",
@@ -458,39 +428,23 @@
             "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
         },
         "@emotion/react": {
-<<<<<<< HEAD
             "version": "11.8.2",
             "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.8.2.tgz",
             "integrity": "sha512-+1bcHBaNJv5nkIIgnGKVsie3otS0wF9f1T1hteF3WeVvMNQEtfZ4YyFpnphGoot3ilU/wWMgP2SgIDuHLE/wAA==",
-=======
-            "version": "11.8.1",
-            "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.8.1.tgz",
-            "integrity": "sha512-XGaie4nRxmtP1BZYBXqC5JGqMYF2KRKKI7vjqNvQxyRpekVAZhb6QqrElmZCAYXH1L90lAelADSVZC4PFsrJ8Q==",
->>>>>>> master
             "requires": {
                 "@babel/runtime": "^7.13.10",
                 "@emotion/babel-plugin": "^11.7.1",
                 "@emotion/cache": "^11.7.1",
                 "@emotion/serialize": "^1.0.2",
-<<<<<<< HEAD
-=======
-                "@emotion/sheet": "^1.1.0",
->>>>>>> master
                 "@emotion/utils": "^1.1.0",
                 "@emotion/weak-memoize": "^0.2.5",
                 "hoist-non-react-statics": "^3.3.1"
             },
             "dependencies": {
                 "@babel/runtime": {
-<<<<<<< HEAD
                     "version": "7.17.7",
                     "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.7.tgz",
                     "integrity": "sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA==",
-=======
-                    "version": "7.17.2",
-                    "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
-                    "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
->>>>>>> master
                     "requires": {
                         "regenerator-runtime": "^0.13.4"
                     }
@@ -530,15 +484,9 @@
                     "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ=="
                 },
                 "csstype": {
-<<<<<<< HEAD
                     "version": "3.0.11",
                     "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
                     "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
-=======
-                    "version": "3.0.10",
-                    "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
-                    "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
->>>>>>> master
                 },
                 "stylis": {
                     "version": "4.0.13",
@@ -577,15 +525,9 @@
             },
             "dependencies": {
                 "@babel/runtime": {
-<<<<<<< HEAD
                     "version": "7.17.7",
                     "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.7.tgz",
                     "integrity": "sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA==",
-=======
-                    "version": "7.17.2",
-                    "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
-                    "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
->>>>>>> master
                     "requires": {
                         "regenerator-runtime": "^0.13.4"
                     }
@@ -616,15 +558,9 @@
                     "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ=="
                 },
                 "csstype": {
-<<<<<<< HEAD
                     "version": "3.0.11",
                     "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
                     "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
-=======
-                    "version": "3.0.10",
-                    "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
-                    "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
->>>>>>> master
                 }
             }
         },
@@ -707,15 +643,9 @@
             }
         },
         "@fortawesome/react-fontawesome": {
-<<<<<<< HEAD
             "version": "0.1.18",
             "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz",
             "integrity": "sha512-RwLIB4TZw0M9gvy5u+TusAA0afbwM4JQIimNH/j3ygd6aIvYPQLqXMhC9ErY26J23rDPyDZldIfPq/HpTTJ/tQ==",
-=======
-            "version": "0.1.17",
-            "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.17.tgz",
-            "integrity": "sha512-dX43Z5IvMaW7fwzU8farosYjKNGfRb2HB/DgjVBHeJZ/NSnuuaujPPx0YOdcAq+n3mqn70tyCde2HM1mqbhiuw==",
->>>>>>> master
             "requires": {
                 "prop-types": "^15.8.1"
             },
@@ -786,15 +716,9 @@
             }
         },
         "@hig/theme-data": {
-<<<<<<< HEAD
             "version": "2.24.0",
             "resolved": "https://registry.npmjs.org/@hig/theme-data/-/theme-data-2.24.0.tgz",
             "integrity": "sha512-/71T3kezuom7z60Bxyxwxo0oHqb2B59jCbdWrgRgUYorK0vO6zjFmQvRmPSgxq2i1bQxQLx12iuzW9cM494pMQ==",
-=======
-            "version": "2.23.1",
-            "resolved": "https://registry.npmjs.org/@hig/theme-data/-/theme-data-2.23.1.tgz",
-            "integrity": "sha512-Yca1iCIs8U1dpkLW1VNiKOJW9fCJdb70f1dc61+R+HO1QJ8jMBu5eOpmQE1NKotJmcazhsXpo6xC11yV1crE4w==",
->>>>>>> master
             "requires": {
                 "tinycolor2": "^1.4.1"
             }
@@ -867,30 +791,11 @@
                         "readable-stream": "^3.6.0"
                     }
                 },
-<<<<<<< HEAD
-=======
-                "chownr": {
-                    "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
-                    "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
-                },
->>>>>>> master
                 "emoji-regex": {
                     "version": "8.0.0",
                     "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
                     "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
                 },
-<<<<<<< HEAD
-=======
-                "fs-minipass": {
-                    "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
-                    "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
-                    "requires": {
-                        "minipass": "^3.0.0"
-                    }
-                },
->>>>>>> master
                 "gauge": {
                     "version": "3.0.2",
                     "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
@@ -935,31 +840,6 @@
                         }
                     }
                 },
-<<<<<<< HEAD
-=======
-                "minipass": {
-                    "version": "3.1.6",
-                    "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
-                    "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
-                    "requires": {
-                        "yallist": "^4.0.0"
-                    }
-                },
-                "minizlib": {
-                    "version": "2.1.2",
-                    "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
-                    "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
-                    "requires": {
-                        "minipass": "^3.0.0",
-                        "yallist": "^4.0.0"
-                    }
-                },
-                "mkdirp": {
-                    "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
-                    "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
-                },
->>>>>>> master
                 "node-fetch": {
                     "version": "2.6.7",
                     "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -968,17 +848,6 @@
                         "whatwg-url": "^5.0.0"
                     }
                 },
-<<<<<<< HEAD
-=======
-                "nopt": {
-                    "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
-                    "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
-                    "requires": {
-                        "abbrev": "1"
-                    }
-                },
->>>>>>> master
                 "npmlog": {
                     "version": "5.0.1",
                     "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
@@ -1016,22 +885,6 @@
                         "ansi-regex": "^5.0.1"
                     }
                 },
-<<<<<<< HEAD
-=======
-                "tar": {
-                    "version": "6.1.11",
-                    "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
-                    "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
-                    "requires": {
-                        "chownr": "^2.0.0",
-                        "fs-minipass": "^2.0.0",
-                        "minipass": "^3.0.0",
-                        "minizlib": "^2.1.1",
-                        "mkdirp": "^1.0.3",
-                        "yallist": "^4.0.0"
-                    }
-                },
->>>>>>> master
                 "tr46": {
                     "version": "0.0.3",
                     "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@@ -1078,15 +931,9 @@
             },
             "dependencies": {
                 "csstype": {
-<<<<<<< HEAD
                     "version": "3.0.11",
                     "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
                     "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
-=======
-                    "version": "3.0.10",
-                    "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
-                    "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
->>>>>>> master
                 },
                 "dom-helpers": {
                     "version": "5.2.1",
@@ -1200,15 +1047,9 @@
             },
             "dependencies": {
                 "@babel/runtime": {
-<<<<<<< HEAD
                     "version": "7.17.7",
                     "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.7.tgz",
                     "integrity": "sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA==",
-=======
-                    "version": "7.17.2",
-                    "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
-                    "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
->>>>>>> master
                     "requires": {
                         "regenerator-runtime": "^0.13.4"
                     }
@@ -1228,15 +1069,6 @@
             "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
             "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="
         },
-<<<<<<< HEAD
-=======
-        "@socket.io/component-emitter": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz",
-            "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==",
-            "dev": true
-        },
->>>>>>> master
         "@szmarczak/http-timer": {
             "version": "5.0.1",
             "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
@@ -1383,19 +1215,11 @@
             }
         },
         "@types/bson": {
-<<<<<<< HEAD
             "version": "4.0.2",
             "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.2.tgz",
             "integrity": "sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q==",
             "requires": {
                 "@types/node": "*"
-=======
-            "version": "4.2.0",
-            "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.2.0.tgz",
-            "integrity": "sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg==",
-            "requires": {
-                "bson": "*"
->>>>>>> master
             }
         },
         "@types/cacheable-request": {
@@ -1445,15 +1269,9 @@
             "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
         },
         "@types/connect": {
-<<<<<<< HEAD
             "version": "3.4.35",
             "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
             "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
-=======
-            "version": "3.4.33",
-            "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
-            "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
->>>>>>> master
             "dev": true,
             "requires": {
                 "@types/node": "*"
@@ -1728,15 +1546,9 @@
             }
         },
         "@types/json-schema": {
-<<<<<<< HEAD
-            "version": "7.0.10",
-            "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.10.tgz",
-            "integrity": "sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A=="
-=======
             "version": "7.0.9",
             "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
             "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ=="
->>>>>>> master
         },
         "@types/keygrip": {
             "version": "1.0.2",
@@ -1745,15 +1557,9 @@
             "dev": true
         },
         "@types/keyv": {
-<<<<<<< HEAD
-            "version": "3.1.4",
-            "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
-            "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
-=======
             "version": "3.1.3",
             "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz",
             "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==",
->>>>>>> master
             "requires": {
                 "@types/node": "*"
             }
@@ -1768,15 +1574,9 @@
             }
         },
         "@types/lodash": {
-<<<<<<< HEAD
-            "version": "4.14.180",
-            "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.180.tgz",
-            "integrity": "sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g==",
-=======
             "version": "4.14.179",
             "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz",
             "integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==",
->>>>>>> master
             "dev": true
         },
         "@types/mime": {
@@ -1810,10 +1610,7 @@
             "version": "3.6.20",
             "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz",
             "integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==",
-<<<<<<< HEAD
             "dev": true,
-=======
->>>>>>> master
             "requires": {
                 "@types/bson": "*",
                 "@types/node": "*"
@@ -1929,15 +1726,9 @@
             }
         },
         "@types/prop-types": {
-<<<<<<< HEAD
-            "version": "15.7.3",
-            "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
-            "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
-=======
             "version": "15.7.4",
             "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
             "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
->>>>>>> master
         },
         "@types/prosemirror-commands": {
             "version": "1.0.4",
@@ -2076,15 +1867,9 @@
             }
         },
         "@types/react": {
-<<<<<<< HEAD
-            "version": "16.14.24",
-            "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.24.tgz",
-            "integrity": "sha512-e7U2WC8XQP/xfR7bwhOhNFZKPTfW1ph+MiqtudKb8tSV8RyCsovQx2sNVtKoOryjxFKpHPPC/yNiGfdeVM5Gyw==",
-=======
             "version": "16.14.23",
             "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.23.tgz",
             "integrity": "sha512-WngBZLuSkP4IAgPi0HOsGCHo6dn3CcuLQnCfC17VbA7YBgipZiZoTOhObwl/93DsFW0Y2a/ZXeonpW4DxirEJg==",
->>>>>>> master
             "requires": {
                 "@types/prop-types": "*",
                 "@types/scheduler": "*",
@@ -2092,15 +1877,9 @@
             },
             "dependencies": {
                 "csstype": {
-<<<<<<< HEAD
-                    "version": "3.0.11",
-                    "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
-                    "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
-=======
                     "version": "3.0.10",
                     "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
                     "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
->>>>>>> master
                 }
             }
         },
@@ -2178,15 +1957,9 @@
             }
         },
         "@types/react-redux": {
-<<<<<<< HEAD
-            "version": "7.1.23",
-            "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.23.tgz",
-            "integrity": "sha512-D02o3FPfqQlfu2WeEYwh3x2otYd2Dk1o8wAfsA0B1C2AJEFxE663Ozu7JzuWbznGgW248NaOF6wsqCGNq9d3qw==",
-=======
             "version": "7.1.22",
             "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.22.tgz",
             "integrity": "sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==",
->>>>>>> master
             "requires": {
                 "@types/hoist-non-react-statics": "^3.3.0",
                 "@types/react": "*",
@@ -2209,10 +1982,6 @@
             "version": "6.8.9",
             "resolved": "https://registry.npmjs.org/@types/react-table/-/react-table-6.8.9.tgz",
             "integrity": "sha512-fVQXjy/EYDbgraScgjDONA291McKqGrw0R0NeK639fx2bS4T19TnXMjg3FjOPlkI3qYTQtFTPADlRYysaQIMpA==",
-<<<<<<< HEAD
-            "dev": true,
-=======
->>>>>>> master
             "requires": {
                 "@types/react": "*"
             }
@@ -2383,15 +2152,9 @@
             "integrity": "sha512-6JqTgijtfXcTJik8NtiNxr2L90ex6ElM00qilOGeUcrEsJLOdzLJSIkXHUYS+KPAYQYtRJQKD6XaXds3HjS+gg=="
         },
         "@types/tough-cookie": {
-<<<<<<< HEAD
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
-            "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A=="
-=======
             "version": "4.0.1",
             "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz",
             "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg=="
->>>>>>> master
         },
         "@types/typescript": {
             "version": "2.0.0",
@@ -2769,18 +2532,6 @@
             },
             "dependencies": {
                 "mime-db": {
-<<<<<<< HEAD
-                    "version": "1.52.0",
-                    "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
-                    "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
-                },
-                "mime-types": {
-                    "version": "2.1.35",
-                    "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
-                    "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-                    "requires": {
-                        "mime-db": "1.52.0"
-=======
                     "version": "1.51.0",
                     "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
                     "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
@@ -2791,7 +2542,6 @@
                     "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
                     "requires": {
                         "mime-db": "1.51.0"
->>>>>>> master
                     }
                 }
             }
@@ -3245,15 +2995,9 @@
             "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
         },
         "asn1": {
-<<<<<<< HEAD
-            "version": "0.2.4",
-            "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
-            "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
-=======
             "version": "0.2.6",
             "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
             "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
->>>>>>> master
             "requires": {
                 "safer-buffer": "~2.1.0"
             }
@@ -3334,15 +3078,9 @@
             "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
         },
         "aws4": {
-<<<<<<< HEAD
-            "version": "1.9.1",
-            "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
-            "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
-=======
             "version": "1.11.0",
             "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
             "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
->>>>>>> master
         },
         "axios": {
             "version": "0.19.2",
@@ -3492,15 +3230,9 @@
             },
             "dependencies": {
                 "core-js": {
-<<<<<<< HEAD
-                    "version": "2.6.11",
-                    "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
-                    "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg=="
-=======
                     "version": "2.6.12",
                     "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
                     "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
->>>>>>> master
                 },
                 "regenerator-runtime": {
                     "version": "0.11.1",
@@ -3661,18 +3393,6 @@
             "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
             "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw=="
         },
-<<<<<<< HEAD
-        "bindings": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
-            "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
-            "optional": true,
-            "requires": {
-                "file-uri-to-path": "1.0.0"
-            }
-        },
-=======
->>>>>>> master
         "bl": {
             "version": "4.0.2",
             "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz",
@@ -3859,21 +3579,12 @@
             "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
         },
         "browserslist": {
-<<<<<<< HEAD
-            "version": "4.20.2",
-            "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz",
-            "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==",
-            "requires": {
-                "caniuse-lite": "^1.0.30001317",
-                "electron-to-chromium": "^1.4.84",
-=======
             "version": "4.19.3",
             "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz",
             "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==",
             "requires": {
                 "caniuse-lite": "^1.0.30001312",
                 "electron-to-chromium": "^1.4.71",
->>>>>>> master
                 "escalade": "^3.1.1",
                 "node-releases": "^2.0.2",
                 "picocolors": "^1.0.0"
@@ -4119,15 +3830,9 @@
             "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
         },
         "caniuse-lite": {
-<<<<<<< HEAD
-            "version": "1.0.30001317",
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz",
-            "integrity": "sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ=="
-=======
             "version": "1.0.30001312",
             "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz",
             "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ=="
->>>>>>> master
         },
         "canvas": {
             "version": "2.9.0",
@@ -4236,16 +3941,6 @@
                 "upath": "^1.1.1"
             },
             "dependencies": {
-<<<<<<< HEAD
-                "fsevents": {
-                    "version": "1.2.13",
-                    "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
-                    "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-                    "optional": true,
-                    "requires": {
-                        "bindings": "^1.5.0",
-                        "nan": "^2.12.1"
-=======
                 "bindings": {
                     "version": "1.5.0",
                     "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
@@ -4737,7 +4432,6 @@
                             "bundled": true,
                             "optional": true
                         }
->>>>>>> master
                     }
                 }
             }
@@ -5739,7 +5433,6 @@
             "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
             "dev": true
         },
-<<<<<<< HEAD
         "d": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
@@ -5750,8 +5443,6 @@
                 "type": "^1.0.1"
             }
         },
-=======
->>>>>>> master
         "d3-array": {
             "version": "1.2.4",
             "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
@@ -11529,12 +11220,7 @@
             "dependencies": {
                 "JSONStream": {
                     "version": "1.3.5",
-<<<<<<< HEAD
-                    "resolved": "",
-                    "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
-=======
                     "bundled": true,
->>>>>>> master
                     "requires": {
                         "jsonparse": "^1.2.0",
                         "through": ">=2.2.7 <3"
@@ -12981,12 +12667,7 @@
                 },
                 "jsonparse": {
                     "version": "1.3.1",
-<<<<<<< HEAD
-                    "resolved": "",
-                    "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
-=======
                     "bundled": true
->>>>>>> master
                 },
                 "jsprim": {
                     "version": "1.4.2",
@@ -14371,12 +14052,7 @@
                 },
                 "strict-uri-encode": {
                     "version": "2.0.0",
-<<<<<<< HEAD
-                    "resolved": "",
-                    "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
-=======
                     "bundled": true
->>>>>>> master
                 },
                 "string-width": {
                     "version": "2.1.1",
@@ -14409,24 +14085,14 @@
                 },
                 "string_decoder": {
                     "version": "1.3.0",
-<<<<<<< HEAD
-                    "resolved": "",
-                    "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
-=======
                     "bundled": true,
->>>>>>> master
                     "requires": {
                         "safe-buffer": "~5.2.0"
                     },
                     "dependencies": {
                         "safe-buffer": {
                             "version": "5.2.0",
-<<<<<<< HEAD
-                            "resolved": "",
-                            "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
-=======
                             "bundled": true
->>>>>>> master
                         }
                     }
                 },
@@ -16830,11 +16496,6 @@
             }
         },
         "react-table": {
-<<<<<<< HEAD
-            "version": "7.7.0",
-            "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.7.0.tgz",
-            "integrity": "sha512-jBlj70iBwOTvvImsU9t01LjFjy4sXEtclBovl3mTiqjz23Reu0DKnRza4zlLtOPACx6j2/7MrQIthIK1Wi+LIA=="
-=======
             "version": "6.11.5",
             "resolved": "https://registry.npmjs.org/react-table/-/react-table-6.11.5.tgz",
             "integrity": "sha512-LM+AS9v//7Y7lAlgTWW/cW6Sn5VOb3EsSkKQfQTzOW8FngB1FUskLLNEVkAYsTX9LjOWR3QlGjykJqCE6eXT/g==",
@@ -16843,7 +16504,6 @@
                 "classnames": "^2.2.5",
                 "react-is": "^16.8.1"
             }
->>>>>>> master
         },
         "react-themeable": {
             "version": "1.1.0",
@@ -17531,37 +17191,6 @@
                 "object-assign": "^4.1.1"
             }
         },
-        "schema-utils": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
-            "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
-            "dev": true,
-            "requires": {
-                "@types/json-schema": "^7.0.8",
-                "ajv": "^6.12.5",
-                "ajv-keywords": "^3.5.2"
-            },
-            "dependencies": {
-                "ajv": {
-                    "version": "6.12.6",
-                    "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-                    "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
-                    "dev": true,
-                    "requires": {
-                        "fast-deep-equal": "^3.1.1",
-                        "fast-json-stable-stringify": "^2.0.0",
-                        "json-schema-traverse": "^0.4.1",
-                        "uri-js": "^4.2.2"
-                    }
-                },
-                "ajv-keywords": {
-                    "version": "3.5.2",
-                    "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
-                    "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
-                    "dev": true
-                }
-            }
-        },
         "scss-loader": {
             "version": "0.0.1",
             "resolved": "https://registry.npmjs.org/scss-loader/-/scss-loader-0.0.1.tgz",
@@ -18933,8 +18562,6 @@
                 "terser": "^5.7.2"
             },
             "dependencies": {
-<<<<<<< HEAD
-=======
                 "ajv": {
                     "version": "6.12.6",
                     "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -18964,7 +18591,6 @@
                         "ajv-keywords": "^3.5.2"
                     }
                 },
->>>>>>> master
                 "serialize-javascript": {
                     "version": "6.0.0",
                     "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
@@ -20182,15 +19808,9 @@
             "dev": true
         },
         "webpack": {
-<<<<<<< HEAD
-            "version": "5.70.0",
-            "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz",
-            "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==",
-=======
             "version": "5.69.1",
             "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.69.1.tgz",
             "integrity": "sha512-+VyvOSJXZMT2V5vLzOnDuMz5GxEqLk7hKWQ56YxPW/PQRUuKimPqmEIJOx8jHYeyo65pKbapbW464mvsKbaj4A==",
->>>>>>> master
             "dev": true,
             "requires": {
                 "@types/eslint-scope": "^3.7.3",
@@ -20202,7 +19822,7 @@
                 "acorn-import-assertions": "^1.7.6",
                 "browserslist": "^4.14.5",
                 "chrome-trace-event": "^1.0.2",
-                "enhanced-resolve": "^5.9.2",
+                "enhanced-resolve": "^5.8.3",
                 "es-module-lexer": "^0.9.0",
                 "eslint-scope": "5.1.1",
                 "events": "^3.2.0",
@@ -20224,13 +19844,6 @@
                     "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
                     "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
                     "dev": true
-<<<<<<< HEAD
-                },
-                "enhanced-resolve": {
-                    "version": "5.9.2",
-                    "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz",
-                    "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==",
-=======
                 },
                 "ajv": {
                     "version": "6.12.6",
@@ -20251,10 +19864,9 @@
                     "dev": true
                 },
                 "enhanced-resolve": {
-                    "version": "5.9.1",
-                    "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.1.tgz",
-                    "integrity": "sha512-jdyZMwCQ5Oj4c5+BTnkxPgDZO/BJzh/ADDmKebayyzNwjVX1AFCeGkOfxNx0mHi2+8BKC5VxUYiw3TIvoT7vhw==",
->>>>>>> master
+                    "version": "5.9.2",
+                    "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz",
+                    "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==",
                     "dev": true,
                     "requires": {
                         "graceful-fs": "^4.2.4",
@@ -20272,8 +19884,6 @@
                     "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
                     "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
                     "dev": true
-<<<<<<< HEAD
-=======
                 },
                 "schema-utils": {
                     "version": "3.1.1",
@@ -20285,7 +19895,6 @@
                         "ajv": "^6.12.5",
                         "ajv-keywords": "^3.5.2"
                     }
->>>>>>> master
                 },
                 "tapable": {
                     "version": "2.2.1",
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index b62b9b3ac..af731ce9f 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -350,7 +350,7 @@ export class CurrentUserUtils {
     }[] {
         if (doc.emptyPresentation === undefined) {
             doc.emptyPresentation = Docs.Create.PresDocument(new List<Doc>(),
-                { title: "Untitled Presentation", _viewType: CollectionViewType.Tree, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0", system: true, cloneFieldFilter: new List<string>(["system"]) });
+                { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0", system: true, cloneFieldFilter: new List<string>(["system"]) });
             ((doc.emptyPresentation as Doc).proto as Doc)["dragFactory-count"] = 0;
         }
         if (doc.emptyCollection === undefined) {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index ad6d90bc3..93d0c6936 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -168,8 +168,8 @@ export class DocumentManager {
         originalTarget = originalTarget ?? targetDoc;
         const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView;
         const docView = getFirstDocView(targetDoc, originatingDoc);
-        const wasHidden = targetDoc.hidden;  // 
-        if (wasHidden) runInAction(() => targetDoc.hidden = false);  // if the target is hidden, un-hide it here.
+        const wasHidden = targetDoc?.hidden;  // 
+        if (wasHidden && targetDoc) runInAction(() => targetDoc.hidden = false);  // if the target is hidden, un-hide it here.
         const focusAndFinish = (didFocus: boolean) => {
             if (originatingDoc?.isPushpin) {
                 if (!didFocus && !wasHidden) {  // don't toggle the hidden state if the doc was already un-hidden as part of this document traversal
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index dcb678046..3bf81d374 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -245,7 +245,7 @@ export class MainView extends React.Component {
             }));
         }
         const pres = Docs.Create.PresDocument(new List<Doc>(),
-            { title: "Untitled Trail", childDontRegisterViews: true, _viewType: CollectionViewType.Tree, _forceActive: true, treeViewOpen: true, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" });
+            { title: "Untitled Trail", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" });
         CollectionDockingView.AddSplit(pres, "left");
         this.userDoc.activePresentation = pres;
         Doc.AddDocToList(this.userDoc.myTrails as Doc, "data", pres);
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ff5c4bab1..751ae631b 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, WidthSym, StrListCast } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
@@ -13,7 +13,7 @@ import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from "../../documents/DocumentTypes";
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
-import { DocumentManager } from '../../util/DocumentManager';
+import { DocumentManager, DocFocusOrOpen } from '../../util/DocumentManager';
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { SelectionManager } from '../../util/SelectionManager';
 import { SnappingManager } from '../../util/SnappingManager';
@@ -31,6 +31,8 @@ import { CollectionTreeView } from './CollectionTreeView';
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TreeView.scss";
 import React = require("react");
+import { PresMovement } from '../nodes/trails/PresEnums';
+import { PresBox } from '../nodes/trails';
 
 export interface TreeViewProps {
     treeView: CollectionTreeView;
@@ -112,13 +114,24 @@ export class TreeView extends React.Component<TreeViewProps> {
     @computed get dataDoc() { return this.doc[DataSym]; }
     @computed get layoutDoc() { return Doc.Layout(this.doc); }
     @computed get fieldKey() { return Doc.LayoutFieldKey(this.doc); }
-    @computed get childDocs() { return this.childDocList(this.fieldKey); }
+    // @computed get childDocs() { return this.childDocList(this.fieldKey); }
+    @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); }
     @computed get childLinks() { return this.childDocList("links"); }
     @computed get childAliases() { return this.childDocList("aliases"); }
     @computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); }
     @computed get selected() { return SelectionManager.IsSelected(this._docRef); }
     //      SelectionManager.Views().lastElement()?.props.Document === this.props.document; }
 
+    @observable _presTimer!: NodeJS.Timeout;
+    @observable _presKeyEventsActive: boolean = false;
+
+    @observable _selectedArray: ObservableMap = new ObservableMap<Doc, any>();
+    // the selected item's index
+    @computed get itemIndex() { return NumCast(this.doc._itemIndex); }
+    // the item that's active 
+    @computed get activeItem() { return Cast(this.childDocs[NumCast(this.doc._itemIndex)], Doc, null); }
+    @computed get targetDoc() { return Cast(this.activeItem?.presentationTargetDoc, Doc, null); }
+
     childDocList(field: string) {
         const layout = Cast(Doc.LayoutField(this.doc), Doc, null);
         return (this.props.dataDoc ? DocListCastOrNull(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
@@ -546,7 +559,80 @@ export class TreeView extends React.Component<TreeViewProps> {
         const icons = StrListCast(this.doc.childContextMenuIcons);
         return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
     }
-    onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
+
+    // TODO: currently doc focus works, but can't seem to edit title
+    // onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
+    onChildClick = () => {
+        return this.props.onChildClick?.() ?? (ScriptField.MakeFunction(`DocFocusOrOpen(self)`)! || this._editTitleScript?.())
+    }
+
+    //Regular click zoom to document on canvas
+    @action
+    selectElement = async (doc: Doc) => {
+        const context = Cast(doc.context, Doc, null);
+        this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
+        if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0);
+        else this.updateCurrentPresentation(context);
+
+        if (this.activeItem.setPosition &&
+            this.activeItem.y !== undefined &&
+            this.activeItem.x !== undefined &&
+            this.targetDoc.x !== undefined &&
+            this.targetDoc.y !== undefined) {
+            const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms));
+            const time = 10;
+            const ydiff = NumCast(this.activeItem.y) - NumCast(this.targetDoc.y);
+            const xdiff = NumCast(this.activeItem.x) - NumCast(this.targetDoc.x);
+
+            for (let i = 0; i < time; i++) {
+                this.targetDoc.x = NumCast(this.targetDoc.x) + xdiff / time;
+                this.targetDoc.y = NumCast(this.targetDoc.y) + ydiff / time;
+                await timer(0.1);
+            }
+        }
+    }
+
+    static keyEventsWrapper = (e: KeyboardEvent) => {
+        PresBox.Instance.keyEvents(e);
+    }
+
+    @action
+    updateCurrentPresentation = (pres?: Doc) => {
+        if (pres) Doc.UserDoc().activePresentation = pres;
+        else Doc.UserDoc().activePresentation = this.doc;
+        document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
+        document.addEventListener("keydown", PresBox.keyEventsWrapper, true);
+        this._presKeyEventsActive = true;
+        // PresBox.Instance = this;
+    }
+
+    //The function that is called when a document is clicked or reached through next or back.
+    //it'll also execute the necessary actions if presentation is playing.
+    public gotoDocument = action((index: number, from?: Doc, group?: boolean) => {
+        Doc.UnBrushAllDocs();
+        if (index >= 0 && index < this.childDocs.length) {
+            this.doc._itemIndex = index;
+            const activeItem: Doc = this.activeItem;
+            const targetDoc: Doc = this.targetDoc;
+
+            if (targetDoc) {
+                targetDoc && runInAction(() => {
+                    if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0;
+                    else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
+                });
+                setTimeout(() => targetDoc.focusSpeed = 500, this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510);
+            }
+            if (targetDoc?.lastFrame !== undefined) {
+                targetDoc._currentFrame = 0;
+            }
+            if (!group) this._selectedArray.clear();
+            this.childDocs[index] && this._selectedArray.set(this.childDocs[index], undefined); //TODO: needs more work on selected arrayUpdate selected array
+            // if (this.layoutDoc._viewType === "stacking" && !group) this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
+            // this.onHideDocument(); //Handles hide after/before
+        }
+    });
+
+
 
     onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
 
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index ca13590de..0c960a95b 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -229,6 +229,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
 
         const script = ScriptCast(this.rootDoc.script);
+        if (!script) { return null };
 
         let noviceList: string[] = [];
         let text: string | undefined;
-- 
cgit v1.2.3-70-g09d2


From 594f585b74bf6ecec3795a4b780da619c66f341d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 13 Apr 2022 10:57:08 -0400
Subject: added images to treeView bullets for docs with icons.  fixed
 following pushpin links to prototypes to  toggle delegates when shown.  gave
 groups a default padding.  fixed creating icons to not create unnecessary
 template docs.  fixed toggling isPushpin. made summaries simple links instead
 of templates.

---
 src/client/documents/Documents.ts                  | 38 ++++++++++++----------
 src/client/util/DocumentManager.ts                 |  5 +--
 src/client/views/DocumentDecorations.tsx           |  5 ++-
 src/client/views/StyleProvider.tsx                 | 13 ++++++--
 src/client/views/collections/TreeView.scss         |  2 +-
 src/client/views/collections/TreeView.tsx          |  5 +--
 .../collections/collectionFreeForm/MarqueeView.tsx |  9 ++---
 src/client/views/nodes/DocumentView.tsx            |  8 +++--
 src/client/views/nodes/LinkDocPreview.tsx          |  9 ++++-
 9 files changed, 59 insertions(+), 35 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 652f8e7e0..465cdf3ec 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -223,6 +223,7 @@ export class DocumentOptions {
     dockingConfig?: string;
     annotationOn?: Doc;
     isPushpin?: boolean;
+    isGroup?: boolean; // whether a collection should use a grouping UI behavior
     _removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
 
     // BACKGROUND GRID
@@ -807,7 +808,7 @@ export namespace Docs {
         }
 
         export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
-            const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Freeform }, id);
+            const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _viewType: CollectionViewType.Freeform }, id);
             documents.map(d => d.context = inst);
             return inst;
         }
@@ -1317,22 +1318,25 @@ export namespace DocUtils {
         const _height = NumCast(doc._height);
         const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false };
 
-        let fieldTemplate: Opt<Doc>;
-        if (doc.data instanceof RichTextField || typeof (doc.data) === "string") {
-            fieldTemplate = Docs.Create.TextDocument("", options);
-        } else if (doc.data instanceof PdfField) {
-            fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options);
-        } else if (doc.data instanceof VideoField) {
-            fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options);
-        } else if (doc.data instanceof AudioField) {
-            fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options);
-        } else if (doc.data instanceof ImageField) {
-            fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options);
-        }
-        const docTemplate = docLayoutTemplate || creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
-
-        fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate);
-        docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
+        if (docLayoutTemplate) {
+            Doc.ApplyTemplateTo(docLayoutTemplate, doc, customName, undefined);
+        } else {
+            let fieldTemplate: Opt<Doc>;
+            if (doc.data instanceof RichTextField || typeof (doc.data) === "string") {
+                fieldTemplate = Docs.Create.TextDocument("", options);
+            } else if (doc.data instanceof PdfField) {
+                fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options);
+            } else if (doc.data instanceof VideoField) {
+                fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options);
+            } else if (doc.data instanceof AudioField) {
+                fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options);
+            } else if (doc.data instanceof ImageField) {
+                fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options);
+            }
+            const docTemplate = creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
+            fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate);
+            docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
+        }
     }
     export function makeCustomView(doc: Doc, custom: boolean, layout: string) {
         Doc.setNativeView(doc);
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 1d603e18f..fb50ecb4a 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -176,12 +176,13 @@ export class DocumentManager {
             });  // if the target is hidden, un-hide it here.
         }
         const focusAndFinish = (didFocus: boolean) => {
+            const finalTargetDoc = docView?.Document ?? targetDoc;
             if (originatingDoc?.isPushpin) {
                 if (!didFocus && !wasHidden) {  // don't toggle the hidden state if the doc was already un-hidden as part of this document traversal
-                    targetDoc.hidden = !targetDoc.hidden;
+                    finalTargetDoc.hidden = !finalTargetDoc.hidden;
                 }
             } else {
-                targetDoc.hidden && (targetDoc.hidden = undefined);
+                finalTargetDoc.hidden && (finalTargetDoc.hidden = undefined);
                 !noSelect && docView?.select(false);
             }
             finished?.();
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 062ca1181..a8d91e0a2 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -453,6 +453,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
             return (collectionAcl === AclAdmin || collectionAcl === AclEdit || GetEffectiveAcl(docView.rootDoc) === AclAdmin);
         });
     }
+    @computed get hasIcons() {
+        return SelectionManager.Views().some(docView => docView.rootDoc.layoutKey === "layout_icon");
+    }
 
     render() {
         const bounds = this.Bounds;
@@ -516,7 +519,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                     left: bounds.x - this._resizeBorderWidth / 2,
                     top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
                 }}>
-                    {!canDelete ? <div /> : topBtn("close", "times", undefined, this.onCloseClick, "Close")}
+                    {!canDelete ? <div /> : topBtn("close", this.hasIcons ? "times" : "window-maximize", undefined, this.onCloseClick, "Close")}
                     {titleArea}
                     {!canOpen ? (null) : topBtn("open", "external-link-alt", this.onMaximizeDown, undefined, "Open in Tab (ctrl: as alias, shift: in new collection)")}
                     {hideResizers ? (null) :
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 9803f9782..dba290b46 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -3,10 +3,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import 'golden-layout/src/css/goldenlayout-base.css';
 import 'golden-layout/src/css/goldenlayout-dark-theme.css';
 import { action, runInAction } from 'mobx';
+import { extname } from 'path';
 import { Doc, Opt, StrListCast } from "../../fields/Doc";
 import { List } from '../../fields/List';
 import { listSpec } from '../../fields/Schema';
-import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types";
+import { BoolCast, Cast, ImageCast, NumCast, StrCast } from "../../fields/Types";
 import { DashColor, lightOrDark } from '../../Utils';
 import { DocumentType } from '../documents/DocumentTypes';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
@@ -88,7 +89,15 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
     const showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle);
     const random = (min: number, max: number, x: number, y: number) => /* min should not be equal to max */ min + ((Math.abs(x * y) * 9301 + 49297) % 233280 / 233280) * (max - min);
     switch (property.split(":")[0]) {
-        case StyleProp.TreeViewIcon: return Doc.toIcon(doc, isOpen);
+        case StyleProp.TreeViewIcon:
+            const icon = Cast(doc?.layout_icon, Doc, null) ? Doc.expandTemplateLayout(Cast(doc?.layout_icon, Doc, null), doc) : undefined;
+            if (icon && ImageCast(doc?.icon, ImageCast(doc?.data))) {
+                const img = ImageCast(doc?.icon, ImageCast(doc?.data));
+                const ext = extname(img.url.href);
+                const url = doc?.icon ? img.url.href : img.url.href.replace(ext, "_s" + ext);
+                return <img src={url} width={20} height={15} style={{ margin: "auto", display: "block", objectFit: "contain" }} />;
+            }
+            return Doc.toIcon(doc, isOpen);
         case StyleProp.DocContents: return undefined;
         case StyleProp.WidgetColor: return isAnnotated ? Colors.LIGHT_BLUE : darkScheme() ? "lightgrey" : "dimgrey";
         case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 2e33d3564..7c75810d3 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -47,7 +47,7 @@
         width: $TREE_BULLET_WIDTH;
         color: $medium-gray;
         margin-top: 3px;
-        transform: scale(1.3, 1.3);
+       // transform: scale(1.3, 1.3); // bcz: why was this here?  It makes displaying images in the treeView for documents that have icons harder.
         border: #80808030 1px solid;
         border-radius: 4px;
     }
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ff5c4bab1..c2d0983da 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -31,6 +31,7 @@ import { CollectionTreeView } from './CollectionTreeView';
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TreeView.scss";
 import React = require("react");
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 
 export interface TreeViewProps {
     treeView: CollectionTreeView;
@@ -471,7 +472,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             onClick={this.bulletClick}
             style={this.props.treeView.outlineMode ? { opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity) } : {
                 color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
-                opacity: checked === "unchecked" ? undefined : 0.4
+                opacity: checked === "unchecked" || typeof iconType !== "string" ? undefined : 0.4
             }}>
             {this.props.treeView.outlineMode ?
                 !(this.doc.text as RichTextField)?.Text ? (null) :
@@ -484,7 +485,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                                     checked === "unchecked" ? "square" :
                                         !this.treeViewOpen ? "caret-right" : "caret-down"} />
                     </div>
-                    {this.onCheckedClick ? (null) : <FontAwesomeIcon icon={iconType} />}
+                    {this.onCheckedClick ? (null) : typeof iconType === "string" ? <FontAwesomeIcon icon={iconType as IconProp} /> : iconType}
                 </div>
             }
         </div>;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index b8f687489..5405ab500 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -519,13 +519,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             d.y = NumCast(d.y) - this.Bounds.top;
             return d;
         });
-        const summary = Docs.Create.TextDocument("", { x: this.Bounds.left, y: this.Bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
-        const portal = Doc.MakeAlias(summary);
-        Doc.GetProto(summary)[Doc.LayoutFieldKey(summary) + "-annotations"] = new List<Doc>(selected);
-        Doc.GetProto(summary).layout_portal = CollectionView.LayoutString(Doc.LayoutFieldKey(summary) + "-annotations");
-        summary._backgroundColor = "#e2ad32";
-        portal.layoutKey = "layout_portal";
-        portal.title = "document collection";
+        const summary = Docs.Create.TextDocument("", { _backgroundColor: "#e2ad32", x: this.Bounds.left, y: this.Bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
+        const portal = Docs.Create.FreeformDocument(selected, { isGroup: true, backgroundColor: "transparent" });
         DocUtils.MakeLink({ doc: summary }, { doc: portal }, "summarizing", "");
 
         this.props.addLiveTextDocument(summary);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 195f6c9e5..8bf9348c7 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -594,8 +594,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @undoBatch @action
     toggleFollowLink = (location: Opt<string>, zoom: boolean, setPushpin: boolean): void => {
         this.Document.ignoreClick = false;
-        this.Document._isLinkButton = !this.Document._isLinkButton;
-        setPushpin && (this.Document.isPushpin = this.Document._isLinkButton);
+        if (setPushpin) {
+            this.Document.isPushpin = !this.Document.isPushpin;
+            this.Document._isLinkButton = this.Document.isPushpin || this.Document._isLinkButton;
+        } else {
+            this.Document._isLinkButton = !this.Document._isLinkButton;
+        }
         if (this.Document._isLinkButton && !this.onClickHandler) {
             this.Document.followLinkZoom = zoom;
             this.Document.followLinkLocation = location;
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index d5f3f3b4e..eca2e3cfd 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -15,6 +15,7 @@ import { DocumentView, DocumentViewSharedProps } from "./DocumentView";
 import './LinkDocPreview.scss';
 import React = require("react");
 import { DocumentType } from '../../documents/DocumentTypes';
+import { DragManager } from '../../util/DragManager';
 
 interface LinkDocPreviewProps {
     linkDoc?: Doc;
@@ -137,7 +138,13 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
     @computed get previewHeader() {
         return !this._linkDoc || !this._targetDoc || !this._linkSrc ? (null) :
             <div className="linkDocPreview-info" ref={this._infoRef}>
-                <div className="linkDocPreview-title">
+                <div className="linkDocPreview-title" style={{ pointerEvents: "all" }}
+                    onPointerDown={e => {
+                        DragManager.StartDocumentDrag([this._infoRef.current!],
+                            new DragManager.DocumentDragData([this._targetDoc!]), e.pageX, e.pageY);
+                        e.stopPropagation();
+                        LinkDocPreview.Clear();
+                    }}>
                     {StrCast(this._targetDoc.title).length > 16 ? StrCast(this._targetDoc.title).substr(0, 16) + "..." : this._targetDoc.title}
                     <p className="linkDocPreview-description"> {StrCast(this._linkDoc.description)}</p>
                 </div>
-- 
cgit v1.2.3-70-g09d2


From 18d21c0616adbdc7e0d0619c3c2d8bdf9b34cc01 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 22 Apr 2022 21:39:08 -0400
Subject: changes to allow PresBox to render using a Tree view

---
 src/client/documents/Documents.ts                 |  7 +--
 src/client/views/collections/TabDocView.tsx       |  9 ++++
 src/client/views/collections/TreeView.tsx         | 54 ++++++++++++-----------
 src/client/views/nodes/DocumentView.tsx           |  3 +-
 src/client/views/nodes/trails/PresBox.tsx         | 13 +++---
 src/client/views/nodes/trails/PresElementBox.scss |  2 +-
 src/client/views/nodes/trails/PresElementBox.tsx  |  4 +-
 7 files changed, 54 insertions(+), 38 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 69ea21541..49e53a214 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -284,6 +284,7 @@ export class DocumentOptions {
     treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view
     treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view
     treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
+    treeViewGrowsHorizontally?: boolean; // whether an embedded tree view of the document can grow horizontally without growing vertically
 
     // Action Button
     buttonMenu?: boolean; // whether a action button should be displayed 
@@ -365,7 +366,7 @@ export namespace Docs {
             [DocumentType.RTF, {
                 layout: { view: FormattedTextBox, dataField: "text" },
                 options: {
-                    _height: 150, _xMargin: 10, _yMargin: 10, nativeDimModifiable: true, nativeHeightUnfrozen: true,
+                    _height: 150, _xMargin: 10, _yMargin: 10, nativeDimModifiable: true, nativeHeightUnfrozen: true, treeViewGrowsHorizontally: true,
                     links: "@links(self)"
                 }
             }],
@@ -460,8 +461,8 @@ export namespace Docs {
                 options: { links: "@links(self)" }
             }],
             [DocumentType.SLIDER, {
-                layout: { view: SliderBox, dataField: defaultDataKey },
-                options: { links: "@links(self)" }
+                layout: { view: SliderBox, dataField: defaultDataKey, },
+                options: { links: "@links(self)", treeViewGrowsHorizontally: true }
             }],
             [DocumentType.PRES, {
                 layout: { view: PresBox, dataField: defaultDataKey },
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index bd3e810c9..136486f47 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -33,6 +33,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TabDocView.scss";
 import React = require("react");
+import { List } from '../../../fields/List';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
@@ -209,9 +210,17 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             const pinDoc = Doc.MakeAlias(doc);
             pinDoc.presentationTargetDoc = doc;
             pinDoc.title = doc.title + " - Slide";
+            pinDoc.data = new List<Doc>();  // the children of the alias' layout are the presentation slide children.  the alias' data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data
             pinDoc.presMovement = PresMovement.Zoom;
             pinDoc.groupWithUp = false;
             pinDoc.context = curPres;
+            // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements.  That way the PresBox could configure all of its children at render time
+            pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
+            pinDoc.treeViewHeaderWidth = "100%"; // forces the header to grow to be the same size as its largest sibling.
+            pinDoc.treeViewFieldKey = "data"; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field
+            pinDoc.treeViewExpandedView = "data";// in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view
+            pinDoc.treeViewGrowsHorizontally = true;// the document can expand horizontally when displayed as a tree view header  
+            pinDoc.treeViewHideHeader = true;  // this will force the document to render itself as the tree view header
             const presArray: Doc[] = PresBox.Instance?.sortArray();
             const size: number = PresBox.Instance?._selectedArray.size;
             const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index c2d0983da..a35304787 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -112,7 +112,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containerCollection.maxEmbedHeight, 200); }
     @computed get dataDoc() { return this.doc[DataSym]; }
     @computed get layoutDoc() { return Doc.Layout(this.doc); }
-    @computed get fieldKey() { return Doc.LayoutFieldKey(this.doc); }
+    @computed get fieldKey() { return StrCast(this.doc._treeViewFieldKey, Doc.LayoutFieldKey(this.doc)); }
     @computed get childDocs() { return this.childDocList(this.fieldKey); }
     @computed get childLinks() { return this.childDocList("links"); }
     @computed get childAliases() { return this.childDocList("aliases"); }
@@ -156,18 +156,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             docView.select(false);
         }
     }
-    @action
-    openLevel = (docView: DocumentView) => {
-        if (this.props.document.isFolder || Doc.IsSystem(this.props.document)) {
-            this.treeViewOpen = !this.treeViewOpen;
-        } else {
-            // choose an appropriate alias or make one. --- choose the first alias that (1) user owns,  (2) has no context field ... otherwise make a new alias
-            // this.props.addDocTab(CurrentUserUtils.ActiveDashboard.isShared ? Doc.MakeAlias(this.props.document) : this.props.document, "add:right");
-            const bestAlias = DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
-            this.props.addDocTab(bestAlias ?? Doc.MakeAlias(this.props.document), "add:right");
 
-        }
-    }
     constructor(props: any) {
         super(props);
         if (!TreeView._openLevelScript) {
@@ -379,8 +368,14 @@ export class TreeView extends React.Component<TreeViewProps> {
         return rows;
     }
 
-    rtfWidth = () => Math.min(this.layoutDoc?.[WidthSym](), (this.props.panelWidth() - treeBulletWidth())) / (this.props.treeView.props.scaling?.() || 1);
-    rtfHeight = () => this.rtfWidth() <= this.layoutDoc?.[WidthSym]() ? Math.min(this.layoutDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
+    rtfWidth = () => {
+        const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ""))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
+        return Math.min(layout[WidthSym](), (this.props.panelWidth() - treeBulletWidth())) / (this.props.treeView.props.scaling?.() || 1);
+    }
+    rtfHeight = () => {
+        const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ""))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
+        return this.rtfWidth() <= layout[WidthSym]() ? Math.min(layout[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
+    }
     rtfOutlineHeight = () => Math.max(this.layoutDoc?.[HeightSym](), treeBulletWidth());
     expandPanelHeight = () => {
         if (this.layoutDoc._fitWidth) return this.docHeight();
@@ -580,13 +575,20 @@ export class TreeView extends React.Component<TreeViewProps> {
     }
     onKeyDown = (e: React.KeyboardEvent) => {
         if (this.doc.treeViewHideHeader || this.props.treeView.outlineMode) {
-            e.stopPropagation();
-            e.preventDefault();
             switch (e.key) {
-                case "Tab": setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150);
+                case "Tab":
+                    e.stopPropagation();
+                    e.preventDefault();
+                    setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150);
                     return UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true), "tab");
-                case "Backspace": return !(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc);
-                case "Enter": return UndoManager.RunInBatch(this.makeTextCollection, "bullet");
+                case "Backspace":
+                    e.stopPropagation();
+                    e.preventDefault();
+                    return !(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc);
+                case "Enter":
+                    e.stopPropagation();
+                    e.preventDefault();
+                    return UndoManager.RunInBatch(this.makeTextCollection, "bullet");
             }
         }
     }
@@ -691,7 +693,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     renderBulletHeader = (contents: JSX.Element, editing: boolean) => {
         return <>
             <div className={`treeView-header` + (editing ? "-editing" : "")} key="titleheader"
-                style={{ width: "max-content" }}
+                style={{ width: StrCast(this.doc.treeViewHeaderWidth, "max-content") }}
                 ref={this._header}
                 onClick={this.ignoreEvent}
                 onPointerDown={this.ignoreEvent}
@@ -705,8 +707,7 @@ export class TreeView extends React.Component<TreeViewProps> {
 
 
     renderEmbeddedDocument = (asText: boolean, isActive: () => boolean | undefined) => {
-        const layout = StrCast(Doc.LayoutField(this.layoutDoc));
-        const isExpandable = layout.includes(FormattedTextBox.name) || layout.includes(SliderBox.name);
+        const isExpandable = this.doc._treeViewGrowsHorizontally;
         const panelWidth = asText || isExpandable ? this.rtfWidth : this.expandPanelWidth;
         const panelHeight = asText ? this.rtfOutlineHeight : isExpandable ? this.rtfHeight : this.expandPanelHeight;
         return <DocumentView key={this.doc[Id]} ref={action((r: DocumentView | null) => this._dref = r)}
@@ -717,6 +718,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             NativeWidth={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfWidth : undefined}
             NativeHeight={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfHeight : undefined}
             LayoutTemplateString={asText ? FormattedTextBox.LayoutString("text") : undefined}
+            LayoutTemplate={this.props.treeView.props.childLayoutTemplate}
             isContentActive={isActive}
             isDocumentActive={isActive}
             styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
@@ -759,10 +761,10 @@ export class TreeView extends React.Component<TreeViewProps> {
     }
 
     // renders the document in the header field instead of a text proxy.
-    @computed get renderDocumentAsHeader() {
+    renderDocumentAsHeader = (asText: boolean) => {
         return <>
             {this.renderBullet}
-            {this.renderEmbeddedDocument(true, this.props.isContentActive)}
+            {this.renderEmbeddedDocument(asText, this.props.isContentActive)}
         </>;
     }
 
@@ -794,9 +796,9 @@ export class TreeView extends React.Component<TreeViewProps> {
                 //onPointerDown={e => this.props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document
                 onKeyDown={this.onKeyDown}>
                 <li className="collection-child">
-                    {hideTitle && this.doc.type !== DocumentType.RTF ?
+                    {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader ? // should test for prop 'treeViewRenderDocWithBulletAsHeader"
                         this.renderEmbeddedDocument(false, returnFalse) :
-                        this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader : this.renderTitleAsHeader, this._editTitle)}
+                        this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeViewRenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)}
                 </li>
             </div>;
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 1eaff3c1c..bcf00e88d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1308,6 +1308,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         TraceMobx();
         const xshift = () => (this.props.Document.isInkMask ? InkingStroke.MaskDim : Math.abs(this.Xshift) <= 0.001 ? this.props.PanelWidth() : undefined);
         const yshift = () => (this.props.Document.isInkMask ? InkingStroke.MaskDim : Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined);
+        const isPresTreeElement: boolean = this.props.treeViewDoc?.type === DocumentType.PRES;
         const isButton: boolean = this.props.Document.type === DocumentType.FONTICON || this.props.Document._viewType === CollectionViewType.Linear;
         return (<div className="contentFittingDocumentView">
             {!this.props.Document || !this.props.PanelWidth() ? (null) : (
@@ -1316,7 +1317,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                         transition: this.props.dataTransition,
                         position: this.props.Document.isInkMask ? "absolute" : undefined,
                         transform: isButton ? undefined : `translate(${this.centeringX}px, ${this.centeringY}px)`,
-                        width: isButton ? "100%" : xshift() ?? `${100 * (this.props.PanelWidth() - this.Xshift * 2) / this.props.PanelWidth()}%`,
+                        width: isButton || isPresTreeElement ? "100%" : xshift() ?? `${100 * (this.props.PanelWidth() - this.Xshift * 2) / this.props.PanelWidth()}%`,
                         height: (!this.props.ignoreAutoHeight && this.layoutDoc.autoHeight && this.layoutDoc.type === DocumentType.RTF) || isButton || this.props.forceAutoHeight ? undefined : yshift() ?? (this.fitWidth ? `${this.panelHeight}px` :
                             `${100 * this.effectiveNativeHeight / this.effectiveNativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%`),
                     }}>
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 2e312ee51..c9c74eca4 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -122,7 +122,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         if (Doc.UserDoc().activePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this);
         if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations.
             Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({
-                title: "pres element template", type: DocumentType.PRESELEMENT, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"
+                title: "pres element template", type: DocumentType.PRESELEMENT, _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"
             }));
             // this script will be called by each presElement to get rendering-specific info that the PresBox knows about but which isn't written to the PresElement
             // this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent
@@ -308,7 +308,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             }
             if (!group) this._selectedArray.clear();
             this.childDocs[index] && this._selectedArray.set(this.childDocs[index], undefined); //Update selected array
-            if (this.layoutDoc._viewType === "stacking" && !group) this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
+            if ([CollectionViewType.Stacking, CollectionViewType.Tree].includes(this.layoutDoc._viewType as any) && !group) this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
             this.onHideDocument(); //Handles hide after/before
         }
     });
@@ -620,9 +620,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         //@ts-ignore
         const viewType = e.target.selectedOptions[0].value as CollectionViewType;
         // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
-        viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined);
+        [CollectionViewType.Tree || CollectionViewType.Stacking].includes(viewType) && (this.rootDoc._pivotField = undefined);
         this.rootDoc._viewType = viewType;
-        if (viewType === CollectionViewType.Stacking) this.layoutDoc._gridGap = 0;
+        if ([CollectionViewType.Tree || CollectionViewType.Stacking].includes(viewType)) this.layoutDoc._gridGap = 0;
     });
 
     /**
@@ -696,7 +696,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         });
         return true;
     }
-    childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement;
+    childLayoutTemplate = () => ![CollectionViewType.Stacking, CollectionViewType.Tree].includes(this.rootDoc._viewType as any) ? undefined : this.presElement;
     removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc);
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight() - 40;
@@ -2262,6 +2262,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     onChange={this.viewChanged}
                     value={mode}>
                     <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Stacking}>List</option>
+                    <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Tree}>Tree</option>
                     <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel3D}>3D Carousel</option>
                 </select>}
                 <div className="presBox-presentPanel" style={{ opacity: this.childDocs.length ? 1 : 0.3 }}>
@@ -2459,7 +2460,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
 }
 ScriptingGlobals.add(function lookupPresBoxField(container: Doc, field: string, data: Doc) {
     if (field === 'indexInPres') return DocListCast(container[StrCast(container.presentationFieldKey)]).indexOf(data);
-    if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 35 : 31;
+    if (field === 'presCollapsedHeight') return [CollectionViewType.Tree || CollectionViewType.Stacking].includes(container._viewType as any) ? 35 : 31;
     if (field === 'presStatus') return container.presStatus;
     if (field === '_itemIndex') return container._itemIndex;
     if (field === 'presBox') return container;
diff --git a/src/client/views/nodes/trails/PresElementBox.scss b/src/client/views/nodes/trails/PresElementBox.scss
index 1ad4b820e..a178be910 100644
--- a/src/client/views/nodes/trails/PresElementBox.scss
+++ b/src/client/views/nodes/trails/PresElementBox.scss
@@ -42,7 +42,7 @@ $slide-active: #5B9FDD;
     background-color: #d5dce2;
     border-radius: 5px;
     height: calc(100% - 7px);
-    width: calc(100% - 15px);
+    width: 100%;
     display: grid;
     grid-template-rows: 16px 10px auto;
     grid-template-columns: max-content max-content max-content max-content auto;
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index a4ec559f5..5c16d743a 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -23,6 +23,7 @@ import { PresBox } from "./PresBox";
 import "./PresElementBox.scss";
 import { PresMovement } from "./PresEnums";
 import React = require("react");
+import { CollectionViewType } from "../../collections/CollectionView";
 /**
  * This class models the view a document added to presentation will have in the presentation.
  * It involves some functionality for its buttons and options.
@@ -87,6 +88,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     isContentActive={this.props.isContentActive}
                     addDocTab={returnFalse}
                     pinToPres={returnFalse}
+                    fitContentsToDoc={returnTrue}
                     PanelWidth={this.embedWidth}
                     PanelHeight={this.embedHeight}
                     ScreenToLocalTransform={Transform.Identity}
@@ -321,7 +323,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
                         boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
                     }}>
-                    <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
+                    <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - (this.presBox._viewType === CollectionViewType.Stacking ? 195 : 220)) : toolbarWidth - (this.presBox._viewType === CollectionViewType.Stacking ? 105 : 145), cursor: isSelected ? 'text' : 'grab' }}>
                         <EditableView
                             ref={this._titleRef}
                             editing={!isSelected ? false : undefined}
-- 
cgit v1.2.3-70-g09d2


From afeb2ac0d4aa914f94596e08fe4030abba050496 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 23 Apr 2022 16:11:14 -0400
Subject: more fixes for treeView to support  hierarchical presentations.

---
 src/client/views/DocComponent.tsx                |  4 ++-
 src/client/views/DocumentButtonBar.tsx           | 46 ++++++++++++------------
 src/client/views/collections/TabDocView.tsx      |  3 +-
 src/client/views/collections/TreeView.tsx        |  9 +++--
 src/client/views/nodes/trails/PresBox.tsx        |  8 ++---
 src/client/views/nodes/trails/PresElementBox.tsx |  4 +++
 6 files changed, 44 insertions(+), 30 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 73a261c40..79aaf2158 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -11,6 +11,7 @@ import { DocUtils } from '../documents/Documents';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
 import { InteractionUtils } from '../util/InteractionUtils';
 import { UndoManager } from '../util/UndoManager';
+import { DocumentView } from './nodes/DocumentView';
 import { Touchable } from './Touchable';
 
 
@@ -41,6 +42,7 @@ interface ViewBoxBaseProps {
     Document: Doc;
     DataDoc?: Doc;
     ContainingCollectionDoc: Opt<Doc>;
+    DocumentView?: () => DocumentView;
     fieldKey: string;
     layerProvider?: (doc: Doc, assign?: boolean) => boolean;
     isSelected: (outsideReaction?: boolean) => boolean;
@@ -63,7 +65,7 @@ export function ViewBoxBaseComponent<P extends ViewBoxBaseProps>() {
         // key where data is stored
         @computed get fieldKey() { return this.props.fieldKey; }
 
-        lookupField = (field: string) => ScriptCast(this.layoutDoc.lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field, container: this.props.ContainingCollectionDoc }).result;
+        lookupField = (field: string) => ScriptCast(this.layoutDoc.lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field, container: this.props.DocumentView?.().props.treeViewDoc ?? this.props.ContainingCollectionDoc }).result;
 
         isContentActive = (outsideReaction?: boolean) => (
             this.props.isContentActive?.() === false ? false :
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index aa9318310..9b95f1525 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -215,28 +215,30 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
     pinWithView = (targetDoc: Doc) => {
         if (targetDoc) {
             TabDocView.PinDoc(targetDoc);
-            const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
-            const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetDoc.type as any) || targetDoc._viewType === CollectionViewType.Stacking;
-            const pannable: boolean = ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG);
-            if (scrollable) {
-                const scroll = targetDoc._scrollTop;
-                activeDoc.presPinView = true;
-                activeDoc.presPinViewScroll = scroll;
-            } else if (targetDoc.type === DocumentType.VID) {
-                activeDoc.presPinTimecode = targetDoc._currentTimecode;
-            } else if (pannable) {
-                const x = targetDoc._panX;
-                const y = targetDoc._panY;
-                const scale = targetDoc._viewScale;
-                activeDoc.presPinView = true;
-                activeDoc.presPinViewX = x;
-                activeDoc.presPinViewY = y;
-                activeDoc.presPinViewScale = scale;
-            } else if (targetDoc.type === DocumentType.COMPARISON) {
-                const width = targetDoc._clipWidth;
-                activeDoc.presPinClipWidth = width;
-                activeDoc.presPinView = true;
-            }
+            setTimeout(() => {
+                const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
+                const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetDoc.type as any) || targetDoc._viewType === CollectionViewType.Stacking;
+                const pannable: boolean = ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG);
+                if (scrollable) {
+                    const scroll = targetDoc._scrollTop;
+                    activeDoc.presPinView = true;
+                    activeDoc.presPinViewScroll = scroll;
+                } else if (targetDoc.type === DocumentType.VID) {
+                    activeDoc.presPinTimecode = targetDoc._currentTimecode;
+                } else if (pannable) {
+                    const x = targetDoc._panX;
+                    const y = targetDoc._panY;
+                    const scale = targetDoc._viewScale;
+                    activeDoc.presPinView = true;
+                    activeDoc.presPinViewX = x;
+                    activeDoc.presPinViewY = y;
+                    activeDoc.presPinViewScale = scale;
+                } else if (targetDoc.type === DocumentType.COMPARISON) {
+                    const width = targetDoc._clipWidth;
+                    activeDoc.presPinClipWidth = width;
+                    activeDoc.presPinView = true;
+                }
+            });
         }
     }
 
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 136486f47..98d6049f0 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -217,9 +217,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements.  That way the PresBox could configure all of its children at render time
             pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
             pinDoc.treeViewHeaderWidth = "100%"; // forces the header to grow to be the same size as its largest sibling.
+            pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc.
             pinDoc.treeViewFieldKey = "data"; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field
             pinDoc.treeViewExpandedView = "data";// in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view
-            pinDoc.treeViewGrowsHorizontally = true;// the document can expand horizontally when displayed as a tree view header  
+            pinDoc.treeViewGrowsHorizontally = true;// the document expands horizontally when displayed as a tree view header  
             pinDoc.treeViewHideHeader = true;  // this will force the document to render itself as the tree view header
             const presArray: Doc[] = PresBox.Instance?.sortArray();
             const size: number = PresBox.Instance?._selectedArray.size;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index a35304787..342424d41 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -110,7 +110,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     @computed get treeViewOpen() { return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, "treeViewOpen", "boolean", true)) || this._transientOpenState; }
     @computed get treeViewExpandedView() { return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView; }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containerCollection.maxEmbedHeight, 200); }
-    @computed get dataDoc() { return this.doc[DataSym]; }
+    @computed get dataDoc() { return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DataSym]; }
     @computed get layoutDoc() { return Doc.Layout(this.doc); }
     @computed get fieldKey() { return StrCast(this.doc._treeViewFieldKey, Doc.LayoutFieldKey(this.doc)); }
     @computed get childDocs() { return this.childDocList(this.fieldKey); }
@@ -280,7 +280,12 @@ export class TreeView extends React.Component<TreeViewProps> {
             (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc), true as boolean);
         const move = (!dropAction || dropAction === "proto" || dropAction === "move" || dropAction === "same") && moveDocument;
         if (canAdd) {
-            return UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === "proto" ? addDoc(d) : false) : addDoc(d)) || added, false));
+            return UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) =>
+                (move ?
+                    move(d, undefined, addDoc) || (dropAction === "proto" ? addDoc(d) : false)
+                    :
+                    addDoc(d)) || added,
+                false));
         }
         return false;
     }
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index c9c74eca4..30ad43562 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -96,7 +96,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @observable private openMovementDropdown: boolean = false;
     @observable private openEffectDropdown: boolean = false;
     @observable private presentTools: boolean = false;
-    @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); }
+    @computed get childDocs() { return DocListCast(this.rootDoc[this.fieldKey]); }
     @computed get tagDocs() {
         const tagDocs: Doc[] = [];
         for (const doc of this.childDocs) {
@@ -697,7 +697,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return true;
     }
     childLayoutTemplate = () => ![CollectionViewType.Stacking, CollectionViewType.Tree].includes(this.rootDoc._viewType as any) ? undefined : this.presElement;
-    removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc);
+    removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc);
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight() - 40;
     isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) &&
@@ -2256,14 +2256,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const isMini: boolean = this.toolbarWidth <= 100;
         return (
             <div className="presBox-buttons" style={{ display: !this.rootDoc._chromeHidden ? "none" : undefined }}>
-                {isMini || Doc.UserDoc().noviceMode ? (null) : <select className="presBox-viewPicker"
+                {isMini ? (null) : <select className="presBox-viewPicker"
                     style={{ display: this.layoutDoc.presStatus === "edit" ? "block" : "none" }}
                     onPointerDown={e => e.stopPropagation()}
                     onChange={this.viewChanged}
                     value={mode}>
                     <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Stacking}>List</option>
                     <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Tree}>Tree</option>
-                    <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel3D}>3D Carousel</option>
+                    {Doc.UserDoc().noviceMode ? (null) : <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel3D}>3D Carousel</option>}
                 </select>}
                 <div className="presBox-presentPanel" style={{ opacity: this.childDocs.length ? 1 : 0.3 }}>
                     <span className={`presBox-button ${this.layoutDoc.presStatus === "edit" ? "present" : ""}`}>
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 5c16d743a..f4dc9b615 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -159,6 +159,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const activeItem = this.rootDoc;
         const dragArray = PresBox.Instance._dragArray;
         const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray());
+        if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc);
+        dragData.dropAction = "move";
+        dragData.treeViewDoc = this.props.docViewPath().lastElement()?.props.treeViewDoc;
+        dragData.moveDocument = this.props.docViewPath().lastElement()?.props.moveDocument;
         const dragItem: HTMLElement[] = [];
         if (dragArray.length === 1) {
             const doc = dragArray[0];
-- 
cgit v1.2.3-70-g09d2


From 239ff2c0423333bb7e154158c1f52ef688875ee7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 24 Apr 2022 14:50:21 -0400
Subject: fixed treeViews to vertically span their containers.  fixed
 foreground coloring of nodes with transparent backgrounds to consider parent
 collection background color

---
 src/client/views/StyleProvider.tsx                 |  5 ++--
 src/client/views/collections/CollectionSubView.tsx | 34 +++++++++++-----------
 .../views/collections/CollectionTreeView.scss      |  6 ++++
 .../views/collections/CollectionTreeView.tsx       |  3 +-
 src/client/views/collections/TreeView.tsx          |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  6 ++++
 .../views/nodes/formattedText/FormattedTextBox.tsx | 16 +++++-----
 7 files changed, 41 insertions(+), 31 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index ba5aaf36a..5c10c2344 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -81,7 +81,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
     const isAnchor = property.includes(":anchor");
     const isAnnotated = property.includes(":annotated");
     const isOpen = property.includes(":open");
-    const fieldKey = (props as any)?.fieldKey ? (props as any).fieldKey + "-" : isCaption ? "caption-" : "";
+    const fieldKey = props?.fieldKey ? props.fieldKey + "-" : isCaption ? "caption-" : "";
     const comicStyle = () => doc && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === "comic";
     const isBackground = () => StrListCast(doc?._layerTags).includes(StyleLayers.Background);
     const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
@@ -114,7 +114,8 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             if (MainView.Instance.LastButton === doc) return Colors.DARK_GRAY;
             const docColor: Opt<string> = StrCast(doc?.[fieldKey + "color"], StrCast(doc?._color));
             if (docColor) return docColor;
-            const backColor = backgroundCol();
+            const docView = props?.DocumentView?.();
+            const backColor = backgroundCol() || docView?.props.styleProvider?.(docView.props.treeViewDoc, docView.props, "backgroundColor");
             if (!backColor) return undefined;
             return lightOrDark(backColor);
         case StyleProp.Hidden: return BoolCast(doc?.hidden);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d8f1287cd..0eb94c394 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,23 +1,32 @@
-import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx";
+import { action, computed, observable } from "mobx";
+import ReactLoading from 'react-loading';
+import * as rp from 'request-promise';
 import CursorField from "../../../fields/CursorField";
-import { Doc, Opt, Field, DocListCast, AclPrivate, StrListCast } from "../../../fields/Doc";
-import { Id, ToString } from "../../../fields/FieldSymbols";
+import { AclPrivate, Doc, DocListCast, Field, Opt, StrListCast } from "../../../fields/Doc";
+import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
 import { listSpec } from "../../../fields/Schema";
 import { ScriptField } from "../../../fields/ScriptField";
+import { Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
 import { WebField } from "../../../fields/URLField";
-import { Cast, ScriptCast, NumCast, StrCast } from "../../../fields/Types";
+import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
 import { GestureUtils } from "../../../pen-gestures/GestureUtils";
-import { Utils, returnFalse, returnEmptyFilter } from "../../../Utils";
+import { returnFalse, Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
+import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
+import { Networking } from "../../Network";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
+import { DragManager, dropActionType } from "../../util/DragManager";
 import { ImageUtils } from "../../util/Import & Export/ImageUtils";
 import { InteractionUtils } from "../../util/InteractionUtils";
+import { SelectionManager } from "../../util/SelectionManager";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { DocComponent } from "../DocComponent";
+import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
+import { OverlayView } from "../OverlayView";
+import { CollectionView, CollectionViewProps, CollectionViewType } from "./CollectionView";
 import React = require("react");
-import ReactLoading from 'react-loading';
-import * as rp from 'request-promise';
-import { Networking } from "../../Network";
 
 
 export interface SubCollectionViewProps extends CollectionViewProps {
@@ -472,13 +481,4 @@ export function CollectionSubView<X>(moreProps?: X) {
     return CollectionSubView;
 }
 
-import { DragManager, dropActionType } from "../../util/DragManager";
-import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTextBox";
-import { CollectionView, CollectionViewType, CollectionViewProps } from "./CollectionView";
-import { SelectionManager } from "../../util/SelectionManager";
-import { OverlayView } from "../OverlayView";
-import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
 
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index b664d9d82..a8eee9c19 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -2,6 +2,7 @@
 
 .collectionTreeView-container {
     transform-origin: top left;
+    height: 100%;
 }
 .collectionTreeView-dropTarget {
     border-width: $COLLECTION_BORDER_WIDTH;
@@ -71,6 +72,11 @@
     display: none;
 }
 
+.collectionTreeView-contents {
+    display: flex;
+    flex-direction: column;
+}
+
 .collectionTreeView-titleBar {
     display: inline-block;
     width: 100%;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index e84517f40..76da96174 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -341,14 +341,13 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             <div className="collectionTreeView-contents" key="tree" style={{
                 ...(!titleBar ? { paddingLeft: this.marginX(), paddingTop: this.marginTop() } : {}),
                 overflow: "auto",
-                height: this.layoutDoc._autoHeight ? "max-content" : "100%"
+                height: "100%"//this.layoutDoc._autoHeight ? "max-content" : "100%"
             }} >
                 {titleBar}
                 <div className="collectionTreeView-container"
                     style={{
                         transform: this.outlineMode ? `scale(${this.contentScaling})` : "",
                         paddingLeft: `${this.marginX()}px`,
-                        height: "max-content",
                         width: this.outlineMode ? `calc(${100 / this.contentScaling}%)` : ""
                     }}
                     onContextMenu={this.onContextMenu}>
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 342424d41..61c7ff78e 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -225,7 +225,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             title: "-title-",
             treeViewExpandedViewLock: true, treeViewExpandedView: "data",
             _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewType: "outline",
-            x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, backgroundColor: "transparent", _width: 1000, _height: 10
+            x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, _width: 1000, _height: 10
         });
         Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text');
         Doc.GetProto(bullet).data = new List<Doc>([]);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index bcf00e88d..504a3afb6 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -104,7 +104,10 @@ export interface DocComponentView {
     snapPt?: (pt: { X: number, Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number, Y: number }, distance: number };
     search?: (str: string, bwd?: boolean, clear?: boolean) => boolean;
 }
+// These props are passed to both FieldViews and DocumentViews 
 export interface DocumentViewSharedProps {
+    fieldKey?: string; // only used by FieldViews but helpful here to allow styleProviders to access fieldKey of FieldViewProps.  In priniciple, passing a fieldKey to a documentView could override or be the default fieldKey for fieldViews
+    DocumentView?: () => DocumentView;
     renderDepth: number;
     Document: Doc;
     DataDoc?: Doc;
@@ -149,6 +152,8 @@ export interface DocumentViewSharedProps {
     createNewFilterDoc?: () => void;
     updateFilterDoc?: (doc: Doc) => void;
 }
+
+// these props are specific to DocuentViews
 export interface DocumentViewProps extends DocumentViewSharedProps {
     // properties specific to DocumentViews but not to FieldView
     freezeDimensions?: boolean;
@@ -173,6 +178,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     onPointerUp?: () => ScriptField;
 }
 
+// these props are only available in DocumentViewIntenral
 export interface DocumentViewInternalProps extends DocumentViewProps {
     NativeWidth: () => number;
     NativeHeight: () => number;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index ac291801b..dc1c67bea 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1,23 +1,23 @@
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { isEqual } from "lodash";
-import { action, computed, IReactionDisposer, reaction, runInAction, observable, trace } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap, selectAll } from "prosemirror-commands";
 import { history } from "prosemirror-history";
 import { inputRules } from 'prosemirror-inputrules';
 import { keymap } from "prosemirror-keymap";
 import { Fragment, Mark, Node, Slice } from "prosemirror-model";
-import { ReplaceStep } from 'prosemirror-transform';
 import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { DateField } from '../../../../fields/DateField';
-import { AclAdmin, AclEdit, AclSelfEdit, DataSym, Doc, DocListCast, DocListCastAsync, Field, ForceServerWrite, HeightSym, Opt, UpdatingFromServer, WidthSym, AclAugment } from "../../../../fields/Doc";
+import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DataSym, Doc, DocListCast, DocListCastAsync, Field, ForceServerWrite, HeightSym, Opt, UpdatingFromServer, WidthSym } from "../../../../fields/Doc";
 import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
 import { PrefetchProxy } from '../../../../fields/Proxy';
 import { RichTextField } from "../../../../fields/RichTextField";
 import { RichTextUtils } from '../../../../fields/RichTextUtils';
-import { Cast, DateCast, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
+import { Cast, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
 import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
 import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
@@ -29,6 +29,7 @@ import { DictationManager } from '../../../util/DictationManager';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from "../../../util/DragManager";
 import { makeTemplate } from '../../../util/DropConverter';
+import { LinkManager } from '../../../util/LinkManager';
 import { SelectionManager } from "../../../util/SelectionManager";
 import { SnappingManager } from '../../../util/SnappingManager';
 import { undoBatch, UndoManager } from "../../../util/UndoManager";
@@ -38,10 +39,11 @@ import { ContextMenu } from '../../ContextMenu';
 import { ContextMenuProps } from '../../ContextMenuItem';
 import { ViewBoxAnnotatableComponent } from "../../DocComponent";
 import { DocumentButtonBar } from '../../DocumentButtonBar';
+import { Colors } from '../../global/globalEnums';
 import { LightboxView } from '../../LightboxView';
 import { AnchorMenu } from '../../pdf/AnchorMenu';
+import { SidebarAnnos } from '../../SidebarAnnos';
 import { StyleProp } from '../../StyleProvider';
-import { AudioBox } from '../AudioBox';
 import { FieldView, FieldViewProps } from "../FieldView";
 import { LinkDocPreview } from '../LinkDocPreview';
 import { DashDocCommentView } from "./DashDocCommentView";
@@ -60,10 +62,6 @@ import { schema } from "./schema_rts";
 import { SummaryView } from "./SummaryView";
 import applyDevTools = require("prosemirror-dev-tools");
 import React = require("react");
-import { SidebarAnnos } from '../../SidebarAnnos';
-import { Colors } from '../../global/globalEnums';
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { LinkManager } from '../../../util/LinkManager';
 const translateGoogleApi = require("translate-google-api");
 
 export interface FormattedTextBoxProps {
-- 
cgit v1.2.3-70-g09d2


From 969ab00c44859b932884bb32fef1b1e8b11d5448 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 24 Apr 2022 15:01:00 -0400
Subject: from last

---
 src/client/util/CurrentUserUtils.ts                |  2 +-
 src/client/views/collections/CollectionSubView.tsx | 33 +++++++++++-----------
 src/client/views/collections/TreeView.tsx          | 12 ++++----
 3 files changed, 22 insertions(+), 25 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index bf722157a..c7309d15e 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -389,7 +389,7 @@ export class CurrentUserUtils {
             const textDoc = Docs.Create.TreeDocument([], {
                 title: "Slide", _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true,
                 allowOverlayDrop: true, treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true,
-                backgroundColor: "transparent", system: true, cloneFieldFilter: new List<string>(["system"])
+                backgroundColor: "white", system: true, cloneFieldFilter: new List<string>(["system"])
             });
             Doc.GetProto(textDoc).title = ComputedField.MakeFunction('self.text?.Text');
             FormattedTextBox.SelectOnLoad = textDoc[Id];
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 0eb94c394..5bdd0c0ac 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,32 +1,23 @@
-import { action, computed, observable } from "mobx";
-import ReactLoading from 'react-loading';
-import * as rp from 'request-promise';
+import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx";
 import CursorField from "../../../fields/CursorField";
-import { AclPrivate, Doc, DocListCast, Field, Opt, StrListCast } from "../../../fields/Doc";
+import { Doc, Opt, Field, DocListCast, AclPrivate, StrListCast } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
 import { listSpec } from "../../../fields/Schema";
 import { ScriptField } from "../../../fields/ScriptField";
-import { Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
 import { WebField } from "../../../fields/URLField";
-import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
+import { Cast, ScriptCast, NumCast, StrCast } from "../../../fields/Types";
 import { GestureUtils } from "../../../pen-gestures/GestureUtils";
-import { returnFalse, Utils } from "../../../Utils";
+import { Utils, returnFalse, returnEmptyFilter } from "../../../Utils";
 import { DocServer } from "../../DocServer";
-import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { Networking } from "../../Network";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { DragManager, dropActionType } from "../../util/DragManager";
 import { ImageUtils } from "../../util/Import & Export/ImageUtils";
 import { InteractionUtils } from "../../util/InteractionUtils";
-import { SelectionManager } from "../../util/SelectionManager";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { DocComponent } from "../DocComponent";
-import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
-import { OverlayView } from "../OverlayView";
-import { CollectionView, CollectionViewProps, CollectionViewType } from "./CollectionView";
 import React = require("react");
+import ReactLoading from 'react-loading';
+import * as rp from 'request-promise';
+import { Networking } from "../../Network";
 
 
 export interface SubCollectionViewProps extends CollectionViewProps {
@@ -481,4 +472,12 @@ export function CollectionSubView<X>(moreProps?: X) {
     return CollectionSubView;
 }
 
-
+import { DragManager, dropActionType } from "../../util/DragManager";
+import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
+import { DocumentType } from "../../documents/DocumentTypes";
+import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTextBox";
+import { CollectionView, CollectionViewType, CollectionViewProps } from "./CollectionView";
+import { SelectionManager } from "../../util/SelectionManager";
+import { OverlayView } from "../OverlayView";
+import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
\ No newline at end of file
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 61c7ff78e..6213850d8 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1,7 +1,8 @@
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
-import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, WidthSym, StrListCast } from '../../../fields/Doc';
+import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { RichTextField } from '../../../fields/RichTextField';
@@ -9,7 +10,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, simulateMouseClick, Utils, returnOne } from '../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, returnTrue, simulateMouseClick, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from "../../documents/DocumentTypes";
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -21,17 +22,14 @@ import { Transform } from '../../util/Transform';
 import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { EditableView } from "../EditableView";
 import { TREE_BULLET_WIDTH } from '../global/globalCssVariables.scss';
-import { DocumentView, DocumentViewProps, StyleProviderFunc, DocumentViewInternal } from '../nodes/DocumentView';
+import { DocumentView, DocumentViewInternal, DocumentViewProps, StyleProviderFunc } from '../nodes/DocumentView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
-import { KeyValueBox } from '../nodes/KeyValueBox';
-import { SliderBox } from '../nodes/SliderBox';
-import { StyleProp, testDocProps } from '../StyleProvider';
+import { StyleProp } from '../StyleProvider';
 import { CollectionTreeView } from './CollectionTreeView';
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TreeView.scss";
 import React = require("react");
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
 
 export interface TreeViewProps {
     treeView: CollectionTreeView;
-- 
cgit v1.2.3-70-g09d2


From cb59842fcb79af7ef72443e08c6a479c3f0af343 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 25 Apr 2022 20:20:48 -0400
Subject:  changed freeformview's with engines to not allow children to be
 edited using setHeight prop since engine layouts are temporary and shouldn't
 edit the doc.  fixed tags to work with pivot view. cleaned up pile views to
 be less hacky..

---
 src/client/documents/Documents.ts                  | 27 +++++++++++++---------
 src/client/views/MainView.tsx                      |  1 +
 src/client/views/SidebarAnnos.tsx                  |  2 +-
 .../views/collections/CollectionPileView.tsx       |  4 ++--
 .../views/collections/CollectionStackingView.tsx   |  6 ++---
 src/client/views/collections/CollectionSubView.tsx |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 src/client/views/collections/TreeView.tsx          |  1 +
 .../CollectionFreeFormLayoutEngines.tsx            | 26 +++++++++++++--------
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  4 +++-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  5 +---
 src/client/views/nodes/DocumentContentsView.tsx    |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 17 +++++++-------
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/nodes/LinkDocPreview.tsx          |  1 +
 src/client/views/nodes/WebBox.tsx                  |  2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 src/fields/Doc.ts                                  |  2 +-
 19 files changed, 62 insertions(+), 48 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 49e53a214..a19530c92 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -14,7 +14,7 @@ import { Cast, NumCast, StrCast } from "../../fields/Types";
 import { AudioField, ImageField, MapField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField";
 import { SharingPermissions } from "../../fields/util";
 import { Upload } from "../../server/SharedMediaTypes";
-import { OmitKeys, Utils } from "../../Utils";
+import { OmitKeys, Utils, aggregateBounds } from "../../Utils";
 import { YoutubeBox } from "../apis/youtube/YoutubeBox";
 import { DocServer } from "../DocServer";
 import { Networking } from "../Network";
@@ -1352,26 +1352,31 @@ export namespace DocUtils {
         if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") doc.deiconifyLayout = layoutKey.replace("layout_", "");
     }
 
-    export function pileup(docList: Doc[], x?: number, y?: number, create: boolean = true) {
+    export function pileup(docList: Doc[], x?: number, y?: number, size: number = 55, create: boolean = true) {
         let w = 0, h = 0;
         runInAction(() => {
             docList.forEach(d => {
                 DocUtils.iconify(d);
-                w = Math.max(d[WidthSym](), w);
-                h = Math.max(d[HeightSym](), h);
+                w = Math.max(NumCast(d._width), w);
+                h = Math.max(NumCast(d._height), h);
             });
-            h = Math.max(h, w * 4 / 3); // converting to an icon does not update the height right away.  so this is a fallback hack to try to do something reasonable
             docList.forEach((d, i) => {
-                d.x = Math.cos(Math.PI * 2 * i / docList.length) * 10 - w / 2;
-                d.y = Math.sin(Math.PI * 2 * i / docList.length) * 10 - h / 2;
+                d.x = Math.cos(Math.PI * 2 * i / docList.length) * size;
+                d.y = Math.sin(Math.PI * 2 * i / docList.length) * size;
+                d._timecodeToShow = undefined;  // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
+            });
+            const aggBounds = aggregateBounds(docList.map(d => ({ x: NumCast(d.x), y: NumCast(d.y), width: NumCast(d._width), height: NumCast(d._height) })), 0, 0);
+            docList.forEach((d, i) => {
+                d.x = NumCast(d.x) - ((aggBounds.r + aggBounds.x) / 2);
+                d.y = NumCast(d.y) - ((aggBounds.b + aggBounds.y) / 2);
                 d._timecodeToShow = undefined;  // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
             });
         });
         if (create) {
-            const newCollection = Docs.Create.PileDocument(docList, { title: "pileup", x: (x || 0) - 55, y: (y || 0) - 55, _width: 110, _height: 100, });
-            newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55;
-            newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55;
-            newCollection._width = newCollection._height = 110;
+            const newCollection = Docs.Create.PileDocument(docList, { title: "pileup", x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2, });
+            newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - size;
+            newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - size;
+            newCollection._width = newCollection._height = size * 2;
             newCollection._jitterRotation = 10;
             return newCollection;
         }
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index a67cb3014..68b4710ed 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -297,6 +297,7 @@ export class MainView extends React.Component {
             searchFilterDocs={returnEmptyDoclist}
             ContainingCollectionView={undefined}
             ContainingCollectionDoc={undefined}
+            suppressSetHeight={true}
             renderDepth={-1}
         />;
     }
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index fae385660..43a02d029 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -88,7 +88,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     removeDocument = (doc: Doc | Doc[]) => this.props.removeDocument(doc, this.sidebarKey);
     docFilters = () => [...StrListCast(this.props.layoutDoc._docFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])];
     showTitle = () => "title";
-    setHeightCallback = (height: number) => this.props.setHeight(height + this.filtersHeight());
+    setHeightCallback = (height: number) => this.props.setHeight?.(height + this.filtersHeight());
     render() {
         const renderTag = (tag: string) => {
             const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`${tag}:${tag}:check`);
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 8832b0f4a..4489601db 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -74,13 +74,13 @@ export class CollectionPileView extends CollectionSubView() {
             this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2;
             this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize);
             this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize);
-            DocUtils.pileup(this.childDocs, undefined, undefined, false);
+            DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false);
             this.layoutDoc._panX = 0;
             this.layoutDoc._panY = -10;
             this.props.Document._pileLayoutEngine = 'pass';
         } else {
             const defaultSize = 25;
-            !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 500);
+            !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 250);
             !this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5);
             if (this.layoutEngine() === 'pass') {
                 this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 8634ea139..509005b45 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -141,7 +141,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             () => this.layoutDoc._columnHeaders = new List()
         );
         this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight,
-            autoHeight => autoHeight && this.props.setHeight(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
+            autoHeight => autoHeight && this.props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
                 this.headerMargin + (this.isStackingView ?
                     Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))) :
                     this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0)))));
@@ -408,7 +408,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                                 Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
                                     Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))));
                             if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) {
-                                this.props.setHeight(height);
+                                this.props.setHeight?.(height);
                             }
                         }
                     }));
@@ -458,7 +458,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                     this.observer = new _global.ResizeObserver(action((entries: any) => {
                         if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
                             const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
-                            this.props.setHeight(this.headerMargin + height);
+                            this.props.setHeight?.(this.headerMargin + height);
                         }
                     }));
                     this.observer.observe(ref);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5bdd0c0ac..30e0adf24 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -453,7 +453,7 @@ export function CollectionSubView<X>(moreProps?: X) {
                 if (completed) completed(set);
                 else {
                     if (isFreeformView && generatedDocuments.length > 1) {
-                        addDocument(DocUtils.pileup(generatedDocuments, options.x!, options.y!)!);
+                        addDocument(DocUtils.pileup(generatedDocuments, options.x!, options.y!)!,);
                     } else {
                         generatedDocuments.forEach(addDocument);
                     }
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 76da96174..41970eb96 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -88,7 +88,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace("px", ""));
             const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), this.marginBot());
             this.layoutDoc._autoHeightMargins = bodyHeight;
-            this.props.setHeight(bodyHeight + titleHeight);
+            this.props.setHeight?.(bodyHeight + titleHeight);
         }
     }
     unobserveHeight = (ref: any) => {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 6213850d8..b9710b3f5 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -30,6 +30,7 @@ import { CollectionTreeView } from './CollectionTreeView';
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TreeView.scss";
 import React = require("react");
+import { KeyValueBox } from '../nodes/KeyValueBox';
 
 export interface TreeViewProps {
     treeView: CollectionTreeView;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 598960af7..16c7df311 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -111,17 +111,17 @@ export function computerStarburstLayout(
     viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[],
     engineProps: any
 ) {
-    const mustFit = pivotDoc[WidthSym]() !== panelDim[0];
+    const mustFit = pivotDoc[WidthSym]() !== panelDim[0]; // if a panel size is set that's not the same as the pivot doc's size, then assume this is in a panel for a content fitting view (like a grid) in which case everything must be scaled to stay within the panel
     const docMap = new Map<string, PoolData>();
-    const burstRadius = mustFit ? panelDim : [NumCast(pivotDoc._starburstRadius, panelDim[0]), NumCast(pivotDoc._starburstRadius, panelDim[1])];
-    const docSize = mustFit ? panelDim[0] * .33 : 75; // assume a icon sized at 75
-    const scaleDim = [burstRadius[0] + docSize, burstRadius[1] + docSize];
+    const docSize = mustFit ? panelDim[0] * .33 : 75; // assume an icon sized at 75
+    const burstRadius = mustFit ? panelDim : [NumCast(pivotDoc._starburstRadius, panelDim[0]) - docSize, NumCast(pivotDoc._starburstRadius, panelDim[1]) - docSize];
+    const scaleDim = [burstRadius[0] * 2 + docSize, burstRadius[1] * 2 + docSize];
     childPairs.forEach(({ layout, data }, i) => {
-        const docSize = layout.layoutKey === "layout_icon" ? mustFit ? panelDim[0] * .33 : 75 : 400; // assume a icon sized at 10750
+        const docSize = layout.layoutKey === "layout_icon" ? (mustFit ? panelDim[0] * .33 : 75) : 400; // assume a icon sized at 75
         const deg = i / childPairs.length * Math.PI * 2;
         docMap.set(layout[Id], {
-            x: Math.cos(deg) * (burstRadius[0] / 3) - docSize / 2,
-            y: Math.sin(deg) * (burstRadius[1] / 3) - docSize * layout[HeightSym]() / layout[WidthSym]() / 2,
+            x: Math.cos(deg) * burstRadius[0] - docSize / 2,
+            y: Math.sin(deg) * burstRadius[1] - docSize * layout[HeightSym]() / layout[WidthSym]() / 2,
             width: docSize,//layout[WidthSym](),
             height: docSize * layout[HeightSym]() / layout[WidthSym](),
             zIndex: NumCast(layout.zIndex),
@@ -129,7 +129,7 @@ export function computerStarburstLayout(
             replica: ""
         });
     });
-    const divider = { type: "div", color: "transparent", x: -burstRadius[0] / 3, y: 0, width: 15, height: 15, payload: undefined };
+    const divider = { type: "div", color: "transparent", x: -burstRadius[0], y: 0, width: 15, height: 15, payload: undefined };
     return normalizeResults(scaleDim, 12, docMap, poolData, viewDefsToJSX, [], 0, [divider]);
 }
 
@@ -267,7 +267,13 @@ export function computePivotLayout(
     });
 
     const dividers = sortedPivotKeys.map((key, i) =>
-        ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters }));
+    ({
+        type: "div", color: "lightGray",
+        x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2,
+        y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander,
+        height: maxColHeight,
+        payload: pivotColumnGroups.get(key)!.filters
+    }));
     groupNames.push(...dividers);
     return normalizeResults(panelDim, max_text, docMap, poolData, viewDefsToJSX, groupNames, 0, []);
 }
@@ -404,7 +410,7 @@ function normalizeResults(
     const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds);
     const docEles = Array.from(docMap.entries()).map(ele => ele[1]);
     const aggBounds = aggregateBounds(extras.concat(grpEles.concat(docEles.map(de => ({ ...de, type: "doc", payload: "" })))).filter(e => e.zIndex !== -99), 0, 0);
-    aggBounds.r = Math.max(minWidth, aggBounds.r - aggBounds.x);
+    aggBounds.r = aggBounds.x + Math.max(minWidth, aggBounds.r - aggBounds.x);
     const wscale = panelDim[0] / (aggBounds.r - aggBounds.x);
     let scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] ? (panelDim[1]) / (aggBounds.b - aggBounds.y) : wscale;
     if (Number.isNaN(scale)) scale = 1;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index eaef1b49c..a14405a0b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1158,6 +1158,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             replica={entry.replica}
             renderIndex={renderIndex}
             dataTransition={entry.transition}
+            suppressSetHeight={this.layoutEngine ? true : false}
             renderCutoffProvider={this.renderCutoffProvider}
             ContainingCollectionView={this.props.CollectionView}
             ContainingCollectionDoc={this.props.Document}
@@ -1300,10 +1301,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return [] as ViewDefResult[];
     }
 
+    @computed get layoutEngine() { return this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine); }
     @computed get doInternalLayoutComputation() {
         TraceMobx();
         const newPool = new Map<string, PoolData>();
-        switch (this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine)) {
+        switch (this.layoutEngine) {
             case "pass": return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) };
             case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) };
             case "pivot": return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) };
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 3e35039e3..6097425e1 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -17,9 +17,6 @@ import { StyleProp } from "../StyleProvider";
 import "./CollectionFreeFormDocumentView.scss";
 import { DocumentView, DocumentViewProps } from "./DocumentView";
 import React = require("react");
-import { DocumentType } from "../../documents/DocumentTypes";
-import { collectionSchema } from "../../../fields/documentSchemas";
-import { CollectionViewType } from "../collections/CollectionView";
 
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
     dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
@@ -174,7 +171,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             style={{
                 outline: this.Highlight ? "orange solid 2px" : "",
                 width: this.panelWidth(),
-                height: !this.ShowTitle && this.layoutDoc.autoHeight && this.rootDoc.type === DocumentType.RTF ? undefined : this.panelHeight(),
+                height: this.panelHeight(),
                 transform: this.transform,
                 transition: this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition),
                 zIndex: this.ZInd,
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 005133eb0..d4e8ffc7f 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -112,7 +112,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
     isSelected: (outsideReaction: boolean) => boolean,
     select: (ctrl: boolean) => void,
     scaling?: () => number,
-    setHeight: (height: number) => void,
+    setHeight?: (height: number) => void,
     layoutKey: string,
 }> {
     @computed get layout(): string {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 504a3afb6..20eabe6a9 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -114,6 +114,7 @@ export interface DocumentViewSharedProps {
     fitContentsToDoc?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitToBox property on a Document
     ContainingCollectionView: Opt<CollectionView>;
     ContainingCollectionDoc: Opt<Doc>;
+    suppressSetHeight?: boolean;
     thumbShown?: () => boolean;
     isHovering?: () => boolean;
     setContentView?: (view: DocComponentView) => any;
@@ -842,11 +843,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin);
     contentScaling = () => this.ContentScale;
     onClickFunc = () => this.onClickHandler;
-    setHeight = (height: number) => {
-        if (this.props.renderDepth !== -1) {
-            this.layoutDoc._height = height;
-        }
-    }
+    setHeight = (height: number) => this.layoutDoc._height = height;
     setContentView = action((view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view);
     isContentActive = (outsideReaction?: boolean) => {
         return this.props.isContentActive() === false ? false : (
@@ -890,7 +887,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 setContentView={this.setContentView}
                 scaling={this.contentScaling}
                 PanelHeight={this.panelHeight}
-                setHeight={this.setHeight}
+                setHeight={!this.props.suppressSetHeight ? this.setHeight : undefined}
                 isContentActive={this.isContentActive}
                 ScreenToLocalTransform={this.screenToLocal}
                 rootSelected={this.rootSelected}
@@ -1207,7 +1204,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         return this.docView?._componentView?.reverseNativeScaling?.() ? 0 :
             returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions));
     }
-    @computed get shouldNotScale() { return (this.fitWidth && !this.nativeWidth) || this.props.treeViewDoc || [CollectionViewType.Docking].includes(this.Document._viewType as any); }
+    @computed get shouldNotScale() {
+        return (this.fitWidth && !this.nativeWidth) ||
+            this.props.ContainingCollectionView?.collectionViewType === CollectionViewType.Time ||
+            this.props.treeViewDoc || [CollectionViewType.Docking].includes(this.Document._viewType as any);
+    }
     @computed get effectiveNativeWidth() { return this.shouldNotScale ? 0 : (this.nativeWidth || NumCast(this.layoutDoc.width)); }
     @computed get effectiveNativeHeight() { return this.shouldNotScale ? 0 : (this.nativeHeight || NumCast(this.layoutDoc.height)); }
     @computed get nativeScaling() {
@@ -1324,7 +1325,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                         position: this.props.Document.isInkMask ? "absolute" : undefined,
                         transform: isButton ? undefined : `translate(${this.centeringX}px, ${this.centeringY}px)`,
                         width: isButton || isPresTreeElement ? "100%" : xshift() ?? `${100 * (this.props.PanelWidth() - this.Xshift * 2) / this.props.PanelWidth()}%`,
-                        height: (!this.props.ignoreAutoHeight && this.layoutDoc.autoHeight && this.layoutDoc.type === DocumentType.RTF) || isButton || this.props.forceAutoHeight ? undefined : yshift() ?? (this.fitWidth ? `${this.panelHeight}px` :
+                        height: isButton || this.props.forceAutoHeight ? undefined : yshift() ?? (this.fitWidth ? `${this.panelHeight}px` :
                             `${100 * this.effectiveNativeHeight / this.effectiveNativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%`),
                     }}>
                     <DocumentViewInternal {...this.props}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 943b9f153..ae9acfe3f 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -22,7 +22,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
     isDocumentActive?: () => boolean;
     isSelected: (outsideReaction?: boolean) => boolean;
     scaling?: () => number;
-    setHeight: (height: number) => void;
+    setHeight?: (height: number) => void;
 
     // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React)
     pointerEvents?: string;
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index eca2e3cfd..55f6d6059 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -195,6 +195,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             ContainingCollectionDoc={undefined}
                             ContainingCollectionView={undefined}
                             renderDepth={-1}
+                            suppressSetHeight={true}
                             PanelWidth={this.width}
                             PanelHeight={this.height}
                             focus={DocUtils.DefaultFocus}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 0fd193977..eeb7b925b 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -164,7 +164,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             autoHeight => {
                 if (autoHeight) {
                     this.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]);
-                    this.props.setHeight(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1));
+                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1));
                 }
             });
 
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index dc1c67bea..710270be4 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1524,7 +1524,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         if (children) {
             const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins);
             const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
-            if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) {  // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
+            if (this.props.setHeight && scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) {  // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
                 const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
                 if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) {
                     setScrollHeight();
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 9aaa6e90f..92a69c02b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -123,7 +123,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
             autoHeight => {
                 if (autoHeight) {
                     this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]);
-                    this.props.setHeight(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1));
+                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1));
                 }
             });
 
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 15df673f3..63af8401c 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1108,7 +1108,7 @@ export namespace Doc {
         if (typeof value === "string") {
             value = value.replace(`,${Utils.noRecursionHack}`, "");
         }
-        const fieldVal = doc[key];
+        const fieldVal = key === "#" ? (StrCast(doc.tags).includes(":#" + value + ":") ? StrCast(doc.tags) : undefined) : doc[key];
         if (Cast(fieldVal, listSpec("string"), []).length) {
             const vals = Cast(fieldVal, listSpec("string"), []);
             const docs = vals.some(v => (v as any) instanceof Doc);
-- 
cgit v1.2.3-70-g09d2


From 08217336445cf2b3cd3efbe97e3c83525f02bf1b Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 26 Apr 2022 22:34:21 -0400
Subject: added image cropping. made treeView icons show up for file system and
 dashboard, and made them persist invisibly to fix triggering on hover. 
 changed tree view filesystem and dashboard to show expanded icons on hover.

---
 src/client/views/MainView.tsx                      |  2 +-
 src/client/views/MarqueeAnnotator.tsx              | 27 ++++++++++++-
 src/client/views/PropertiesView.tsx                |  4 +-
 src/client/views/StyleProvider.scss                |  2 +-
 src/client/views/collections/TreeView.scss         | 23 +++++++++--
 src/client/views/collections/TreeView.tsx          | 16 ++++----
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 19 +++++----
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/ImageBox.tsx                | 45 ++++++++++++++++++++++
 .../views/nodes/formattedText/FormattedTextBox.tsx |  3 +-
 src/client/views/pdf/AnchorMenu.tsx                | 16 +++++++-
 11 files changed, 132 insertions(+), 27 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 68b4710ed..b73074899 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -362,7 +362,7 @@ export class MainView extends React.Component {
                         pinToPres={emptyFunction}
                         docViewPath={returnEmptyDoclist}
                         layerProvider={undefined}
-                        styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards ? DashboardStyleProvider : DefaultStyleProvider}
+                        styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === Doc.UserDoc().myFilesystem ? DashboardStyleProvider : DefaultStyleProvider}
                         rootSelected={returnTrue}
                         removeDocument={returnFalse}
                         ScreenToLocalTransform={this.mainContainerXf}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 563261dec..a6b012bd6 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -5,7 +5,7 @@ import { Id } from "../../fields/FieldSymbols";
 import { List } from "../../fields/List";
 import { NumCast } from "../../fields/Types";
 import { GetEffectiveAcl } from "../../fields/util";
-import { Utils } from "../../Utils";
+import { unimplementedFunction, Utils } from "../../Utils";
 import { Docs } from "../documents/Documents";
 import { CurrentUserUtils } from "../util/CurrentUserUtils";
 import { DragManager } from "../util/DragManager";
@@ -33,6 +33,7 @@ export interface MarqueeAnnotatorProps {
     getPageFromScroll?: (top: number) => number;
     finishMarquee: (x?: number, y?: number, PointerEvent?: PointerEvent) => void;
     anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
+    anchorMenuCrop?: (anchor: Doc | undefined, addCrop: boolean) => Doc | undefined;
 }
 @observer
 export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
@@ -63,6 +64,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
         doc.addEventListener("pointermove", this.onSelectMove);
         doc.addEventListener("pointerup", this.onSelectEnd);
 
+        AnchorMenu.Instance.OnCrop = (e: PointerEvent) => this.props.anchorMenuCrop?.(this.highlight("rgba(173, 216, 230, 0.75)", true), true);
         AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight("rgba(173, 216, 230, 0.75)", true));
         AnchorMenu.Instance.Highlight = this.highlight;
         AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => this.highlight("rgba(173, 216, 230, 0.75)", true, savedAnnotations);
@@ -93,6 +95,29 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
                 }
             });
         });
+        /**
+         * This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation.  
+         * It also initiates a Drag/Drop interaction to place the text annotation.
+         */
+        AnchorMenu.Instance.StartCropDrag = !this.props.anchorMenuCrop ? unimplementedFunction : action((e: PointerEvent, ele: HTMLElement) => {
+            e.preventDefault();
+            e.stopPropagation();
+            var cropRegion: Doc | undefined;
+            const sourceAnchorCreator = () => {
+                cropRegion = this.highlight("rgba(173, 216, 230, 0.75)", true); // hyperlink color
+                cropRegion && this.props.addDocument(cropRegion);
+                return cropRegion;
+            };
+            const targetCreator = (annotationOn: Doc | undefined) => this.props.anchorMenuCrop!(cropRegion, false)!;
+            DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
+                dragComplete: e => {
+                    if (!e.aborted && e.linkDocument) {
+                        Doc.GetProto(e.linkDocument).linkRelationship = "cropped image";
+                        Doc.GetProto(e.linkDocument).title = "crop: " + this.props.docView.rootDoc.title;
+                    }
+                }
+            });
+        });
     }
     componentWillUnmount() {
         const doc = (this.props.iframe?.()?.contentDocument ?? document);
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 91cf83619..b63395c76 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1360,12 +1360,12 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
                     {this.optionsSubMenu}
 
+                    {this.fieldsSubMenu}
+
                     {this.sharingSubMenu}
 
                     {isNovice ? null : this.filtersSubMenu}
 
-                    {isNovice ? null : this.fieldsSubMenu}
-
                     {isNovice ? null : this.layoutSubMenu}
                 </div>;
             }
diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss
index f26ed1f2d..8929954c8 100644
--- a/src/client/views/StyleProvider.scss
+++ b/src/client/views/StyleProvider.scss
@@ -25,5 +25,5 @@
 }
 
 .styleProvider-treeView-icon {
-    display: none;
+    opacity: 0;
 }
\ No newline at end of file
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 7c75810d3..4707ebb80 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -21,7 +21,9 @@
     }
 
     .treeView-bulletIcons {
-        width: $TREE_BULLET_WIDTH;
+       // width: $TREE_BULLET_WIDTH; 
+        width: 100%;
+        height: 100%;
 
         .treeView-expandIcon {
             display: none;
@@ -37,10 +39,17 @@
 
         &:hover {
             .treeView-expandIcon {
-                display: unset;
+                display: unset; 
             }
         }
     }
+    .treeView-bulletIcons:hover img {
+        left: 14px;
+        position: absolute;
+        transform-origin: center left;
+        transform: scale(6);
+        pointer-events:none;
+    }
 
     .bullet {
         position: relative;
@@ -60,6 +69,10 @@
     pointer-events: all;
 }
 
+.bullet:hover {
+    z-index: 100;
+}
+
 .treeView-openRight {
     display: none;
     height: 17px;
@@ -123,7 +136,9 @@
         }
 
         >svg {
-            display: none;
+            //display: none;
+            opacity: 0;
+            pointer-events: none;
         }
     }
 }
@@ -150,6 +165,8 @@
         >svg,
         .styleProvider-treeView-icon {
             display: inherit;
+            opacity: unset;
+            pointer-events: unset;
         }
     }
 }
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index b9710b3f5..9108acfcf 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -101,8 +101,9 @@ export class TreeView extends React.Component<TreeViewProps> {
     get displayName() { return "TreeView(" + this.props.document.title + ")"; }  // this makes mobx trace() statements more descriptive
     get defaultExpandedView() {
         return this.doc.viewType === CollectionViewType.Docking ? this.fieldKey :
-            this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "layout") :
-                this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.UserDoc().noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields");
+            this.props.treeView.dashboardMode ? this.fieldKey :
+                this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "aliases") :
+                    this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.UserDoc().noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields");
     }
 
     @computed get doc() { return this.props.document; }
@@ -491,15 +492,12 @@ export class TreeView extends React.Component<TreeViewProps> {
     }
 
     @computed get validExpandViewTypes() {
-        if (this.props.treeView.dashboardMode && Doc.UserDoc().noviceMode) {
-            return [this.doc.viewType === CollectionViewType.Docking ? this.fieldKey : "layout"];
-        }
-        const annos = () => DocListCast(this.doc[this.fieldKey + "-annotations"]).length ? "annotations" : "";
-        const links = () => DocListCast(this.doc.links).length ? "links" : "";
-        const data = () => this.childDocs ? this.fieldKey : "";
+        const annos = () => DocListCast(this.doc[this.fieldKey + "-annotations"]).length && !this.props.treeView.dashboardMode ? "annotations" : "";
+        const links = () => DocListCast(this.doc.links).length && !this.props.treeView.dashboardMode ? "links" : "";
+        const data = () => this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : "";
         const aliases = () => this.props.treeView.dashboardMode ? "" : "aliases";
         const fields = () => Doc.UserDoc().noviceMode ? "" : "fields";
-        const layout = this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"];
+        const layout = (this.props.treeView.dashboardMode && Doc.UserDoc().noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"];
         return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [aliases(), links(), annos()] : []), fields()].filter(m => m);
     }
     @action
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index bdae5a4f8..f0b3d70a0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -936,8 +936,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (deltaScale * invTransform.Scale > 20) {
             deltaScale = 20 / invTransform.Scale;
         }
-        if (deltaScale * invTransform.Scale < 1 && this.isAnnotationOverlay) {
-            deltaScale = 1 / invTransform.Scale;
+        if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) {
+            deltaScale = NumCast(this.rootDoc._viewScaleMin, 1) / invTransform.Scale;
         }
 
         const localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
@@ -989,8 +989,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || CurrentUserUtils.OverlayDocs.includes(this.Document)) {
             this._viewTransition = panTime;
             const scale = this.getLocalTransform().inverse().Scale;
-            const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
-            const newPanY = Math.min((this.props.Document.scrollHeight !== undefined ? NumCast(this.Document.scrollHeight) : (1 - 1 / scale) * this.nativeHeight), Math.max(0, panY));
+            const minScale = NumCast(this.rootDoc._viewScaleMin, 1);
+            const minPanX = NumCast(this.rootDoc._panXMin, 0);
+            const minPanY = NumCast(this.rootDoc._panYMin, 0);
+            const newPanX = Math.min(
+                minPanX + (1 - minScale / scale) * NumCast(this.rootDoc._panXMax, this.nativeWidth), Math.max(minPanX, panX));
+            const newPanY = Math.min((this.props.Document.scrollHeight !== undefined ? NumCast(this.Document.scrollHeight) :
+                minPanY + (1 - minScale / scale) * NumCast(this.rootDoc._panYMax, this.nativeHeight)), Math.max(minPanY, panY));
             !this.Document._verticalScroll && (this.Document._panX = this.isAnnotationOverlay ? newPanX : panX);
             !this.Document._horizontalScroll && (this.Document._panY = this.isAnnotationOverlay ? newPanY : panY);
         }
@@ -1056,9 +1061,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 HistoryUtil.pushState(state);
             }
         }
-        if (SelectionManager.Views().length !== 1 || SelectionManager.Views()[0].Document !== doc) {
-            SelectionManager.DeselectAll();
-        }
+        // if (SelectionManager.Views().length !== 1 || SelectionManager.Views()[0].Document !== doc) {
+        //     SelectionManager.DeselectAll();
+        // }
         if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined) {
             this.props.focus(doc, options);
         } else {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 20eabe6a9..9d738180b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1084,7 +1084,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         TraceMobx();
         const thumb = ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url.href.replace(".png", "_m.png");
         const isButton = this.props.Document.type === DocumentType.FONTICON;
-        if (!(this.props.Document instanceof Doc) || GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate || this.hidden) return null;
+        if (!(this.props.Document instanceof Doc) || GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate || (this.hidden && !this.props.treeViewDoc)) return null;
         return this.docContents ??
             <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
                 id={this.props.Document[Id]}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index a1de944d8..aadad5ffa 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -14,6 +14,8 @@ import { TraceMobx } from '../../../fields/util';
 import { emptyFunction, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils';
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices';
+import { Docs, DocUtils } from '../../documents/Documents';
+import { DocumentType } from '../../documents/DocumentTypes';
 import { Networking } from '../../Network';
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 import { DragManager } from '../../util/DragManager';
@@ -127,6 +129,48 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         this.layoutDoc._height = w;
     });
 
+    crop = (region: Doc | undefined, addCrop?: boolean) => {
+        if (!region) return;
+        const cropping = Doc.MakeCopy(region, true);
+        Doc.GetProto(region).lockedPosition = true;
+        Doc.GetProto(region).title = "region:" + this.rootDoc.title;
+        Doc.GetProto(region).isPushpin = true;
+        this.addDocument(region);
+        const anchx = NumCast(cropping.x);
+        const anchy = NumCast(cropping.y);
+        const anchw = NumCast(cropping._width);
+        const anchh = NumCast(cropping._height);
+        const viewScale = NumCast(this.rootDoc[this.fieldKey + "-nativeWidth"]) / anchw;
+        cropping.title = "crop: " + this.rootDoc.title;
+        cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
+        cropping.y = NumCast(this.rootDoc.y);
+        cropping._width = anchw * (this.props.scaling?.() || 1);
+        cropping._height = anchh * (this.props.scaling?.() || 1);
+        cropping.isLinkButton = undefined;
+        const croppingProto = Doc.GetProto(cropping);
+        croppingProto.annotationOn = undefined;
+        croppingProto.isPrototype = true;
+        croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
+        croppingProto.type = DocumentType.IMG;
+        croppingProto.layout = ImageBox.LayoutString("data")
+        croppingProto.data = ObjectField.MakeCopy(this.rootDoc[this.fieldKey] as ObjectField);
+        croppingProto["data-nativeWidth"] = anchw;
+        croppingProto["data-nativeHeight"] = anchh;
+        croppingProto.viewScale = viewScale;
+        croppingProto.viewScaleMin = viewScale;
+        croppingProto.panX = anchx / viewScale;
+        croppingProto.panY = anchy / viewScale;
+        croppingProto.panXMin = (anchx) / viewScale;
+        croppingProto.panXMax = (anchw) / viewScale;
+        croppingProto.panYMin = (anchy) / viewScale;
+        croppingProto.panYMax = (anchh) / viewScale;
+        if (addCrop) {
+            DocUtils.MakeLink({ doc: region }, { doc: cropping }, "cropped image", "");
+        }
+        this.props.bringToFront(cropping);
+        return cropping;
+    }
+
     specificContextMenu = (e: React.MouseEvent): void => {
         const field = Cast(this.dataDoc[this.fieldKey], ImageField);
         if (field) {
@@ -367,6 +411,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     savedAnnotations={this._savedAnnotations}
                     annotationLayer={this._annotationLayer.current}
                     mainCont={this._mainCont.current}
+                    anchorMenuCrop={this.crop}
                 />}
         </div >);
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 710270be4..41e2fc266 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -19,7 +19,7 @@ import { RichTextField } from "../../../../fields/RichTextField";
 import { RichTextUtils } from '../../../../fields/RichTextUtils';
 import { Cast, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
 import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
 import { DocServer } from "../../../DocServer";
 import { Docs, DocUtils } from '../../../documents/Documents';
@@ -219,6 +219,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             return undefined;
         });
         AnchorMenu.Instance.onMakeAnchor = this.getAnchor;
+        AnchorMenu.Instance.StartCropDrag = unimplementedFunction;
         /**
          * This function is used by the PDFmenu to create an anchor highlight and a new linked text annotation.  
          * It also initiates a Drag/Drop interaction to place the text annotation.
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index ad3afb775..29d068817 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -46,8 +46,10 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
 
     public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search
 
+    public OnCrop: (e: PointerEvent) => void = unimplementedFunction;
     public OnClick: (e: PointerEvent) => void = unimplementedFunction;
     public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
+    public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
     public Highlight: (color: string, isPushpin: boolean) => Opt<Doc> = (color: string, isPushpin: boolean) => undefined;
     public GetAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
     public Delete: () => void = unimplementedFunction;
@@ -79,6 +81,13 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
         }, returnFalse, e => this.OnClick?.(e));
     }
 
+    cropDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, (e: PointerEvent) => {
+            this.StartCropDrag(e, this._commentCont.current!);
+            return true;
+        }, returnFalse, e => this.OnCrop?.(e));
+    }
+
     @action
     highlightClicked = (e: React.MouseEvent) => {
         if (!this.Highlight(this.highlightColor, false) && this.Pinned) {
@@ -161,7 +170,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                         <FontAwesomeIcon style={{ position: "absolute", transform: "scale(0.5)", transformOrigin: "top left", top: 12, left: 12 }} icon={"link"} size="lg" />
                     </button>
                 </Tooltip>,
-                <LinkPopup key="popup" showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor} />
+                <LinkPopup key="popup" showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor} />,
+                AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? <></> : <Tooltip key="crop" title={<div className="dash-tooltip">{"Click/Drag to create cropped image"}</div>}>
+                    <button className="antimodeMenu-button annotate" onPointerDown={this.cropDown} style={{ cursor: "grab" }}>
+                        <FontAwesomeIcon icon="image" size="lg" />
+                    </button>
+                </Tooltip>,
             ] : [
                 <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}>
                     <button className="antimodeMenu-button" onPointerDown={this.Delete}>
-- 
cgit v1.2.3-70-g09d2


From 5d9487362545d451b80240a894e84bedd68d2e15 Mon Sep 17 00:00:00 2001
From: Aubrey-Li <aubreylys@hotmail.com>
Date: Wed, 27 Apr 2022 00:35:39 -0400
Subject: tree view presentation move to slide

---
 src/client/views/collections/TreeView.tsx | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 12bab3cd1..c0037ff1b 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -102,7 +102,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     get defaultExpandedView() {
         return this.doc.viewType === CollectionViewType.Docking ? this.fieldKey :
             this.props.treeView.dashboardMode ? this.fieldKey :
-                this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "aliases") :
+                this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "aliases") : // for displaying 
                     this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.UserDoc().noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields");
     }
 
@@ -811,6 +811,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             fitContentsToDoc={returnTrue}
             hideDecorationTitle={this.props.treeView.outlineMode}
             hideResizeHandles={this.props.treeView.outlineMode}
+            onClick={this.onChildClick}
             focus={this.refocus}
             ContentScaling={returnOne}
             hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
@@ -879,7 +880,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                 ref={this.createTreeDropTarget}
                 onDrop={this.onTreeDrop}
                 //onPointerDown={e => this.props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document
-                onKeyDown={this.onKeyDown}>
+                onKeyDown={this.onKeyDown}
+            >
                 <li className="collection-child">
                     {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader ? // should test for prop 'treeViewRenderDocWithBulletAsHeader"
                         this.renderEmbeddedDocument(false, returnFalse) :
-- 
cgit v1.2.3-70-g09d2


From 9f3f64bb5bd3c7d5c97dfcbad39306cab465b822 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 27 Apr 2022 12:02:29 -0400
Subject: fixed double-click on file sys to lightbox the doc.  adjusted how
 aliases are chosen when opening file sys doc.  fixed sorting UI of treeviews

---
 src/client/views/StyleProvider.tsx                 |  2 +-
 .../views/collections/CollectionTreeView.scss      |  5 +-
 src/client/views/collections/TreeView.scss         | 11 ++++
 src/client/views/collections/TreeView.tsx          | 74 ++++++++++++++--------
 4 files changed, 63 insertions(+), 29 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 5c10c2344..34418e170 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -213,7 +213,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
 }
 
 export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, offIcon: IconProp, clickFunc?: () => void) {
-    return <div className={`styleProvider-treeView-icon${doc[field] ? "-active" : ""}`}
+    return <div title={field} className={`styleProvider-treeView-icon${doc[field] ? "-active" : ""}`}
         onClick={undoBatch(action((e: React.MouseEvent) => {
             e.stopPropagation();
             clickFunc ? clickFunc() : (doc[field] = doc[field] ? undefined : true);
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index a8eee9c19..93523a6cf 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -1,5 +1,6 @@
 @import "../global/globalCssVariables";
 
+  
 .collectionTreeView-container {
     transform-origin: top left;
     height: 100%;
@@ -31,9 +32,11 @@
             width: unset;
             height: unset;
         }
+        &:hover {
+            cursor: ns-resize;
+        }
     }
 
-
     .no-indent {
         padding-left: 0;
         width: max-content;
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 4707ebb80..b91737a1d 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -62,6 +62,17 @@
     }
 }
 
+.treeView-sorting {
+    position: absolute;
+    height: max-content;
+    pointer-events: none;
+    color: white;
+    border-radius: 4px;
+    font-size: 10px;
+}
+.treeView-container-active {
+    cursor: default;
+}
 .treeView-container-outline-active
 .treeView-container-active {
     z-index: 100;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 9108acfcf..3a49297f8 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -79,6 +79,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     static _editTitleOnLoad: Opt<{ id: string, parent: TreeView | CollectionTreeView | undefined }>;
     static _openTitleScript: Opt<ScriptField | undefined>;
     static _openLevelScript: Opt<ScriptField | undefined>;
+    static _sortUIMap = [["up", "crimson", "↑"], ["down", "blue", "↓"], ["z", "green", "z"], ["x", "darkgray", '\u00A0\u00A0\u00A0']];
     private _header: React.RefObject<HTMLDivElement> = React.createRef();
     private _tref = React.createRef<HTMLDivElement>();
     @observable _docRef: Opt<DocumentView>;
@@ -156,6 +157,17 @@ export class TreeView extends React.Component<TreeViewProps> {
             docView.select(false);
         }
     }
+    @action
+    openLevel = (docView: DocumentView) => {
+        if (this.props.document.isFolder || Doc.IsSystem(this.props.document)) {
+            this.treeViewOpen = !this.treeViewOpen;
+        } else {
+            // choose an appropriate alias or make one. --- choose the first alias that (1) user owns,  (2) has no context field ... otherwise make a new alias
+            const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
+            const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail);
+            this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), "lightbox");
+        }
+    }
 
     constructor(props: any) {
         super(props);
@@ -399,13 +411,16 @@ export class TreeView extends React.Component<TreeViewProps> {
         TraceMobx();
         const expandKey = this.treeViewExpandedView;
         if (["links", "annotations", "aliases", this.fieldKey].includes(expandKey)) {
+            const sorting = StrCast(this.doc.treeViewSortCriterion);
+            const color = (TreeView._sortUIMap.find((sortUIfields) => sortUIfields[0] === sorting) ?? TreeView._sortUIMap.lastElement())[1];
+            const label = (TreeView._sortUIMap.find((sortUIfields) => sortUIfields[0] === sorting) ?? TreeView._sortUIMap.lastElement())[2];
             const key = (expandKey === "annotations" ? `${this.fieldKey}-` : "") + expandKey;
             const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key);
             const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
                 // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't),
                 // then the modification would be done here
                 const ordering = StrCast(this.doc.treeViewSortCriterion);
-                if (ordering === "Z") {
+                if (ordering === "z") {
                     const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering);
                     doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000;
                     docs.push(doc);
@@ -418,24 +433,29 @@ export class TreeView extends React.Component<TreeViewProps> {
             const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
             const docs = expandKey === "aliases" ? this.childAliases : expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs;
             let downX = 0, downY = 0;
-            const sortings = ["up", "down", "Z", undefined];
+            const sortings = this.props.treeView.rootDoc === Doc.UserDoc().myFilesystem ? ["up", "down", "x"] : ["up", "down", "z", "x"];
             const curSort = Math.max(0, sortings.indexOf(Cast(this.doc.treeViewSortCriterion, "string", null)));
-            return <ul key={expandKey + "more"} title={"sort: " + sortings[curSort]} className={this.doc.treeViewHideTitle ? "no-indent" : ""}
-                onPointerDown={e => { downX = e.clientX; downY = e.clientY; e.stopPropagation(); }}
-                onClick={(e) => {
-                    if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
-                        !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortings[(curSort + 1) % sortings.length]);
-                        e.stopPropagation();
-                    }
-                }}>
-                {!docs ? (null) :
-                    TreeView.GetChildElements(docs, this.props.treeView, this, this.layoutDoc,
-                        this.dataDoc, this.props.containerCollection, this.props.prevSibling, addDoc, remDoc, this.move,
-                        StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform,
-                        this.props.isContentActive, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
-                        [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged,
-                        this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems())}
-            </ul >;
+            return <>
+                {!docs?.length ? (null) : <div className={'treeView-sorting'} style={{ background: color }} >
+                    {label}
+                </div>}
+                <ul key={expandKey + "more"} title="click to change sort order" className={this.doc.treeViewHideTitle ? "no-indent" : ""}
+                    onPointerDown={e => { downX = e.clientX; downY = e.clientY; e.stopPropagation(); }}
+                    onClick={(e) => {
+                        if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
+                            !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortings[(curSort + 1) % sortings.length]);
+                            e.stopPropagation();
+                        }
+                    }}>
+                    {!docs ? (null) :
+                        TreeView.GetChildElements(docs, this.props.treeView, this, this.layoutDoc,
+                            this.dataDoc, this.props.containerCollection, this.props.prevSibling, addDoc, remDoc, this.move,
+                            StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform,
+                            this.props.isContentActive, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
+                            [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged,
+                            this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems())}
+                </ul >
+            </>;
         } else if (this.treeViewExpandedView === "fields") {
             return <ul key={this.doc[Id] + this.doc.title}>
                 <div style={{ display: "inline-block" }} >
@@ -497,7 +517,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const data = () => this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : "";
         const aliases = () => this.props.treeView.dashboardMode ? "" : "aliases";
         const fields = () => Doc.UserDoc().noviceMode ? "" : "fields";
-        const layout = (this.props.treeView.dashboardMode && Doc.UserDoc().noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"];
+        const layout = (Doc.UserDoc().noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"];
         return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [aliases(), links(), annos()] : []), fields()].filter(m => m);
     }
     @action
@@ -512,9 +532,9 @@ export class TreeView extends React.Component<TreeViewProps> {
     @computed get headerElements() {
         return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? (null)
             : <>
-                {this.doc.hideContextMenu ? (null) : <FontAwesomeIcon key="bars" icon="bars" size="sm" onClick={e => { this.showContextMenu(e); e.stopPropagation(); }} />}
+                {this.doc.hideContextMenu ? (null) : <FontAwesomeIcon title="context menu" key="bars" icon="bars" size="sm" onClick={e => { this.showContextMenu(e); e.stopPropagation(); }} />}
                 {this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? (null) :
-                    <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView} onPointerDown={this.expandNextviewType}>
+                    <span className="collectionTreeView-keyHeader" title="type of expanded data" key={this.treeViewExpandedView} onPointerDown={this.expandNextviewType}>
                         {this.treeViewExpandedView}
                     </span>}
             </>;
@@ -771,9 +791,9 @@ export class TreeView extends React.Component<TreeViewProps> {
     }
 
     @computed get renderBorder() {
-        const sorting = this.doc[`${this.fieldKey}-sortCriterion`];
-        return <div className={`treeView-border${this.props.treeView.outlineMode ? "outline" : ""}`}
-            style={{ borderColor: sorting === undefined ? undefined : sorting === "up" ? "crimson" : sorting === "down" ? "blue" : "green" }}>
+        const sorting = StrCast(this.doc.treeViewSortCriterion);
+        const color = (TreeView._sortUIMap.find((sortUIfields) => sortUIfields[0] === sorting) ?? TreeView._sortUIMap.lastElement())[1];
+        return <div className={`treeView-border${this.props.treeView.outlineMode ? "outline" : ""}`} style={{ borderColor: color }}>
             {!this.treeViewOpen ? (null) : this.renderContent}
         </div>;
     }
@@ -822,9 +842,9 @@ export class TreeView extends React.Component<TreeViewProps> {
             };
             docs.sort(function (d1, d2): 0 | 1 | -1 {
                 const a = (criterion === "up" ? d2 : d1);
-                const b = (criterion === "up" ? d1 : d2);
-                const first = a[criterion === "Z" ? "zIndex" : "title"];
-                const second = b[criterion === "Z" ? "zIndex" : "title"];
+                const b = (criterion === "down" ? d1 : d2);
+                const first = a[criterion === "z" ? "zIndex" : "title"];
+                const second = b[criterion === "z" ? "zIndex" : "title"];
                 if (typeof first === 'number' && typeof second === 'number') return (first - second) > 0 ? 1 : -1;
                 if (typeof first === 'string' && typeof second === 'string') return sortAlphaNum(first, second);
                 return criterion ? 1 : -1;
-- 
cgit v1.2.3-70-g09d2


From ce94cdd070035ef6374eeb471ecf6e4542b4ba20 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 28 Apr 2022 13:53:09 -0400
Subject: fixed rendering of slides in filesystem view to not render the UI,
 just the doc name

---
 src/client/documents/Documents.ts           | 1 +
 src/client/views/collections/TabDocView.tsx | 2 +-
 src/client/views/collections/TreeView.tsx   | 4 ++--
 3 files changed, 4 insertions(+), 3 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 087d32a60..741868a99 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -282,6 +282,7 @@ export class DocumentOptions {
     strokeWidth?: number;
     freezeChildren?: string; // whether children are now allowed to be added and or removed from a collection
     treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view
+    treeViewHideHeaderIfTemplate?: boolean; // whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)
     treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view
     treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
     treeViewGrowsHorizontally?: boolean; // whether an embedded tree view of the document can grow horizontally without growing vertically
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 98d6049f0..8e45ec3b3 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -221,7 +221,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             pinDoc.treeViewFieldKey = "data"; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field
             pinDoc.treeViewExpandedView = "data";// in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view
             pinDoc.treeViewGrowsHorizontally = true;// the document expands horizontally when displayed as a tree view header  
-            pinDoc.treeViewHideHeader = true;  // this will force the document to render itself as the tree view header
+            pinDoc.treeViewHideHeaderIfTemplate = true;  // this will force the document to render itself as the tree view header
             const presArray: Doc[] = PresBox.Instance?.sortArray();
             const size: number = PresBox.Instance?._selectedArray.size;
             const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 3a49297f8..647476784 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -596,7 +596,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
     }
     onKeyDown = (e: React.KeyboardEvent) => {
-        if (this.doc.treeViewHideHeader || this.props.treeView.outlineMode) {
+        if (this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) {
             switch (e.key) {
                 case "Tab":
                     e.stopPropagation();
@@ -810,7 +810,7 @@ export class TreeView extends React.Component<TreeViewProps> {
 
     render() {
         TraceMobx();
-        const hideTitle = this.doc.treeViewHideHeader || this.props.treeView.outlineMode;
+        const hideTitle = this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode;
         return this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? "<" + this.doc.title + ">" : // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles
             <div className={`treeView-container${this.props.isContentActive() ? "-active" : ""}`}
                 ref={this.createTreeDropTarget}
-- 
cgit v1.2.3-70-g09d2


From 314ed039ea4d5128c84de8ec1f06c1ccb0d0e3ec Mon Sep 17 00:00:00 2001
From: Aubrey-Li <aubreylys@hotmail.com>
Date: Mon, 2 May 2022 20:29:48 -0400
Subject: PresBox indexing rework

---
 .../views/collections/CollectionTreeView.tsx       | 10 +++-
 src/client/views/collections/CollectionView.tsx    |  4 ++
 src/client/views/collections/TreeView.tsx          | 35 ++++++++++++--
 src/client/views/nodes/trails/PresBox.tsx          | 54 ++++++++++++++++++----
 tsconfig.json                                      |  1 +
 5 files changed, 92 insertions(+), 12 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 41970eb96..5dafb08c0 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -37,6 +37,10 @@ export type collectionTreeViewProps = {
     treeViewSkipFields?: string[]; // prevents specific fields from being displayed (see LinkBox)
     onCheckedClick?: () => ScriptField;
     onChildClick?: () => ScriptField;
+    // TODO: [AL] add these fields
+    AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
+    RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
+    hierarchyIndex?: number[];
 };
 
 @observer
@@ -250,7 +254,11 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             this.props.dontRegisterView || Cast(this.props.Document.childDontRegisterViews, "boolean", null),
             this.observeHeight,
             this.unobserveHeight,
-            this.childContextMenuItems()
+            this.childContextMenuItems(),
+            //TODO: [AL] add these
+            this.props.AddToMap,
+            this.props.RemFromMap,
+            this.props.hierarchyIndex,
         );
     }
     @computed get titleBar() {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ee2c28b5f..07bd3957c 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -79,6 +79,10 @@ export interface CollectionViewProps extends FieldViewProps {
     childIgnoreNativeSize?: boolean;
     childClickScript?: ScriptField;
     childDoubleClickScript?: ScriptField;
+    //TODO: [AL] add these fields
+    AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
+    RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
+    hierarchyIndex?: number[];
 }
 @observer
 export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps>() {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index c0037ff1b..304d68a20 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -63,6 +63,10 @@ export interface TreeViewProps {
     onChildClick?: () => ScriptField;
     skipFields?: string[];
     firstLevel: boolean;
+    // TODO: [AL] add these
+    AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
+    RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
+    hierarchyIndex?: number[];
 }
 
 const treeBulletWidth = function () { return Number(TREE_BULLET_WIDTH.replace("px", "")); };
@@ -190,6 +194,13 @@ export class TreeView extends React.Component<TreeViewProps> {
         this._treeEle && this.props.unobserveHeight(this._treeEle);
         document.removeEventListener("pointermove", this.onDragMove, true);
         document.removeEventListener("pointermove", this.onDragUp, true);
+        // TODO: [AL] add these
+        this.props.RemFromMap?.(this.doc, this.props.hierarchyIndex!);
+    }
+
+    componentDidMount() {
+        // TODO: [AL] add these
+        this.props.AddToMap?.(this.doc, this.props.hierarchyIndex!);
     }
 
     onDragUp = (e: PointerEvent) => {
@@ -356,7 +367,12 @@ export class TreeView extends React.Component<TreeViewProps> {
                     this.props.dropAction, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform, this.props.isContentActive,
                     this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
                     [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged,
-                    this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems());
+                    this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems(),
+                    // TODO: [AL] Add these
+                    this.props.AddToMap,
+                    this.props.RemFromMap,
+                    this.props.hierarchyIndex
+                );
             } else {
                 contentElement = <EditableView key="editableView"
                     contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
@@ -444,7 +460,12 @@ export class TreeView extends React.Component<TreeViewProps> {
                         StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform,
                         this.props.isContentActive, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
                         [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged,
-                        this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems())}
+                        this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems(),
+                        // TODO: [AL] add these
+                        this.props.AddToMap,
+                        this.props.RemFromMap,
+                        this.props.hierarchyIndex,
+                    )}
             </ul >;
         } else if (this.treeViewExpandedView === "fields") {
             return <ul key={this.doc[Id] + this.doc.title}>
@@ -946,7 +967,11 @@ export class TreeView extends React.Component<TreeViewProps> {
         dontRegisterView: boolean | undefined,
         observerHeight: (ref: any) => void,
         unobserveHeight: (ref: any) => void,
-        contextMenuItems: ({ script: ScriptField, filter: ScriptField, label: string, icon: string }[])
+        contextMenuItems: ({ script: ScriptField, filter: ScriptField, label: string, icon: string }[]),
+        // TODO: [AL] add these
+        AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[],
+        RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[],
+        hierarchyIndex?: number[],
     ) {
         const viewSpecScript = Cast(containerCollection.viewSpecScript, ScriptField);
         if (viewSpecScript) {
@@ -987,6 +1012,10 @@ export class TreeView extends React.Component<TreeViewProps> {
                 dataDoc={pair.data}
                 containerCollection={containerCollection}
                 prevSibling={docs[i]}
+                // TODO: [AL] add these
+                hierarchyIndex={[...hierarchyIndex!, i]}
+                AddToMap={AddToMap}
+                RemFromMap={RemFromMap}
                 treeView={treeView}
                 indentDocument={indent}
                 outdentDocument={outdent}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 4fa52565e..60d54c433 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -98,7 +98,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @observable private openMovementDropdown: boolean = false;
     @observable private openEffectDropdown: boolean = false;
     @observable private presentTools: boolean = false;
-    @computed get childDocs() { return DocListCast(this.rootDoc[this.fieldKey]); }
+    // @computed get childDocs() { return DocListCast(this.rootDoc[this.fieldKey]); }
+    // TODO: [AL] add childDocs() and treeMap fields
+    // @computed get childDocs() { return DocListCast(this.rootDoc.presentationaLinearizedDocuments); }
+    //_treeViewMap:Map<number[], Doc>
+    @computed get childDocs() { return DocListCast(this.rootDoc.presentationLinearizedDocuments); }
+    @observable _treeViewMap: Map<string, Doc> = new Map<string, Doc>();
+
     @computed get tagDocs() {
         const tagDocs: Doc[] = [];
         for (const doc of this.childDocs) {
@@ -134,6 +140,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 { field: "string", data: Doc.name, container: Doc.name });
         }
         this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox
+        //TODO: [AL] change this
+        this.props.Document.presentationLinearizedDocuments = new List<Doc>();
     }
     @computed get selectedDocumentView() {
         if (SelectionManager.Views().length) return SelectionManager.Views()[0];
@@ -214,6 +222,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     //TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time 
+    // TODO: to handle child slides (entering into subtrail and exiting), also the next() and back() functions
     // No more frames in current doc and next slide is defined, therefore move to next slide 
     nextSlide = (activeNext: Doc) => {
         const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
@@ -741,7 +750,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     //Regular click
     @action
     selectElement = async (doc: Doc) => {
-        console.log("got here", this.childDocs.indexOf(doc))
+        console.log("child docs are:", doc);
+        console.log("got here", this.childDocs.indexOf(doc));
         const context = Cast(doc.context, Doc, null);
         this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
         if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0);
@@ -2416,6 +2426,29 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         PresBox.startMarquee = true;
     }
 
+    AddToMap = (treeViewDoc: Doc, index: number[]): Doc[] => {
+        this._treeViewMap.set(String(index), treeViewDoc);
+        this.props.Document.presentationaLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap)); // this is a flat array of Docs
+        return this.childDocs;
+    }
+
+    RemFromMap = (treeViewDoc: Doc, index: number[]): Doc[] => {
+        this._treeViewMap.delete(String(index))
+        this.props.Document.presentationaLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap));
+        return this.childDocs;
+    }
+
+    // TODO: [AL] implement sort function for an array of numbers (e.g. arr[1,2,4] v arr[1,2,1])
+    sort = (treeViewMap: Map<string, Doc>): Doc[] => {
+        // TODO
+        const sortedMap = [...treeViewMap.entries()].sort();
+        var sortedDocs = [];
+        for (var kv of sortedMap) {
+            sortedDocs.push(kv[1]);
+        }
+        return sortedDocs;
+    }
+
     render() {
         // calling this method for keyEvents
         this.isPres;
@@ -2465,6 +2498,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                 dontRegisterView={true}
                                 focus={this.selectElement}
                                 ScreenToLocalTransform={this.getTransform}
+                                // TODO: [AL] implement AddToMap, RemFromMap functions (outside this)
+                                AddToMap={this.AddToMap}
+                                RemFromMap={this.RemFromMap}
+                                hierarchyIndex={[]}
                             /> : (null)
                         }
                     </div>
@@ -2480,11 +2517,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             </div>;
     }
 }
-ScriptingGlobals.add(function lookupPresBoxField(container: Doc, field: string, data: Doc) {
-    if (field === 'indexInPres') return DocListCast(container[StrCast(container.presentationFieldKey)]).indexOf(data);
-    if (field === 'presCollapsedHeight') return [CollectionViewType.Tree || CollectionViewType.Stacking].includes(container._viewType as any) ? 35 : 31;
-    if (field === 'presStatus') return container.presStatus;
-    if (field === '_itemIndex') return container._itemIndex;
-    if (field === 'presBox') return container;
+// this func communicates with PresBoxElement to send information of the doc
+ScriptingGlobals.add(function lookupPresBoxField(presBoxDoc: Doc, field: string, presEleDoc: Doc) {
+    if (field === 'indexInPres') return DocListCast(presBoxDoc.presentationLinearizedDocuments).indexOf(presEleDoc);
+    if (field === 'presCollapsedHeight') return [CollectionViewType.Tree || CollectionViewType.Stacking].includes(presBoxDoc._viewType as any) ? 35 : 31;
+    if (field === 'presStatus') return presBoxDoc.presStatus;
+    if (field === '_itemIndex') return presBoxDoc._itemIndex;
+    if (field === 'presBox') return presBoxDoc;
     return undefined;
 });
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index f688f18ea..993ab13b9 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,7 @@
 {
     "compilerOptions": {
         "target": "es5",
+        "downlevelIteration": true,
         // "module": "system",
         "removeComments": true,
         "experimentalDecorators": true,
-- 
cgit v1.2.3-70-g09d2


From ca26b43095622d07ae81fc08d4037be38d9a8b28 Mon Sep 17 00:00:00 2001
From: Aubrey-Li <aubreylys@hotmail.com>
Date: Tue, 3 May 2022 18:10:55 -0400
Subject: implement child slide sorting

---
 src/client/views/collections/TreeView.tsx |  2 +-
 src/client/views/nodes/trails/PresBox.tsx | 27 ++++++++++++++++++++-------
 2 files changed, 21 insertions(+), 8 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 304d68a20..f9497eb4a 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1013,7 +1013,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 containerCollection={containerCollection}
                 prevSibling={docs[i]}
                 // TODO: [AL] add these
-                hierarchyIndex={[...hierarchyIndex!, i]}
+                hierarchyIndex={[...hierarchyIndex!, i + 1]}
                 AddToMap={AddToMap}
                 RemFromMap={RemFromMap}
                 treeView={treeView}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 60d54c433..cfc7b0416 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -103,7 +103,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     // @computed get childDocs() { return DocListCast(this.rootDoc.presentationaLinearizedDocuments); }
     //_treeViewMap:Map<number[], Doc>
     @computed get childDocs() { return DocListCast(this.rootDoc.presentationLinearizedDocuments); }
-    @observable _treeViewMap: Map<string, Doc> = new Map<string, Doc>();
+    @observable _treeViewMap: Map<number, Doc> = new Map<number, Doc>();
 
     @computed get tagDocs() {
         const tagDocs: Doc[] = [];
@@ -750,7 +750,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     //Regular click
     @action
     selectElement = async (doc: Doc) => {
-        console.log("child docs are:", doc);
+        console.log("tree docs are:", this._treeViewMap);
+        console.log("child docs are:", this.childDocs);
+        console.log("linearized docs:", this.rootDoc.presentationLinearizedDocuments);
         console.log("got here", this.childDocs.indexOf(doc));
         const context = Cast(doc.context, Doc, null);
         this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
@@ -2427,19 +2429,30 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     AddToMap = (treeViewDoc: Doc, index: number[]): Doc[] => {
-        this._treeViewMap.set(String(index), treeViewDoc);
-        this.props.Document.presentationaLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap)); // this is a flat array of Docs
+        var indexNum = 0;
+        for (let i = 0; i < index.length; i++) {
+            indexNum += (index[i] * (10 ** (-i)));
+        }
+        this._treeViewMap.set(indexNum, treeViewDoc);
+        console.log(String(index), treeViewDoc)
+        this.props.Document.presentationLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap)); // this is a flat array of Docs
+        console.log(this.props.Document.presentationLinearizedDocuments)
         return this.childDocs;
     }
 
     RemFromMap = (treeViewDoc: Doc, index: number[]): Doc[] => {
-        this._treeViewMap.delete(String(index))
-        this.props.Document.presentationaLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap));
+        var indexNum = 0;
+        for (let i = 0; i < index.length; i++) {
+            indexNum += (index[i] * (10 ** (-i)));
+        }
+        console.log(String(index), treeViewDoc)
+        this._treeViewMap.delete(indexNum)
+        this.props.Document.presentationLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap));
         return this.childDocs;
     }
 
     // TODO: [AL] implement sort function for an array of numbers (e.g. arr[1,2,4] v arr[1,2,1])
-    sort = (treeViewMap: Map<string, Doc>): Doc[] => {
+    sort = (treeViewMap: Map<number, Doc>): Doc[] => {
         // TODO
         const sortedMap = [...treeViewMap.entries()].sort();
         var sortedDocs = [];
-- 
cgit v1.2.3-70-g09d2


From 32d46a0b641022cf0dd1fe0cf15629cf75057b59 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 4 May 2022 16:03:51 -0400
Subject: cleaned up treeview sorting.

---
 src/client/views/StyleProvider.tsx        | 10 +++++++
 src/client/views/collections/TreeView.tsx | 46 +++++++++++++++++--------------
 src/client/views/nodes/FilterBox.tsx      |  2 ++
 3 files changed, 37 insertions(+), 21 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index a530ff90a..ca9826ab9 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -24,6 +24,7 @@ import { SliderBox } from './nodes/SliderBox';
 import "./StyleProvider.scss";
 import React = require("react");
 import { InkingStroke } from './InkingStroke';
+import { TreeSort } from './collections/TreeView';
 
 export enum StyleLayers {
     Background = "background"
@@ -31,6 +32,7 @@ export enum StyleLayers {
 
 export enum StyleProp {
     TreeViewIcon = "treeViewIcon",
+    TreeViewSortings = "treeViewSortings",// options for how to sort tree view items
     DocContents = "docContents",          // when specified, the JSX returned will replace the normal rendering of the document view
     Opacity = "opacity",                  // opacity of the document view
     Hidden = "hidden",                    // whether the document view should not be isplayed
@@ -98,6 +100,14 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 return <img src={url} width={20} height={15} style={{ margin: "auto", display: "block", objectFit: "contain" }} />;
             }
             return Doc.toIcon(doc, isOpen);
+
+        case StyleProp.TreeViewSortings:
+            const allSorts: { [key: string]: { color: string, label: string } | undefined } = {};
+            allSorts[TreeSort.Down] = { color: "blue", label: "↓" };
+            allSorts[TreeSort.Up] = { color: "crimson", label: "↑" };
+            if (doc?._viewType === CollectionViewType.Freeform) allSorts[TreeSort.Zindex] = { color: "green", label: "z" };
+            allSorts[TreeSort.None] = { color: "darkgray", label: '\u00A0\u00A0\u00A0' };
+            return allSorts;
         case StyleProp.DocContents: return undefined;
         case StyleProp.WidgetColor: return isAnnotated ? Colors.LIGHT_BLUE : darkScheme() ? "lightgrey" : "dimgrey";
         case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 647476784..72480b094 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -67,7 +67,12 @@ export interface TreeViewProps {
 
 const treeBulletWidth = function () { return Number(TREE_BULLET_WIDTH.replace("px", "")); };
 
-@observer
+export enum TreeSort {
+    Up = "up",
+    Down = "down",
+    Zindex = "z",
+    None = "none"
+};
 /**
  * Renders a treeView of a collection of documents
  * 
@@ -75,11 +80,11 @@ const treeBulletWidth = function () { return Number(TREE_BULLET_WIDTH.replace("p
  * treeViewOpen : flag denoting whether the documents sub-tree (contents) is visible or hidden
  * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree
  */
+@observer
 export class TreeView extends React.Component<TreeViewProps> {
     static _editTitleOnLoad: Opt<{ id: string, parent: TreeView | CollectionTreeView | undefined }>;
     static _openTitleScript: Opt<ScriptField | undefined>;
     static _openLevelScript: Opt<ScriptField | undefined>;
-    static _sortUIMap = [["up", "crimson", "↑"], ["down", "blue", "↓"], ["z", "green", "z"], ["x", "darkgray", '\u00A0\u00A0\u00A0']];
     private _header: React.RefObject<HTMLDivElement> = React.createRef();
     private _tref = React.createRef<HTMLDivElement>();
     @observable _docRef: Opt<DocumentView>;
@@ -410,17 +415,18 @@ export class TreeView extends React.Component<TreeViewProps> {
     @computed get renderContent() {
         TraceMobx();
         const expandKey = this.treeViewExpandedView;
+        const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string, label: string } };
         if (["links", "annotations", "aliases", this.fieldKey].includes(expandKey)) {
-            const sorting = StrCast(this.doc.treeViewSortCriterion);
-            const color = (TreeView._sortUIMap.find((sortUIfields) => sortUIfields[0] === sorting) ?? TreeView._sortUIMap.lastElement())[1];
-            const label = (TreeView._sortUIMap.find((sortUIfields) => sortUIfields[0] === sorting) ?? TreeView._sortUIMap.lastElement())[2];
+            const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None);
+            const sortKeys = Object.keys(sortings);
+            const curSortIndex = Math.max(0, sortKeys.findIndex(val => val === sorting));
             const key = (expandKey === "annotations" ? `${this.fieldKey}-` : "") + expandKey;
             const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key);
             const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
                 // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't),
                 // then the modification would be done here
                 const ordering = StrCast(this.doc.treeViewSortCriterion);
-                if (ordering === "z") {
+                if (ordering === TreeSort.Zindex) {
                     const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering);
                     doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000;
                     docs.push(doc);
@@ -433,17 +439,15 @@ export class TreeView extends React.Component<TreeViewProps> {
             const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
             const docs = expandKey === "aliases" ? this.childAliases : expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs;
             let downX = 0, downY = 0;
-            const sortings = this.props.treeView.rootDoc === Doc.UserDoc().myFilesystem ? ["up", "down", "x"] : ["up", "down", "z", "x"];
-            const curSort = Math.max(0, sortings.indexOf(Cast(this.doc.treeViewSortCriterion, "string", null)));
             return <>
-                {!docs?.length ? (null) : <div className={'treeView-sorting'} style={{ background: color }} >
-                    {label}
+                {!docs?.length ? (null) : <div className={'treeView-sorting'} style={{ background: sortings[sorting]?.color }} >
+                    {sortings[sorting]?.label}
                 </div>}
                 <ul key={expandKey + "more"} title="click to change sort order" className={this.doc.treeViewHideTitle ? "no-indent" : ""}
                     onPointerDown={e => { downX = e.clientX; downY = e.clientY; e.stopPropagation(); }}
                     onClick={(e) => {
                         if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
-                            !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortings[(curSort + 1) % sortings.length]);
+                            !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]);
                             e.stopPropagation();
                         }
                     }}>
@@ -791,9 +795,9 @@ export class TreeView extends React.Component<TreeViewProps> {
     }
 
     @computed get renderBorder() {
-        const sorting = StrCast(this.doc.treeViewSortCriterion);
-        const color = (TreeView._sortUIMap.find((sortUIfields) => sortUIfields[0] === sorting) ?? TreeView._sortUIMap.lastElement())[1];
-        return <div className={`treeView-border${this.props.treeView.outlineMode ? "outline" : ""}`} style={{ borderColor: color }}>
+        const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None);
+        const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string, label: string } };
+        return <div className={`treeView-border${this.props.treeView.outlineMode ? "outline" : ""}`} style={{ borderColor: sortings[sorting]?.color }}>
             {!this.treeViewOpen ? (null) : this.renderContent}
         </div>;
     }
@@ -827,11 +831,11 @@ export class TreeView extends React.Component<TreeViewProps> {
 
     public static sortDocs(childDocs: Doc[], criterion: string | undefined) {
         const docs = childDocs.slice();
-        if (criterion) {
+        if (criterion !== TreeSort.None) {
             const sortAlphaNum = (a: string, b: string): 0 | 1 | -1 => {
                 const reN = /[0-9]*$/;
-                const aA = a.replace(reN, ""); // get rid of trailing numbers
-                const bA = b.replace(reN, "");
+                const aA = a.replace(reN, "") ? a.replace(reN, "") : +a; // get rid of trailing numbers
+                const bA = b.replace(reN, "") ? b.replace(reN, "") : +b;
                 if (aA === bA) {  // if header string matches, then compare numbers numerically
                     const aN = parseInt(a.match(reN)![0], 10);
                     const bN = parseInt(b.match(reN)![0], 10);
@@ -841,10 +845,10 @@ export class TreeView extends React.Component<TreeViewProps> {
                 }
             };
             docs.sort(function (d1, d2): 0 | 1 | -1 {
-                const a = (criterion === "up" ? d2 : d1);
-                const b = (criterion === "down" ? d1 : d2);
-                const first = a[criterion === "z" ? "zIndex" : "title"];
-                const second = b[criterion === "z" ? "zIndex" : "title"];
+                const a = (criterion === TreeSort.Up ? d2 : d1);
+                const b = (criterion === TreeSort.Up ? d1 : d2);
+                const first = a[criterion === TreeSort.Zindex ? "zIndex" : "title"];
+                const second = b[criterion === TreeSort.Zindex ? "zIndex" : "title"];
                 if (typeof first === 'number' && typeof second === 'number') return (first - second) > 0 ? 1 : -1;
                 if (typeof first === 'string' && typeof second === 'string') return sortAlphaNum(first, second);
                 return criterion ? 1 : -1;
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index ba65acee0..dc0ab5ec2 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -386,6 +386,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     options={options}
                     isMulti={false}
                     onChange={val => this.facetClick((val as UserOptions).value)}
+                    onKeyDown={e => e.stopPropagation()}
                     value={null}
                     closeMenuOnSelect={true}
                 />
@@ -420,6 +421,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     whenChildContentsActiveChanged={returnFalse}
                     treeViewHideTitle={true}
                     focus={returnFalse}
+                    onCheckedClick={this.scriptField}
                     treeViewHideHeaderFields={false}
                     dontRegisterView={true}
                     styleProvider={this.FilterStyleProvider}
-- 
cgit v1.2.3-70-g09d2


From f072a9f2c1ad69eb8ae4242fa5d2e18bbd94f6ef Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 6 May 2022 11:45:44 -0400
Subject: changed following links to open up icons all the way down to the
 target document. allow StartLink to work with webBox w/ text selection. 
 fixed web clippings to have a cursor and grab keyDown events.

---
 src/client/util/DocumentManager.ts                 | 42 +++++++++++++++-------
 .../util/Import & Export/DirectoryImportBox.tsx    |  2 +-
 src/client/util/LinkManager.ts                     | 11 +++---
 src/client/util/SharingManager.tsx                 | 30 ++++++++--------
 src/client/views/DocumentDecorations.tsx           | 13 ++++---
 src/client/views/MainView.tsx                      |  2 +-
 src/client/views/collections/TabDocView.tsx        |  2 +-
 src/client/views/collections/TreeView.tsx          |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../collectionLinear/CollectionLinearView.tsx      |  2 +-
 .../collectionSchema/CollectionSchemaCells.tsx     |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  3 +-
 src/client/views/nodes/LinkDescriptionPopup.tsx    |  1 +
 src/client/views/nodes/PDFBox.tsx                  |  1 +
 src/client/views/nodes/WebBox.scss                 |  3 ++
 src/client/views/nodes/WebBox.tsx                  | 11 +++---
 src/client/views/nodes/trails/PresBox.tsx          |  4 +--
 src/client/views/search/SearchBox.tsx              |  2 +-
 18 files changed, 84 insertions(+), 51 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index b6c28d2fe..aeddc3249 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -156,7 +156,7 @@ export class DocumentManager {
         targetDoc: Doc,        // document to display
         willZoom: boolean,     // whether to zoom doc to take up most of screen
         createViewFunc = DocumentManager.addView, // how to create a view of the doc if it doesn't exist
-        docContext?: Doc,  // context to load that should contain the target
+        docContext: Doc[],  // context to load that should contain the target
         linkDoc?: Doc,   // link that's being followed
         closeContextIfNotFound: boolean = false, // after opening a context where the document should be, this determines whether the context should be closed if the Doc isn't actually there
         originatingDoc: Opt<Doc> = undefined, // doc that initiated the display of the target odoc
@@ -190,31 +190,40 @@ export class DocumentManager {
             finished?.();
         };
         const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && getFirstDocView(annotatedDoc);
-        const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined;
-        const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext : undefined;
+        const contextDocs = docContext.length ? await DocListCastAsync(docContext[0].data) : undefined;
+        const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext.lastElement() : undefined;
         const targetDocContext = contextDoc || annotatedDoc;
         const targetDocContextView = (targetDocContext && getFirstDocView(targetDocContext)) ||
             (wasHidden && annoContainerView);// if we have an annotation container and the target was hidden, then try again because we just un-hid the document above
         const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView;
-        if ((!docView && targetDoc.type !== DocumentType.MARKER) && annoContainerView) {
+        if (annoContainerView) {
             if (annoContainerView.props.Document.layoutKey === "layout_icon") {
-                annoContainerView.iconify(() => this.jumpToDocument(
-                    targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc,
-                    finished, originalTarget, noSelect, presZoom));
+                annoContainerView.iconify(() => annoContainerView.focus(targetDoc, {
+                    originalTarget, willZoom, scale: presZoom, afterFocus: (didFocus: boolean) =>
+                        new Promise<ViewAdjustment>(res => {
+                            focusAndFinish(true);
+                            res(ViewAdjustment.doNothing);
+                        })
+                }));
                 return;
-            } else {
+            } else if (!docView && targetDoc.type !== DocumentType.MARKER) {
                 annoContainerView.focus(targetDoc);  // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below
             }
         }
         if (focusView) {
             !noSelect && Doc.linkFollowHighlight(focusView.rootDoc); //TODO:glr make this a setting in PresBox
-            focusView.focus(targetDoc, {
+            const doFocus = (forceDidFocus: boolean) => focusView.focus(originalTarget ?? targetDoc, {
                 originalTarget, willZoom, scale: presZoom, afterFocus: (didFocus: boolean) =>
                     new Promise<ViewAdjustment>(res => {
-                        focusAndFinish(didFocus);
+                        focusAndFinish(forceDidFocus || didFocus);
                         res(ViewAdjustment.doNothing);
                     })
             });
+            if (focusView.props.Document.layoutKey === "layout_icon") {
+                focusView.iconify(() => doFocus(true));
+            } else {
+                doFocus(false);
+            }
         } else {
             if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default
                 createViewFunc(Doc.BrushDoc(targetDoc), finished); // bcz: should we use this?: Doc.MakeAlias(targetDoc)));
@@ -228,7 +237,7 @@ export class DocumentManager {
                             targetDocContext._viewTransition = undefined;
                             if (targetDocContext.layoutKey === "layout_icon") {
                                 targetDocContextView.iconify(() => this.jumpToDocument(
-                                    targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc,
+                                    resolvedTarget ?? targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc,
                                     finished, originalTarget, noSelect, presZoom));
                             }
                             return ViewAdjustment.doNothing;
@@ -263,7 +272,16 @@ export class DocumentManager {
                         };
                         setTimeout(() => findView(0), 0);
                     }
-                } else {  // there's no context view so we need to create one first and try again when that finishes
+                } else {
+                    if (docContext.length && docContext[0]?.layoutKey === "layout_icon") {
+                        const docContextView = this.getFirstDocumentView(docContext[0]);
+                        if (docContextView) {
+                            return docContextView.iconify(() => this.jumpToDocument(
+                                targetDoc, willZoom, createViewFunc, docContext.slice(1, docContext.length), linkDoc, closeContextIfNotFound, originatingDoc,
+                                finished, originalTarget, noSelect, presZoom));
+                        }
+                    }
+                    // there's no context view so we need to create one first and try again when that finishes
                     const finishFunc = () => this.jumpToDocument(targetDoc, true, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished, originalTarget);
                     createViewFunc(targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target
                         finishFunc);
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 39e9251a5..37571ae01 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -161,7 +161,7 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
             await GooglePhotos.Export.CollectionToAlbum({ collection: importContainer });
             Doc.AddDocToList(Doc.GetProto(parent.props.Document), "data", importContainer);
             !this.persistent && this.props.removeDocument && this.props.removeDocument(doc);
-            DocumentManager.Instance.jumpToDocument(importContainer, true);
+            DocumentManager.Instance.jumpToDocument(importContainer, true, undefined, []);
         }
 
         runInAction(() => {
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 9445533dc..b28662a57 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,3 +1,4 @@
+import { validationResult } from "express-validator/check";
 import { action, observable, observe } from "mobx";
 import { computedFn } from "mobx-utils";
 import { DirectLinksSym, Doc, DocListCast, Field, Opt } from "../../fields/Doc";
@@ -241,10 +242,12 @@ export class LinkManager {
                     } else {
                         const containerAnnoDoc = Cast(target.annotationOn, Doc, null);
                         const containerDoc = containerAnnoDoc || target;
-                        const containerDocContext = Cast(containerDoc?.context, Doc, null);
-                        const targetContext = LightboxView.LightboxDoc ? containerAnnoDoc || containerDocContext : containerDocContext;
-                        const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
-                        DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "lightbox"), finished), targetNavContext, linkDoc, undefined, sourceDoc, allFinished);
+                        var containerDocContext = containerDoc?.context ? [Cast(containerDoc?.context, Doc, null)] : [] as Doc[];
+                        while (containerDocContext.length && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && containerDocContext[0].context) {
+                            containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext];
+                        }
+                        const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]] : containerDocContext;
+                        DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "lightbox"), finished), targetContexts, linkDoc, undefined, sourceDoc, allFinished);
                     }
                 } else {
                     allFinished();
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 6d7f7e8df..11450309a 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -370,11 +370,11 @@ export class SharingManager extends React.Component<{}> {
         if (!uniform) dropdownValues.unshift("-multiple-");
         if (override) dropdownValues.unshift("None");
         return dropdownValues.filter(permission => !Doc.UserDoc().noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission =>
-            (
-                <option key={permission} value={permission}>
-                    {permission}
-                </option>
-            )
+        (
+            <option key={permission} value={permission}>
+                {permission}
+            </option>
+        )
         );
     }
 
@@ -388,7 +388,7 @@ export class SharingManager extends React.Component<{}> {
                 onClick={() => {
                     let context: Opt<CollectionView>;
                     if (this.targetDoc && this.targetDocView && docs.length === 1 && (context = this.targetDocView.props.ContainingCollectionView)) {
-                        DocumentManager.Instance.jumpToDocument(this.targetDoc, true, undefined, context.props.Document);
+                        DocumentManager.Instance.jumpToDocument(this.targetDoc, true, undefined, [context.props.Document]);
                     }
                 }}
                 onPointerEnter={action(() => {
@@ -548,10 +548,10 @@ export class SharingManager extends React.Component<{}> {
                                 {this.sharingOptions(uniform)}
                             </select>
                         ) : (
-                                <div className={"permissions-dropdown"}>
-                                    {permissions}
-                                </div>
-                            )}
+                            <div className={"permissions-dropdown"}>
+                                {permissions}
+                            </div>
+                        )}
                     </div>
                 </div>
             );
@@ -572,7 +572,7 @@ export class SharingManager extends React.Component<{}> {
                         <div className="edit-actions">
                             <div className={"permissions-dropdown"}>
                                 Owner
-                        </div>
+                            </div>
                         </div>
                     </div>
                 ) : null,
@@ -622,10 +622,10 @@ export class SharingManager extends React.Component<{}> {
                                 {this.sharingOptions(uniform, group.title === "Override")}
                             </select>
                         ) : (
-                                <div className={"permissions-dropdown"}>
-                                    {permissions}
-                                </div>
-                            )}
+                            <div className={"permissions-dropdown"}>
+                                {permissions}
+                            </div>
+                        )}
                     </div>
                 </div>
             );
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index eb2bcc18c..936946df0 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -113,7 +113,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         }
     }
 
-    titleEntered = (e: React.KeyboardEvent) => e.key === "Enter" && (e.target as any).blur();
+    titleEntered = (e: React.KeyboardEvent) => {
+        if (e.key === "Enter") {
+            e.stopPropagation();
+            (e.target as any).blur();
+        }
+    }
 
     @action onTitleDown = (e: React.PointerEvent): void => {
         setupMoveUpEvents(this, e, e => this.onBackgroundMove(true, e), (e) => { }, action((e) => {
@@ -288,7 +293,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         if (fixedAspect && (resizeHdl === "documentDecorations-bottomRightResizer" || resizeHdl === "documentDecorations-topLeftResizer")) { // need to generalize for bl and tr drag handles
             const project = (p: number[], a: number[], b: number[]) => {
                 const atob = [b[0] - a[0], b[1] - a[1]];
-                const atop = [p[0] - a[0], p[1] - a[1]]; first
+                const atop = [p[0] - a[0], p[1] - a[1]];
                 const len = atob[0] * atob[0] + atob[1] * atob[1];
                 let dot = atop[0] * atob[0] + atop[1] * atob[1];
                 const t = dot / len;
@@ -501,7 +506,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                     value={this._accumulatedTitle}
                     onBlur={e => this.titleBlur()}
                     onChange={action(e => this._accumulatedTitle = e.target.value)}
-                    onKeyPress={this.titleEntered} /> :
+                    onKeyDown={this.titleEntered} /> :
                 <div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown} >
                     <span className={`documentDecorations-titleSpan${colorScheme}`}>{`${this.selectionTitle}`}</span>
                 </div>;
@@ -521,7 +526,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         const useRotation = seldoc.ComponentView instanceof InkingStroke || seldoc.ComponentView instanceof ImageBox;
         const resizerScheme = colorScheme ? "documentDecorations-resizer" + colorScheme : "";
 
-        const rotation = NumCast(seldoc.rootDoc._jitterRotation)
+        const rotation = NumCast(seldoc.rootDoc._jitterRotation);
         const rdeg = rotation / 180 * Math.PI;
 
         return (<div className={`documentDecorations${colorScheme}`}>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index c794c73db..db51c54f8 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -133,7 +133,7 @@ export class MainView extends React.Component {
         window.addEventListener("paste", KeyManager.Instance.paste as any);
         document.addEventListener("dash", (e: any) => {  // event used by chrome plugin to tell Dash which document to focus on
             const id = FormattedTextBox.GetDocFromUrl(e.detail);
-            DocServer.GetRefField(id).then(doc => (doc instanceof Doc) ? DocumentManager.Instance.jumpToDocument(doc, false, undefined) : (null));
+            DocServer.GetRefField(id).then(doc => (doc instanceof Doc) ? DocumentManager.Instance.jumpToDocument(doc, false, undefined, []) : (null));
         });
         document.addEventListener("linkAnnotationToDash", Hypothesis.linkListener);
         this.initEventListeners();
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 78b125e07..8dfc7edc7 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -256,7 +256,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 }
                 PresBox.Instance?._selectedArray.clear();
                 pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array
-                DocumentManager.Instance.jumpToDocument(doc, false, undefined);
+                DocumentManager.Instance.jumpToDocument(doc, false, undefined, []);
                 batch.end();
             });
         }
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 72480b094..164021358 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -72,7 +72,7 @@ export enum TreeSort {
     Down = "down",
     Zindex = "z",
     None = "none"
-};
+}
 /**
  * Renders a treeView of a collection of documents
  * 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5d1e1892c..5b3a7db41 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1423,7 +1423,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
 
     replaceCanvases = (oldDiv: HTMLElement, newDiv: HTMLElement) => {
-        if (oldDiv.childNodes) {
+        if (oldDiv.childNodes && newDiv) {
             for (let i = 0; i < oldDiv.childNodes.length; i++) {
                 this.replaceCanvases(oldDiv.childNodes[i] as HTMLElement, newDiv.childNodes[i] as HTMLElement);
             }
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index e3d4f86c1..c615bfb8e 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -231,7 +231,7 @@ export class CollectionLinearView extends CollectionSubView() {
                         <span className="bottomPopup-text">
                             Currently playing:
                             {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) =>
-                                <span className="audio-title" onPointerDown={() => DocumentManager.Instance.jumpToDocument(clip, true)}>
+                                <span className="audio-title" onPointerDown={() => DocumentManager.Instance.jumpToDocument(clip, true, undefined, [])}>
                                     {clip.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? "" : ",")}
                                 </span>)}
                         </span>
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx
index c2bb3b3ac..adcd9e1e3 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx
@@ -199,7 +199,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc);
             const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null);
             // Jump to the this document
-            DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext,
+            DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext ? [targetContext] : [],
                 undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc));
         }
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8570f6fff..02ea87103 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -663,7 +663,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             }
             if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) {
                 const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.() ?? this.props.Document;
-                de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, undefined, undefined, undefined, undefined, [de.x, de.y]);
+                de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, undefined, undefined, undefined, undefined, [de.x, de.y - 50]);
             }
         }
     }
@@ -857,6 +857,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     }
     @observable _retryThumb = 1;
     thumbShown = () => !this.props.isSelected() && LightboxView.LightboxDoc !== this.rootDoc && this.thumb &&
+        !Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) &&
         !this._componentView?.isAnyChildContentActive?.() ? true : false
     @computed get contents() {
         TraceMobx();
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx
index a9d33f161..ccac66996 100644
--- a/src/client/views/nodes/LinkDescriptionPopup.tsx
+++ b/src/client/views/nodes/LinkDescriptionPopup.tsx
@@ -54,6 +54,7 @@ export class LinkDescriptionPopup extends React.Component<{}> {
                 top: LinkDescriptionPopup.popupY ? LinkDescriptionPopup.popupY : 350,
             }}>
             <input className="linkDescriptionPopup-input"
+                onKeyDown={e => e.stopPropagation()}
                 onKeyPress={e => e.key === "Enter" && this.onDismiss(true)}
                 placeholder={"(Optional) Enter link description..."}
                 onChange={(e) => this.descriptionChanged(e)}>
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 69662d53a..48465976a 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -75,6 +75,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
 
     updateIcon = () => {
+        return; // currently we render pdf icons as text labels
         const docViewContent = this.props.docViewPath().lastElement().ContentDiv!;
         const newDiv = docViewContent.cloneNode(true) as HTMLDivElement;
         newDiv.style.width = (this.layoutDoc[WidthSym]()).toString();
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index b037e7220..d8dd074a5 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -156,6 +156,9 @@
             position: absolute;
             top: 0;
             left: 0;
+            cursor: text;
+            padding: 15px;
+            height: 100%
         }
 
         .webBox-cont {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 80961c92f..f441e5d36 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -207,8 +207,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
 
     @action
-    createTextAnnotation = (sel: Selection, selRange: Range) => {
-        if (this._mainCont.current) {
+    createTextAnnotation = (sel: Selection, selRange: Range | undefined) => {
+        if (this._mainCont.current && selRange) {
             const clientRects = selRange.getClientRects();
             for (let i = 0; i < clientRects.length; i++) {
                 const rect = clientRects.item(i);
@@ -235,7 +235,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     menuControls = () => this.urlEditor; // controls to be added to the top bar when a document of this type is selected
 
     scrollFocus = (doc: Doc, smooth: boolean) => {
-        this.props.select(true);
+        this.props.select(false); // hack to preven the webBox from being replaced with a thumbnail that currently doesn't show the the anchors
         if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), !smooth);
         if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) {
             this.toggleSidebar(!smooth);
@@ -252,7 +252,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             }
         }
         this._initialScroll = NumCast(this.layoutDoc._scrollTop);
-        return 0;
+        return undefined;
     }
 
     getAnchor = () => {
@@ -279,7 +279,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             const scale = (this.props.scaling?.() || 1) * mainContBounds.scale;
             const sel = this._iframe.contentWindow.getSelection();
             if (sel) {
-                this._textAnnotationCreator = () => this.createTextAnnotation(sel, sel.getRangeAt(0));
+                this._textAnnotationCreator = () => this.createTextAnnotation(sel, !sel.isCollapsed ? sel.getRangeAt(0) : undefined);
                 AnchorMenu.Instance.jumpTo(e.clientX * scale + mainContBounds.translateX,
                     e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._scrollTop) * scale);
             }
@@ -650,6 +650,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @computed get content() {
         const interactive = !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && this.props.pointerEvents !== "none" && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting;
         return <div className={"webBox-cont" + (interactive ? "-interactive" : "")}
+            onKeyDown={e => e.stopPropagation()}
             style={{ width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]) || `100%` : "100%", }}>
             {this.urlContent}
         </div>;
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 30ad43562..820d7ef96 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -389,11 +389,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             LightboxView.SetLightboxDoc(targetDoc);
         } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
             LightboxView.SetLightboxDoc(undefined);
-            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right
+            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, [srcContext], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right
         } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
             LightboxView.SetLightboxDoc(undefined);
             //awaiting jump so that new scale can be found, since jumping is async     
-            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right    
+            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, [srcContext], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right    
         }
         // After navigating to the document, if it is added as a presPinView then it will
         // adjust the pan and scale to that of the pinView when it was added.
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 9257cb75e..3d36efbc4 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -365,7 +365,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      * or opening it in a new tab.
      */
     selectElement = async (doc: Doc, finishFunc: () => void) => {
-        await DocumentManager.Instance.jumpToDocument(doc, true, undefined, undefined, undefined, undefined, undefined, finishFunc);
+        await DocumentManager.Instance.jumpToDocument(doc, true, undefined, [], undefined, undefined, undefined, finishFunc);
     }
 
     /**
-- 
cgit v1.2.3-70-g09d2


From 57c1b8235b26a1b6a315922b4dc2926e1e597674 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 13 May 2022 18:17:10 -0400
Subject: removed layerProvider functionality.

---
 src/client/documents/Documents.ts                  |  3 +-
 src/client/views/DocComponent.tsx                  |  4 --
 src/client/views/GestureOverlay.tsx                |  1 -
 src/client/views/InkingStroke.tsx                  |  2 +-
 src/client/views/LightboxView.tsx                  |  1 -
 src/client/views/MainView.tsx                      |  6 ---
 src/client/views/OverlayView.tsx                   |  1 -
 src/client/views/Palette.tsx                       |  1 -
 src/client/views/PropertiesView.tsx                |  2 -
 src/client/views/StyleProvider.tsx                 | 52 +++-------------------
 src/client/views/TemplateMenu.tsx                  |  1 -
 src/client/views/collections/CollectionMenu.tsx    |  1 -
 .../collections/CollectionStackedTimeline.tsx      |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  2 -
 .../views/collections/CollectionTreeView.tsx       |  1 -
 src/client/views/collections/CollectionView.tsx    |  2 +-
 src/client/views/collections/TabDocView.tsx        | 19 +-------
 src/client/views/collections/TreeView.tsx          |  2 -
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 24 +++++-----
 .../collections/collectionFreeForm/MarqueeView.tsx | 10 ++---
 .../collectionLinear/CollectionLinearView.tsx      |  1 -
 .../CollectionMulticolumnView.tsx                  |  1 -
 .../CollectionMultirowView.tsx                     |  1 -
 .../collectionSchema/CollectionSchemaView.tsx      |  1 -
 .../collections/collectionSchema/SchemaTable.tsx   |  1 -
 src/client/views/linking/LinkPopup.tsx             |  3 +-
 src/client/views/nodes/AudioBox.tsx                |  2 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  2 -
 src/client/views/nodes/DocumentView.tsx            |  5 +--
 src/client/views/nodes/FilterBox.tsx               |  1 -
 src/client/views/nodes/ImageBox.tsx                |  2 +-
 src/client/views/nodes/KeyValuePair.tsx            |  1 -
 src/client/views/nodes/LinkAnchorBox.tsx           |  1 -
 src/client/views/nodes/LinkDocPreview.tsx          |  1 -
 src/client/views/nodes/VideoBox.tsx                |  2 +-
 src/client/views/nodes/WebBox.tsx                  |  6 +--
 .../views/nodes/formattedText/DashDocView.tsx      |  1 -
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 src/client/views/nodes/trails/PresBox.tsx          |  2 +-
 src/client/views/nodes/trails/PresElementBox.tsx   |  1 -
 src/client/views/pdf/Annotation.tsx                |  2 +-
 src/client/views/search/SearchBox.tsx              |  2 +-
 src/fields/Doc.ts                                  |  2 +-
 src/mobile/AudioUpload.tsx                         |  1 -
 src/mobile/MobileInterface.tsx                     |  1 -
 src/server/server_Initialization.ts                |  2 +-
 46 files changed, 41 insertions(+), 143 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index d9c2e0d8b..797a129c4 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -122,7 +122,6 @@ export class DocumentOptions {
     _scrollTop?: number; // scroll location for pdfs
     _noAutoscroll?: boolean;// whether collections autoscroll when this item is dragged
     _chromeHidden?: boolean; // whether the editing chrome for a document is hidden
-    _layerTags?: List<string>; // layer tags a document has (used for tab filtering "layers" in document tab)
     _searchDoc?: boolean; // is this a search document (used to change UI for search results in schema view)
     _forceActive?: boolean; // flag to handle pointer events when not selected (or otherwise active)
     _stayInCollection?: boolean;// whether the document should remain in its collection when someone tries to drag and drop it elsewhere
@@ -426,7 +425,7 @@ export namespace Docs {
                     childDontRegisterViews: true, _isLinkButton: true, _height: 150, description: "", showCaption: "description",
                     backgroundColor: "lightblue", // lightblue is default color for linking dot and link documents text comment area
                     links: "@links(self)",
-                    _removeDropProperties: new List(["_layerTags", "isLinkButton"]),
+                    _removeDropProperties: new List(["isLinkButton"]),
                 }
             }],
             [DocumentType.LINKDB, {
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 79aaf2158..9c176a4fd 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -44,7 +44,6 @@ interface ViewBoxBaseProps {
     ContainingCollectionDoc: Opt<Doc>;
     DocumentView?: () => DocumentView;
     fieldKey: string;
-    layerProvider?: (doc: Doc, assign?: boolean) => boolean;
     isSelected: (outsideReaction?: boolean) => boolean;
     isContentActive: () => boolean | undefined;
     renderDepth: number;
@@ -85,7 +84,6 @@ export interface ViewBoxAnnotatableProps {
     DataDoc?: Doc;
     fieldKey: string;
     filterAddDocument?: (doc: Doc[]) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
-    layerProvider?: (doc: Doc, assign?: boolean) => boolean;
     isContentActive: () => boolean | undefined;
     select: (isCtrlPressed: boolean) => void;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
@@ -209,13 +207,11 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                             if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc);
                             doc.context = this.props.Document;
                             if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
-                            this.props.layerProvider?.(doc, true);
                             Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
                         });
                     }
                     else {
                         added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => {  // only make a pushpin if we have acl's to edit the document
-                            this.props.layerProvider?.(doc, true);
                             //DocUtils.LeavePushpin(doc);
                             doc._stayInCollection = undefined;
                             doc.context = this.props.Document;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 50dca0a99..482b62479 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -881,7 +881,6 @@ export class GestureOverlay extends Touchable {
                 isContentActive={returnFalse}
                 renderDepth={0}
                 styleProvider={returnEmptyString}
-                layerProvider={undefined}
                 docViewPath={returnEmptyDoclist}
                 focus={DocUtils.DefaultFocus}
                 whenChildContentsActiveChanged={emptyFunction}
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 3d9c048e5..d0f01c363 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -332,7 +332,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
             inkStrokeWidth, inkStrokeWidth + (highlightIndex && closed && fillColor && (new Color(fillColor)).alpha() < 1 ? 6 : 15),
             StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap),
             StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" || suppressFill ? "none" : fillColor, startMarker, endMarker,
-            markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0,
+            markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.rootDoc._lockedPosition ? "none" : "visiblepainted"), 0.0,
             false, downHdlr);
         const fsize = +(StrCast(this.props.Document.fontSize, "12px").replace("px", ""));
         // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size. 
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 59ed0dc92..9882693ee 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -246,7 +246,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                         docFilters={this.docFilters}
                         removeDocument={undefined}
                         styleProvider={DefaultStyleProvider}
-                        layerProvider={returnTrue}
                         ScreenToLocalTransform={this.lightboxScreenToLocal}
                         PanelWidth={this.lightboxWidth}
                         PanelHeight={this.lightboxHeight}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index db51c54f8..2e1d10955 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -281,7 +281,6 @@ export class MainView extends React.Component {
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
             docViewPath={returnEmptyDoclist}
-            layerProvider={undefined}
             styleProvider={undefined}
             rootSelected={returnTrue}
             isContentActive={returnTrue}
@@ -361,7 +360,6 @@ export class MainView extends React.Component {
                         addDocTab={this.addDocTabFunc}
                         pinToPres={emptyFunction}
                         docViewPath={returnEmptyDoclist}
-                        layerProvider={undefined}
                         styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === Doc.UserDoc().myFilesystem ? DashboardStyleProvider : DefaultStyleProvider}
                         rootSelected={returnTrue}
                         removeDocument={returnFalse}
@@ -402,7 +400,6 @@ export class MainView extends React.Component {
                 docViewPath={returnEmptyDoclist}
                 focus={DocUtils.DefaultFocus}
                 styleProvider={DefaultStyleProvider}
-                layerProvider={undefined}
                 isContentActive={returnTrue}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
@@ -516,7 +513,6 @@ export class MainView extends React.Component {
                     dropAction={"alias"}
                     setHeight={returnFalse}
                     styleProvider={DefaultStyleProvider}
-                    layerProvider={undefined}
                     rootSelected={returnTrue}
                     bringToFront={emptyFunction}
                     select={emptyFunction}
@@ -591,7 +587,6 @@ export class MainView extends React.Component {
                     ContainingCollectionDoc={undefined}
                     Document={DocumentLinksButton.invisibleWebDoc}
                     dropAction={"move"}
-                    layerProvider={undefined}
                     styleProvider={undefined}
                     isSelected={returnFalse}
                     select={returnFalse}
@@ -673,7 +668,6 @@ export class MainView extends React.Component {
                             rootSelected={returnFalse}
                             renderDepth={0}
                             setHeight={returnFalse}
-                            layerProvider={undefined}
                             styleProvider={undefined}
                             addDocTab={returnFalse}
                             pinToPres={returnFalse}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 0f51cf9b2..ebad2981d 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -195,7 +195,6 @@ export class OverlayView extends React.Component {
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={DefaultStyleProvider}
-                    layerProvider={undefined}
                     docViewPath={returnEmptyDoclist}
                     addDocTab={returnFalse}
                     pinToPres={emptyFunction}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 529697f71..954529bc9 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -54,7 +54,6 @@ export default class Palette extends React.Component<PaletteProps> {
                             focus={emptyFunction}
                             docViewPath={returnEmptyDoclist}
                             styleProvider={returnEmptyString}
-                            layerProvider={undefined}
                             whenChildContentsActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
                             docFilters={returnEmptyFilter}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 21c688421..bba2ac211 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -303,7 +303,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     fitContentsToDoc={returnTrue}
                     rootSelected={returnFalse}
                     styleProvider={DefaultStyleProvider}
-                    layerProvider={undefined}
                     docViewPath={returnEmptyDoclist}
                     freezeDimensions={true}
                     dontCenter={"y"}
@@ -1010,7 +1009,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             createNewFilterDoc={this.createNewFilterDoc}
                             updateFilterDoc={this.updateFilterDoc}
                             docViewPath={returnEmptyDoclist}
-                            layerProvider={undefined}
                             dontCenter="y"
                         />
                     </div>
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 5056dedaf..334415b38 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -26,10 +26,6 @@ import React = require("react");
 import { InkingStroke } from './InkingStroke';
 import { TreeSort } from './collections/TreeView';
 
-export enum StyleLayers {
-    Background = "background"
-}
-
 export enum StyleProp {
     TreeViewIcon = "treeViewIcon",
     TreeViewSortings = "treeViewSortings",// options for how to sort tree view items
@@ -56,14 +52,9 @@ export enum StyleProp {
 
 function darkScheme() { return CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark; }
 
-function toggleBackground(doc: Doc) {
+function toggleLockedPosition(doc: Doc) {
     UndoManager.RunInBatch(() => runInAction(() => {
-        const layers = StrListCast(doc._layerTags);
-        if (!layers.includes(StyleLayers.Background)) {
-            if (!layers.length) doc._layerTags = new List<string>([StyleLayers.Background]);
-            else layers.push(StyleLayers.Background);
-        }
-        else layers.splice(layers.indexOf(StyleLayers.Background), 1);
+        doc._lockedPosition = !doc._lockedPosition;
     }), "toggleBackground");
 }
 
@@ -86,7 +77,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
     const isOpen = property.includes(":open");
     const fieldKey = props?.fieldKey ? props.fieldKey + "-" : isCaption ? "caption-" : "";
     const comicStyle = () => doc && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === "comic";
-    const isBackground = () => StrListCast(doc?._layerTags).includes(StyleLayers.Background);
+    const isBackground = () => doc && BoolCast(doc._lockedPosition);
     const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
     const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
     const showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle);
@@ -177,7 +168,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)";
                 default: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE); break;
             }
-            if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = DashColor(docColor).fade(0.5).toString();
+            if (docColor && !doc) docColor = DashColor(docColor).fade(0.5).toString();
             return docColor;
         }
         case StyleProp.BoxShadow: {
@@ -205,17 +196,15 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.PointerEvents:
             if (doc?.type === DocumentType.MARKER) return "none";
             if (props?.pointerEvents?.() === "none") return "none";
-            const layer = doc && props?.layerProvider?.(doc);
             const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name);
-            if (opacity() === 0 || (isInk && !docProps?.treeViewDoc) || doc?.isInkMask) return "none";
-            if (layer === false && !selected && !SnappingManager.GetIsDragging()) return "none";
-            if (!isInk && layer === true) return "all";
+            if (doc?._lockedPosition || opacity() === 0 || (isInk && !docProps?.treeViewDoc) || doc?.isInkMask) return "none";
+            if (!isInk) return "all";
             return undefined;
         case StyleProp.Decorations:
             if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform || doc?.x !== undefined || doc?.y !== undefined) {
                 return doc && (isBackground() || selected) && (props?.renderDepth || 0) > 0 &&
                     ((doc.type === DocumentType.COL && doc._viewType !== CollectionViewType.Pile) || [DocumentType.RTF, DocumentType.IMG, DocumentType.INK].includes(doc.type as DocumentType)) ?
-                    <div className="styleProvider-lock" onClick={() => toggleBackground(doc)}>
+                    <div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
                         <FontAwesomeIcon icon={isBackground() ? "lock" : "unlock"} style={{ color: isBackground() ? "red" : undefined }} size="lg" />
                     </div>
                     : (null);
@@ -251,30 +240,3 @@ export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps
     }
     return DefaultStyleProvider(doc, props, property);
 }
-
-//
-// a preliminary semantic-"layering/grouping" mechanism for determining interactive properties of documents
-//  currently, the provider tests whether the docuemnt's layer field matches the activeLayer field of the tab.
-//     if it matches, then the document gets pointer events, otherwise it does not.
-//
-export function DefaultLayerProvider(thisDoc: Doc) {
-    return (doc: Doc, assign?: boolean) => {
-        if (doc.z) return true;
-        if (assign) {
-            const activeLayer = StrCast(thisDoc?.activeLayer);
-            if (activeLayer) {
-                const layers = Cast(doc._layerTags, listSpec("string"), []);
-                if (layers.length && !layers.includes(activeLayer)) layers.push(activeLayer);
-                else if (!layers.length) doc._layerTags = new List<string>([activeLayer]);
-                if (activeLayer === "red" || activeLayer === "green" || activeLayer === "blue") doc._backgroundColor = activeLayer;
-            }
-            return true;
-        } else {
-            if (Doc.AreProtosEqual(doc, thisDoc)) return true;
-            const layers = StrListCast(doc._layerTags);
-            if (!layers.length && !thisDoc?.activeLayer) return true;
-            if (layers.includes(StrCast(thisDoc?.activeLayer))) return true;
-            return false;
-        }
-    };
-}
\ No newline at end of file
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index b3a24e031..636f7042f 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -131,7 +131,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 ContainingCollectionDoc={undefined}
                 ContainingCollectionView={undefined}
                 styleProvider={DefaultStyleProvider}
-                layerProvider={undefined}
                 setHeight={returnFalse}
                 docViewPath={returnEmptyDoclist}
                 docFilters={returnEmptyFilter}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 364a2440e..b3fbd4ca4 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -108,7 +108,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps>{
                 dropAction={"alias"}
                 setHeight={returnFalse}
                 styleProvider={DefaultStyleProvider}
-                layerProvider={undefined}
                 rootSelected={returnTrue}
                 bringToFront={emptyFunction}
                 select={emptyFunction}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index de307416f..683b6d51d 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -392,7 +392,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
     // handles dragging and dropping markers in timeline
     @action
     internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number) {
-        if (!de.embedKey && this.props.layerProvider?.(this.props.Document) !== false && this.props.Document._isGroup) return false;
+        if (!de.embedKey && this.props.Document._isGroup) return false;
         if (!super.onInternalDrop(e, de)) return false;
 
         // determine x coordinate of drop and assign it to the documents being dragged  --- see internalDocDrop of collectionFreeFormView.tsx for how it's done when dropping onto a 2D freeform view
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 509005b45..4338dedcc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -222,7 +222,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             PanelWidth={width}
             PanelHeight={height}
             styleProvider={this.styleProvider}
-            layerProvider={this.props.layerProvider}
             docViewPath={this.props.docViewPath}
             fitWidth={this.props.childFitWidth}
             isContentActive={emptyFunction}
@@ -543,7 +542,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                     renderDepth={this.props.renderDepth}
                     focus={emptyFunction}
                     styleProvider={this.props.styleProvider}
-                    layerProvider={this.props.layerProvider}
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 41970eb96..5e89016db 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -296,7 +296,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     renderDepth={this.props.renderDepth + 1}
                     focus={emptyFunction}
                     styleProvider={this.props.styleProvider}
-                    layerProvider={this.props.layerProvider}
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ee2c28b5f..7c5f49b42 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -261,7 +261,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             CollectionView: this,
         };
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
-            style={{ pointerEvents: this.props.layerProvider?.(this.rootDoc) === false ? "none" : undefined }}>
+            style={{ pointerEvents: this.rootDoc._lockedPosition ? "none" : undefined }}>
             {this.showIsTagged()}
             {this.renderSubView(this.collectionViewType, props)}
         </div>);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 8dfc7edc7..73e5a9178 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -26,7 +26,7 @@ import { Colors, Shadows } from '../global/globalEnums';
 import { LightboxView } from '../LightboxView';
 import { DocFocusOptions, DocumentView, DocumentViewProps } from "../nodes/DocumentView";
 import { PinProps, PresBox, PresMovement } from '../nodes/trails';
-import { DefaultLayerProvider, DefaultStyleProvider, StyleLayers, StyleProp } from '../StyleProvider';
+import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
 import { CollectionDockingView } from './CollectionDockingView';
 import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
@@ -94,20 +94,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
 
             if (tab.element[0].children[1].children.length === 1) {
-                const toggle = document.createElement("div");
-                toggle.style.width = "10px";
-                toggle.style.height = "calc(100% - 2px)";
-                toggle.style.left = "-2px";
-                toggle.style.bottom = "1px";
-                toggle.style.borderTopRightRadius = "7px";
-                toggle.style.position = "relative";
-                toggle.style.display = "inline-block";
-                toggle.style.background = "transparent";
-                toggle.onclick = (e: MouseEvent) => {
-                    if (tab.contentItem === tab.header.parent.getActiveContentItem()) {
-                        tab.DashDoc.activeLayer = tab.DashDoc.activeLayer ? undefined : StyleLayers.Background;
-                    }
-                };
                 iconWrap.className = "lm_iconWrap";
                 iconWrap.id = "lm_iconWrap";
                 closeWrap.className = "lm_iconWrap";
@@ -357,7 +343,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     disableMinimap = () => !this._document || (this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform);
     hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.hideMinimap);
 
-    @computed get layerProvider() { return this._document && DefaultLayerProvider(this._document); }
     @computed get docView() {
         return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
             <><DocumentView key={this._document[Id]} ref={action((r: DocumentView) => this._view = r)}
@@ -369,7 +354,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 isContentActive={returnTrue}
                 PanelWidth={this.PanelWidth}
                 PanelHeight={this.PanelHeight}
-                layerProvider={this.layerProvider}
                 styleProvider={DefaultStyleProvider}
                 docFilters={CollectionDockingView.Instance.childDocFilters}
                 docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
@@ -520,7 +504,6 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={TabMinimapView.miniStyleProvider}
-                    layerProvider={undefined}
                     addDocTab={this.props.addDocTab}
                     pinToPres={TabDocView.PinDoc}
                     docFilters={CollectionDockingView.Instance.childDocFilters}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 164021358..d608f800c 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -663,7 +663,6 @@ export class TreeView extends React.Component<TreeViewProps> {
                 hideDecorationTitle={this.props.treeView.outlineMode}
                 hideResizeHandles={this.props.treeView.outlineMode}
                 styleProvider={this.titleStyleProvider}
-                layerProvider={returnTrue}
                 docViewPath={returnEmptyDoclist}
                 treeViewDoc={this.props.treeView.props.Document}
                 addDocument={undefined}
@@ -760,7 +759,6 @@ export class TreeView extends React.Component<TreeViewProps> {
             renderDepth={this.props.renderDepth + 1}
             treeViewDoc={this.props.treeView?.props.Document}
             rootSelected={returnTrue}
-            layerProvider={returnTrue}
             docViewPath={this.props.treeView.props.docViewPath}
             docFilters={returnEmptyFilter}
             docRangeFilters={returnEmptyFilter}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4f79d19ad..322944d92 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -44,7 +44,7 @@ import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
 import { PresBox } from "../../nodes/trails/PresBox";
 import { VideoBox } from "../../nodes/VideoBox";
 import { CreateImage } from "../../nodes/WebBoxRenderer";
-import { StyleLayers, StyleProp } from "../../StyleProvider";
+import { StyleProp } from "../../StyleProvider";
 import { CollectionDockingView } from "../CollectionDockingView";
 import { CollectionSubView } from "../CollectionSubView";
 import { CollectionViewType } from "../CollectionView";
@@ -122,8 +122,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @observable ChildDrag: DocumentView | undefined; // child document view being dragged.  needed to update drop areas of groups when a group item is dragged.
 
     @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
-    @computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); }
-    @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && this.props.isContentActive(); }
     @computed get fitToContentVals() {
         return {
             bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 },
@@ -222,8 +220,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) {
-        if (!de.embedKey && !this.ChildDrag && this.props.layerProvider?.(this.props.Document) !== false && this.props.Document._isGroup) return false;
-        if (!super.onInternalDrop(e, de)) return false;
+        if (!de.embedKey && !this.ChildDrag && this.rootDoc._isGroup) return false;
+        if (this.rootDoc._lockedPosition || !super.onInternalDrop(e, de)) return false;
         const refDoc = docDragData.droppedDocuments[0];
         const [xpo, ypo] = this.getContainerTransform().transformPoint(de.x, de.y);
         const z = NumCast(refDoc.z);
@@ -251,7 +249,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             const nd = [Doc.NativeWidth(layoutDoc), Doc.NativeHeight(layoutDoc)];
             layoutDoc._width = NumCast(layoutDoc._width, 300);
             layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? nd[1] / nd[0] * NumCast(layoutDoc._width) : 300);
-            !StrListCast(d._layerTags).includes(StyleLayers.Background) && (d._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
+            (d._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
         }
 
         (docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(docDragData.droppedDocuments);
@@ -418,8 +416,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 styleProp = colors[cluster % colors.length];
                 const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor);
                 // override the cluster color with an explicitly set color on a non-background document.  then override that with an explicitly set color on a background document
-                set?.filter(s => !StrListCast(s._layerTags).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor));
-                set?.filter(s => StrListCast(s._layerTags).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor));
+                set?.map(s => styleProp = StrCast(s.backgroundColor));
             }
         } //else if (doc && NumCast(doc.group, -1) !== -1) styleProp = "gray";
         return styleProp;
@@ -1017,7 +1014,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     bringToFront = (doc: Doc, sendToBack?: boolean) => {
-        if (sendToBack || StrListCast(doc._layerTags).includes(StyleLayers.Background)) {
+        if (sendToBack) {
             doc.zIndex = 0;
         } else if (doc.isInkMask) {
             doc.zIndex = 5000;
@@ -1155,7 +1152,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     pointerEvents = () => {
         const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
-        const pointerEvents = this.props.isContentActive() === false ? "none" : this.backgroundActive || this.props.childPointerEvents ? "all" :
+        const pointerEvents = this.props.isContentActive() === false ? "none" : this.props.childPointerEvents ? "all" :
             (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : this.props.pointerEvents?.();
         return pointerEvents;
     }
@@ -1195,7 +1192,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
             docViewPath={this.props.docViewPath}
             styleProvider={this.getClusterColor}
-            layerProvider={this.props.layerProvider}
             dataProvider={this.childDataProvider}
             sizeProvider={this.childSizeProvider}
             freezeDimensions={BoolCast(this.props.Document.childFreezeDimensions, this.props.childFreezeDimensions)}
@@ -1614,7 +1610,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const isDocInView = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => intersectRect(docDims(doc), rect);
 
         const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) };
-        let snappableDocs = activeDocs.filter(doc => !StrListCast(doc._layerTags).includes(StyleLayers.Background) && doc.z === undefined && isDocInView(doc, selRect));  // first see if there are any foreground docs to snap to
+        let snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect));  // first see if there are any foreground docs to snap to
         !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect))); // if not, see if there are background docs to snap to
         !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z !== undefined && isDocInView(doc, otherBounds))); // if not, then why not snap to floating docs
 
@@ -1739,7 +1735,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             onContextMenu={this.onContextMenu}
             style={{
                 pointerEvents: this.props.Document.type === DocumentType.MARKER ? "none" :  // bcz: ugh.. this is here to prevent markers, which render as freeform views, from grabbing events -- need a better approach.
-                    this.backgroundEvents ? "all" : this.props.pointerEvents?.() as any,
+                    this.props.pointerEvents?.() as any,
                 transform: `scale(${this.contentScaling || 1})`,
                 width: `${100 / (this.contentScaling || 1)}%`,
                 height: this.isAnnotationOverlay && this.Document.scrollHeight ? NumCast(this.Document.scrollHeight) : `${100 / (this.contentScaling || 1)}%`// : this.isAnnotationOverlay ? (this.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight()
@@ -1767,7 +1763,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     </svg>
                 </div>}
 
-            {this.props.Document._isGroup && SnappingManager.GetIsDragging() && (this.ChildDrag || this.props.layerProvider?.(this.props.Document) === false) ?
+            {this.props.Document._isGroup && SnappingManager.GetIsDragging() && this.ChildDrag ?
                 <div className="collectionFreeForm-groupDropper" ref={this.createGroupEventsTarget} style={{
                     width: this.ChildDrag ? "10000" : "100%",
                     height: this.ChildDrag ? "10000" : "100%",
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 5f303b428..1c4d47d57 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -28,7 +28,6 @@ import { CollectionView } from "../CollectionView";
 import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
 import "./MarqueeView.scss";
 import React = require("react");
-import { StyleLayers } from "../../StyleProvider";
 import { TreeView } from "../TreeView";
 import { VideoBox } from "../../nodes/VideoBox";
 import { ImageField, WebField } from "../../../../fields/URLField";
@@ -348,7 +347,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         this.hideMarquee();
     }
 
-    getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, layers: string[], makeGroup: Opt<boolean>) => {
+    getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, makeGroup: Opt<boolean>) => {
         const newCollection = creator ? creator(selected, { title: "nested stack", }) : ((doc: Doc) => {
             Doc.GetProto(doc).data = new List<Doc>(selected);
             Doc.GetProto(doc).title = makeGroup ? "grouping" : "nested freeform";
@@ -357,7 +356,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             return doc;
         })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
         newCollection.system = undefined;
-        newCollection._layerTags = new List<string>(layers);
         newCollection._width = this.Bounds.width;
         newCollection._height = this.Bounds.height;
         newCollection._isGroup = makeGroup;
@@ -437,7 +435,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             }));
             this.props.removeDocument?.(selected);
         }
-        const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined, [], group);
+        const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined, group);
         this.props.addDocument?.(newCollection);
         this.props.selectDocuments([newCollection]);
         MarqueeOptionsMenu.Instance.fadeOut(true);
@@ -531,7 +529,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
 
     @action
     background = (e: KeyboardEvent | React.PointerEvent | undefined) => {
-        const newCollection = this.getCollection([], undefined, [StyleLayers.Background], undefined);
+        const newCollection = this.getCollection([], undefined, undefined);
         this.props.addDocument?.(newCollection);
         MarqueeOptionsMenu.Instance.fadeOut(true);
         this.hideMarquee();
@@ -617,7 +615,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                 (this.touchesLine(bounds) || this.boundingShape(bounds)) && selection.push(doc);
             }
         };
-        this.props.activeDocuments().filter(doc => this.props.layerProvider?.(doc) !== false && !doc.z).map(selectFunc);
+        this.props.activeDocuments().filter(doc => !doc.z && !doc._lockedPosition).map(selectFunc);
         if (!selection.length && selectBackgrounds) this.props.activeDocuments().filter(doc => doc.z === undefined).map(selectFunc);
         if (!selection.length) this.props.activeDocuments().filter(doc => doc.z !== undefined).map(selectFunc);
         return selection;
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index c615bfb8e..bec582dcd 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -155,7 +155,6 @@ export class CollectionLinearView extends CollectionSubView() {
                 renderDepth={this.props.renderDepth + 1}
                 focus={emptyFunction}
                 styleProvider={this.props.styleProvider}
-                layerProvider={this.props.layerProvider}
                 docViewPath={returnEmptyDoclist}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 6929a1cd8..92f9b2f49 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -219,7 +219,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
             styleProvider={this.props.styleProvider}
-            layerProvider={this.props.layerProvider}
             docViewPath={this.props.docViewPath}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 7e2b83230..4c4054b09 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -218,7 +218,6 @@ export class CollectionMultirowView extends CollectionSubView() {
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
             styleProvider={this.props.styleProvider}
-            layerProvider={this.props.layerProvider}
             docViewPath={this.props.docViewPath}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index a93762ea4..b731479a5 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -417,7 +417,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     docRangeFilters={this.childDocRangeFilters}
                     searchFilterDocs={this.searchFilterDocs}
                     styleProvider={DefaultStyleProvider}
-                    layerProvider={undefined}
                     docViewPath={returnEmptyDoclist}
                     ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                     ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx
index 605481ddf..bea5b3be6 100644
--- a/src/client/views/collections/collectionSchema/SchemaTable.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx
@@ -573,7 +573,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         Document={this._showDoc}
                         DataDoc={this._showDataDoc}
                         styleProvider={DefaultStyleProvider}
-                        layerProvider={undefined}
                         docViewPath={returnEmptyDoclist}
                         freezeDimensions={true}
                         focus={DocUtils.DefaultFocus}
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index c8be9069c..4b33ef8ae 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -67,7 +67,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                     <input defaultValue={""} autoComplete="off" type="text" placeholder="Search for Document..." id="search-input"
                         className="linkPopup-searchBox searchBox-input" /> */}
 
-                    <SearchBox 
+                    <SearchBox
                         Document={CurrentUserUtils.MySearchPanelDoc}
                         DataDoc={CurrentUserUtils.MySearchPanelDoc}
                         linkFrom={linkDoc}
@@ -83,7 +83,6 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                         pinToPres={emptyFunction}
                         rootSelected={returnTrue}
                         styleProvider={DefaultStyleProvider}
-                        layerProvider={undefined}
                         removeDocument={undefined}
                         ScreenToLocalTransform={Transform.Identity}
                         PanelWidth={this.getPWidth}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index e28e5b453..d97cb6f84 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -654,7 +654,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             className="audiobox-container"
             onContextMenu={this.specificContextMenu}
             onClick={!this.path && !this._recorder ? this.recordAudioAnnotation : undefined}
-            style={{ pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined }}
+            style={{ pointerEvents: this.layoutDoc._lockedPosition ? "none" : undefined }}
         >
             {!this.path ? this.recordingControls : this.playbackControls}
         </div>;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index edadd59c0..5a0ab9110 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -21,7 +21,6 @@ import React = require("react");
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
     dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
     sizeProvider?: (doc: Doc, replica: string) => { width: number, height: number } | undefined;
-    layerProvider: ((doc: Doc, assign?: boolean) => boolean) | undefined;
     renderCutoffProvider: (doc: Doc) => boolean;
     zIndex?: number;
     highlight?: boolean;
@@ -159,7 +158,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             ...this.props,
             CollectionFreeFormDocumentView: this.returnThis,
             styleProvider: this.styleProvider,
-            layerProvider: this.props.layerProvider,
             ScreenToLocalTransform: this.screenToLocalTransform,
             PanelWidth: this.panelWidth,
             PanelHeight: this.panelHeight,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f30d093a1..c999b3224 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -37,7 +37,7 @@ import { DocComponent } from "../DocComponent";
 import { EditableView } from '../EditableView';
 import { InkingStroke } from "../InkingStroke";
 import { LightboxView } from "../LightboxView";
-import { StyleLayers, StyleProp } from "../StyleProvider";
+import { StyleProp } from "../StyleProvider";
 import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "./DocumentContentsView";
 import { DocumentLinksButton } from './DocumentLinksButton';
@@ -123,7 +123,6 @@ export interface DocumentViewSharedProps {
     PanelHeight: () => number;
     docViewPath: () => DocumentView[];
     dataTransition?: string; // specifies animation transition - used by collectionPile and potentially other layout engines when changing the size of documents so that the change won't be abrupt
-    layerProvider: undefined | ((doc: Doc, assign?: boolean) => boolean);
     styleProvider: Opt<StyleProviderFunc>;
     focus: DocFocusFunc;
     fitWidth?: (doc: Doc) => boolean;
@@ -474,7 +473,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             let stopPropagate = true;
             let preventDefault = true;
-            !StrListCast(this.props.Document._layerTags).includes(StyleLayers.Background) && (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
+            (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
             if (this._doubleTap && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
                 if (this._timeout) {
                     clearTimeout(this._timeout);
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 78adf63cb..a47e17dfc 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -423,7 +423,6 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     treeViewHideHeaderFields={false}
                     dontRegisterView={true}
                     styleProvider={this.FilterStyleProvider}
-                    layerProvider={this.props.layerProvider}
                     docViewPath={this.props.docViewPath}
                     scriptContext={this.props.scriptContext}
                     moveDocument={returnFalse}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index e7c43e5cd..3b04aa807 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -379,7 +379,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             style={{
                 width: this.props.PanelWidth() ? undefined : `100%`,
                 height: this.props.PanelWidth() ? undefined : `100%`,
-                pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined,
+                pointerEvents: this.layoutDoc._lockedPosition ? "none" : undefined,
                 borderRadius
             }} >
             <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 881cbf2bb..80def3025 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -60,7 +60,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             docRangeFilters: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
-            layerProvider: undefined,
             docViewPath: returnEmptyDoclist,
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 437d29f39..7fd289a97 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -89,7 +89,6 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
     openLinkTargetOnRight = (e: React.MouseEvent) => {
         const alias = Doc.MakeAlias(Cast(this.layoutDoc[this.fieldKey], Doc, null));
         alias._isLinkButton = undefined;
-        alias._layerTags = undefined;
         alias.layoutKey = "layout";
         this.props.addDocTab(alias, "add:right");
     }
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 375434933..ba515fb89 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -179,7 +179,6 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             moveDocument={returnFalse}
                             rootSelected={returnFalse}
                             styleProvider={this.props.docProps?.styleProvider}
-                            layerProvider={this.props.docProps?.layerProvider}
                             docViewPath={returnEmptyDoclist}
                             ScreenToLocalTransform={Transform.Identity}
                             isDocumentActive={returnFalse}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 3b4c94562..c350e3139 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -809,7 +809,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / this.scaling()}px` : borderRad;
         return (<div className="videoBox" onContextMenu={this.specificContextMenu} ref={this._mainCont}
             style={{
-                pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined,
+                pointerEvents: this.layoutDoc._lockedPosition ? "none" : undefined,
                 borderRadius,
                 overflow: this.props.docViewPath?.().slice(-1)[0].fitWidth ? "auto" : undefined
             }} onWheel={e => { e.stopPropagation(); e.preventDefault(); }}>
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 20e01be05..445df8ddd 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -74,7 +74,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); }
     @computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); }
     @computed get webField() { return Cast(this.dataDoc[this.props.fieldKey], WebField)?.url; }
-    @computed get webThumb() { return this.props.thumbShown?.() && ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop ? this.layoutDoc.thumb : undefined))?.url }
+    @computed get webThumb() { return this.props.thumbShown?.() && ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop ? this.layoutDoc.thumb : undefined))?.url; }
 
     constructor(props: any) {
         super(props);
@@ -134,7 +134,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         returnedfilename => setTimeout(action(() => {
                             this.lockout = false;
                             this.layoutDoc.thumb = new ImageField(returnedfilename);
-                            this.layoutDoc.thumbScrollTop = scrollTop
+                            this.layoutDoc.thumbScrollTop = scrollTop;
                         }), 500));
                 })
                 .catch(function (error: any) {
@@ -717,7 +717,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     pointerEvents = () => !this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none";
     annotationPointerEvents = () => this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none";
     render() {
-        const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents?.() as any;
+        const pointerEvents = this.layoutDoc._lockedPosition ? "none" : this.props.pointerEvents?.() as any;
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const scale = previewScale * (this.props.scaling?.() || 1);
         const renderAnnotations = (docFilters?: () => string[]) =>
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 364be461f..1d8e3a2cf 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -182,7 +182,6 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     removeDocument={this.removeDoc}
                     isDocumentActive={returnFalse}
                     isContentActive={this._textBox.props.isContentActive}
-                    layerProvider={this._textBox.props.layerProvider}
                     styleProvider={this._textBox.props.styleProvider}
                     docViewPath={this._textBox.props.docViewPath}
                     ScreenToLocalTransform={this.getDocTransform}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 29117794e..f2a222cee 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1630,7 +1630,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const active = this.props.isContentActive();
         const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
-        const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false);
+        const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
         if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
         const minimal = this.props.ignoreAutoHeight;
         const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0);
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 820d7ef96..64f5a296f 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -700,7 +700,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc);
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight() - 40;
-    isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) &&
+    isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && !this.layoutDoc._lockedPosition) &&
         (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
 
     /**
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index f4dc9b615..ef918d991 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -80,7 +80,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     Document={this.targetDoc}
                     DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     styleProvider={this.styleProvider}
-                    layerProvider={this.props.layerProvider}
                     docViewPath={returnEmptyDoclist}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index fb2e33e2a..5bdce273d 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -26,7 +26,7 @@ export
             {DocListCast(this.props.anno.textInlineAnnotations).map(a =>
                 <RegionAnnotation pointerEvents={this.props.pointerEvents} {...this.props} document={a} key={a[Id]} />
             )}
-        </div>
+        </div>;
     }
 }
 
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 2905e96d9..152b7bbcb 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -127,7 +127,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     static foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) {
         let newarray: Doc[] = [];
         var depth = 0;
-        let visited: Doc[] = [];
+        const visited: Doc[] = [];
         while (docs.length > 0) {
             newarray = [];
             docs.filter(d => d && !visited.includes(d)).forEach(d => {
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 9de8d0831..194b3ba27 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1026,7 +1026,7 @@ export namespace Doc {
         if (status === DocBrushStatus.unbrushed) {
             const lastBrushed = Array.from(brushManager.BrushedDoc.keys()).lastElement();
             if (lastBrushed) {
-                for (var link of LinkManager.Instance.getAllDirectLinks(lastBrushed)) {
+                for (const link of LinkManager.Instance.getAllDirectLinks(lastBrushed)) {
                     const a1 = Cast(link.anchor1, Doc, null);
                     const a2 = Cast(link.anchor2, Doc, null);
                     if (Doc.AreProtosEqual(a1, doc) || Doc.AreProtosEqual(a2, doc) ||
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 88221732e..418464f0e 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -96,7 +96,6 @@ export class AudioUpload extends React.Component {
                         isDocumentActive={returnTrue}
                         isContentActive={emptyFunction}
                         focus={emptyFunction}
-                        layerProvider={undefined}
                         styleProvider={() => "rgba(0,0,0,0)"}
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index cfcc48608..78ec706d7 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -214,7 +214,6 @@ export class MobileInterface extends React.Component {
                     isContentActive={emptyFunction}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={this.whitebackground}
-                    layerProvider={undefined}
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index bdea57cb2..fd000a83c 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -195,7 +195,7 @@ function proxyServe(req: any, requrl: string, response: any) {
                 console.log("EROR?: ", e);
             }
         } else req.pipe(request(requrl)).pipe(response);
-    }
+    };
     retrieveHTTPBody = () => {
         req.headers.cookie = "";
         req.pipe(request(requrl))
-- 
cgit v1.2.3-70-g09d2


From ee1fa0ad22f1643888e4c467c6f8df837cc69178 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 17 May 2022 10:18:45 -0400
Subject: fixed pointerevents on treview open icon.  added browse mode for
 freeformcollections

---
 src/client/util/DragManager.ts                     | 24 ++++++++++++----------
 src/client/views/collections/TabDocView.tsx        |  2 +-
 src/client/views/collections/TreeView.tsx          | 13 ++++++++----
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 23 ++++++++++++++++-----
 .../CollectionMulticolumnView.tsx                  |  2 +-
 .../CollectionMultirowView.tsx                     |  2 +-
 6 files changed, 43 insertions(+), 23 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 037da132b..5a00e0c04 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -456,17 +456,19 @@ export namespace DragManager {
                 dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : dragData.defaultDropAction;
             }
             if (((e.target as any)?.className === "lm_tabs" || e?.shiftKey) && dragData.draggedDocuments.length === 1) {
-                if (!startWindowDragTimer) startWindowDragTimer = setTimeout(async () => {
-                    startWindowDragTimer = undefined;
-                    dragData.dropAction = dragData.userDropAction || "same";
-                    AbortDrag();
-                    await finishDrag?.(new DragCompleteEvent(true, dragData));
-                    DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, (aborted) => {
-                        if (!aborted && (dragData.dropAction === "move" || dragData.dropAction === "same")) {
-                            dragData.removeDocument?.(dragData.draggedDocuments[0]);
-                        }
-                    });
-                }, 500);
+                if (!startWindowDragTimer) {
+                    startWindowDragTimer = setTimeout(async () => {
+                        startWindowDragTimer = undefined;
+                        dragData.dropAction = dragData.userDropAction || "same";
+                        AbortDrag();
+                        await finishDrag?.(new DragCompleteEvent(true, dragData));
+                        DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, (aborted) => {
+                            if (!aborted && (dragData.dropAction === "move" || dragData.dropAction === "same")) {
+                                dragData.removeDocument?.(dragData.draggedDocuments[0]);
+                            }
+                        });
+                    }, 500);
+                }
             } else {
                 clearTimeout(startWindowDragTimer);
                 startWindowDragTimer = undefined;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 1310a582c..cebc3f779 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -85,7 +85,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             titleEle.value = doc.title;
             titleEle.onkeydown = (e: KeyboardEvent) => {
                 e.stopPropagation();
-            }
+            };
             titleEle.onchange = undoBatch(action((e: any) => {
                 titleEle.size = e.currentTarget.value.length + 3;
                 Doc.GetProto(doc).title = e.currentTarget.value;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index d608f800c..c004b4d49 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -494,10 +494,15 @@ export class TreeView extends React.Component<TreeViewProps> {
         return <div className={`bullet${this.props.treeView.outlineMode ? "-outline" : ""}`} key={"bullet"}
             title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
             onClick={this.bulletClick}
-            style={this.props.treeView.outlineMode ? { opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity) } : {
-                color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
-                opacity: checked === "unchecked" || typeof iconType !== "string" ? undefined : 0.4
-            }}>
+            style={this.props.treeView.outlineMode ?
+                {
+                    opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity)
+                } :
+                {
+                    pointerEvents: this.props.isContentActive() ? "all" : undefined,
+                    opacity: checked === "unchecked" || typeof iconType !== "string" ? undefined : 0.4,
+                    color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
+                }}>
             {this.props.treeView.outlineMode ?
                 !(this.doc.text as RichTextField)?.Text ? (null) :
                     <FontAwesomeIcon size="sm" icon={[this.childDocs?.length && !this.treeViewOpen ? "fas" : "far", "circle"]} /> :
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a60253914..68a51ef69 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -53,6 +53,7 @@ import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCurso
 import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
+import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
 
 export const panZoomSchema = createSchema({
     _panX: "number",
@@ -154,7 +155,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action setKeyFrameEditing = (set: boolean) => this._keyframeEditing = set;
     getKeyFrameEditing = () => this._keyframeEditing;
-    onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
+    onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick, ScriptCast(this.layoutDoc.onBrowseClick));
     onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
     elementFunc = () => this._layoutElements;
     shrinkWrap = () => {
@@ -621,7 +622,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
 
     onClick = (e: React.MouseEvent) => {
-        if ((Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) {
+
+        if (this.layoutDoc.onBrowseClick) {
+            this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1);
+            e.stopPropagation();
+            e.preventDefault();
+        }
+        else if ((Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) {
             if (e.shiftKey) {
                 if (Date.now() - this._lastTap < 300) { // reset zoom of freeform view to 1-to-1 on a shift + double click 
                     this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1);
@@ -1127,7 +1134,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const screen = { left: cx - pw / 2, right: cx + pw / 2, top: cy - ph / 2, bot: cy + ph / 2 };
 
         if (scale) {
-            const maxZoom = 2; // sets the limit for how far we will zoom. this is useful for preventing small text boxes from filling the screen. So probably needs to be more sophisticated to consider more about the target and context
+            const maxZoom = 5; // sets the limit for how far we will zoom. this is useful for preventing small text boxes from filling the screen. So probably needs to be more sophisticated to consider more about the target and context
             return {
                 panX: (bounds.left + bounds.right) / 2,
                 panY: (bounds.top + bounds.bot) / 2,
@@ -1549,7 +1556,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         const viewctrls = ContextMenu.Instance.findByDescription("UI Controls...");
         const viewCtrlItems = viewctrls && "subitems" in viewctrls ? viewctrls.subitems : [];
-
+        viewCtrlItems.push({ description: (this.layoutDoc.onChildClick ? "Leave" : "Enter") + " Browse Mode", event: () => this.layoutDoc.onBrowseClick = this.layoutDoc.onBrowseClick ? undefined : ScriptField.MakeScript("CollectionBrowseClick(documentView)", { documentView: "any" }), icon: "compress-arrows-alt" });
         !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null;
         !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null;
         !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" });
@@ -1973,4 +1980,10 @@ class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFor
                 }
             }} />;
     }
-}
\ No newline at end of file
+}
+
+export function CollectionBrowseClick(dv: DocumentView) {
+    dv.props.focus(dv.props.Document, { willZoom: true });
+    Doc.linkFollowHighlight(dv?.props.Document, false);
+}
+ScriptingGlobals.add(CollectionBrowseClick);
\ No newline at end of file
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index c18b4cec7..b6b59a2d6 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -212,7 +212,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                         dropInd = Math.ceil(index / 2 + (de.x - brect.x > brect.width / 2 ? 0 : -1));
                     }
                 }
-            })
+            });
             if (super.onInternalDrop(e, de)) {
                 de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
                     d._dimUnit = "*";
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 95456cf46..4074f8d69 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -212,7 +212,7 @@ export class CollectionMultirowView extends CollectionSubView() {
                         dropInd = Math.ceil(index / 2 + (de.y - brect.y > brect.height / 2 ? 0 : -1));
                     }
                 }
-            })
+            });
             if (super.onInternalDrop(e, de)) {
                 de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
                     d._dimUnit = "*";
-- 
cgit v1.2.3-70-g09d2


From 6df80c76b4046ef1ac9e98e52f766dfaf540ead2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 20 May 2022 12:51:51 -0400
Subject: removed enumerables field stuff which was hacky and never used. 
 cleaned up some of currentUserUtils initialiazation.  fixed treeView sorting
 for 'none" which fixes problem with slide template.

---
 src/client/documents/Documents.ts                  |  24 --
 src/client/util/CurrentUserUtils.ts                | 242 +++++----------------
 .../views/collections/CollectionStackingView.tsx   |   1 -
 src/client/views/collections/TreeView.tsx          |   2 +-
 src/client/views/nodes/ComparisonBox.tsx           |   2 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |  14 --
 6 files changed, 57 insertions(+), 228 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2dd8de089..4be9674f7 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1406,30 +1406,6 @@ export namespace DocUtils {
         return undefined;
     }
 
-    export async function addFieldEnumerations(doc: Opt<Doc>, enumeratedFieldKey: string, enumerations: { title: string, _backgroundColor?: string, color?: string }[]) {
-        let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey);
-        if (!(optionsCollection instanceof Doc)) {
-            optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set`, system: true }, enumeratedFieldKey);
-            Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc);
-        }
-        const options = optionsCollection as Doc;
-        const targetDoc = doc && Doc.GetProto(Cast(doc.rootDocument, Doc, null) || doc);
-        const docFind = `options.data?.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"])?`;
-        targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(docFind + `._backgroundColor || "white"`, undefined, { options }));
-        targetDoc && (targetDoc.color = ComputedField.MakeFunction(docFind + `.color || "black"`, undefined, { options }));
-        targetDoc && (targetDoc.borderRounding = ComputedField.MakeFunction(docFind + `.borderRounding`, undefined, { options }));
-        enumerations.map(enumeration => {
-            const found = DocListCast(options.data).find(d => d.title === enumeration.title);
-            if (found) {
-                found._backgroundColor = enumeration._backgroundColor || found._backgroundColor;
-                found._color = enumeration.color || found._color;
-            } else {
-                Doc.AddDocToList(options, "data", Docs.Create.TextDocument(enumeration.title, { ...enumeration, system: true }));
-            }
-        });
-        return optionsCollection;
-    }
-
     // /**
     //  * 
     //  * @param dms Degree Minute Second format exif gps data
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 8fed6e940..e0580d3c4 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -75,201 +75,68 @@ export class CurrentUserUtils {
     @observable public static searchPanelWidth: number = 0;
 
     // sets up the default User Templates - slideView,  headerView
-    static setupUserTemplateButtons(doc: Doc) {
-        // Prototype for mobile button (not sure if 'Advanced Item Prototypes' is ideal location)
-        if (doc["template-mobile-button"] === undefined) {
-            const queryTemplate = this.mobileButton({
-                title: "NEW MOBILE BUTTON",
-                onClick: undefined,
-            },
-                [this.createToolButton({
-                    ignoreClick: true,
-                    icon: "mobile",
-                    btnType: ButtonType.ToolButton,
-                    backgroundColor: "transparent"
-                }),
-                this.mobileTextContainer({},
-                    [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])]);
-            doc["template-mobile-button"] = CurrentUserUtils.createToolButton({
-                onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, title: "mobile button", icon: "mobile", btnType: ButtonType.ToolButton,
-            });
-        }
-
-        if (doc["template-button-slides"] === undefined) {
-            const slideTemplate = Docs.Create.MultirowDocument(
-                [
-                    Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }),
-                    Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) })
-                ],
-                { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true }
-            );
-            slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
-            doc["template-button-slides"] = CurrentUserUtils.createToolButton({
-                onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, title: "presentation slide", icon: "address-card",
-                btnType: ButtonType.ToolButton
-            });
-        }
-
-        if (doc["template-button-link"] === undefined) {  // set _backgroundColor to transparent to prevent link dot from obscuring document it's attached to.
-            const linkTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _autoHeight: true, system: true }, "header")); // text needs to be a space to allow templateText to be created
-            linkTemplate.system = true;
-            Doc.GetProto(linkTemplate).layout =
-                "<div>" +
-                "    <FormattedTextBox {...props} dontSelectOnLoad={'true'} height='{this._headerHeight||75}px' ignoreAutoHeight={'true'} background='{this._headerColor||`lightGray`}' fieldKey={'header'}/>" +
-                "    <FormattedTextBox {...props} position='absolute' top='{(this._headerHeight||75)*scale}px' height='calc({100/scale}% - {this._headerHeight||75}px)' fieldKey={'text'}/>" +
-                "</div>";
-            (linkTemplate.proto as Doc).isTemplateDoc = makeTemplate(linkTemplate.proto as Doc, true, "linkView");
-
-            const rtf2 = {
-                doc: {
-                    type: "doc", content: [
-                        {
-                            type: "paragraph",
-                            content: [{
-                                type: "dashField",
-                                attrs: {
-                                    fieldKey: "src",
-                                    hideKey: false
-                                }
-                            }]
-                        },
-                        { type: "paragraph" },
-                        {
-                            type: "paragraph",
-                            content: [{
-                                type: "dashField",
-                                attrs: {
-                                    fieldKey: "dst",
-                                    hideKey: false
-                                }
-                            }]
-                        }]
+    static setupExperimentalTemplateButtons(doc: Doc) {
+        if (doc["template-experimental-buttons"] === undefined) {
+            const requiredTypeNameFields = [
+                {
+                    type: "slide", icon: "address-card", template: Docs.Create.MultirowDocument(
+                        [
+                            Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }),
+                            Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) })
+                        ],
+                        { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true }
+                    )
                 },
-                selection: { type: "text", anchor: 1, head: 1 },
-                storedMarks: []
-            };
-            linkTemplate.header = new RichTextField(JSON.stringify(rtf2), "");
-
-            doc["template-button-link"] = CurrentUserUtils.createToolButton({
-                onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, title: "link view", icon: "window-maximize", system: true,
-                btnType: ButtonType.ToolButton
+                {
+                    type: "mobile", icon: "mobile", template: this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, },
+                        [this.createToolButton({ ignoreClick: true, icon: "mobile", btnType: ButtonType.ToolButton, backgroundColor: "transparent" }),
+                        this.mobileTextContainer({},
+                            [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])
+                        ]
+                    )
+                },
+            ];
+            const requiredTypes = requiredTypeNameFields.map(({ type, icon, template }) => {
+                if (doc[`template-button-${type}`] === undefined) {
+                    template.isTemplateDoc = makeTemplate(template);
+                    doc[`template-button-${type}`] = CurrentUserUtils.createToolButton({
+                        onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
+                        dragFactory: new PrefetchProxy(template) as any as Doc,
+                        title: type,
+                        icon,
+                        btnType: ButtonType.ToolButton,
+                    });
+                }
+                return doc[`template-button-${type}`] as Doc;
             });
-        }
 
-        // if (doc["template-button-switch"] === undefined) {
-        //     const { FreeformDocument, MulticolumnDocument, TextDocument } = Docs.Create;
-
-        //     const yes = FreeformDocument([], { title: "yes", _height: 35, _width: 50, _dimUnit: DimUnit.Pixel, _dimMagnitude: 40, system: true });
-        //     const name = TextDocument("name", { title: "name", _height: 35, _width: 70, _dimMagnitude: 1, system: true });
-        //     const no = FreeformDocument([], { title: "no", _height: 100, _width: 100, system: true });
-        //     const labelTemplate = {
-        //         doc: {
-        //             type: "doc", content: [{
-        //                 type: "paragraph",
-        //                 content: [{ type: "dashField", attrs: { fieldKey: "PARAMS", hideKey: true } }]
-        //             }]
-        //         },
-        //         selection: { type: "text", anchor: 1, head: 1 },
-        //         storedMarks: []
-        //     };
-        //     Doc.GetProto(name).text = new RichTextField(JSON.stringify(labelTemplate), "PARAMS");
-        //     Doc.GetProto(yes).backgroundColor = ComputedField.MakeFunction("self[this.PARAMS] ? 'green':'red'");
-        //     // Doc.GetProto(no).backgroundColor = ComputedField.MakeFunction("!self[this.PARAMS] ? 'red':'white'");
-        //     // Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = true");
-        //     Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = !self[this.PARAMS]");
-        //     // Doc.GetProto(no).onClick = ScriptField.MakeScript("self[this.PARAMS] = false");
-        //     const box = MulticolumnDocument([/*no, */ yes, name], { title: "value", _width: 120, _height: 35, system: true });
-        //     box.isTemplateDoc = makeTemplate(box, true, "switch");
-
-        //     doc["template-button-switch"] = CurrentUserUtils.createToolButton({
-        //         onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-        //         dragFactory: new PrefetchProxy(box) as any as Doc, title: "data switch", icon: "toggle-on", system: true,
-        //         btnType: ButtonType.ToolButton
-        //     });
-        // }
-
-        const requiredTypes = [
-            doc["template-button-slides"] as Doc,
-            doc["template-mobile-button"] as Doc,
-            doc["template-button-link"] as Doc,
-            //doc["template-button-switch"] as Doc]
-        ];
-        if (doc["template-buttons"] === undefined) {
-            doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, {
-                title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title", _chromeHidden: true,
+            doc["template-experimental-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, {
+                title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true,
                 hidden: ComputedField.MakeFunction("IsNoviceMode()") as any,
                 _stayInCollection: true, _hideContextMenu: true, _forceActive: true,
                 _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
                 dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true
             }));
-        } else {
-            const curButnTypes = Cast(doc["template-buttons"], Doc, null);
-            DocListCastAsync(curButnTypes.data).then(async curBtns => {
-                curBtns && await Promise.all(curBtns);
-                requiredTypes.map(btype => Doc.AddDocToList(curButnTypes, "data", btype));
-            });
         }
-        return doc["template-buttons"] as Doc;
+        return doc["template-experimental-buttons"] as Doc;
     }
 
     // setup the different note type skins
     static setupNoteTemplates(doc: Doc) {
-        if (doc["template-note-Note"] === undefined) {
-            const noteView = Docs.Create.TextDocument("", {
-                title: "text", isTemplateDoc: true, backgroundColor: "yellow", system: true, icon: "sticky-note",
-                _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
-            });
-            noteView.isTemplateDoc = makeTemplate(noteView, true, "Note");
-            doc["template-note-Note"] = new PrefetchProxy(noteView);
-        }
-        if (doc["template-note-Idea"] === undefined) {
-            const noteView = Docs.Create.TextDocument("", {
-                title: "text", backgroundColor: "pink", system: true, icon: "lightbulb",
-                _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
-            });
-            noteView.isTemplateDoc = makeTemplate(noteView, true, "Idea");
-            doc["template-note-Idea"] = new PrefetchProxy(noteView);
-        }
-        if (doc["template-note-Topic"] === undefined) {
-            const noteView = Docs.Create.TextDocument("", {
-                title: "text", backgroundColor: "lightblue", system: true, icon: "book-open",
-                _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
-            });
-            noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic");
-            doc["template-note-Topic"] = new PrefetchProxy(noteView);
-        }
-        // if (doc["template-note-Todo"] === undefined) {
-        //     const noteView = Docs.Create.TextDocument("", {
-        //         title: "text", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption",
-        //         layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus"), system: true,
-        //         _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
-        //     });
-        //     noteView.isTemplateDoc = makeTemplate(noteView, true, "Todo");
-        //     doc["template-note-Todo"] = new PrefetchProxy(noteView);
-        // }
-        // const taskStatusValues = [
-        //     { title: "todo", _backgroundColor: "blue", color: "white", system: true },
-        //     { title: "in progress", _backgroundColor: "yellow", color: "black", system: true },
-        //     { title: "completed", _backgroundColor: "green", color: "white", system: true }
-        // ];
-        // if (doc.fieldTypes === undefined) {
-        //     doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations", system: true });
-        //     DocUtils.addFieldEnumerations(Doc.GetProto(doc["template-note-Todo"] as any as Doc), "taskStatus", taskStatusValues);
-        // }
-
         if (doc["template-notes"] === undefined) {
-            doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc], // doc["template-note-Todo"] as any as Doc],
-                { title: "Note Layouts", _height: 75, system: true }));
-        } else {
-            const curNoteTypes = Cast(doc["template-notes"], Doc, null);
-            const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc];//, doc["template-note-Todo"] as any as Doc];
-            DocListCastAsync(curNoteTypes.data).then(async curNotes => {
-                curNotes && await Promise.all(curNotes);
-                requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype));
-            });
+            const requiredTypeNameFields = [
+                { type: "Note", backgroundColor: "yellow", icon: "sticky-note" },
+                { type: "Idea", backgroundColor: "pink", icon: "lightbulb" },
+                { type: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
+            const requiredTypes = requiredTypeNameFields.map(({ type, backgroundColor, icon }) =>
+                doc[`template-note-${type}`] as Doc ??
+                (() => {
+                    const noteView = Docs.Create.TextDocument("", { title: "text", backgroundColor, system: true, icon });
+                    noteView.isTemplateDoc = makeTemplate(noteView, true, type);
+                    return doc[`template-note-${type}`] = new PrefetchProxy(noteView);
+                })());
+
+            doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument(requiredTypes, { title: "Note Layouts", _height: 75, system: true }));
         }
 
         return doc["template-notes"] as Doc;
@@ -277,11 +144,12 @@ export class CurrentUserUtils {
 
     // creates Note templates, and initial "user" templates
     static setupDocTemplates(doc: Doc) {
-        const noteTemplates = CurrentUserUtils.setupNoteTemplates(doc);
-        const userTemplateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
-        const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc);
         if (doc.templateDocs === undefined) {
-            doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], {
+            doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([
+                CurrentUserUtils.setupNoteTemplates(doc),
+                CurrentUserUtils.setupExperimentalTemplateButtons(doc),
+                CurrentUserUtils.setupClickEditorTemplates(doc)
+            ], {
                 title: "template layouts", _xMargin: 0, system: true,
                 dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
             }));
@@ -717,7 +585,7 @@ export class CurrentUserUtils {
     static async setupToolsBtnPanel(doc: Doc) {
         // setup a masonry view of all he creators
         const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
-        const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
+        const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc);
 
         doc["tabs-button-tools"] = undefined;
 
@@ -1260,7 +1128,7 @@ export class CurrentUserUtils {
         doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode;
         doc.title = Doc.CurrentUserEmail;
         doc._raiseWhenDragged = true;
-        doc._showLabel = false;
+        doc._showLabel = true;
         doc._showMenuLabel = true;
         doc.textAlign = StrCast(doc.textAlign, "left");
         doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)");
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4338dedcc..4630b3bf2 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -482,7 +482,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         if (value && this.columnHeaders) {
             const schemaHdrField = new SchemaHeaderField(value);
             this.columnHeaders.push(schemaHdrField);
-            DocUtils.addFieldEnumerations(undefined, this.pivotField, [{ title: value, _backgroundColor: "schemaHdrField.color" }]);
             return true;
         }
         return false;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index c004b4d49..65f8fe248 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -895,7 +895,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
         }
 
-        const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion));
+        const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion, TreeSort.None));
         const rowWidth = () => panelWidth() - treeBulletWidth();
         const treeViewRefs = new Map<Doc, TreeView | undefined>();
         return docs.filter(child => child instanceof Doc).map((child, i) => {
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 49cd39f43..5ea6d567a 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -76,7 +76,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         const clearButton = (which: string) => {
             return <div className={`clear-button ${which}`}
                 onPointerDown={e => e.stopPropagation()} // prevent triggering slider movement in registerSliding 
-                onClick={e => this.clearDoc(e, `compareBox-${which}`)}>
+                onClick={e => this.clearDoc(e, which)}>
                 <FontAwesomeIcon className={`clear-button ${which}`} icon={"times"} size="sm" />
             </div>;
         };
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 34908e54b..1a8352b72 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -58,7 +58,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     _textBoxDoc: Doc;
     _fieldKey: string;
     _fieldStringRef = React.createRef<HTMLSpanElement>();
-    @observable _showEnumerables: boolean = false;
     @observable _dashDoc: Doc | undefined;
 
     constructor(props: IDashFieldViewInternal) {
@@ -110,7 +109,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
                         r?.addEventListener("keydown", e => this.fieldSpanKeyDown(e, r));
                         r?.addEventListener("blur", e => r && this.updateText(r.textContent!, false));
                         r?.addEventListener("pointerdown", action((e) => {
-                            this._showEnumerables = true;
                             e.stopPropagation();
                         }));
                     }} >
@@ -124,7 +122,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     @action
     fieldSpanKeyDown = (e: KeyboardEvent, span: HTMLSpanElement) => {
         if (e.key === "Enter") {  // handle the enter key by "submitting" the current text to Dash's database. 
-            e.ctrlKey && DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, [{ title: span.textContent! }]);
             this.updateText(span.textContent!, true);
             e.preventDefault();// prevent default to avoid a newline from being generated and wiping out this field view
         }
@@ -142,7 +139,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
 
     @action
     updateText = (nodeText: string, forceMatch: boolean) => {
-        this._showEnumerables = false;
         if (nodeText) {
             const newText = nodeText.startsWith(":=") || nodeText.startsWith("=:=") ? ":=-computed-" : nodeText;
 
@@ -154,7 +150,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
                 (options instanceof Doc) && DocListCast(options.data).forEach(opt => (forceMatch ? StrCast(opt.title).startsWith(newText) : StrCast(opt.title) === newText) && (modText = StrCast(opt.title)));
                 if (modText) {
                     //  elementfieldSpan.innerHTML = this._dashDoc![this._fieldKey as string] = modText;
-                    DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, []);
                     Doc.SetInPlace(this._dashDoc!, this._fieldKey, modText, true);
                 } // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key
                 else if (nodeText.startsWith(":=")) {
@@ -178,13 +173,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
         }
     }
 
-    // display a collection of all the enumerable values for this field
-    onPointerDownEnumerables = async (e: any) => {
-        e.stopPropagation();
-        const collview = await DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, [{ title: this._fieldKey }]);
-        collview instanceof Doc && this.props.tbox.props.addDocTab(collview, "add:right");
-    }
-
 
     // clicking on the label creates a pivot view collection of all documents
     // in the same collection.  The pivot field is the fieldKey of this label
@@ -220,8 +208,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
 
             {this.props.fieldKey.startsWith("#") ? (null) : this.fieldValueContent}
 
-            {!this._showEnumerables ? (null) : <div className="dashFieldView-enumerables" onPointerDown={this.onPointerDownEnumerables} />}
-
         </div >;
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 3fe0e0e02a6c9bd717b3df9b000c13d1131f6eb4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 23 May 2022 12:28:31 -0400
Subject: cleaning up singleLine text box api and TreeView types

---
 src/client/util/CurrentUserUtils.ts                |  7 +--
 src/client/views/MainView.tsx                      |  5 +-
 .../views/collections/CollectionTreeView.tsx       | 29 ++++++----
 src/client/views/collections/TreeView.tsx          | 35 ++++++------
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 34 ++++++++++--
 .../collections/collectionFreeForm/MarqueeView.tsx | 13 +++--
 src/client/views/nodes/DocumentView.tsx            |  2 +
 src/client/views/nodes/FieldView.tsx               |  3 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  7 +--
 .../formattedText/ProsemirrorExampleTransfer.ts    | 62 ++++++----------------
 10 files changed, 101 insertions(+), 96 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 85769d915..1ebb5365a 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -16,6 +16,7 @@ import { Docs, DocumentOptions, DocUtils } from "../documents/Documents";
 import { DocumentType } from "../documents/DocumentTypes";
 import { CollectionDockingView } from "../views/collections/CollectionDockingView";
 import { CollectionFreeFormView } from "../views/collections/collectionFreeForm";
+import { TreeViewType } from "../views/collections/CollectionTreeView";
 import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
 import { TreeView } from "../views/collections/TreeView";
 import { Colors } from "../views/global/globalEnums";
@@ -215,7 +216,7 @@ export class CurrentUserUtils {
         if (doc.emptySlide === undefined) {
             doc.emptySlide = Docs.Create.TreeDocument([], {
                 ...standardOps(), title: ComputedField.MakeFunction('self.text?.Text') as any, _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, "dragFactory-count": undefined,
-                allowOverlayDrop: true, treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white"
+                allowOverlayDrop: true, treeViewType: TreeViewType.outline, _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white"
             });
         }
         if (doc.emptyHeader === undefined) {
@@ -563,7 +564,7 @@ export class CurrentUserUtils {
                 title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true, freezeChildren: "remove|add",
                 treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias",
                 treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newDashboardButton,
-                _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: "fileSystem", isFolder: true, system: true,
+                _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true,
                 explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files."
             }));
             const toggleDarkTheme = ScriptField.MakeScript(`this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`);
@@ -616,7 +617,7 @@ export class CurrentUserUtils {
                 title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100,
                 treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias",
                 treeViewTruncateTitleWidth: 150, ignoreClick: true,
-                isFolder: true, treeViewType: "fileSystem", childHideLinkButton: true,
+                isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true,
                 _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true,
                 explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
             }));
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 6a2df3b51..09a57843c 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -8,11 +8,9 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import * as ReactDOM from 'react-dom';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
-import { List } from '../../fields/List';
 import { PrefetchProxy } from '../../fields/Proxy';
 import { ScriptField } from '../../fields/ScriptField';
 import { PromiseValue, StrCast } from '../../fields/Types';
-import { TraceMobx } from '../../fields/util';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
@@ -34,6 +32,7 @@ import { CollectionDockingView } from './collections/CollectionDockingView';
 import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu';
 import { CollectionLinearView } from './collections/collectionLinear';
 import { CollectionMenu } from './collections/CollectionMenu';
+import { TreeViewType } from './collections/CollectionTreeView';
 import { CollectionViewType } from './collections/CollectionView';
 import "./collections/TreeView.scss";
 import { ComponentDecorations } from './ComponentDecorations';
@@ -263,7 +262,7 @@ export class MainView extends React.Component {
                 title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100,
                 treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias",
                 treeViewTruncateTitleWidth: 150, ignoreClick: true,
-                isFolder: true, treeViewType: "fileSystem", childHideLinkButton: true,
+                isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true,
                 _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true,
                 explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
             }));
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 5e89016db..99ffb9bb0 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -27,6 +27,7 @@ import { CollectionSubView } from "./CollectionSubView";
 import "./CollectionTreeView.scss";
 import { TreeView } from "./TreeView";
 import React = require("react");
+import { FieldViewProps } from "../nodes/FieldView";
 const _global = (window /* browser */ || global /* node */) as any;
 
 export type collectionTreeViewProps = {
@@ -39,6 +40,12 @@ export type collectionTreeViewProps = {
     onChildClick?: () => ScriptField;
 };
 
+export enum TreeViewType {
+    outline = "outline",
+    fileSystem = "fileSystem",
+    default = "default"
+}
+
 @observer
 export class CollectionTreeView extends CollectionSubView<Partial<collectionTreeViewProps>>() {
     private _treedropDisposer?: DragManager.DragDropDisposer;
@@ -54,8 +61,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     @computed get dataDoc() { return this.props.DataDoc || this.doc; }
     @computed get treeViewtruncateTitleWidth() { return NumCast(this.doc.treeViewTruncateTitleWidth, this.panelWidth()); }
     @computed get treeChildren() { TraceMobx(); return this.props.childDocuments || this.childDocs; }
-    @computed get outlineMode() { return this.doc.treeViewType === "outline"; }
-    @computed get fileSysMode() { return this.doc.treeViewType === "fileSystem"; }
+    @computed get outlineMode() { return this.doc.treeViewType === TreeViewType.outline }
+    @computed get fileSysMode() { return this.doc.treeViewType === TreeViewType.fileSystem; }
     @computed get dashboardMode() { return this.doc === Doc.UserDoc().myDashboards; }
 
     @observable _explainerHeight = 0; // height of the description of the tree view
@@ -180,13 +187,20 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             height={"auto"}
             GetValue={() => StrCast(this.dataDoc.title)}
             SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => {
-                if (enter && this.props.Document.treeViewType === "outline") this.makeTextCollection(this.treeChildren);
+                if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren);
                 this.dataDoc.title = value;
                 return true;
             })} />;
     }
 
 
+    onKey = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
+        if (this.outlineMode && e.key === "Enter") {
+            e.stopPropagation();
+            this.makeTextCollection(this.treeChildren);
+            return true;
+        }
+    }
     get documentTitle() {
         return <FormattedTextBox
             {...this.props}
@@ -199,6 +213,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             PanelWidth={this.documentTitleWidth}
             PanelHeight={this.documentTitleHeight}
             scaling={returnOne}
+            onKey={this.onKey}
             docFilters={returnEmptyFilter}
             docRangeFilters={returnEmptyFilter}
             searchFilterDocs={returnEmptyDoclist}
@@ -257,13 +272,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
         return this.dataDoc === null ? (null) :
             <div className="collectionTreeView-titleBar" key={this.doc[Id]}
                 style={!this.outlineMode ? { paddingLeft: this.marginX(), paddingTop: this.marginTop() } : {}}
-                ref={r => this._titleRef = r}
-                onKeyDown={e => {
-                    if (this.outlineMode) {
-                        e.stopPropagation();
-                        e.key === "Enter" && this.makeTextCollection(this.treeChildren);
-                    }
-                }}>
+                ref={r => this._titleRef = r}>
                 {this.outlineMode ? this.documentTitle : this.editableTitle}
             </div>;
     }
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 65f8fe248..70ad23f41 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -26,11 +26,12 @@ import { DocumentView, DocumentViewInternal, DocumentViewProps, StyleProviderFun
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
 import { StyleProp } from '../StyleProvider';
-import { CollectionTreeView } from './CollectionTreeView';
+import { CollectionTreeView, TreeViewType } from './CollectionTreeView';
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TreeView.scss";
 import React = require("react");
 import { KeyValueBox } from '../nodes/KeyValueBox';
+import { FieldViewProps } from '../nodes/FieldView';
 
 export interface TreeViewProps {
     treeView: CollectionTreeView;
@@ -241,7 +242,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             layout: CollectionView.LayoutString("data"),
             title: "-title-",
             treeViewExpandedViewLock: true, treeViewExpandedView: "data",
-            _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewType: "outline",
+            _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewType: TreeViewType.outline,
             x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, _width: 1000, _height: 10
         });
         Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text');
@@ -604,24 +605,29 @@ export class TreeView extends React.Component<TreeViewProps> {
         if (property.startsWith(StyleProp.Decorations)) return (null);
         return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
     }
-    onKeyDown = (e: React.KeyboardEvent) => {
+    onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
         if (this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) {
             switch (e.key) {
                 case "Tab":
-                    e.stopPropagation();
-                    e.preventDefault();
+                    e.stopPropagation?.();
+                    e.preventDefault?.();
                     setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150);
-                    return UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true), "tab");
+                    UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true), "tab");
+                    return true;
                 case "Backspace":
-                    e.stopPropagation();
-                    e.preventDefault();
-                    return !(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc);
+                    if (!(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc)) {
+                        e.stopPropagation?.();
+                        e.preventDefault?.();
+                        return true;
+                    }
+                    break;
                 case "Enter":
-                    e.stopPropagation();
-                    e.preventDefault();
+                    e.stopPropagation?.();
+                    e.preventDefault?.();
                     return UndoManager.RunInBatch(this.makeTextCollection, "bullet");
             }
         }
+        return false;
     }
     titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth() - 2 * treeBulletWidth()));
 
@@ -758,6 +764,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             hideResizeHandles={this.props.treeView.outlineMode}
             focus={this.refocus}
             ContentScaling={returnOne}
+            onKey={this.onKeyDown}
             hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
             dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
             ScreenToLocalTransform={this.docTransform}
@@ -800,7 +807,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     @computed get renderBorder() {
         const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None);
         const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string, label: string } };
-        return <div className={`treeView-border${this.props.treeView.outlineMode ? "outline" : ""}`} style={{ borderColor: sortings[sorting]?.color }}>
+        return <div className={`treeView-border${this.props.treeView.outlineMode ? TreeViewType.outline : ""}`} style={{ borderColor: sortings[sorting]?.color }}>
             {!this.treeViewOpen ? (null) : this.renderContent}
         </div>;
     }
@@ -821,9 +828,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? "<" + this.doc.title + ">" : // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles
             <div className={`treeView-container${this.props.isContentActive() ? "-active" : ""}`}
                 ref={this.createTreeDropTarget}
-                onDrop={this.onTreeDrop}
-                //onPointerDown={e => this.props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document
-                onKeyDown={this.onKeyDown}>
+                onDrop={this.onTreeDrop}>
                 <li className="collection-child">
                     {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader ? // should test for prop 'treeViewRenderDocWithBulletAsHeader"
                         this.renderEmbeddedDocument(false, returnFalse) :
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index df09569ef..3b32cf57d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,18 +1,18 @@
 import { Bezier } from "bezier-js";
-import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { computedFn } from "mobx-utils";
 import { DateField } from "../../../../fields/DateField";
-import { Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc";
+import { DataSym, Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc";
 import { Id } from "../../../../fields/FieldSymbols";
 import { InkData, InkField, InkTool, PointData, Segment } from "../../../../fields/InkField";
 import { List } from "../../../../fields/List";
 import { ObjectField } from "../../../../fields/ObjectField";
 import { RichTextField } from "../../../../fields/RichTextField";
-import { ImageField } from "../../../../fields/URLField";
 import { createSchema, listSpec } from "../../../../fields/Schema";
 import { ScriptField } from "../../../../fields/ScriptField";
 import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
+import { ImageField } from "../../../../fields/URLField";
 import { TraceMobx } from "../../../../fields/util";
 import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
 import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUpEvents, Utils } from "../../../../Utils";
@@ -26,6 +26,7 @@ import { DragManager, dropActionType } from "../../../util/DragManager";
 import { HistoryUtil } from "../../../util/History";
 import { InteractionUtils } from "../../../util/InteractionUtils";
 import { LinkManager } from "../../../util/LinkManager";
+import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
 import { SearchUtil } from "../../../util/SearchUtil";
 import { SelectionManager } from "../../../util/SelectionManager";
 import { ColorScheme } from "../../../util/SettingsManager";
@@ -47,13 +48,14 @@ import { CreateImage } from "../../nodes/WebBoxRenderer";
 import { StyleProp } from "../../StyleProvider";
 import { CollectionDockingView } from "../CollectionDockingView";
 import { CollectionSubView } from "../CollectionSubView";
+import { TreeViewType } from "../CollectionTreeView";
 import { CollectionViewType } from "../CollectionView";
 import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines";
 import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
 import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
-import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
+import { FieldView, FieldViewProps } from "../../nodes/FieldView";
 
 export const panZoomSchema = createSchema({
     _panX: "number",
@@ -957,7 +959,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
-        if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === "outline") return;
+        if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
         if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming
             e.stopPropagation();
         }
@@ -1160,6 +1162,27 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
 
+    @undoBatch
+    @action
+    onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
+        const docView = fieldProps.DocumentView?.();
+        if (docView && docView.rootDoc._singleLine && ["Tab", "Enter"].includes(e.key)) {
+            e.stopPropagation?.();
+            const below = !e.altKey && e.key !== "Tab";
+            const layoutKey = StrCast(docView.LayoutFieldKey);
+            const newDoc = Doc.MakeCopy(docView.rootDoc, true);
+            const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)];
+            newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
+            if (below) newDoc.y = NumCast(docView.rootDoc.y) + NumCast(docView.rootDoc._height) + 10;
+            else newDoc.x = NumCast(docView.rootDoc.x) + NumCast(docView.rootDoc._width) + 10;
+            if (layoutKey !== "layout" && docView.rootDoc[layoutKey] instanceof Doc) {
+                newDoc[layoutKey] = docView.rootDoc[layoutKey];
+            }
+            Doc.GetProto(newDoc).text = undefined;
+            FormattedTextBox.SelectOnLoad = newDoc[Id];
+            return this.addDocument?.(newDoc);
+        }
+    }
     pointerEvents = () => {
         const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
         const pointerEvents = this.props.isContentActive() === false ? "none" :
@@ -1185,6 +1208,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             LayoutTemplateString={childLayout.z ? undefined : this.props.childLayoutString}
             rootSelected={childData ? this.rootSelected : returnFalse}
             onClick={this.onChildClickHandler}
+            onKey={this.onKeyDown}
             onDoubleClick={this.onChildDoubleClickHandler}
             onBrowseClick={this.onBrowseClickHandler}
             ScreenToLocalTransform={childLayout.z ? this.getContainerTransform : this.getTransform}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 1c4d47d57..29bdae170 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,14 +1,15 @@
 import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
-import { AclAugment, AclAdmin, AclEdit, DataSym, Doc, Opt } from "../../../../fields/Doc";
+import { AclAdmin, AclAugment, AclEdit, DataSym, Doc, Opt } from "../../../../fields/Doc";
 import { Id } from "../../../../fields/FieldSymbols";
 import { InkData, InkField, InkTool } from "../../../../fields/InkField";
 import { List } from "../../../../fields/List";
 import { RichTextField } from "../../../../fields/RichTextField";
 import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
+import { ImageField } from "../../../../fields/URLField";
 import { GetEffectiveAcl } from "../../../../fields/util";
-import { Utils, intersectRect, returnFalse } from "../../../../Utils";
+import { intersectRect, returnFalse, Utils } from "../../../../Utils";
 import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
 import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
 import { DocumentType } from "../../../documents/DocumentTypes";
@@ -21,17 +22,15 @@ import { ContextMenu } from "../../ContextMenu";
 import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
 import { PresBox } from "../../nodes/trails/PresBox";
 import { PresMovement } from "../../nodes/trails/PresEnums";
+import { VideoBox } from "../../nodes/VideoBox";
+import { pasteImageBitmap } from "../../nodes/WebBoxRenderer";
 import { PreviewCursor } from "../../PreviewCursor";
 import { CollectionDockingView } from "../CollectionDockingView";
 import { SubCollectionViewProps } from "../CollectionSubView";
-import { CollectionView } from "../CollectionView";
+import { TreeView } from "../TreeView";
 import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
 import "./MarqueeView.scss";
 import React = require("react");
-import { TreeView } from "../TreeView";
-import { VideoBox } from "../../nodes/VideoBox";
-import { ImageField, WebField } from "../../../../fields/URLField";
-import { pasteImageBitmap } from "../../nodes/WebBoxRenderer";
 
 interface MarqueeViewProps {
     getContainerTransform: () => Transform;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f5ad47ca7..f7312e59c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -50,6 +50,7 @@ import { ScriptingBox } from "./ScriptingBox";
 import { PresBox } from './trails/PresBox';
 import React = require("react");
 import { DocServer } from "../../DocServer";
+import { FieldViewProps } from "./FieldView";
 const { Howl } = require('howler');
 
 interface Window {
@@ -178,6 +179,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     onPointerDown?: () => ScriptField;
     onPointerUp?: () => ScriptField;
     onBrowseClick?: () => (ScriptField | undefined);
+    onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => (boolean | undefined);
 }
 
 // these props are only available in DocumentViewIntenral
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 94937430e..79c1f1c40 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -5,7 +5,7 @@ import { DateField } from "../../../fields/DateField";
 import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc";
 import { List } from "../../../fields/List";
 import { WebField } from "../../../fields/URLField";
-import { DocumentViewSharedProps } from "./DocumentView";
+import { DocumentView, DocumentViewSharedProps } from "./DocumentView";
 import { ScriptField } from "../../../fields/ScriptField";
 
 //
@@ -25,6 +25,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
     scaling?: () => number;
     setHeight?: (height: number) => void;
     onBrowseClick?: () => (ScriptField | undefined);
+    onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => (boolean | undefined);
 
     // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React)
     pointerEvents?: () => Opt<string>;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 164bcb9b0..0e29461a6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -17,6 +17,7 @@ import { InkTool } from '../../../../fields/InkField';
 import { PrefetchProxy } from '../../../../fields/Proxy';
 import { RichTextField } from "../../../../fields/RichTextField";
 import { RichTextUtils } from '../../../../fields/RichTextUtils';
+import { ComputedField } from '../../../../fields/ScriptField';
 import { Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
 import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
 import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
@@ -62,7 +63,6 @@ import { schema } from "./schema_rts";
 import { SummaryView } from "./SummaryView";
 import applyDevTools = require("prosemirror-dev-tools");
 import React = require("react");
-import { ComputedField } from '../../../../fields/ScriptField';
 const translateGoogleApi = require("translate-google-api");
 
 export interface FormattedTextBoxProps {
@@ -1471,11 +1471,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             }, "titler");
         }
     }
+
     onKeyDown = (e: React.KeyboardEvent) => {
-        // single line text boxes need to pass through tab/enter/backspace so that their containers can respond (eg, an outline container)
-        if (this.rootDoc._singleLine && ((e.key === "Backspace" && !this.dataDoc[this.fieldKey]?.Text) || ["Tab", "Enter"].includes(e.key))) {
-            return;
-        }
         if (e.altKey) {
             e.preventDefault();
             return;
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index c76eda859..0dd0a8411 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -1,20 +1,15 @@
-import { chainCommands, exitCode, joinDown, joinUp, lift, deleteSelection, joinBackward, selectNodeBackward, setBlockType, splitBlockKeepMarks, toggleMark, wrapIn, newlineInCode } from "prosemirror-commands";
-import { liftTarget } from "prosemirror-transform";
+import { chainCommands, deleteSelection, exitCode, joinBackward, joinDown, joinUp, lift, newlineInCode, selectNodeBackward, setBlockType, splitBlockKeepMarks, toggleMark, wrapIn } from "prosemirror-commands";
 import { redo, undo } from "prosemirror-history";
 import { Schema } from "prosemirror-model";
-import { liftListItem, sinkListItem } from "./prosemirrorPatches.js";
-import { splitListItem, wrapInList, } from "prosemirror-schema-list";
-import { EditorState, Transaction, TextSelection } from "prosemirror-state";
-import { SelectionManager } from "../../../util/SelectionManager";
-import { NumCast, BoolCast, Cast, StrCast } from "../../../../fields/Types";
-import { Doc, DataSym, DocListCast, AclAugment, AclSelfEdit } from "../../../../fields/Doc";
-import { FormattedTextBox } from "./FormattedTextBox";
-import { Id } from "../../../../fields/FieldSymbols";
-import { Docs } from "../../../documents/Documents";
-import { Utils } from "../../../../Utils";
-import { listSpec } from "../../../../fields/Schema";
-import { List } from "../../../../fields/List";
+import { splitListItem, wrapInList } from "prosemirror-schema-list";
+import { EditorState, TextSelection, Transaction } from "prosemirror-state";
+import { liftTarget } from "prosemirror-transform";
+import { AclAugment, AclSelfEdit, Doc } from "../../../../fields/Doc";
 import { GetEffectiveAcl } from "../../../../fields/util";
+import { Utils } from "../../../../Utils";
+import { Docs } from "../../../documents/Documents";
+import { SelectionManager } from "../../../util/SelectionManager";
+import { liftListItem, sinkListItem } from "./prosemirrorPatches.js";
 
 const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
 
@@ -48,29 +43,6 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
         keys[key] = cmd;
     }
 
-    /// bcz; Argh!!  replace with an onEnter func that conditionally handles Enter 
-    const addTextBox = (below: boolean, force?: boolean) => {
-        if (props.Document.treeViewType === "outline") return true;  // bcz: Arghh .. need to determine if this is an treeViewOutlineBox in which case Enter's are ignored..
-        const layoutDoc = props.Document;
-        const originalDoc = layoutDoc.rootDocument || layoutDoc;
-        if (force || props.Document._singleLine) {
-            const layoutKey = StrCast(originalDoc.layoutKey);
-            const newDoc = Doc.MakeCopy(originalDoc, true);
-            const dataField = originalDoc[Doc.LayoutFieldKey(newDoc)];
-            newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
-            if (below) newDoc.y = NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10;
-            else newDoc.x = NumCast(originalDoc.x) + NumCast(originalDoc._width) + 10;
-            if (layoutKey !== "layout" && originalDoc[layoutKey] instanceof Doc) {
-                newDoc[layoutKey] = originalDoc[layoutKey];
-            }
-            Doc.GetProto(newDoc).text = undefined;
-            FormattedTextBox.SelectOnLoad = newDoc[Id];
-            props.addDocument(newDoc);
-            return true;
-        }
-        return false;
-    };
-
     const canEdit = (state: any) => {
         switch (GetEffectiveAcl(props.Document)) {
             case AclAugment: return false;
@@ -109,11 +81,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
     bind("Ctrl-i", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && wrapInList(schema.nodes.ordered_list)(state as any, dispatch as any));
 
     bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
-        /// bcz; Argh!!  replace layotuTEmpalteString with a onTab prop conditionally handles Tab);
-        if (props.Document._singleLine) {
-            if (!props.LayoutTemplateString) return addTextBox(false, true);
-            return true;
-        }
+        if (props.onKey?.({ key: "Tab" }, props)) return true;
         if (!canEdit(state)) return true;
         const ref = state.selection;
         const range = ref.$from.blockRange(ref.$to);
@@ -138,8 +106,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
     });
 
     bind("Shift-Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
-        /// bcz; Argh!!  replace with a onShiftTab prop conditionally handles Tab);
-        if (props.Document._singleLine) return true;
+        if (props.onKey?.({ key: "Tab", shiftKey: true })) return true; // single line docs don't process tabs so that their containers can decide what to do.  This should be a prop
         if (!canEdit(state)) return true;
         const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
 
@@ -188,13 +155,14 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
     };
 
     //Command to create a text document to the right of the selected textbox
-    bind("Alt-Enter", () => addTextBox(false, true));
+    bind("Alt-Enter", () => true);
 
     //Command to create a text document to the bottom of the selected textbox
-    bind("Ctrl-Enter", () => addTextBox(true, true));
+    bind("Ctrl-Enter", () => true);
 
     // backspace = chainCommands(deleteSelection, joinBackward, selectNodeBackward);
     bind("Backspace", (state: EditorState<S>, dispatch: (tx: Transaction<Schema<any, any>>) => void) => {
+        if (props.onKey?.(event, props)) return true;
         if (!canEdit(state)) return true;
 
         if (!deleteSelection(state, (tx: Transaction<S>) => {
@@ -216,8 +184,8 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
     //newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock
     //command to break line
     bind("Enter", (state: EditorState<S>, dispatch: (tx: Transaction<Schema<any, any>>) => void) => {
-        if (addTextBox(true, false)) return true;
 
+        if (props.onKey?.(event, props)) return true;
         if (!canEdit(state)) return true;
 
         const trange = state.selection.$from.blockRange(state.selection.$to);
-- 
cgit v1.2.3-70-g09d2


From 31b2606fa6ac49b0a78e46fcedff05fd2e2366b7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 3 Jun 2022 09:49:15 -0400
Subject: fixed tree view crash

---
 src/client/views/collections/CollectionView.tsx | 2 +-
 src/client/views/collections/TreeView.tsx       | 9 +++++----
 2 files changed, 6 insertions(+), 5 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 0de61c9b2..965f0a352 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -82,7 +82,7 @@ export interface CollectionViewProps extends FieldViewProps {
     //TODO: [AL] add these fields
     AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
     RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[];
-    hierarchyIndex?: number[];
+    hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views) 
 }
 @observer
 export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps>() {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 3840afb04..661db7997 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -213,12 +213,12 @@ export class TreeView extends React.Component<TreeViewProps> {
         document.removeEventListener("pointermove", this.onDragMove, true);
         document.removeEventListener("pointermove", this.onDragUp, true);
         // TODO: [AL] add these
-        this.props.RemFromMap?.(this.doc, this.props.hierarchyIndex!);
+        this.props.hierarchyIndex !== undefined && this.props.RemFromMap?.(this.doc, this.props.hierarchyIndex);
     }
 
     componentDidMount() {
         // TODO: [AL] add these
-        this.props.AddToMap?.(this.doc, this.props.hierarchyIndex!);
+        this.props.hierarchyIndex !== undefined && this.props.AddToMap?.(this.doc, this.props.hierarchyIndex);
     }
 
     onDragUp = (e: PointerEvent) => {
@@ -293,7 +293,8 @@ export class TreeView extends React.Component<TreeViewProps> {
     @undoBatch
     treeDrop = (e: Event, de: DragManager.DropEvent) => {
         const pt = [de.x, de.y];
-        const rect = this._header.current!.getBoundingClientRect();
+        if (!this._header.current) return;
+        const rect = this._header.current.getBoundingClientRect();
         const before = pt[1] < rect.top + rect.height / 2;
         const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
         if (de.complete.linkDragData) {
@@ -978,7 +979,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 containerCollection={containerCollection}
                 prevSibling={docs[i]}
                 // TODO: [AL] add these
-                hierarchyIndex={[...hierarchyIndex!, i + 1]}
+                hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined}
                 AddToMap={AddToMap}
                 RemFromMap={RemFromMap}
                 treeView={treeView}
-- 
cgit v1.2.3-70-g09d2


From ba7824a91da113cc813c58b678719092c96d79a2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 3 Jun 2022 16:02:24 -0400
Subject: fixed opening closed tabs from Files sidebar to re-use best Alias
 before making a new alias.

---
 src/.DS_Store                                      | Bin 8196 -> 8196 bytes
 src/client/util/CurrentUserUtils.ts                |   2 +-
 src/client/util/DocumentManager.ts                 |  28 ++++++++++-----------
 src/client/views/LightboxView.tsx                  |   5 ++--
 src/client/views/collections/TabDocView.tsx        |  15 ++++++++++-
 src/client/views/collections/TreeView.tsx          |   4 +--
 src/client/views/nodes/DocumentIcon.tsx            |   4 +--
 src/client/views/nodes/DocumentView.tsx            |   4 ---
 src/client/views/nodes/button/FontIconBox.tsx      |  11 ++++----
 .../views/nodes/formattedText/DashFieldView.tsx    |   6 ++---
 .../views/nodes/formattedText/FormattedTextBox.tsx |   2 +-
 src/client/views/nodes/trails/PresBox.tsx          |  14 ++---------
 src/client/views/pdf/PDFViewer.tsx                 |   2 +-
 13 files changed, 48 insertions(+), 49 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/.DS_Store b/src/.DS_Store
index b0987293b..4bf9cdac7 100644
Binary files a/src/.DS_Store and b/src/.DS_Store differ
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 2ed6c3cbe..85ad58726 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -869,7 +869,7 @@ export class CurrentUserUtils {
                             Doc.AddDocToList(menuBtnDoc, "data", newSubMenuBtnDoc, after, false, !prevSub);
                         }
                         prevSub = params.title;
-                    })
+                    });
                 }
                 prev = params.title;
             });
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index aeddc3249..a82f99d5a 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -16,7 +16,7 @@ import { SelectionManager } from './SelectionManager';
 export class DocumentManager {
 
     //global holds all of the nodes (regardless of which collection they're in)
-    @observable public DocumentViews: DocumentView[] = [];
+    @observable public DocumentViews = new Set<DocumentView>();
     @observable public LinkAnchorBoxViews: DocumentView[] = [];
     @observable public RecordingEvent = 0;
     @observable public LinkedDocumentViews: { a: DocumentView, b: DocumentView, l: Doc }[] = [];
@@ -46,7 +46,7 @@ export class DocumentManager {
             // this.LinkedDocumentViews.forEach(view => console.log("  LV = " + view.a.props.Document.title + "/" + view.a.props.LayoutTemplateString + " --> " +
             //     view.b.props.Document.title + "/" + view.b.props.LayoutTemplateString));
         } else {
-            this.DocumentViews.push(view);
+            this.DocumentViews.add(view);
         }
     }
     public RemoveView = action((view: DocumentView) => {
@@ -61,8 +61,7 @@ export class DocumentManager {
             const index = this.LinkAnchorBoxViews.indexOf(view);
             this.LinkAnchorBoxViews.splice(index, 1);
         } else {
-            const index = this.DocumentViews.indexOf(view);
-            index !== -1 && this.DocumentViews.splice(index, 1);
+            this.DocumentViews.delete(view);
         }
         SelectionManager.DeselectView(view);
     });
@@ -70,13 +69,13 @@ export class DocumentManager {
     //gets all views
     public getDocumentViewsById(id: string) {
         const toReturn: DocumentView[] = [];
-        DocumentManager.Instance.DocumentViews.map(view => {
+        Array.from(DocumentManager.Instance.DocumentViews).map(view => {
             if (view.rootDoc[Id] === id) {
                 toReturn.push(view);
             }
         });
         if (toReturn.length === 0) {
-            DocumentManager.Instance.DocumentViews.map(view => {
+            Array.from(DocumentManager.Instance.DocumentViews).map(view => {
                 const doc = view.rootDoc.proto;
                 if (doc && doc[Id] && doc[Id] === id) {
                     toReturn.push(view);
@@ -96,14 +95,14 @@ export class DocumentManager {
         const passes = preferredCollection ? [preferredCollection, undefined] : [undefined];
 
         for (const pass of passes) {
-            DocumentManager.Instance.DocumentViews.map(view => {
+            Array.from(DocumentManager.Instance.DocumentViews).map(view => {
                 if (view.rootDoc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
                     toReturn = view;
                     return;
                 }
             });
             if (!toReturn) {
-                DocumentManager.Instance.DocumentViews.map(view => {
+                Array.from(DocumentManager.Instance.DocumentViews).map(view => {
                     const doc = view.rootDoc.proto;
                     if (doc && doc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
                         toReturn = view;
@@ -122,9 +121,8 @@ export class DocumentManager {
     }
 
     public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
-        const docViews = DocumentManager.Instance.DocumentViews;
         const views: DocumentView[] = [];
-        docViews.map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view));
+        Array.from(DocumentManager.Instance.DocumentViews).map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view));
         return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined);
     }
     public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
@@ -133,8 +131,8 @@ export class DocumentManager {
     }
     public getDocumentViews(toFind: Doc): DocumentView[] {
         const toReturn: DocumentView[] = [];
-        const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.IsLightboxDocView(view.docViewPath));
-        const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.IsLightboxDocView(view.docViewPath));
+        const docViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => !LightboxView.IsLightboxDocView(view.docViewPath));
+        const lightViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => LightboxView.IsLightboxDocView(view.docViewPath));
 
         // heuristic to return the "best" documents first:
         //   choose a document in the lightbox first
@@ -290,7 +288,7 @@ export class DocumentManager {
         }
     }
 }
-export function DocFocusOrOpen(doc: any, collectionDoc?: Doc) {
+export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) {
     const cv = collectionDoc && DocumentManager.Instance.getDocumentView(collectionDoc);
     const dv = DocumentManager.Instance.getDocumentView(doc, (cv?.ComponentView as CollectionFreeFormView)?.props.CollectionView);
     if (dv && Doc.AreProtosEqual(dv.props.Document, doc)) {
@@ -300,7 +298,9 @@ export function DocFocusOrOpen(doc: any, collectionDoc?: Doc) {
     else {
         const context = doc.context !== Doc.UserDoc().myFilesystem && Cast(doc.context, Doc, null);
         const showDoc = context || doc;
-        CollectionDockingView.AddSplit(showDoc === Doc.GetProto(showDoc) ? Doc.MakeAlias(showDoc) : showDoc, "right") && context &&
+        const bestAlias = showDoc === Doc.GetProto(showDoc) ? DocListCast(showDoc.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail) : showDoc;
+
+        CollectionDockingView.AddSplit(bestAlias ? bestAlias : Doc.MakeAlias(showDoc), "right") && context &&
             setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc));
     }
 }
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index ddfc8b249..3d2769f66 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -275,9 +275,8 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                 <div className="lightboxView-tabBtn" title={"open in tab"}
                     onClick={e => {
                         e.stopPropagation();
-                        // CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, "");
-                        LightboxView.openInTabFunc(LightboxView._docTarget || LightboxView._doc!, "inPlace");
-                        console.log("lightbox to tab triggered")
+                        CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, "");
+                        //LightboxView.openInTabFunc(LightboxView._docTarget || LightboxView._doc!, "inPlace");
                         SelectionManager.DeselectAll();
                         LightboxView.SetLightboxDoc(undefined);
                     }}>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 8d84e9a56..d64cb2fd7 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -66,6 +66,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     get stack() { return (this.props as any).glContainer.parent.parent; }
     get tab() { return (this.props as any).glContainer.tab; }
     get view() { return this._view; }
+    _lastTab: any;
+    _lastView: DocumentView | undefined;
 
     @action
     init = (tab: any, doc: Opt<Doc>) => {
@@ -266,6 +268,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
     componentWillUnmount() {
         this._tabReaction?.();
+        this._view && DocumentManager.Instance.RemoveView(this._view);
         this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
 
         this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged);
@@ -353,7 +356,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
     @computed get docView() {
         return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
-            <><DocumentView key={this._document[Id]} ref={action((r: DocumentView) => this._view = r)}
+            <><DocumentView key={this._document[Id]} ref={action((r: DocumentView) => {
+                this._lastView && DocumentManager.Instance.RemoveView(this._lastView);
+                this._view = r;
+                this._lastView = this._view;
+            })}
                 renderDepth={0}
                 Document={this._document}
                 DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
@@ -409,6 +416,12 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 height: "100%", width: "100%"
             }} ref={ref => {
                 if (this._mainCont = ref) {
+                    if (this._lastTab) {
+                        console.log("DUP tab")
+                        this._view && DocumentManager.Instance.RemoveView(this._view);
+                        CollectionDockingView.Instance.tabMap.delete(this._lastTab);
+                    }
+                    this._lastTab = this.tab;
                     (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
                     DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
                     new _global.ResizeObserver(action((entries: any) => this._forceInvalidateScreenToLocal++)).observe(ref);
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 661db7997..9de44fb00 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -183,7 +183,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             this.treeViewOpen = !this.treeViewOpen;
         } else {
             // choose an appropriate alias or make one. --- choose the first alias that (1) user owns,  (2) has no context field ... otherwise make a new alias
-            const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
+            const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
             const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail);
             this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), "lightbox");
         }
@@ -609,7 +609,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     // TODO: currently doc focus works, but can't seem to edit title
     // onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
     onChildClick = () => {
-        return this.props.onChildClick?.() ?? (ScriptField.MakeFunction(`DocFocusOrOpen(self)`)! || this._editTitleScript?.())
+        return this.props.onChildClick?.() ?? (ScriptField.MakeFunction(`DocFocusOrOpen(self)`)! || this._editTitleScript?.());
     }
 
     onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx
index a9c998757..56de2d1fc 100644
--- a/src/client/views/nodes/DocumentIcon.tsx
+++ b/src/client/views/nodes/DocumentIcon.tsx
@@ -52,7 +52,7 @@ export class DocumentIconContainer extends React.Component {
                 };
             },
             getVars() {
-                const docs = DocumentManager.Instance.DocumentViews;
+                const docs = Array.from(DocumentManager.Instance.DocumentViews);
                 const capturedVariables: { [name: string]: Field } = {};
                 usedDocuments.forEach(index => capturedVariables[`d${index}`] = docs[index].props.Document);
                 return { capturedVariables };
@@ -60,6 +60,6 @@ export class DocumentIconContainer extends React.Component {
         };
     }
     render() {
-        return DocumentManager.Instance.DocumentViews.map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
+        return Array.from(DocumentManager.Instance.DocumentViews).map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
     }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 14ededaf8..6e4d6a52e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -242,7 +242,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown); }
     @computed get onPointerUpHandler() { return this.props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp); }
 
-
     componentWillUnmount() { this.cleanupHandlers(true); }
     componentDidMount() { this.setupHandlers(); }
     //componentDidUpdate() { this.setupHandlers(); }
@@ -1126,9 +1125,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     render() {
         TraceMobx();
         const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : Doc.DocBrushStatus.unbrushed) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString
-        if (highlightIndex === 6) {
-            console.log("")
-        }
         const highlightColor = ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "orange", "lightBlue"][highlightIndex];
         const highlightStyle = ["solid", "dashed", "solid", "solid", "solid"][highlightIndex];
         const excludeTypes = !this.props.treeViewDoc ? [DocumentType.FONTICON, DocumentType.INK] : [DocumentType.FONTICON];
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index d29160458..b21a28d8e 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -231,7 +231,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
 
         const script = ScriptCast(this.rootDoc.script);
-        if (!script) { return null };
+        if (!script) { return null; }
 
         let noviceList: string[] = [];
         let text: string | undefined;
@@ -459,7 +459,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const buttonText = StrCast(this.rootDoc.buttonText);
 
         // TODO:glr Add label of button type
-        let button = this.defaultButton;
+        let button: JSX.Element | null = this.defaultButton;
 
         switch (this.type) {
             case ButtonType.TextButton:
@@ -527,9 +527,10 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         }
 
         return !this.layoutDoc.toolTip || this.type === ButtonType.DropdownList || this.type === ButtonType.ColorButton || this.type === ButtonType.NumberButton || this.type === ButtonType.EditableText ? button :
-            <Tooltip title={<div className="dash-tooltip">{StrCast(this.layoutDoc.toolTip)}</div>}>
-                {button}
-            </Tooltip>;
+            button !== null ?
+                <Tooltip title={<div className="dash-tooltip">{StrCast(this.layoutDoc.toolTip)}</div>}>
+                    {button}
+                </Tooltip > : null
     }
 }
 
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 6a3f9ed00..bb3791f1e 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -86,7 +86,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     public static fieldContent(textBoxDoc: Doc, dashDoc: Doc, fieldKey: string) {
         const dashVal = dashDoc[fieldKey] ?? dashDoc[DataSym][fieldKey] ?? (fieldKey === "PARAMS" ? textBoxDoc[fieldKey] : "");
         const fval = dashVal instanceof List ? dashVal.join(DashFieldViewInternal.multiValueDelimeter) : StrCast(dashVal).startsWith(":=") || dashVal === "" ? Doc.Layout(textBoxDoc)[fieldKey] : dashVal;
-        return { boolVal: Cast(fval, "boolean", null), strVal: Field.toString(fval as Field) || "" }
+        return { boolVal: Cast(fval, "boolean", null), strVal: Field.toString(fval as Field) || "" };
     }
 
     // set the display of the field's value (checkbox for booleans, span of text for strings)
@@ -241,8 +241,8 @@ export class DashFieldViewMenu extends AntimodeMenu<AntimodeMenuProps> {
         const hideMenu = () => {
             this.fadeOut(true);
             document.removeEventListener("pointerdown", hideMenu);
-        }
-        document.addEventListener("pointerdown", hideMenu)
+        };
+        document.addEventListener("pointerdown", hideMenu);
     }
     render() {
         const buttons = [
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index ce82821b6..434fccf8d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1202,7 +1202,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 const tr = this._editorView.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size).setStoredMarks(storedMarks);
                 this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
             } else if (this._editorView && curText && !FormattedTextBox.DontSelectInitialText) {
-                selectAll(this._editorView.state, this._editorView?.dispatch)
+                selectAll(this._editorView.state, this._editorView?.dispatch);
                 this.startUndoTypingBatch();
             } else if (this._editorView) {
                 this._editorView.dispatch(this._editorView.state.tr.addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index f4e792acd..0af7715fe 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -2435,9 +2435,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             indexNum += (index[i] * (10 ** (-i)));
         }
         this._treeViewMap.set(indexNum, treeViewDoc);
-        console.log(String(index), treeViewDoc)
         this.props.Document.presentationLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap)); // this is a flat array of Docs
-        console.log(this.props.Document.presentationLinearizedDocuments)
         return this.childDocs;
     }
 
@@ -2447,21 +2445,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             indexNum += (index[i] * (10 ** (-i)));
         }
         console.log(String(index), treeViewDoc)
-        this._treeViewMap.delete(indexNum)
+        this._treeViewMap.delete(indexNum);
         this.props.Document.presentationLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap));
         return this.childDocs;
     }
 
     // TODO: [AL] implement sort function for an array of numbers (e.g. arr[1,2,4] v arr[1,2,1])
-    sort = (treeViewMap: Map<number, Doc>): Doc[] => {
-        // TODO
-        const sortedMap = [...treeViewMap.entries()].sort();
-        var sortedDocs = [];
-        for (var kv of sortedMap) {
-            sortedDocs.push(kv[1]);
-        }
-        return sortedDocs;
-    }
+    sort = (treeViewMap: Map<number, Doc>) => [...treeViewMap.entries()].sort().map(kv => kv[1]);
 
     render() {
         // calling this method for keyEvents
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6db36f36a..d5fd425ad 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -154,7 +154,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         if (doc !== this.props.rootDoc && mainCont) {
             const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1);
             const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, .1 * windowHeight, NumCast(this.props.Document.scrollHeight));
-            if (scrollTo !== undefined && scrollTo != this.props.layoutDoc._scrollTop) {
+            if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) {
                 focusSpeed = 500;
 
                 if (!this._pdfViewer) this._initialScroll = scrollTo;
-- 
cgit v1.2.3-70-g09d2

