From 46cf6c823ca8ab628cd8c5bd7fdfe8945344a014 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 16 May 2023 14:50:29 -0400
Subject: fixed bugs with goldenlayout dragging and undoing.  fixed searching
 for filter values in sidebars.  Stopped creating empty list for collections
 when datafield() is accessed because it messes up undo of a collection. fixed
 tab title editing.  from marquee.  Added UndoStack UI and additional naming
 support in code.

---
 src/client/views/nodes/LinkDocPreview.tsx | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'src/client/views/nodes/LinkDocPreview.tsx')

diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index c6172ee01..450176a49 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -123,7 +123,6 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                                 this._markerTargetDoc = linkTarget;
                                 this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget;
                             }
-                            this._toolTipText = 'link to ' + this._targetDoc?.title;
                             if (LinkDocPreview.LinkInfo?.noPreview || this._linkSrc?.followLinkToggle || this._markerTargetDoc?.type === DocumentType.PRES) this.followLink();
                         }
                     })
@@ -296,7 +295,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                 className="linkDocPreview"
                 ref={this._linkDocRef}
                 onPointerDown={this.followLinkPointerDown}
-                style={{ display: !this._toolTipText ? 'none' : undefined, left: this.props.location[0], top: this.props.location[1], width: this.width() + borders, height: this.height() + borders + (this.props.showHeader ? 37 : 0) }}>
+                style={{ left: this.props.location[0], top: this.props.location[1], width: this.width() + borders, height: this.height() + borders + (this.props.showHeader ? 37 : 0) }}>
                 {this.docPreview}
             </div>
         );
-- 
cgit v1.2.3-70-g09d2


From 562e965cbc3d7629014ad3902e1177d5cbefd57c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 6 Jun 2023 18:48:59 -0400
Subject: updated Symbol naming.  fixed various compile errors related to type
 checking.

---
 src/client/documents/Documents.ts                  |   3 +-
 src/client/util/DictationManager.ts                |   4 +-
 src/client/util/DocumentManager.ts                 |   3 +-
 src/client/util/LinkManager.ts                     |  17 +-
 src/client/util/SharingManager.tsx                 |  23 ++-
 src/client/views/DocComponent.tsx                  |  14 +-
 src/client/views/DocumentDecorations.tsx           |   9 +-
 src/client/views/InkTranscription.tsx              |  11 +-
 src/client/views/InkingStroke.tsx                  |  11 +-
 src/client/views/MainView.tsx                      |   4 +-
 src/client/views/OverlayView.tsx                   |   9 +-
 src/client/views/PropertiesView.tsx                |  29 +--
 src/client/views/collections/CollectionMenu.tsx    |   4 +-
 .../views/collections/CollectionNoteTakingView.tsx |  11 +-
 .../views/collections/CollectionPileView.tsx       |  19 +-
 .../views/collections/CollectionStackingView.tsx   |  13 +-
 .../views/collections/CollectionTreeView.tsx       |  19 +-
 src/client/views/collections/TabDocView.tsx        |  11 +-
 src/client/views/collections/TreeView.tsx          |  15 +-
 .../CollectionFreeFormLayoutEngines.tsx            |  11 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  25 +--
 .../collections/collectionFreeForm/MarqueeView.tsx |   5 +-
 .../collectionLinear/CollectionLinearView.tsx      |  17 +-
 .../collectionSchema/SchemaTableCell.tsx           |   4 +-
 src/client/views/nodes/ColorBox.tsx                |   5 +-
 src/client/views/nodes/DocumentView.tsx            |  17 +-
 src/client/views/nodes/EquationBox.tsx             |   6 +-
 src/client/views/nodes/ImageBox.tsx                |  11 +-
 src/client/views/nodes/KeyValueBox.tsx             |   2 +-
 src/client/views/nodes/KeyValuePair.tsx            |   7 +-
 src/client/views/nodes/LinkDocPreview.tsx          |  17 +-
 src/client/views/nodes/MapBox/MapBox2.tsx          |   5 +-
 src/client/views/nodes/PDFBox.tsx                  |  27 +--
 .../views/nodes/RecordingBox/RecordingBox.tsx      |   3 +-
 src/client/views/nodes/ScreenshotBox.tsx           |  12 +-
 src/client/views/nodes/VideoBox.tsx                |  17 +-
 src/client/views/nodes/WebBox.tsx                  |  25 +--
 src/client/views/nodes/button/FontIconBox.tsx      |  11 +-
 .../views/nodes/formattedText/DashDocView.tsx      |   9 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  29 +--
 src/client/views/nodes/trails/PresElementBox.tsx   |  13 +-
 src/client/views/pdf/PDFViewer.tsx                 |   5 +-
 src/fields/Doc.ts                                  | 228 ++++++++++-----------
 src/fields/DocSymbols.ts                           |  26 +++
 src/fields/FieldSymbols.ts                         |  21 +-
 src/fields/List.ts                                 |  92 ++++-----
 src/fields/util.ts                                 |  80 +++-----
 47 files changed, 496 insertions(+), 463 deletions(-)
 create mode 100644 src/fields/DocSymbols.ts

(limited to 'src/client/views/nodes/LinkDocPreview.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 515a870b5..934b9e307 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -2,7 +2,8 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { action, runInAction } from 'mobx';
 import { basename } from 'path';
 import { DateField } from '../../fields/DateField';
-import { Doc, DocListCast, Field, Initializing, Opt, updateCachedAcls } from '../../fields/Doc';
+import { Doc, DocListCast, Field, Opt, updateCachedAcls } from '../../fields/Doc';
+import { Initializing } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { HtmlField } from '../../fields/HtmlField';
 import { InkField, PointData } from '../../fields/InkField';
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 6c710728b..717473aa1 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -5,7 +5,7 @@ import { Doc, Opt } from '../../fields/Doc';
 import { List } from '../../fields/List';
 import { RichTextField } from '../../fields/RichTextField';
 import { listSpec } from '../../fields/Schema';
-import { Cast, CastCtor } from '../../fields/Types';
+import { Cast, CastCtor, DocCast } from '../../fields/Types';
 import { AudioField, ImageField } from '../../fields/URLField';
 import { Utils } from '../../Utils';
 import { Docs } from '../documents/Documents';
@@ -328,7 +328,7 @@ export namespace DictationManager {
                 {
                     action: (target: DocumentView) => {
                         const newBox = Docs.Create.TextDocument('', { _width: 400, _height: 200, title: 'My Outline', _layout_autoHeight: true });
-                        const proto = newBox.proto!;
+                        const proto = DocCast(newBox.proto);
                         const prompt = 'Press alt + r to start dictating here...';
                         const head = 3;
                         const anchor = head + prompt.length;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 642ea26da..1f8f4fd45 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -115,8 +115,7 @@ export class DocumentManager {
         });
         if (toReturn.length === 0) {
             DocumentManager.Instance.DocumentViews.forEach(view => {
-                const doc = view.rootDoc.proto;
-                if (doc && doc[Id] && doc[Id] === id) {
+                if (Doc.GetProto(view.rootDoc)?.[Id] === id) {
                     toReturn.push(view);
                 }
             });
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 5e6107e5f..41c2fa889 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,6 +1,7 @@
 import { action, observable, observe } from 'mobx';
 import { computedFn } from 'mobx-utils';
-import { DirectLinksSym, Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc';
+import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc';
+import { DirectLinks } from '../../fields/DocSymbols';
 import { List } from '../../fields/List';
 import { ProxyField } from '../../fields/Proxy';
 import { Cast, DocCast, PromiseValue, StrCast } from '../../fields/Types';
@@ -55,8 +56,8 @@ export class LinkManager {
                             a2 &&
                             Promise.all([Doc.GetProto(a1), Doc.GetProto(a2)]).then(
                                 action(protos => {
-                                    (protos[0] as Doc)?.[DirectLinksSym].add(link);
-                                    (protos[1] as Doc)?.[DirectLinksSym].add(link);
+                                    (protos[0] as Doc)?.[DirectLinks].add(link);
+                                    (protos[1] as Doc)?.[DirectLinks].add(link);
                                 })
                             );
                     });
@@ -69,9 +70,9 @@ export class LinkManager {
             Promise.all([a1, a2]).then(
                 action(() => {
                     if (a1 instanceof Doc && a2 instanceof Doc && ((a1.author !== undefined && a2.author !== undefined) || link.author === Doc.CurrentUserEmail)) {
-                        Doc.GetProto(a1)[DirectLinksSym].delete(link);
-                        Doc.GetProto(a2)[DirectLinksSym].delete(link);
-                        Doc.GetProto(link)[DirectLinksSym].delete(link);
+                        Doc.GetProto(a1)[DirectLinks].delete(link);
+                        Doc.GetProto(a2)[DirectLinks].delete(link);
+                        Doc.GetProto(link)[DirectLinks].delete(link);
                     }
                 })
             );
@@ -153,7 +154,7 @@ export class LinkManager {
         return this.relatedLinker(anchor);
     } // finds all links that contain the given anchor
     public getAllDirectLinks(anchor: Doc): Doc[] {
-        return Array.from(Doc.GetProto(anchor)[DirectLinksSym] ?? []);
+        return Array.from(Doc.GetProto(anchor)[DirectLinks] ?? []);
     } // finds all links that contain the given anchor
 
     relatedLinker = computedFn(function relatedLinker(this: any, anchor: Doc): Doc[] {
@@ -161,7 +162,7 @@ export class LinkManager {
             console.log('WAITING FOR DOC/PROTO IN LINKMANAGER');
             return [];
         }
-        const dirLinks = Doc.GetProto(anchor)[DirectLinksSym];
+        const dirLinks = Doc.GetProto(anchor)[DirectLinks];
         const annos = DocListCast(anchor[Doc.LayoutFieldKey(anchor) + '_annotations']);
         if (!annos) debugger;
         return annos.reduce((list, anno) => [...list, ...LinkManager.Instance.relatedLinker(anno)], Array.from(dirLinks).slice());
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 0eecb31cf..97e64ab71 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -5,7 +5,8 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import Select from 'react-select';
 import * as RequestPromise from 'request-promise';
-import { AclAdmin, AclPrivate, AclSym, AclUnset, DataSym, Doc, DocListCast, DocListCastAsync, HierarchyMapping } from '../../fields/Doc';
+import { Doc, DocListCast, DocListCastAsync, HierarchyMapping } from '../../fields/Doc';
+import { AclAdmin, AclPrivate, DocAcl, AclUnset, DocData } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
 import { NumCast, StrCast } from '../../fields/Types';
@@ -158,7 +159,7 @@ export class SharingManager extends React.Component<{}> {
 
         const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.props.Document);
         return !docs
-            .map(doc => (this.layoutDocAcls ? doc : doc[DataSym]))
+            .map(doc => (this.layoutDocAcls ? doc : doc[DocData]))
             .map(doc => {
                 doc.author === Doc.CurrentUserEmail && !doc[myAcl] && distributeAcls(myAcl, SharingPermissions.Admin, doc, undefined, undefined, isDashboard);
 
@@ -192,7 +193,7 @@ export class SharingManager extends React.Component<{}> {
 
         // ! ensures it returns true if document has been shared successfully, false otherwise
         return !docs
-            .map(doc => (this.layoutDocAcls ? doc : doc[DataSym]))
+            .map(doc => (this.layoutDocAcls ? doc : doc[DocData]))
             .map(doc => {
                 doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmailNormalized}`] && distributeAcls(`acl-${Doc.CurrentUserEmailNormalized}`, SharingPermissions.Admin, doc, undefined, undefined, isDashboard);
 
@@ -273,7 +274,7 @@ export class SharingManager extends React.Component<{}> {
                 doc.isShared = true;
                 doc.backgroundColor = 'green';
             } else {
-                const acls = doc[DataSym][AclSym];
+                const acls = doc[DocData][DocAcl];
                 if (
                     Object.keys(acls)
                         .filter(key => key !== `acl-${Doc.CurrentUserEmailNormalized}` && key !== 'acl-Me')
@@ -485,7 +486,7 @@ export class SharingManager extends React.Component<{}> {
         const groups = this.groupSort === 'ascending' ? groupList.slice().sort(this.sortGroups) : this.groupSort === 'descending' ? groupList.slice().sort(this.sortGroups).reverse() : groupList;
 
         // handles the case where multiple documents are selected
-        let docs = SelectionManager.Views().length < 2 ? [this.layoutDocAcls ? this.targetDoc : this.targetDoc?.[DataSym]] : SelectionManager.Views().map(docView => (this.layoutDocAcls ? docView.props.Document : docView.props.Document?.[DataSym]));
+        let docs = SelectionManager.Views().length < 2 ? [this.layoutDocAcls ? this.targetDoc : this.targetDoc?.[DocData]] : SelectionManager.Views().map(docView => (this.layoutDocAcls ? docView.props.Document : docView.props.Document?.[DocData]));
 
         if (this.myDocAcls) {
             const newDocs: Doc[] = [];
@@ -493,21 +494,21 @@ export class SharingManager extends React.Component<{}> {
             docs = newDocs.filter(doc => GetEffectiveAcl(doc) === AclAdmin);
         }
 
-        const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DataSym];
+        const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DocData];
 
         // tslint:disable-next-line: no-unnecessary-callback-wrapper
         const effectiveAcls = docs.map(doc => GetEffectiveAcl(doc));
         const admin = this.myDocAcls ? Boolean(docs.length) : effectiveAcls.every(acl => acl === AclAdmin);
 
         // users in common between all docs
-        const commonKeys = intersection(...docs.map(doc => (this.layoutDocAcls ? doc : doc[DataSym])).map(doc => doc?.[AclSym] && Object.keys(doc[AclSym])));
+        const commonKeys = intersection(...docs.map(doc => (this.layoutDocAcls ? doc : doc[DocData])).map(doc => doc?.[DocAcl] && Object.keys(doc[DocAcl])));
 
         // the list of users shared with
         const userListContents: (JSX.Element | null)[] = users
             .filter(({ user }) => (docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(user.email)}`) : docs[0]?.author !== user.email))
             .map(({ user, linkDatabase, sharingDoc, userColor }) => {
                 const userKey = `acl-${normalizeEmail(user.email)}`;
-                const uniform = docs.map(doc => (this.layoutDocAcls ? doc : doc[DataSym])).every(doc => doc?.[AclSym]?.[userKey] === docs[0]?.[AclSym]?.[userKey]);
+                const uniform = docs.map(doc => (this.layoutDocAcls ? doc : doc[DocData])).every(doc => doc?.[DocAcl]?.[userKey] === docs[0]?.[DocAcl]?.[userKey]);
                 const permissions = uniform ? StrCast(targetDoc?.[userKey]) : '-multiple-';
 
                 return !permissions ? null : (
@@ -533,7 +534,7 @@ export class SharingManager extends React.Component<{}> {
         userListContents.unshift(
             sameAuthor ? (
                 <div key={'owner'} className={'container'}>
-                    <span className={'padding'}>{targetDoc?.author === Doc.CurrentUserEmail ? 'Me' : targetDoc?.author}</span>
+                    <span className="padding">{targetDoc?.author === Doc.CurrentUserEmail ? 'Me' : StrCast(targetDoc?.author)}</span>
                     <div className="edit-actions">
                         <div className={'permissions-dropdown'}>Owner</div>
                     </div>
@@ -555,8 +556,8 @@ export class SharingManager extends React.Component<{}> {
         const groupListContents = groupListMap.map(group => {
             const groupKey = `acl-${StrCast(group.title)}`;
             const uniform = docs
-                .map(doc => (this.layoutDocAcls ? doc : doc[DataSym]))
-                .every(doc => (this.layoutDocAcls ? doc?.[AclSym]?.[groupKey] === docs[0]?.[AclSym]?.[groupKey] : doc?.[DataSym]?.[AclSym]?.[groupKey] === docs[0]?.[DataSym]?.[AclSym]?.[groupKey]));
+                .map(doc => (this.layoutDocAcls ? doc : doc[DocData]))
+                .every(doc => (this.layoutDocAcls ? doc?.[DocAcl]?.[groupKey] === docs[0]?.[DocAcl]?.[groupKey] : doc?.[DocData]?.[DocAcl]?.[groupKey] === docs[0]?.[DocData]?.[DocAcl]?.[groupKey]));
             const permissions = uniform ? StrCast(targetDoc?.[`acl-${StrCast(group.title)}`]) : '-multiple-';
 
             return !permissions ? null : (
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index ffb2d92f6..6fab4430d 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,7 +1,7 @@
 import { action, computed, observable } from 'mobx';
 import { DateField } from '../../fields/DateField';
-import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast, Opt } from '../../fields/Doc';
-import { InkTool } from '../../fields/InkField';
+import { DocListCast, Opt, Doc } from '../../fields/Doc';
+import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocAcl, DocData } from '../../fields/DocSymbols';
 import { List } from '../../fields/List';
 import { Cast, ScriptCast } from '../../fields/Types';
 import { denormalizeEmail, distributeAcls, GetEffectiveAcl, inheritParentAcls, SharingPermissions } from '../../fields/util';
@@ -36,7 +36,7 @@ export function DocComponent<P extends DocComponentProps>() {
         }
         // This is the data part of a document -- ie, the data that is constant across all views of the document
         @computed get dataDoc() {
-            return this.props.Document[DataSym] as Doc;
+            return this.props.Document[DocData] as Doc;
         }
         // key where data is stored
         @computed get fieldKey() {
@@ -74,7 +74,7 @@ export function ViewBoxBaseComponent<P extends ViewBoxBaseProps>() {
         }
         // This is the data part of a document -- ie, the data that is constant across all views of the document
         @computed get dataDoc() {
-            return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym];
+            return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DocData];
         }
         // key where data is stored
         @computed get fieldKey() {
@@ -118,7 +118,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
         }
         // This is the data part of a document -- ie, the data that is constant across all views of the document
         @computed get dataDoc() {
-            return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym];
+            return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DocData];
         }
 
         // key where data is stored
@@ -185,7 +185,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
             if (this.props.filterAddDocument?.(docs) === false || docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.props.Document))) {
                 return false;
             }
-            const targetDataDoc = this.props.Document[DataSym];
+            const targetDataDoc = this.props.Document[DocData];
             const effectiveAcl = GetEffectiveAcl(targetDataDoc);
 
             if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
@@ -193,7 +193,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
             }
             const added = docs;
             if (added.length) {
-                const aclKeys = Object.keys(this.props.Document[AclSym] ?? {});
+                const aclKeys = Object.keys(this.props.Document[DocAcl] ?? {});
                 aclKeys.forEach(key =>
                     added.forEach(d => {
                         if (d.author === denormalizeEmail(key.substring(4)) && !d.createdFrom) {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 72c6d449a..e4d50b143 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -6,7 +6,8 @@ import { action, computed, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { FaUndo } from 'react-icons/fa';
 import { DateField } from '../../fields/DateField';
-import { AclAdmin, AclEdit, DataSym, Doc, DocListCast, Field, HeightSym, WidthSym } from '../../fields/Doc';
+import { Doc, DocListCast, Field } from '../../fields/Doc';
+import { AclAdmin, AclEdit, DocData, Height, Width } from '../../fields/DocSymbols';
 import { InkField } from '../../fields/InkField';
 import { RichTextField } from '../../fields/RichTextField';
 import { ScriptField } from '../../fields/ScriptField';
@@ -279,8 +280,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 // open centered in a new workspace with Shift Key
                 const embedding = Doc.MakeEmbedding(selectedDocs[0].rootDoc);
                 embedding.embedContainer = undefined;
-                embedding.x = -embedding[WidthSym]() / 2;
-                embedding.y = -embedding[HeightSym]() / 2;
+                embedding.x = -embedding[Width]() / 2;
+                embedding.y = -embedding[Height]() / 2;
                 CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right);
             } else if (e.altKey) {
                 // open same document in new tab
@@ -765,7 +766,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             seldocview.props.hideDeleteButton ||
             seldocview.rootDoc.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
-                const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DataSym]) : AclEdit;
+                const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit;
                 return (docView.rootDoc.stayInCollection && !docView.rootDoc.timelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
             });
 
diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx
index 025538160..e38474ea0 100644
--- a/src/client/views/InkTranscription.tsx
+++ b/src/client/views/InkTranscription.tsx
@@ -1,7 +1,8 @@
 import * as iink from 'iink-js';
 import { action, observable } from 'mobx';
 import * as React from 'react';
-import { Doc, DocListCast, HeightSym, WidthSym } from '../../fields/Doc';
+import { Doc, DocListCast } from '../../fields/Doc';
+import { Height, Width } from '../../fields/DocSymbols';
 import { InkData, InkField, InkTool } from '../../fields/InkField';
 import { Cast, DateCast, NumCast } from '../../fields/Types';
 import { aggregateBounds } from '../../Utils';
@@ -283,8 +284,8 @@ export class InkTranscription extends React.Component {
             action(d => {
                 const x = NumCast(d.x);
                 const y = NumCast(d.y);
-                const width = d[WidthSym]();
-                const height = d[HeightSym]();
+                const width = d[Width]();
+                const height = d[Height]();
                 bounds.push({ x, y, width, height });
             })
         );
@@ -323,8 +324,8 @@ export class InkTranscription extends React.Component {
         // Gets a collection based on the selected nodes using a marquee view ref
         const newCollection = marqViewRef?.getCollection(selected, undefined, true);
         if (newCollection) {
-            newCollection.height = newCollection[HeightSym]();
-            newCollection.width = newCollection[WidthSym]();
+            newCollection.height = newCollection[Height]();
+            newCollection.width = newCollection[Width]();
             // if the grouping we are creating is an individual word
             if (word) {
                 newCollection.title = word;
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 545e20ed1..91452fbf5 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -23,7 +23,8 @@
 import React = require('react');
 import { action, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, HeightSym, WidthSym } from '../../fields/Doc';
+import { Doc } from '../../fields/Doc';
+import { Height, Width } from '../../fields/DocSymbols';
 import { InkData, InkField } from '../../fields/InkField';
 import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types';
 import { TraceMobx } from '../../fields/util';
@@ -370,10 +371,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
         const strokeColor = !closed && fillColor && fillColor !== 'transparent' ? fillColor : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color) ?? StrCast(this.layoutDoc.color);
 
         // bcz: Hack!! Not really sure why, but having fractional values for width/height of mask ink strokes causes the dragging clone (see DragManager) to be offset from where it should be.
-        if (isInkMask && (this.layoutDoc[WidthSym]() !== Math.round(this.layoutDoc[WidthSym]()) || this.layoutDoc[HeightSym]() !== Math.round(this.layoutDoc[HeightSym]()))) {
+        if (isInkMask && (this.layoutDoc[Width]() !== Math.round(this.layoutDoc[Width]()) || this.layoutDoc[Height]() !== Math.round(this.layoutDoc[Height]()))) {
             setTimeout(() => {
-                this.layoutDoc._width = Math.round(NumCast(this.layoutDoc[WidthSym]()));
-                this.layoutDoc._height = Math.round(NumCast(this.layoutDoc[HeightSym]()));
+                this.layoutDoc._width = Math.round(NumCast(this.layoutDoc[Width]()));
+                this.layoutDoc._height = Math.round(NumCast(this.layoutDoc[Height]()));
             });
         }
 
@@ -464,7 +465,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                         style={{
                             color: StrCast(this.layoutDoc.textColor, 'black'),
                             pointerEvents: this.props.isDocumentActive?.() ? 'all' : undefined,
-                            width: this.layoutDoc[WidthSym](),
+                            width: this.layoutDoc[Width](),
                             transform: `scale(${this.props.NativeDimScaling?.() || 1})`,
                             transformOrigin: 'top left',
                             //top: (this.props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this.props.NativeDimScaling?.() || 1)) / 2,
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 50f451c0a..8e112dddb 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -10,7 +10,7 @@ import 'normalize.css';
 import * as React from 'react';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
 import { ScriptField } from '../../fields/ScriptField';
-import { StrCast } from '../../fields/Types';
+import { DocCast, StrCast } from '../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
@@ -854,7 +854,7 @@ export class MainView extends React.Component {
         this._leftMenuFlyoutWidth = this._leftMenuFlyoutWidth || 250;
         //setTimeout(action(() => (this._leftMenuFlyoutWidth += 0.5)));
 
-        this._sidebarContent.proto = button.target as any;
+        this._sidebarContent.proto = DocCast(button.target);
         this.LastButton = button;
     });
 
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 00f9aa879..59865cba3 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -3,7 +3,8 @@ import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import * as React from 'react';
 import ReactLoading from 'react-loading';
-import { Doc, DocListCast, HeightSym, WidthSym } from '../../fields/Doc';
+import { Doc, DocListCast } from '../../fields/Doc';
+import { Height, Width } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { NumCast } from '../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../Utils';
@@ -177,7 +178,7 @@ export class OverlayView extends React.Component {
                     offsety = 0;
                 const dref = React.createRef<HTMLDivElement>();
                 const onPointerMove = action((e: PointerEvent, down: number[]) => {
-                 if (e.cancelBubble) return false;  // if the overlay doc processed the move event (e.g., to pan its contents), then the event should be marked as canceled since propagation can't be stopped
+                    if (e.cancelBubble) return false; // if the overlay doc processed the move event (e.g., to pan its contents), then the event should be marked as canceled since propagation can't be stopped
                     if (e.buttons === 1) {
                         d.overlayX = e.clientX + offsetx;
                         d.overlayY = e.clientY + offsety;
@@ -214,8 +215,8 @@ export class OverlayView extends React.Component {
                             bringToFront={emptyFunction}
                             addDocument={undefined}
                             removeDocument={this.removeOverlayDoc}
-                            PanelWidth={d[WidthSym]}
-                            PanelHeight={d[HeightSym]}
+                            PanelWidth={d[Width]}
+                            PanelHeight={d[Height]}
                             ScreenToLocalTransform={this.docScreenToLocalXf(d)}
                             renderDepth={1}
                             hideDecorations={true}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 5c3ed39a4..1111886d8 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -7,7 +7,8 @@ import { intersection } from 'lodash';
 import { action, computed, Lambda, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { ColorState, SketchPicker } from 'react-color';
-import { AclAdmin, AclSym, DataSym, Doc, Field, FieldResult, HeightSym, HierarchyMapping, NumListCast, Opt, StrListCast, WidthSym } from '../../fields/Doc';
+import { Doc, Field, FieldResult, HierarchyMapping, NumListCast, Opt, StrListCast } from '../../fields/Doc';
+import { AclAdmin, DocAcl, DocData, Height, Width } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { InkField } from '../../fields/InkField';
 import { List } from '../../fields/List';
@@ -69,7 +70,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return this.selectedDoc?.type === DocumentType.LINK;
     }
     @computed get dataDoc() {
-        return this.selectedDoc?.[DataSym];
+        return this.selectedDoc?.[DocData];
     }
 
     @observable layoutFields: boolean = false;
@@ -116,16 +117,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return this.selectedDoc?.type === DocumentType.INK;
     }
 
-    rtfWidth = () => (!this.selectedDoc ? 0 : Math.min(this.selectedDoc?.[WidthSym](), this.props.width - 20));
-    rtfHeight = () => (!this.selectedDoc ? 0 : this.rtfWidth() <= this.selectedDoc?.[WidthSym]() ? Math.min(this.selectedDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT);
+    rtfWidth = () => (!this.selectedDoc ? 0 : Math.min(this.selectedDoc?.[Width](), this.props.width - 20));
+    rtfHeight = () => (!this.selectedDoc ? 0 : this.rtfWidth() <= this.selectedDoc?.[Width]() ? Math.min(this.selectedDoc?.[Height](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT);
 
     @action
     docWidth = () => {
         if (this.selectedDoc) {
             const layoutDoc = this.selectedDoc;
             const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._layout_fitWidth);
-            if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20));
-            return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
+            if (aspect) return Math.min(layoutDoc[Width](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20));
+            return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[Width](), this.props.width - 20) : this.props.width - 20;
         } else {
             return 0;
         }
@@ -205,7 +206,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     @undoBatch
     setKeyValue = (value: string) => {
-        const docs = SelectionManager.Views().length < 2 && this.selectedDoc ? [this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc] : SelectionManager.Views().map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc));
+        const docs = SelectionManager.Views().length < 2 && this.selectedDoc ? [this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc!] : SelectionManager.Views().map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc));
         docs.forEach(doc => {
             if (value.indexOf(':') !== -1) {
                 const newVal = value[0].toUpperCase() + value.substring(1, value.length);
@@ -220,7 +221,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 const tags = StrListCast(doc.tags);
                 if (!tags.includes(value)) {
                     tags.push(value);
-                    doc[DataSym].tags = tags.length ? new List<string>(tags) : undefined;
+                    doc[DocData].tags = tags.length ? new List<string>(tags) : undefined;
                 }
                 return true;
             }
@@ -301,7 +302,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
      */
     @undoBatch
     changePermissions = (e: any, user: string) => {
-        const docs = (SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(dv => dv.props.Document)).filter(doc => doc).map(doc => (this.layoutDocAcls ? doc : DocCast(doc)[DataSym]));
+        const docs = (SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(dv => dv.props.Document)).filter(doc => doc).map(doc => (this.layoutDocAcls ? doc! : DocCast(doc)[DocData]));
         SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs);
     };
 
@@ -388,7 +389,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @computed get sharingTable() {
         // all selected docs
         const docs =
-            SelectionManager.Views().length < 2 ? [this.layoutDocAcls ? this.selectedDoc : this.selectedDoc?.[DataSym]] : SelectionManager.Views().map(docView => (this.layoutDocAcls ? docView.props.Document : docView.props.Document[DataSym]));
+            SelectionManager.Views().length < 2 && this.selectedDoc ? [this.layoutDocAcls ? this.selectedDoc : this.dataDoc!] : SelectionManager.Views().map(docView => (this.layoutDocAcls ? docView.props.Document : docView.props.Document[DocData]));
 
         const target = docs[0];
 
@@ -397,7 +398,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         const showAdmin = effectiveAcls.every(acl => acl === AclAdmin);
 
         // users in common between all docs
-        const commonKeys: string[] = intersection(...docs.map(doc => doc?.[AclSym] && Object.keys(doc[AclSym]).filter(key => key !== 'acl-Me')));
+        const commonKeys: string[] = intersection(...docs.map(doc => doc?.[DocAcl] && Object.keys(doc[DocAcl]).filter(key => key !== 'acl-Me')));
 
         const tableEntries = [];
 
@@ -405,9 +406,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         if (commonKeys.length) {
             for (const key of commonKeys) {
                 const name = denormalizeEmail(key.substring(4));
-                const uniform = docs.every(doc => doc?.[AclSym]?.[key] === docs[0]?.[AclSym]?.[key]);
+                const uniform = docs.every(doc => doc?.[DocAcl]?.[key] === docs[0]?.[DocAcl]?.[key]);
                 if (name !== Doc.CurrentUserEmail && name !== target.author && name !== 'Public' && name !== 'Override' /* && sidebarUsersDisplayed![name] !== false*/) {
-                    tableEntries.push(this.sharingItem(name, showAdmin, uniform ? HierarchyMapping.get(target[AclSym][key])!.name : '-multiple-'));
+                    tableEntries.push(this.sharingItem(name, showAdmin, uniform ? HierarchyMapping.get(target[DocAcl][key])!.name : '-multiple-'));
                 }
             }
         }
@@ -416,7 +417,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         // shifts the current user, owner, public to the top of the doc.
         // tableEntries.unshift(this.sharingItem("Override", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Override"] === docs[0]["acl-Override"]) ? (AclMap.get(target[AclSym]?.["acl-Override"]) || "None") : "-multiple-"));
         if (ownerSame) tableEntries.unshift(this.sharingItem(StrCast(target.author), showAdmin, 'Owner'));
-        tableEntries.unshift(this.sharingItem('Public', showAdmin, docs.filter(doc => doc).every(doc => doc['acl-Public'] === target['acl-Public']) ? target['acl-Public'] || SharingPermissions.None : '-multiple-'));
+        tableEntries.unshift(this.sharingItem('Public', showAdmin, StrCast(docs.filter(doc => doc).every(doc => doc['acl-Public'] === target['acl-Public']) ? target['acl-Public'] || SharingPermissions.None : '-multiple-')));
         tableEntries.unshift(
             this.sharingItem(
                 'Me',
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 6dd76465e..dc430667b 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -14,7 +14,7 @@ import { ObjectField } from '../../../fields/ObjectField';
 import { RichTextField } from '../../../fields/RichTextField';
 import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
@@ -347,7 +347,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
 
     @undoBatch
     viewChanged = (e: React.ChangeEvent) => {
-        const target = this.document !== Doc.MyLeftSidebarPanel ? this.document : (this.document.proto as Doc);
+        const target = this.document !== Doc.MyLeftSidebarPanel ? this.document : DocCast(this.document.proto);
         //@ts-ignore
         target._type_collection = e.target.selectedOptions[0].value;
     };
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index a65e23911..fc265e2b9 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -2,7 +2,8 @@ import React = require('react');
 import { CursorProperty } from 'csstype';
 import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
-import { DataSym, Doc, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { Doc, Field, Opt } from '../../../fields/Doc';
+import { DocData, Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
@@ -225,7 +226,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 ref={r => (dref = r || undefined)}
                 Document={doc}
                 pointerEvents={this.blockPointerEventsWhenDragging}
-                DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])}
+                DataDoc={dataDoc ?? (!Doc.AreProtosEqual(doc[DocData], doc) ? doc[DocData] : undefined)}
                 renderDepth={this.props.renderDepth + 1}
                 PanelWidth={width}
                 PanelHeight={height}
@@ -284,7 +285,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         const existingHeader = this.colHeaderData.find(sh => sh.heading === heading);
         const existingWidth = existingHeader?.width ? existingHeader.width : 0;
         const maxWidth = existingWidth > 0 ? existingWidth * this.availableWidth : this.maxColWidth;
-        const width = d.layout_fitWidth ? maxWidth : d[WidthSym]();
+        const width = d.layout_fitWidth ? maxWidth : d[Width]();
         return Math.min(maxWidth - CollectionNoteTakingViewColumn.ColumnMargin, width < maxWidth ? width : maxWidth);
     }
 
@@ -294,8 +295,8 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
         const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField ? undefined : this.props.DataDoc;
         const maxHeight = (lim => (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1));
-        const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[WidthSym]() : 0);
-        const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[HeightSym]() : 0);
+        const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[Width]() : 0);
+        const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[Height]() : 0);
         if (nw && nh) {
             const docWid = this.getDocWidth(d);
             return Math.min(maxHeight, (docWid * nh) / nw);
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index ea0fbbc54..bbc91aa6e 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -1,6 +1,7 @@
 import { action, computed, IReactionDisposer, reaction } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, HeightSym, WidthSym } from '../../../fields/Doc';
+import { Doc, DocListCast } from '../../../fields/Doc';
+import { Height, Width } from '../../../fields/DocSymbols';
 import { NumCast, StrCast } from '../../../fields/Types';
 import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils';
 import { DocUtils } from '../../documents/Documents';
@@ -73,12 +74,12 @@ export class CollectionPileView extends CollectionSubView() {
     // toggles the pileup between starburst to compact
     toggleStarburst = action(() => {
         if (this.layoutEngine() === computeStarburstLayout.name) {
-            if (this.rootDoc[WidthSym]() !== NumCast(this.rootDoc._starburstDiameter, 500)) {
-                this.rootDoc._starburstDiameter = this.rootDoc[WidthSym]();
+            if (this.rootDoc[Width]() !== NumCast(this.rootDoc._starburstDiameter, 500)) {
+                this.rootDoc._starburstDiameter = this.rootDoc[Width]();
             }
             const defaultSize = 110;
-            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2;
-            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2;
+            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2;
+            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 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, NumCast(this.layoutDoc._width) / 2, false);
@@ -87,10 +88,10 @@ export class CollectionPileView extends CollectionSubView() {
             this.props.Document._pileLayoutEngine = computePassLayout.name;
         } else {
             const defaultSize = NumCast(this.rootDoc._starburstDiameter, 500);
-            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2;
-            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2;
-            this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym]();
-            this.layoutDoc._starburstPileHeight = this.layoutDoc[HeightSym]();
+            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - defaultSize / 2;
+            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - defaultSize / 2;
+            this.layoutDoc._starburstPileWidth = this.layoutDoc[Width]();
+            this.layoutDoc._starburstPileHeight = this.layoutDoc[Height]();
             this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0;
             this.layoutDoc._width = this.layoutDoc._height = defaultSize;
             this.props.Document._pileLayoutEngine = computeStarburstLayout.name;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index e2e352857..56f53afe6 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -3,7 +3,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { CursorProperty } from 'csstype';
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
-import { DataSym, Doc, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { Doc, Opt } from '../../../fields/Doc';
+import { DocData, Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
@@ -285,7 +286,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             const layout_fieldKey = 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;
+            newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
             if (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) {
                 newDoc[layout_fieldKey] = docView.rootDoc[layout_fieldKey];
             }
@@ -320,7 +321,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             <DocumentView
                 ref={r => (dref = r || undefined)}
                 Document={doc}
-                DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])}
+                DataDoc={dataDoc ?? (!Doc.AreProtosEqual(doc[DocData], doc) ? doc[DocData] : undefined)}
                 renderDepth={this.props.renderDepth + 1}
                 PanelWidth={width}
                 PanelHeight={height}
@@ -377,7 +378,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
         const maxWidth = this.columnWidth / this.numGroupColumns;
         if (!this.layoutDoc._columnsFill && !(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d))) {
-            return Math.min(d[WidthSym](), maxWidth);
+            return Math.min(d[Width](), maxWidth);
         }
         return maxWidth;
     }
@@ -386,8 +387,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
         const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField ? undefined : this.props.DataDoc;
         const maxHeight = (lim => (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1));
-        const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[WidthSym]() : 0);
-        const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[HeightSym]() : 0);
+        const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[Width]() : 0);
+        const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[Height]() : 0);
         if (nw && nh) {
             const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
             const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 095e34c39..969658238 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,6 +1,7 @@
 import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
-import { DataSym, Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
+import { DocData, Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { listSpec } from '../../../fields/Schema';
@@ -154,15 +155,15 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     @action
     remove = (doc: Doc | Doc[]): boolean => {
         const docs = doc instanceof Doc ? [doc] : doc;
-        const targetDataDoc = this.doc[DataSym];
+        const targetDataDoc = this.doc[DocData];
         const value = DocListCast(targetDataDoc[this.props.fieldKey]);
         const result = value.filter(v => !docs.includes(v));
         if ((doc instanceof Doc ? [doc] : doc).some(doc => SelectionManager.Views().some(dv => Doc.AreProtosEqual(dv.rootDoc, doc)))) SelectionManager.DeselectAll();
-        if (result.length !== value.length) {
-            const ind = targetDataDoc[this.props.fieldKey].indexOf(doc);
-            const prev = ind && targetDataDoc[this.props.fieldKey][ind - 1];
+        if (result.length !== value.length && doc instanceof Doc) {
+            const ind = DocListCast(targetDataDoc[this.props.fieldKey]).indexOf(doc);
+            const prev = ind && DocListCast(targetDataDoc[this.props.fieldKey])[ind - 1];
             this.props.removeDocument?.(doc);
-            if (ind > 0) {
+            if (ind > 0 && prev) {
                 FormattedTextBox.SelectOnLoad = prev[Id];
                 DocumentManager.Instance.getDocumentView(prev, this.props.DocumentView?.())?.select(false);
             }
@@ -175,7 +176,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     addDoc = (docs: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
         const doAddDoc = (doc: Doc | Doc[]) =>
             (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => {
-                const res = flg && Doc.AddDocToList(this.doc[DataSym], this.props.fieldKey, doc, relativeTo, before);
+                const res = flg && Doc.AddDocToList(this.doc[DocData], this.props.fieldKey, doc, relativeTo, before);
                 res && (doc.embedContainer = this.props.Document);
                 return res;
             }, true);
@@ -368,8 +369,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     marginX = () => NumCast(this.doc._xMargin);
     marginTop = () => NumCast(this.doc._yMargin);
     marginBot = () => NumCast(this.doc._yMargin);
-    documentTitleWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.panelWidth());
-    documentTitleHeight = () => (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.layout_autoHeightMargins);
+    documentTitleWidth = () => Math.min(this.layoutDoc?.[Width](), this.panelWidth());
+    documentTitleHeight = () => (this.layoutDoc?.[Height]() || 0) - NumCast(this.layoutDoc.layout_autoHeightMargins);
     truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
     onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
     panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1));
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index b20d05433..710e33b1c 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -5,11 +5,11 @@ import { clamp } from 'lodash';
 import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as ReactDOM from 'react-dom/client';
-import { DataSym, Doc, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { Doc, Opt } from '../../../fields/Doc';
+import { DocData, Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { FieldId } from '../../../fields/RefField';
-import { listSpec } from '../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
 import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils';
 import { DocServer } from '../../DocServer';
@@ -292,7 +292,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             PresBox.Instance?.clearSelectedArray();
             pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); //Update selected array
         });
-        if ( // open the presentation trail if it's not already opened
+        if (
+            // open the presentation trail if it's not already opened
             !Array.from(CollectionDockingView.Instance?.tabMap ?? [])
                 .map(d => d.DashDoc)
                 .includes(curPres)
@@ -423,7 +424,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     LayoutTemplateString={this.props.keyValue ? KeyValueBox.LayoutString() : undefined}
                     hideTitle={this.props.keyValue}
                     Document={this._document}
-                    DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
+                    DataDoc={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined}
                     onBrowseClick={MainView.Instance.exploreMode}
                     waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick}
                     isContentActive={returnTrue}
@@ -533,7 +534,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                                 return 'gray';
                         }
                     })(doc.type as DocumentType);
-                    return !background ? undefined : <div style={{ width: doc[WidthSym](), height: doc[HeightSym](), position: 'absolute', display: 'block', background }} />;
+                    return !background ? undefined : <div style={{ width: doc[Width](), height: doc[Height](), position: 'absolute', display: 'block', background }} />;
             }
         }
     };
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index f5877fa1a..ca9471f6f 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -2,7 +2,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, Field, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
+import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
+import { DocData, Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { RichTextField } from '../../../fields/RichTextField';
@@ -146,7 +147,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return NumCast(this.props.treeViewParent.maxEmbedHeight, 200);
     }
     @computed get dataDoc() {
-        return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DataSym];
+        return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DocData];
     }
     @computed get layoutDoc() {
         return Doc.Layout(this.doc);
@@ -191,10 +192,10 @@ export class TreeView extends React.Component<TreeViewProps> {
     };
     @undoBatch @action remove = (doc: Doc | Doc[], key: string) => {
         this.props.treeView.props.select(false);
-        const ind = this.dataDoc[key].indexOf(doc);
+        const ind = DocListCast(this.dataDoc[key]).indexOf(doc instanceof Doc ? doc : doc.lastElement());
 
         const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
-        res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.DocumentView?.())?.select(false);
+        res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.props.treeView.props.DocumentView?.())?.select(false);
         return res;
     };
 
@@ -410,7 +411,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     embeddedPanelHeight = () => {
         const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
         return Math.min(
-            layoutDoc[HeightSym](),
+            layoutDoc[Height](),
             this.MAX_EMBED_HEIGHT,
             (() => {
                 const aspect = Doc.NativeAspect(layoutDoc);
@@ -419,7 +420,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     ? !Doc.NativeHeight(layoutDoc)
                         ? NumCast(layoutDoc._height)
                         : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.treeViewParent._height)))
-                    : (this.embeddedPanelWidth() * layoutDoc[HeightSym]()) / layoutDoc[WidthSym]();
+                    : (this.embeddedPanelWidth() * layoutDoc[Height]()) / layoutDoc[Width]();
             })()
         );
     };
@@ -1190,7 +1191,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 const childLayout = Doc.Layout(pair.layout);
                 const rowHeight = () => {
                     const aspect = Doc.NativeAspect(childLayout);
-                    return aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym]();
+                    return aspect ? Math.min(childLayout[Width](), rowWidth()) / aspect : childLayout[Height]();
                 };
                 return (
                     <TreeView
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index fee4705e6..1e76d373c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -1,4 +1,5 @@
-import { Doc, Field, FieldResult, HeightSym, WidthSym } from '../../../../fields/Doc';
+import { Doc, Field, FieldResult } from '../../../../fields/Doc';
+import { Height, Width } from '../../../../fields/DocSymbols';
 import { Id, ToString } from '../../../../fields/FieldSymbols';
 import { ObjectField } from '../../../../fields/ObjectField';
 import { RefField } from '../../../../fields/RefField';
@@ -90,8 +91,8 @@ export function computePassLayout(poolData: Map<string, PoolData>, pivotDoc: Doc
         docMap.set(layout[Id], {
             x: NumCast(layout.x),
             y: NumCast(layout.y),
-            width: layout[WidthSym](),
-            height: layout[HeightSym](),
+            width: layout[Width](),
+            height: layout[Height](),
             pair: { layout, data },
             transition: 'all .3s',
             replica: '',
@@ -105,8 +106,8 @@ export function computeStarburstLayout(poolData: Map<string, PoolData>, pivotDoc
     const burstDiam = [NumCast(pivotDoc._width), NumCast(pivotDoc._height)];
     const burstScale = NumCast(pivotDoc._starburstDocScale, 1);
     childPairs.forEach(({ layout, data }, i) => {
-        const aspect = layout[HeightSym]() / layout[WidthSym]();
-        const docSize = Math.min(Math.min(400, layout[WidthSym]()), Math.min(400, layout[WidthSym]()) / aspect) * burstScale;
+        const aspect = layout[Height]() / layout[Width]();
+        const docSize = Math.min(Math.min(400, layout[Width]()), Math.min(400, layout[Width]()) / aspect) * burstScale;
         const deg = (i / childPairs.length) * Math.PI * 2;
         docMap.set(layout[Id], {
             x: Math.min(burstDiam[0] / 2 - docSize, Math.max(-burstDiam[0] / 2, (Math.cos(deg) * burstDiam[0]) / 2 - docSize / 2)),
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8b9698293..811a77fa8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -4,7 +4,8 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction,
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { DateField } from '../../../../fields/DateField';
-import { DataSym, Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
+import { DocData, Height, Width } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { InkData, InkField, InkTool, PointData, Segment } from '../../../../fields/InkField';
 import { List } from '../../../../fields/List';
@@ -707,7 +708,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             case GestureUtils.Gestures.Rectangle:
                 if (this._inkToTextStartX && this._inkToTextStartY) {
                     const end = this.getTransform().transformPoint(Math.max(...ge.points.map(p => p.X)), Math.max(...ge.points.map(p => p.Y)));
-                    const setDocs = this.getActiveDocuments().filter(s => s.proto?.type === 'rtf' && s.color);
+                    const setDocs = this.getActiveDocuments().filter(s => DocCast(s.proto)?.type === DocumentType.RTF && s.color);
                     const sets = setDocs.map(sd => {
                         return Cast(sd.text, RichTextField)?.Text as string;
                     });
@@ -719,9 +720,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     const inks = this.getActiveDocuments().filter(doc => {
                         if (doc.type === 'ink') {
                             const l = NumCast(doc.x);
-                            const r = l + doc[WidthSym]();
+                            const r = l + doc[Width]();
                             const t = NumCast(doc.y);
-                            const b = t + doc[HeightSym]();
+                            const b = t + doc[Height]();
                             const pass = !(this._inkToTextStartX! > r || end[0] < l || this._inkToTextStartY! > b || end[1] < t);
                             return pass;
                         }
@@ -1201,7 +1202,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     calculatePanIntoView = (doc: Doc, xf: Transform, scale?: number) => {
         const layoutdoc = Doc.Layout(doc);
         const pt = xf.transformPoint(NumCast(doc.x), NumCast(doc.y));
-        const pt2 = xf.transformPoint(NumCast(doc.x) + layoutdoc[WidthSym](), NumCast(doc.y) + layoutdoc[HeightSym]());
+        const pt2 = xf.transformPoint(NumCast(doc.x) + layoutdoc[Width](), NumCast(doc.y) + layoutdoc[Height]());
         const bounds = { left: pt[0], right: pt2[0], top: pt[1], bot: pt2[1], width: pt2[0] - pt[0], height: pt2[1] - pt[1] };
 
         if (scale !== undefined) {
@@ -1251,7 +1252,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             const layout_fieldKey = 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;
+            newDoc[DocData][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 (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) {
@@ -1291,8 +1292,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 onDoubleClick={this.onChildDoubleClickHandler}
                 onBrowseClick={this.onBrowseClickHandler}
                 ScreenToLocalTransform={childLayout.z ? this.getContainerTransform : this.getTransform}
-                PanelWidth={childLayout[WidthSym]}
-                PanelHeight={childLayout[HeightSym]}
+                PanelWidth={childLayout[Width]}
+                PanelHeight={childLayout[Height]}
                 docFilters={this.childDocFilters}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
@@ -1558,14 +1559,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 this._disposers.groupBounds = reaction(
                     () => {
                         if (this.Document._isGroup && this.childDocs.length === this.childDocList?.length) {
-                            const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() }));
+                            const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[Width](), height: cd[Height]() }));
                             return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding));
                         }
                         return undefined;
                     },
                     cbounds => {
                         if (cbounds) {
-                            const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2];
+                            const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[Width]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[Height]() / 2];
                             const p = [NumCast(this.layoutDoc[this.panXFieldKey]), NumCast(this.layoutDoc[this.panYFieldKey])];
                             const pbounds = {
                                 x: cbounds.x - p[0] + c[0],
@@ -1631,8 +1632,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         CollectionFreeFormView.UpdateIcon(
             this.layoutDoc[Id] + '-icon' + new Date().getTime(),
             this.props.docViewPath().lastElement().ContentDiv!,
-            this.layoutDoc[WidthSym](),
-            this.layoutDoc[HeightSym](),
+            this.layoutDoc[Width](),
+            this.layoutDoc[Height](),
             this.props.PanelWidth(),
             this.props.PanelHeight(),
             0,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 641088675..d50c8d2c4 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,6 +1,7 @@
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { AclAdmin, AclAugment, AclEdit, DataSym, Doc, Opt } from '../../../../fields/Doc';
+import { Doc, Opt } from '../../../../fields/Doc';
+import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { InkData, InkField, InkTool } from '../../../../fields/InkField';
 import { List } from '../../../../fields/List';
@@ -325,7 +326,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         } else {
             this._downX = x;
             this._downY = y;
-            const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
+            const effectiveAcl = GetEffectiveAcl(this.props.Document[DocData]);
             if ([AclAdmin, AclEdit, AclAugment].includes(effectiveAcl)) {
                 PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge, this.props.slowLoadDocuments);
             }
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 3561844da..ca6b8705d 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -3,9 +3,10 @@ import { Tooltip } from '@material-ui/core';
 import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { Doc, HeightSym, Opt, WidthSym } from '../../../../fields/Doc';
+import { Doc, Opt } from '../../../../fields/Doc';
+import { Height, Width } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnTrue, StopEvent, Utils } from '../../../../Utils';
 import { CollectionViewType } from '../../../documents/DocumentTypes';
 import { DocumentManager } from '../../../util/DocumentManager';
@@ -40,12 +41,12 @@ export class CollectionLinearView extends CollectionSubView() {
         this._dropDisposer?.();
         this._widthDisposer?.();
         this._selectedDisposer?.();
-        this.childLayoutPairs.map((pair, ind) => ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log));
+        this.childLayoutPairs.map((pair, ind) => ScriptCast(DocCast(pair.layout.proto)?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log));
     }
 
     componentDidMount() {
         this._widthDisposer = reaction(
-            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[WidthSym]() || this.dimension()) + tot + 4, 0) : 0),
+            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0),
             width => this.childDocs.length && (this.layoutDoc._width = width),
             { fireImmediately: true }
         );
@@ -61,11 +62,11 @@ export class CollectionLinearView extends CollectionSubView() {
                         if (isSelected) {
                             selected = pair;
                         } else {
-                            ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
+                            ScriptCast(DocCast(pair.layout.proto)?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
                         }
                     });
                     if (selected && selected.layout) {
-                        ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
+                        ScriptCast(DocCast(selected.layout.proto)?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
                     }
                 }),
             { fireImmediately: true }
@@ -204,8 +205,8 @@ export class CollectionLinearView extends CollectionSubView() {
                     rootSelected={this.props.isSelected}
                     removeDocument={this.props.removeDocument}
                     ScreenToLocalTransform={docXf}
-                    PanelWidth={doc[WidthSym]}
-                    PanelHeight={nested || doc._height ? doc[HeightSym] : this.dimension}
+                    PanelWidth={doc[Width]}
+                    PanelHeight={nested || doc._height ? doc[Height] : this.dimension}
                     renderDepth={this.props.renderDepth + 1}
                     dontRegisterView={BoolCast(this.rootDoc.childDontRegisterViews)}
                     focus={emptyFunction}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 01bfbcddb..876693474 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -6,7 +6,7 @@ import DatePicker from 'react-datepicker';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field } from '../../../../fields/Doc';
 import { RichTextField } from '../../../../fields/RichTextField';
-import { BoolCast, Cast, DateCast, FieldValue } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast, DocCast, FieldValue } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
 import { FInfo } from '../../../documents/Documents';
@@ -58,7 +58,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                 break;
             }
             protoCount++;
-            doc = doc.proto;
+            doc = DocCast(doc.proto);
         }
         const parenCount = Math.max(0, protoCount - 1);
         const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue';
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index 330cc3971..aae759702 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -2,7 +2,8 @@ import React = require('react');
 import { action } from 'mobx';
 import { observer } from 'mobx-react';
 import { ColorState, SketchPicker } from 'react-color';
-import { Doc, HeightSym, WidthSym } from '../../../fields/Doc';
+import { Doc } from '../../../fields/Doc';
+import { Height, Width } from '../../../fields/DocSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { StrCast } from '../../../fields/Types';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -48,7 +49,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     render() {
-        const scaling = Math.min(this.layoutDoc.layout_fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[HeightSym](), this.props.PanelWidth() / this.rootDoc[WidthSym]());
+        const scaling = Math.min(this.layoutDoc.layout_fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[Height](), this.props.PanelWidth() / this.rootDoc[Width]());
         return (
             <div
                 className={`colorBox-container${this.props.isContentActive() ? '-interactive' : ''}`}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index cc105326f..1c7ef5217 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -3,7 +3,8 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
-import { AclPrivate, AnimationSym, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
+import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
+import { AclPrivate, Animation, DocData, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
@@ -794,7 +795,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : [];
         !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' });
         !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.props.Document), icon: 'hand-point-right' });
-        !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.props.Document[DataSym]), icon: 'hand-point-right' });
+        !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.props.Document[DocData]), icon: 'hand-point-right' });
 
         let documentationDescription: string | undefined = undefined;
         let documentationLink: string | undefined = undefined;
@@ -1146,7 +1147,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     renderDoc = (style: object) => {
         TraceMobx();
-        return !DocCast(this.Document) || GetEffectiveAcl(this.Document[DataSym]) === AclPrivate
+        return !DocCast(this.Document) || GetEffectiveAcl(this.Document[DocData]) === AclPrivate
             ? null
             : this.docContents ?? (
                   <div
@@ -1231,7 +1232,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents,
                 }}>
                 <>
-                    {DocumentViewInternal.AnimationEffect(renderDoc, this.rootDoc[AnimationSym], this.rootDoc)}
+                    {DocumentViewInternal.AnimationEffect(renderDoc, this.rootDoc[Animation], this.rootDoc)}
                     {borderPath?.jsx}
                 </>
             </div>
@@ -1265,8 +1266,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
 
     public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => {
         this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer);
-        this.rootDoc[AnimationSym] = presEffect;
-        this.AnimEffectTimer = setTimeout(() => (this.rootDoc[AnimationSym] = undefined), timeInMs);
+        this.rootDoc[Animation] = presEffect;
+        this.AnimEffectTimer = setTimeout(() => (this.rootDoc[Animation] = undefined), timeInMs);
     };
     public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => {
         this.rootDoc._viewTransition = `${transProp} ${timeInMs}ms`;
@@ -1579,7 +1580,7 @@ ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuff
 ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
     const linkSource = Cast(linkCollection.linkSource, Doc, null);
     const collectedLinks = DocListCast(Doc.GetProto(linkCollection).data);
-    let wid = linkSource[WidthSym]();
+    let wid = linkSource[Width]();
     const links = LinkManager.Links(linkSource);
     links.forEach(link => {
         const other = LinkManager.getOppositeAnchor(link, linkSource);
@@ -1589,7 +1590,7 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
             embedding.x = wid;
             embedding.y = 0;
             embedding._lockedPosition = false;
-            wid += otherdoc[WidthSym]();
+            wid += otherdoc[Width]();
             Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', embedding);
         }
     });
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index f17ab06e7..8c6eb4532 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -2,7 +2,7 @@ import EquationEditor from 'equation-editor-react';
 import { action, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { WidthSym } from '../../../fields/Doc';
+import { Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { NumCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
@@ -67,7 +67,7 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
         if (e.key === 'Tab') {
             const graph = Docs.Create.FunctionPlotDocument([this.rootDoc], {
-                x: NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym](),
+                x: NumCast(this.layoutDoc.x) + this.layoutDoc[Width](),
                 y: NumCast(this.layoutDoc.y),
                 _width: 400,
                 _height: 300,
@@ -104,7 +104,7 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     fontSize: StrCast(this.rootDoc._fontSize),
                 }}
                 onKeyDown={e => e.stopPropagation()}>
-                <EquationEditor ref={this._ref} value={this.dataDoc.text || 'x'} spaceBehavesLikeTab={true} onChange={this.onChange} autoCommands="pi theta sqrt sum prod alpha beta gamma rho" autoOperatorNames="sin cos tan" />
+                <EquationEditor ref={this._ref} value={StrCast(this.dataDoc.text, 'x')} spaceBehavesLikeTab={true} onChange={this.onChange} autoCommands="pi theta sqrt sum prod alpha beta gamma rho" autoOperatorNames="sin cos tan" />
             </div>
         );
     }
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 068d39391..5b302e7ce 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -3,7 +3,8 @@ import { Tooltip } from '@material-ui/core';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { extname } from 'path';
-import { DataSym, Doc, DocListCast, Opt, WidthSym } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { DocData, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
@@ -106,7 +107,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         );
         const layoutDoc = this.layoutDoc;
         this._disposers.path = reaction(
-            () => ({ nativeSize: this.nativeSize, width: this.layoutDoc[WidthSym]() }),
+            () => ({ nativeSize: this.nativeSize, width: this.layoutDoc[Width]() }),
             ({ nativeSize, width }) => {
                 if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) {
                     this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
@@ -150,7 +151,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             } else if (de.altKey || !this.dataDoc[this.fieldKey]) {
                 const layoutDoc = de.complete.docDragData?.draggedDocuments[0];
                 const targetField = Doc.LayoutFieldKey(layoutDoc);
-                const targetDoc = layoutDoc[DataSym];
+                const targetDoc = layoutDoc[DocData];
                 if (targetDoc[targetField] instanceof ImageField) {
                     this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
                     Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc), this.fieldKey);
@@ -230,7 +231,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         croppingProto.freeform_panYMax = anchh / viewScale;
         if (addCrop) {
             DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
-            cropping.x = NumCast(this.rootDoc.x) + this.rootDoc[WidthSym]();
+            cropping.x = NumCast(this.rootDoc.x) + this.rootDoc[Width]();
             cropping.y = NumCast(this.rootDoc.y);
             this.props.addDocTab(cropping, OpenWhere.inParent);
         }
@@ -302,7 +303,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
 
     considerGooglePhotosLink = () => {
-        const remoteUrl = this.dataDoc.googlePhotosUrl;
+        const remoteUrl = StrCast(this.dataDoc.googlePhotosUrl); // bcz: StrCast or URLCast???
         return !remoteUrl ? null : <img draggable={false} style={{ transformOrigin: 'bottom right' }} id={'google-photos'} src={'/assets/google_photos.png'} onClick={() => window.open(remoteUrl)} />;
     };
 
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 88a82e8e6..5b6b0b5a7 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -84,7 +84,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
     public static ApplyKVPScript(doc: Doc, key: string, kvpScript: KVPScript, forceOnDelegate?: boolean): boolean {
         const { script, type, onDelegate } = kvpScript;
         //const target = onDelegate ? Doc.Layout(doc.layout) : Doc.GetProto(doc); // bcz: TODO need to be able to set fields on layout templates
-        const target = forceOnDelegate || onDelegate || key.startsWith('_') ? doc : doc.proto || doc;
+        const target = forceOnDelegate || onDelegate || key.startsWith('_') ? doc : DocCast(doc.proto, doc);
         let field: Field;
         if (type === 'computed') {
             field = new ComputedField(script);
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 91df928c4..4e348c67c 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -13,6 +13,7 @@ import { KeyValueBox } from './KeyValueBox';
 import './KeyValueBox.scss';
 import './KeyValuePair.scss';
 import React = require('react');
+import { DocCast } from '../../../fields/Types';
 
 // Represents one row in a key value plane
 
@@ -87,7 +88,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
                 break;
             }
             protoCount++;
-            doc = doc.proto;
+            doc = DocCast(doc.proto);
         }
         const parenCount = Math.max(0, protoCount - 1);
         const keyStyle = protoCount === 0 ? 'black' : 'blue';
@@ -104,12 +105,12 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
                             onClick={undoBatch(() => {
                                 if (Object.keys(props.Document).indexOf(props.fieldKey) !== -1) {
                                     delete props.Document[props.fieldKey];
-                                } else delete props.Document.proto![props.fieldKey];
+                                } else delete DocCast(props.Document.proto)?.[props.fieldKey];
                             })}>
                             X
                         </button>
                         <input className="keyValuePair-td-key-check" type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} />
-                        <div className='keyValuePair-keyField' style={{ marginLeft: 35 * (props.fieldKey.match(/_/g)?.length ||0), color: keyStyle }}>
+                        <div className="keyValuePair-keyField" style={{ marginLeft: 35 * (props.fieldKey.match(/_/g)?.length || 0), color: keyStyle }}>
                             {'('.repeat(parenCount)}
                             {props.fieldKey}
                             {')'.repeat(parenCount)}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 450176a49..079e1b56d 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -3,11 +3,12 @@ import { Tooltip } from '@material-ui/core';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import wiki from 'wikijs';
-import { Doc, DocCastAsync, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { Doc, DocCastAsync, Opt } from '../../../fields/Doc';
+import { Height, Width } from '../../../fields/DocSymbols';
 import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils';
 import { DocServer } from '../../DocServer';
-import { Docs, DocUtils } from '../../documents/Documents';
+import { Docs } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DragManager } from '../../util/DragManager';
 import { LinkFollower } from '../../util/LinkFollower';
@@ -183,17 +184,17 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
 
     width = () => {
         if (!this._targetDoc) return 225;
-        if (this._targetDoc[WidthSym]() < this._targetDoc?.[HeightSym]()) {
-            return (Math.min(225, this._targetDoc[HeightSym]()) * this._targetDoc[WidthSym]()) / this._targetDoc[HeightSym]();
+        if (this._targetDoc[Width]() < this._targetDoc?.[Height]()) {
+            return (Math.min(225, this._targetDoc[Height]()) * this._targetDoc[Width]()) / this._targetDoc[Height]();
         }
-        return Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225));
+        return Math.min(225, NumCast(this._targetDoc?.[Width](), 225));
     };
     height = () => {
         if (!this._targetDoc) return 225;
-        if (this._targetDoc[WidthSym]() > this._targetDoc?.[HeightSym]()) {
-            return (Math.min(225, this._targetDoc[WidthSym]()) * this._targetDoc[HeightSym]()) / this._targetDoc[WidthSym]();
+        if (this._targetDoc[Width]() > this._targetDoc?.[Height]()) {
+            return (Math.min(225, this._targetDoc[Width]()) * this._targetDoc[Height]()) / this._targetDoc[Width]();
         }
-        return Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225));
+        return Math.min(225, NumCast(this._targetDoc?.[Height](), 225));
     };
     @computed get previewHeader() {
         return !this._linkDoc || !this._markerTargetDoc || !this._targetDoc || !this._linkSrc ? null : (
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 9354f9639..18fcc951a 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -3,7 +3,8 @@ import { Autocomplete, GoogleMap, GoogleMapProps, Marker } from '@react-google-m
 import { action, computed, IReactionDisposer, observable, ObservableMap, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { Doc, DocListCast, Opt, WidthSym } from '../../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
+import { Width } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
 import { NumCast, StrCast } from '../../../../fields/Types';
@@ -367,7 +368,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         .ScreenToLocalTransform()
                         .scale(this.props.NativeDimScaling?.() || 1)
                         .transformDirection(delta[0], delta[1]);
-                    const fullWidth = this.layoutDoc[WidthSym]();
+                    const fullWidth = this.layoutDoc[Width]();
                     const mapWidth = fullWidth - this.sidebarWidth();
                     if (this.sidebarWidth() + localDelta[0] > 0) {
                         this._showSidebar = true;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 95fbb274d..6ee1b67f2 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -3,7 +3,8 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
 import { observer } from 'mobx-react';
 import * as Pdfjs from 'pdfjs-dist';
 import 'pdfjs-dist/web/pdf_viewer.css';
-import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { ComputedField } from '../../../fields/ScriptField';
@@ -63,7 +64,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         super(props);
         const nw = Doc.NativeWidth(this.Document, this.dataDoc) || 927;
         const nh = Doc.NativeHeight(this.Document, this.dataDoc) || 1200;
-        !this.Document._layout_fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
+        !this.Document._layout_fitWidth && (this.Document._height = this.Document[Width]() * (nh / nw));
         if (this.pdfUrl) {
             if (PDFBox.pdfcache.get(this.pdfUrl.url.href)) runInAction(() => (this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href)));
             else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action((pdf: any) => (this._pdf = pdf)));
@@ -104,15 +105,15 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
         const docViewContent = this.props.docViewPath().lastElement().ContentDiv!;
         const newDiv = docViewContent.cloneNode(true) as HTMLDivElement;
-        newDiv.style.width = this.layoutDoc[WidthSym]().toString();
-        newDiv.style.height = this.layoutDoc[HeightSym]().toString();
+        newDiv.style.width = this.layoutDoc[Width]().toString();
+        newDiv.style.height = this.layoutDoc[Height]().toString();
         this.replaceCanvases(docViewContent, newDiv);
         const htmlString = this._pdfViewer?._mainCont.current && new XMLSerializer().serializeToString(newDiv);
 
         const anchx = NumCast(cropping.x);
         const anchy = NumCast(cropping.y);
-        const anchw = cropping[WidthSym]() * (this.props.NativeDimScaling?.() || 1);
-        const anchh = cropping[HeightSym]() * (this.props.NativeDimScaling?.() || 1);
+        const anchw = cropping[Width]() * (this.props.NativeDimScaling?.() || 1);
+        const anchh = cropping[Height]() * (this.props.NativeDimScaling?.() || 1);
         const viewScale = 1;
         cropping.title = 'crop: ' + this.rootDoc.title;
         cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
@@ -169,8 +170,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             CollectionFreeFormView.UpdateIcon(
                 filename,
                 docViewContent,
-                this.layoutDoc[WidthSym](),
-                this.layoutDoc[HeightSym](),
+                this.layoutDoc[Width](),
+                this.layoutDoc[Height](),
                 this.props.PanelWidth(),
                 this.props.PanelHeight(),
                 NumCast(this.layoutDoc._layout_scrollTop),
@@ -260,8 +261,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.dataDoc[this.props.fieldKey + '_numPages'] = np;
         Doc.SetNativeWidth(this.dataDoc, Math.max(Doc.NativeWidth(this.dataDoc), (nw * 96) / 72));
         Doc.SetNativeHeight(this.dataDoc, (nh * 96) / 72);
-        this.layoutDoc._height = this.layoutDoc[WidthSym]() / (Doc.NativeAspect(this.dataDoc) || 1);
-        !this.Document._layout_fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
+        this.layoutDoc._height = this.layoutDoc[Width]() / (Doc.NativeAspect(this.dataDoc) || 1);
+        !this.Document._layout_fitWidth && (this.Document._height = this.Document[Width]() * (nh / nw));
     };
 
     public search = action((searchString: string, bwd?: boolean, clear: boolean = false) => {
@@ -336,7 +337,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.NativeDimScaling?.() || 1)) / nativeWidth;
                 if (ratio >= 1) {
                     this.layoutDoc.nativeWidth = nativeWidth * ratio;
-                    onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]);
+                    onButton && (this.layoutDoc._width = this.layoutDoc[Width]() + localDelta[0]);
                     this.layoutDoc._show_sidebar = nativeWidth !== this.layoutDoc._nativeWidth;
                 }
                 return false;
@@ -357,11 +358,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
         if (preview) {
             this._previewNativeWidth = nativeWidth * sideratio;
-            this._previewWidth = (this.layoutDoc[WidthSym]() * nativeWidth * sideratio) / curNativeWidth;
+            this._previewWidth = (this.layoutDoc[Width]() * nativeWidth * sideratio) / curNativeWidth;
             this._showSidebar = true;
         } else {
             this.layoutDoc.nativeWidth = nativeWidth * pdfratio;
-            this.layoutDoc._width = (this.layoutDoc[WidthSym]() * nativeWidth * pdfratio) / curNativeWidth;
+            this.layoutDoc._width = (this.layoutDoc[Width]() * nativeWidth * pdfratio) / curNativeWidth;
             this.layoutDoc._show_sidebar = nativeWidth !== this.layoutDoc._nativeWidth;
         }
     });
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index 80b12b96e..04f11a5df 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -11,6 +11,7 @@ import { DocumentType } from '../../../documents/DocumentTypes';
 import { Presentation } from '../../../util/TrackMovements';
 import { Doc } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
+import { DocCast } from '../../../../fields/Types';
 
 @observer
 export class RecordingBox extends ViewBoxBaseComponent() {
@@ -57,7 +58,7 @@ export class RecordingBox extends ViewBoxBaseComponent() {
     render() {
         return (
             <div className="recordingBox" ref={this._ref}>
-                {!this.result && <RecordingView setResult={this.setResult} setDuration={this.setVideoDuration} id={this.rootDoc.proto?.[Id] || ''} />}
+                {!this.result && <RecordingView setResult={this.setResult} setDuration={this.setVideoDuration} id={DocCast(this.rootDoc.proto)?.[Id] || ''} />}
             </div>
         );
     }
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 7bf765042..1e178b123 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -5,10 +5,11 @@ import { computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 // import { BufferAttribute, Camera, Vector2, Vector3 } from 'three';
 import { DateField } from '../../../fields/DateField';
-import { Doc, HeightSym, WidthSym } from '../../../fields/Doc';
+import { Doc } from '../../../fields/Doc';
+import { Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { ComputedField } from '../../../fields/ScriptField';
-import { Cast, NumCast } from '../../../fields/Types';
+import { Cast, DocCast, NumCast } from '../../../fields/Types';
 import { AudioField, VideoField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
 import { emptyFunction, returnFalse, returnOne, returnZero } from '../../../Utils';
@@ -24,6 +25,7 @@ import { FieldView, FieldViewProps } from './FieldView';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
 import './ScreenshotBox.scss';
 import { VideoBox } from './VideoBox';
+
 declare class MediaRecorder {
     constructor(e: any, options?: any); // whatever MediaRecorder has
 }
@@ -140,7 +142,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         if (!nativeWidth || !nativeHeight) {
             if (!nativeWidth) Doc.SetNativeWidth(this.dataDoc, 1200);
             Doc.SetNativeHeight(this.dataDoc, (nativeWidth || 1200) / aspect);
-            this.layoutDoc._height = (this.layoutDoc[WidthSym]() || 0) / aspect;
+            this.layoutDoc._height = (this.layoutDoc[Width]() || 0) / aspect;
         }
     };
 
@@ -277,7 +279,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         dictationTextProto.mediaState = ComputedField.MakeFunction('self.recordingSource.mediaState');
         this.dataDoc[this.fieldKey + '-dictation'] = dictationText;
     };
-    videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], this.layoutDoc[WidthSym]())) * this.props.PanelWidth();
+    videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], this.layoutDoc[Height]()) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], this.layoutDoc[Width]())) * this.props.PanelWidth();
     formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight());
     render() {
         TraceMobx();
@@ -315,7 +317,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                         {!(this.dataDoc[this.fieldKey + '-dictation'] instanceof Doc) ? null : (
                             <FormattedTextBox
                                 {...this.props}
-                                Document={this.dataDoc[this.fieldKey + '-dictation']}
+                                Document={DocCast(this.dataDoc[this.fieldKey + '-dictation'])}
                                 fieldKey={'text'}
                                 PanelHeight={this.formattedPanelHeight}
                                 select={emptyFunction}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 9cf929679..34dcde23b 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -3,7 +3,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { basename } from 'path';
-import { Doc, HeightSym, StrListCast, WidthSym } from '../../../fields/Doc';
+import { Doc, StrListCast } from '../../../fields/Doc';
+import { Height, Width } from '../../../fields/DocSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
@@ -14,6 +15,7 @@ import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { Networking } from '../../Network';
 import { DocumentManager } from '../../util/DocumentManager';
+import { FollowLinkScript } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
 import { ReplayMovements } from '../../util/ReplayMovements';
 import { SelectionManager } from '../../util/SelectionManager';
@@ -33,8 +35,6 @@ import { FieldView, FieldViewProps } from './FieldView';
 import { RecordingBox } from './RecordingBox';
 import { PinProps, PresBox } from './trails';
 import './VideoBox.scss';
-import { ScriptField } from '../../../fields/ScriptField';
-import { FollowLinkScript } from '../../util/LinkFollower';
 const path = require('path');
 
 /**
@@ -111,7 +111,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     // returns the presentation data if it exists, null otherwise
     @computed get presentation() {
         const data = this.dataDoc[this.fieldKey + '-presentation'];
-        return data ? JSON.parse(data) : null;
+        return data ? JSON.parse(StrCast(data)) : null;
     }
 
     @computed private get timeline() {
@@ -354,8 +354,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     updateIcon = () => {
         const makeIcon = (returnedfilename: string) => {
             this.dataDoc.icon = new ImageField(returnedfilename);
-            this.dataDoc.icon_nativeWidth = this.layoutDoc[WidthSym]();
-            this.dataDoc.icon_nativeHeight = this.layoutDoc[HeightSym]();
+            this.dataDoc.icon_nativeWidth = this.layoutDoc[Width]();
+            this.dataDoc.icon_nativeHeight = this.layoutDoc[Height]();
         };
         this.Snapshot(undefined, undefined, makeIcon);
     };
@@ -465,7 +465,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 { fireImmediately: true }
             );
 
-            (!this.dataDoc[this.fieldKey + '_thumbnails'] || this.dataDoc[this.fieldKey + '_thumbnails'].length != VideoBox.numThumbnails) && this.getVideoThumbnails();
+            (!this.dataDoc[this.fieldKey + '_thumbnails'] || StrListCast(this.dataDoc[this.fieldKey + '_thumbnails']).length != VideoBox.numThumbnails) && this.getVideoThumbnails();
         }
     };
 
@@ -870,7 +870,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 }),
                 returnFalse,
                 () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations),
-                false, false
+                false,
+                false
             );
         }
     };
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index a898398a1..48f77469f 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -2,16 +2,18 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as WebRequest from 'web-request';
-import { Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc';
+import { Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { HtmlField } from '../../../fields/HtmlField';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
+import { RefField } from '../../../fields/RefField';
 import { listSpec } from '../../../fields/Schema';
 import { Cast, ImageCast, NumCast, StrCast, WebCast } from '../../../fields/Types';
 import { ImageField, WebField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, getWordAtPoint, removeStyleSheetRule, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, getWordAtPoint, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from '../../util/DragManager';
@@ -37,7 +39,6 @@ import { LinkDocPreview } from './LinkDocPreview';
 import { PinProps, PresBox } from './trails';
 import './WebBox.scss';
 import React = require('react');
-import { RefField } from '../../../fields/RefField';
 const { CreateImage } = require('./WebBoxRenderer');
 const _global = (window /* browser */ || global) /* node */ as any;
 const htmlToText = require('html-to-text');
@@ -84,7 +85,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return this._url ? WebBox.urlHash(this._url) + '' : '';
     }
     @computed get scrollHeight() {
-        return Math.max(this.layoutDoc[HeightSym](), this._scrollHeight);
+        return Math.max(this.layoutDoc[Height](), this._scrollHeight);
     }
     @computed get allAnnotations() {
         return DocListCast(this.dataDoc[this.annotationKey]);
@@ -214,7 +215,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 if (!nativeWidth || !nativeHeight || Math.abs(nativeWidth / nativeHeight - youtubeaspect) > 0.05) {
                     if (!nativeWidth) Doc.SetNativeWidth(this.layoutDoc, 600);
                     Doc.SetNativeHeight(this.layoutDoc, (nativeWidth || 600) / youtubeaspect);
-                    this.layoutDoc._height = this.layoutDoc[WidthSym]() / youtubeaspect;
+                    this.layoutDoc._height = this.layoutDoc[Width]() / youtubeaspect;
                 }
             } // else it's an HTMLfield
         } else if (this.webField && !this.dataDoc.text) {
@@ -281,7 +282,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     focus = (anchor: Doc, options: DocFocusOptions) => {
         if (anchor !== this.rootDoc && this._outerRef.current) {
             const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-            const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), anchor[HeightSym](), NumCast(this.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + anchor[HeightSym](), this._scrollHeight));
+            const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), anchor[Height](), NumCast(this.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + anchor[Height](), this._scrollHeight));
             if (scrollTo !== undefined) {
                 if (this._initialScroll === undefined) {
                     const focusTime = options.zoomTime ?? 500;
@@ -460,7 +461,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 this._scrollHeight = Math.max(this._scrollHeight, (iframeContent.body.children[0] as any)?.scrollHeight || 0);
                 if (this._scrollHeight) {
                     this.rootDoc.nativeHeight = Math.min(NumCast(this.rootDoc.nativeHeight), this._scrollHeight);
-                    this.layoutDoc.height = Math.min(this.layoutDoc[HeightSym](), (this.layoutDoc[WidthSym]() * NumCast(this.rootDoc.nativeHeight)) / NumCast(this.rootDoc.nativeWidth));
+                    this.layoutDoc.height = Math.min(this.layoutDoc[Height](), (this.layoutDoc[Width]() * NumCast(this.rootDoc.nativeHeight)) / NumCast(this.rootDoc.nativeWidth));
                 }
             };
             initHeights();
@@ -784,7 +785,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 if (ratio >= 1) {
                     this.layoutDoc.nativeWidth = nativeWidth * ratio;
                     this.layoutDoc.nativeHeight = nativeHeight * (1 + ratio);
-                    onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]);
+                    onButton && (this.layoutDoc._width = this.layoutDoc[Width]() + localDelta[0]);
                     this.layoutDoc._layout_showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
                 }
                 return false;
@@ -820,9 +821,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     toggleSidebar = action((preview: boolean = false) => {
         var nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
         if (!nativeWidth) {
-            const defaultNativeWidth = this.rootDoc[this.fieldKey] instanceof WebField ? 850 : this.Document[WidthSym]();
+            const defaultNativeWidth = this.rootDoc[this.fieldKey] instanceof WebField ? 850 : this.Document[Width]();
             Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || defaultNativeWidth);
-            Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || (this.Document[HeightSym]() / this.Document[WidthSym]()) * defaultNativeWidth);
+            Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || (this.Document[Height]() / this.Document[Width]()) * defaultNativeWidth);
             nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
         }
         const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth;
@@ -830,11 +831,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
         if (preview) {
             this._previewNativeWidth = nativeWidth * sideratio;
-            this._previewWidth = (this.layoutDoc[WidthSym]() * nativeWidth * sideratio) / curNativeWidth;
+            this._previewWidth = (this.layoutDoc[Width]() * nativeWidth * sideratio) / curNativeWidth;
             this._showSidebar = true;
         } else {
             this.layoutDoc._layout_showSidebar = !this.layoutDoc._layout_showSidebar;
-            this.layoutDoc._width = (this.layoutDoc[WidthSym]() * nativeWidth * pdfratio) / curNativeWidth;
+            this.layoutDoc._width = (this.layoutDoc[Width]() * nativeWidth * pdfratio) / curNativeWidth;
             if (!this.layoutDoc._layout_showSidebar && !(this.dataDoc[this.fieldKey] instanceof WebField)) {
                 this.layoutDoc.nativeWidth = this.dataDoc[this.fieldKey + '_nativeWidth'] = undefined;
             } else {
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index fb29f95f4..7f08de246 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -5,7 +5,8 @@ import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { ColorState, SketchPicker } from 'react-color';
-import { Doc, HeightSym, StrListCast, WidthSym } from '../../../../fields/Doc';
+import { Doc, StrListCast } from '../../../../fields/Doc';
+import { Height, Width } from '../../../../fields/DocSymbols';
 import { InkTool } from '../../../../fields/InkField';
 import { ScriptField } from '../../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
@@ -757,8 +758,8 @@ export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) {
                 action(d => {
                     const x = NumCast(d.x);
                     const y = NumCast(d.y);
-                    const width = d[WidthSym]();
-                    const height = d[HeightSym]();
+                    const width = d[Width]();
+                    const height = d[Height]();
                     bounds.push({ x, y, width, height });
                 })
             );
@@ -795,8 +796,8 @@ export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) {
             // TODO: nda - this is the code to actually get a new grouped collection
             const newCollection = marqViewRef?.getCollection(selected, undefined, true);
             if (newCollection) {
-                newCollection.height = newCollection[HeightSym]();
-                newCollection.width = newCollection[WidthSym]();
+                newCollection.height = newCollection[Height]();
+                newCollection.width = newCollection[Width]();
             }
 
             // nda - bug: when deleting a stroke before leaving writing mode, delete the stroke from unprocessed ink docs
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index c929b7ff3..1d41eb379 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -2,8 +2,9 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { NodeSelection } from 'prosemirror-state';
 import * as ReactDOM from 'react-dom/client';
-import { Doc, HeightSym, WidthSym } from '../../../../fields/Doc';
-import { Cast, NumCast, StrCast } from '../../../../fields/Types';
+import { Doc } from '../../../../fields/Doc';
+import { Height, Width } from '../../../../fields/DocSymbols';
+import { NumCast, StrCast } from '../../../../fields/Types';
 import { emptyFunction, returnFalse, Utils } from '../../../../Utils';
 import { DocServer } from '../../../DocServer';
 import { Docs, DocUtils } from '../../../documents/Documents';
@@ -210,8 +211,8 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     addDocTab={this._textBox.props.addDocTab}
                     pinToPres={returnFalse}
                     renderDepth={this._textBox.props.renderDepth + 1}
-                    PanelWidth={this._finalLayout[WidthSym]}
-                    PanelHeight={this._finalLayout[HeightSym]}
+                    PanelWidth={this._finalLayout[Width]}
+                    PanelHeight={this._finalLayout[Height]}
                     focus={this.outerFocus}
                     whenChildContentsActiveChanged={returnFalse}
                     bringToFront={emptyFunction}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index fb0c0d2ab..bea789a5c 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -12,9 +12,11 @@ import { Fragment, Mark, Node, Slice } from 'prosemirror-model';
 import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state';
 import { EditorView } from 'prosemirror-view';
 import { DateField } from '../../../../fields/DateField';
-import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, CssSym, Doc, DocListCast, Field, ForceServerWrite, HeightSym, Opt, StrListCast, UpdatingFromServer, WidthSym } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
+import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, Height, UpdatingFromServer, Width } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
+import { List } from '../../../../fields/List';
 import { PrefetchProxy } from '../../../../fields/Proxy';
 import { RichTextField } from '../../../../fields/RichTextField';
 import { RichTextUtils } from '../../../../fields/RichTextUtils';
@@ -34,6 +36,7 @@ import { DragManager } from '../../../util/DragManager';
 import { MakeTemplate } from '../../../util/DropConverter';
 import { IsFollowLinkScript } from '../../../util/LinkFollower';
 import { LinkManager } from '../../../util/LinkManager';
+import { RTFMarkup } from '../../../util/RTFMarkup';
 import { SelectionManager } from '../../../util/SelectionManager';
 import { SnappingManager } from '../../../util/SnappingManager';
 import { undoBatch, UndoManager } from '../../../util/UndoManager';
@@ -68,8 +71,6 @@ import { schema } from './schema_rts';
 import { SummaryView } from './SummaryView';
 import applyDevTools = require('prosemirror-dev-tools');
 import React = require('react');
-import { RTFMarkup } from '../../../util/RTFMarkup';
-import { List } from '../../../../fields/List';
 const translateGoogleApi = require('translate-google-api');
 export const GoogleRef = 'googleDocId';
 type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;
@@ -544,8 +545,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             } else if (de.embedKey) {
                 const target = dragData.droppedDocuments[0];
                 const node = schema.nodes.dashDoc.create({
-                    width: target[WidthSym](),
-                    height: target[HeightSym](),
+                    width: target[Width](),
+                    height: target[Height](),
                     title: 'dashDoc',
                     docId: target[Id],
                     float: 'unset',
@@ -646,7 +647,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             const hr = Math.round(Date.now() / 1000 / 60 / 60);
             numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-hr-' + (hr - i), { opacity: ((10 - i - 1) / 10).toString() }));
         }
-        this.layoutDoc[CssSym] = this.layoutDoc[CssSym] + 1; // css changes happen outside of react/mobx.  so we need to set a flag that will notify anyone intereted in layout changes triggered by css changes (eg., CollectionLinkView)
+        this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css changes happen outside of react/mobx.  so we need to set a flag that will notify anyone intereted in layout changes triggered by css changes (eg., CollectionLinkView)
     };
 
     @observable _showSidebar = false;
@@ -682,7 +683,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             .scale(this.props.NativeDimScaling?.() || 1)
             .transformDirection(delta[0], delta[1]);
         const sidebarWidth = (NumCast(this.layoutDoc._width) * Number(this.layout_sidebarWidthPercent.replace('%', ''))) / 100;
-        const width = this.layoutDoc[WidthSym]() + localDelta[0];
+        const width = this.layoutDoc[Width]() + localDelta[0];
         this.layoutDoc._layout_sidebarWidthPercent = Math.max(0, (sidebarWidth + localDelta[0]) / width) * 100 + '%';
         this.layoutDoc.width = width;
         this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%';
@@ -1163,7 +1164,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             () => {
                 const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc?.proto), this.fieldKey) ? DocCast(this.layoutDoc?.proto) : this?.dataDoc;
                 const whichDoc = !this.dataDoc || !this.layoutDoc ? undefined : dataDoc?.[this.fieldKey + '_noTemplate'] || !this.layoutDoc[this.fieldKey] ? dataDoc : this.layoutDoc;
-                return !whichDoc ? undefined : { data: Cast(whichDoc[this.fieldKey], RichTextField, null), str: Field.toString(whichDoc[this.fieldKey]) };
+                return !whichDoc ? undefined : { data: Cast(whichDoc[this.fieldKey], RichTextField, null), str: Field.toString(DocCast(whichDoc[this.fieldKey])) };
             },
             incomingValue => {
                 if (this._editorView && this._applyingChange !== this.fieldKey) {
@@ -1208,7 +1209,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             () => this.props.isSelected(),
             action(selected => {
                 if (FormattedTextBox._globalHighlights.has('Bold Text')) {
-                    this.layoutDoc[CssSym] = this.layoutDoc[CssSym] + 1; // css change happens outside of mobx/react, so this will notify anyone interested in the layout that it has changed
+                    this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css change happens outside of mobx/react, so this will notify anyone interested in the layout that it has changed
                 }
                 if (RichTextMenu.Instance?.view === this._editorView && !selected) {
                     RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined);
@@ -2000,14 +2001,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         return this.props.fieldKey + (usePath && (!usePath.includes(':hover') || this._isHovering) ? `_${usePath.replace(':hover', '')}` : '');
     }
     @observable _isHovering = false;
-    onPassiveWheel = (e:WheelEvent) => { 
+    onPassiveWheel = (e: WheelEvent) => {
         // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
         if (this.props.isContentActive() && !this.props.allowScroll) {
             if (!NumCast(this.layoutDoc._layout_scrollTop) && e.deltaY <= 0) e.preventDefault();
             e.stopPropagation();
         }
-    }
-    _oldWheel:any;
+    };
+    _oldWheel: any;
     render() {
         TraceMobx();
         const active = this.props.isContentActive() || this.props.isSelected();
@@ -2029,8 +2030,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 onPointerLeave={action(() => (this._isHovering = false))}
                 ref={r => {
                     this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-                    this._oldWheel= r;
-                    r?.addEventListener('wheel', this.onPassiveWheel,  { passive: false } );
+                    this._oldWheel = r;
+                    r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
                 }}
                 style={{
                     ...(this.props.dontScale
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index f197a8a8d..154c879a0 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -2,12 +2,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
+import { Height, Width } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils';
-import { Docs, DocUtils } from '../../../documents/Documents';
+import { Docs } from '../../../documents/Documents';
 import { CollectionViewType } from '../../../documents/DocumentTypes';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
@@ -322,7 +323,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     };
 
     removeAllRecordingInOverlay = () => {
-        DocListCast(Doc.MyOverlayDocs.data).filter(doc => doc.slides === this.rootDoc).forEach(Doc.RemFromMyOverlay);
+        DocListCast(Doc.MyOverlayDocs.data)
+            .filter(doc => doc.slides === this.rootDoc)
+            .forEach(Doc.RemFromMyOverlay);
     };
 
     static removeEveryExistingRecordingInOverlay = () => {
@@ -386,8 +389,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
             activeItem.recording = recording;
 
             // make recording box appear in the bottom right corner of the screen
-            recording.overlayX = window.innerWidth - recording[WidthSym]() - 20;
-            recording.overlayY = window.innerHeight - recording[HeightSym]() - 20;
+            recording.overlayX = window.innerWidth - recording[Width]() - 20;
+            recording.overlayY = window.innerHeight - recording[Height]() - 20;
             Doc.AddToMyOverlay(recording);
         }
     };
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 999e3eeb6..bc0cad636 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -2,7 +2,8 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio
 import { observer } from 'mobx-react';
 import * as Pdfjs from 'pdfjs-dist';
 import 'pdfjs-dist/web/pdf_viewer.css';
-import { Doc, DocListCast, Field, HeightSym, Opt } from '../../../fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc';
+import { Height } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
@@ -181,7 +182,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         let focusSpeed: Opt<number>;
         if (doc !== this.props.rootDoc && mainCont) {
             const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-            const scrollTo = Utils.scrollIntoView(scrollTop, doc[HeightSym](), NumCast(this.props.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, this._scrollHeight);
+            const scrollTo = Utils.scrollIntoView(scrollTop, doc[Height](), NumCast(this.props.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, this._scrollHeight);
             if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._layout_scrollTop) {
                 if (!this._pdfViewer) this._initialScroll = { loc: scrollTo, easeFunc: options.easeFunc };
                 else if (!options.instant) this._scrollStopper = smoothScroll((focusSpeed = options.zoomTime ?? 500), mainCont, scrollTo, options.easeFunc, this._scrollStopper);
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index d0e5d03b3..72eeedcff 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -11,9 +11,38 @@ import { SelectionManager } from '../client/util/SelectionManager';
 import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from '../client/util/SerializationHelper';
 import { undoable, UndoManager } from '../client/util/UndoManager';
 import { decycle } from '../decycler/decycler';
+import * as JSZipUtils from '../JSZipUtils';
 import { DashColor, incrementTitleCopy, intersectRect, Utils } from '../Utils';
 import { DateField } from './DateField';
-import { Copy, HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from './FieldSymbols';
+import {
+    AclAdmin,
+    AclAugment,
+    AclEdit,
+    AclPrivate,
+    AclReadonly,
+    AclSelfEdit,
+    AclUnset,
+    Animation,
+    CachedUpdates,
+    DirectLinks,
+    DocAcl,
+    DocCss,
+    DocData,
+    DocFields,
+    DocLayout,
+    FieldKeys,
+    FieldTuples,
+    ForceServerWrite,
+    Height,
+    Highlight,
+    Initializing,
+    Self,
+    SelfProxy,
+    Update,
+    UpdatingFromServer,
+    Width,
+} from './DocSymbols';
+import { Copy, HandleUpdate, Id, OnUpdate, Parent, ToScriptString, ToString } from './FieldSymbols';
 import { InkField, InkTool } from './InkField';
 import { List, ListFieldName } from './List';
 import { ObjectField } from './ObjectField';
@@ -26,7 +55,6 @@ import { Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Ty
 import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField';
 import { deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from './util';
 import JSZip = require('jszip');
-import * as JSZipUtils from '../JSZipUtils';
 export namespace Field {
     export function toKeyValueString(doc: Doc, key: string): string {
         const onDelegate = Object.keys(doc).includes(key.replace(/^_/, ''));
@@ -93,28 +121,6 @@ export function DocListCast(field: FieldResult, defaultVal: Doc[] = []) {
     return Cast(field, listSpec(Doc), defaultVal).filter(d => d instanceof Doc) as Doc[];
 }
 
-export const WidthSym = Symbol('Width');
-export const HeightSym = Symbol('Height');
-export const AnimationSym = Symbol('Animation');
-export const HighlightSym = Symbol('Highlight');
-export const DataSym = Symbol('Data');
-export const LayoutSym = Symbol('Layout');
-export const FieldsSym = Symbol('Fields');
-export const CssSym = Symbol('Css');
-export const AclSym = Symbol('Acl');
-export const DirectLinksSym = Symbol('DirectLinks');
-export const AclUnset = Symbol('AclUnset');
-export const AclPrivate = Symbol('AclOwnerOnly');
-export const AclReadonly = Symbol('AclReadOnly');
-export const AclAugment = Symbol('AclAugment');
-export const AclSelfEdit = Symbol('AclSelfEdit');
-export const AclEdit = Symbol('AclEdit');
-export const AclAdmin = Symbol('AclAdmin');
-export const UpdatingFromServer = Symbol('UpdatingFromServer');
-export const Initializing = Symbol('Initializing');
-export const ForceServerWrite = Symbol('ForceServerWrite');
-export const CachedUpdates = Symbol('Cached updates');
-
 export enum aclLevel {
     unset = -1,
     unshared = 0,
@@ -141,15 +147,15 @@ export const ReverseHierarchyMap: Map<string, { level: aclLevel; acl: symbol }>
 export function updateCachedAcls(doc: Doc) {
     if (!doc) return;
 
-    const target = (doc as any)?.__fields ?? doc;
+    const target = (doc as any)?.__fieldTuples ?? doc;
     const permissions: { [key: string]: symbol } = !target.author || target.author === Doc.CurrentUserEmail ? { 'acl-Me': AclAdmin } : {};
     Object.keys(target).filter(key => key.startsWith('acl') && (permissions[key] = ReverseHierarchyMap.get(StrCast(target[key]))!.acl));
-    if (Object.keys(permissions).length || doc[AclSym]?.length) {
-        runInAction(() => (doc[AclSym] = permissions));
+    if (Object.keys(permissions).length || doc[DocAcl]?.length) {
+        runInAction(() => (doc[DocAcl] = permissions));
     }
 
     if (doc.proto instanceof Promise) {
-        doc.proto.then(updateCachedAcls);
+        doc.proto.then(proto => updateCachedAcls(DocCast(proto)));
         return doc.proto;
     }
 }
@@ -295,25 +301,20 @@ export class Doc extends RefField {
             set: setter,
             get: getter,
             // getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter
-            has: (target, key) => GetEffectiveAcl(target) !== AclPrivate && key in target.__fields,
+            has: (target, key) => GetEffectiveAcl(target) !== AclPrivate && key in target.__fieldTuples,
             ownKeys: target => {
-                const obj = {} as any;
-                if (GetEffectiveAcl(target) !== AclPrivate) Object.assign(obj, target.___fieldKeys);
-                runInAction(() => (obj.__LAYOUT__ = target.__LAYOUT__));
-                return Object.keys(obj);
+                const keys = GetEffectiveAcl(target) !== AclPrivate ? Object.keys(target[FieldKeys]) : [];
+                return [...keys, '__LAYOUT__'];
             },
             getOwnPropertyDescriptor: (target, prop) => {
-                if (prop.toString() === '__LAYOUT__') {
+                if (prop.toString() === '__LAYOUT__' || !(prop in target[FieldKeys])) {
                     return Reflect.getOwnPropertyDescriptor(target, prop);
                 }
-                if (prop in target.__fieldKeys) {
-                    return {
-                        configurable: true, //TODO Should configurable be true?
-                        enumerable: true,
-                        value: 0, //() => target.__fields[prop])
-                    };
-                }
-                return Reflect.getOwnPropertyDescriptor(target, prop);
+                return {
+                    configurable: true, //TODO Should configurable be true?
+                    enumerable: true,
+                    value: 0, //() => target.__fieldTuples[prop])
+                };
             },
             deleteProperty: deleteProperty,
             defineProperty: () => {
@@ -327,41 +328,35 @@ export class Doc extends RefField {
         return docProxy;
     }
 
-    proto: Opt<Doc>;
     [key: string]: FieldResult;
 
     @serializable(alias('fields', map(autoObject(), { afterDeserialize: afterDocDeserialize })))
-    private get __fields() {
-        return this.___fields;
+    private get __fieldTuples() {
+        return this[FieldTuples];
     }
-    private set __fields(value) {
-        this.___fields = value;
+    private set __fieldTuples(value) {
+        // called by deserializer to set all fields in one shot
+        this[FieldTuples] = value;
         for (const key in value) {
             const field = value[key];
-            field !== undefined && (this.__fieldKeys[key] = true);
+            field !== undefined && (this[FieldKeys][key] = true);
             if (!(field instanceof ObjectField)) continue;
             field[Parent] = this[Self];
             field[OnUpdate] = updateFunction(this[Self], key, field, this[SelfProxy]);
         }
     }
-    private get __fieldKeys() {
-        return this.___fieldKeys;
-    }
-    private set __fieldKeys(value) {
-        this.___fieldKeys = value;
-    }
 
-    @observable private ___fields: any = {};
-    @observable private ___fieldKeys: any = {};
+    @observable private [FieldTuples]: any = {};
+    @observable private [FieldKeys]: any = {};
     /// all of the raw acl's that have been set on this document.  Use GetEffectiveAcl to determine the actual ACL of the doc for editing
-    @observable public [AclSym]: { [key: string]: symbol } = {};
-    @observable public [CssSym]: number = 0; // incrementer denoting a change to CSS layout
-    @observable public [DirectLinksSym]: Set<Doc> = new Set();
-    @observable public [AnimationSym]: Opt<Doc>;
-    @observable public [HighlightSym]: boolean = false;
+    @observable public [DocAcl]: { [key: string]: symbol } = {};
+    @observable public [DocCss]: number = 0; // incrementer denoting a change to CSS layout
+    @observable public [DirectLinks]: Set<Doc> = new Set();
+    @observable public [Animation]: Opt<Doc>;
+    @observable public [Highlight]: boolean = false;
     static __Anim(Doc: Doc) {
         // for debugging to print AnimationSym field easily.
-        return Doc[AnimationSym];
+        return Doc[Animation];
     }
 
     private [UpdatingFromServer]: boolean = false;
@@ -374,15 +369,15 @@ export class Doc extends RefField {
 
     private [Self] = this;
     private [SelfProxy]: any;
-    public [FieldsSym] = () => this[Self].___fields; // Object.keys(this).reduce((fields, key) => { fields[key] = this[key]; return fields; }, {} as any);
-    public [WidthSym] = () => NumCast(this[SelfProxy]._width);
-    public [HeightSym] = () => NumCast(this[SelfProxy]._height);
+    public [DocFields] = () => this[Self][FieldTuples]; // Object.keys(this).reduce((fields, key) => { fields[key] = this[key]; return fields; }, {} as any);
+    public [Width] = () => NumCast(this[SelfProxy]._width);
+    public [Height] = () => NumCast(this[SelfProxy]._height);
     public [ToScriptString] = () => `idToDoc("${this[Self][Id]}")`;
     public [ToString] = () => `Doc(${GetEffectiveAcl(this[SelfProxy]) === AclPrivate ? '-inaccessible-' : this[SelfProxy].title})`;
-    public get [LayoutSym]() {
+    public get [DocLayout]() {
         return this[SelfProxy].__LAYOUT__;
     }
-    public get [DataSym](): Doc {
+    public get [DocData](): Doc {
         const self = this[SelfProxy];
         return self.resolvedDataDoc && !self.isTemplateForField ? self : Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self);
     }
@@ -535,17 +530,17 @@ export namespace Doc {
         if (key.startsWith('_')) key = key.substring(1);
         const hasProto = Doc.GetProto(doc) !== doc ? Doc.GetProto(doc) : undefined;
         const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1;
-        const onProto = hasProto && Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1;
+        const onProto = hasProto && Object.getOwnPropertyNames(hasProto).indexOf(key) !== -1;
         if (onDeleg || !hasProto || (!onProto && !defaultProto)) {
             doc[key] = value;
-        } else doc.proto![key] = value;
+        } else hasProto[key] = value;
     }
     export function GetAllPrototypes(doc: Doc): Doc[] {
         const protos: Doc[] = [];
         let d: Opt<Doc> = doc;
         while (d) {
             protos.push(d);
-            d = FieldValue(d.proto);
+            d = DocCast(FieldValue(d.proto));
         }
         return protos;
     }
@@ -585,7 +580,7 @@ export namespace Doc {
     // return the doc's proto, but rather recursively searches through the proto inheritance chain
     // and returns the document who's proto is undefined or whose proto is marked as a data doc ('isDataDoc').
     export function GetProto(doc: Doc): Doc {
-        const proto = doc && (Doc.GetT(doc, 'isDataDoc', 'boolean', true) ? doc : doc.proto || doc);
+        const proto = doc && (Doc.GetT(doc, 'isDataDoc', 'boolean', true) ? doc : DocCast(doc.proto, doc));
         return proto === doc ? proto : Doc.GetProto(proto);
     }
     export function GetDataDoc(doc: Doc): Doc {
@@ -599,7 +594,7 @@ export namespace Doc {
         let proto: Doc | undefined = doc;
         while (proto) {
             Object.keys(proto).forEach(key => results.add(key));
-            proto = proto.proto;
+            proto = DocCast(FieldValue(proto.proto));
         }
 
         return Array.from(results);
@@ -676,7 +671,7 @@ export namespace Doc {
         const bounds = docList.reduce(
             (bounds, doc) => {
                 const [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
-                const [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
+                const [bptX, bptY] = [sptX + doc[Width](), sptY + doc[Height]()];
                 return {
                     x: Math.min(sptX, bounds.x),
                     y: Math.min(sptY, bounds.y),
@@ -700,7 +695,7 @@ export namespace Doc {
         embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`);
         embedding.author = Doc.CurrentUserEmail;
 
-        Doc.AddDocToList(Doc.GetProto(doc)[DataSym], 'proto_embeddings', embedding);
+        Doc.AddDocToList(Doc.GetProto(doc)[DocData], 'proto_embeddings', embedding);
 
         return embedding;
     }
@@ -772,7 +767,7 @@ export namespace Doc {
                 }
             })
         );
-        Array.from(doc[DirectLinksSym]).forEach(async link => {
+        Array.from(doc[DirectLinks]).forEach(async link => {
             if (
                 cloneLinks ||
                 ((cloneMap.has(DocCast(link.link_anchor_1)?.[Id]) || cloneMap.has(DocCast(DocCast(link.link_anchor_1)?.annotationOn)?.[Id])) &&
@@ -930,7 +925,7 @@ export namespace Doc {
             if (templateLayoutDoc.resolvedDataDoc === (targetDoc.rootDocument || Doc.GetProto(targetDoc))) {
                 expandedTemplateLayout = templateLayoutDoc; // reuse an existing template layout if its for the same document with the same params
             } else {
-                templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = Cast(templateLayoutDoc.proto, Doc, null) || templateLayoutDoc); // if the template has already been applied (ie, a nested template), then use the template's prototype
+                templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = DocCast(templateLayoutDoc.proto, templateLayoutDoc)); // if the template has already been applied (ie, a nested template), then use the template's prototype
                 if (!targetDoc[expandedLayoutFieldKey]) {
                     _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey, true);
                     setTimeout(
@@ -969,7 +964,7 @@ export namespace Doc {
             const field = ProxyField.WithoutProxy(() => doc[key]);
             if (key === 'proto' && copyProto) {
                 if (doc.proto instanceof Doc && overwrite.proto instanceof Doc) {
-                    overwrite[key] = Doc.Overwrite(doc[key]!, overwrite.proto);
+                    overwrite[key] = Doc.Overwrite(doc.proto, overwrite.proto);
                 }
             } else {
                 if (field instanceof RefField) {
@@ -991,38 +986,37 @@ export namespace Doc {
         const copy = new Doc(copyProtoId, true);
         updateCachedAcls(copy);
         const exclude = [...StrListCast(doc.cloneFieldFilter), 'dragFactory_count', 'cloneFieldFilter'];
-        Object.keys(doc).forEach(key => {
-            if (exclude.includes(key)) return;
-            const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
-            const field = key === 'author' ? Doc.CurrentUserEmail : ProxyField.WithoutProxy(() => doc[key]);
-            if (key === 'proto' && copyProto) {
-                if (doc[key] instanceof Doc) {
-                    copy[key] = Doc.MakeCopy(doc[key]!, false);
-                }
-            } else {
-                if (field instanceof RefField) {
-                    copy[key] = field;
-                } else if (cfield instanceof ComputedField) {
-                    copy[key] = cfield[Copy](); // ComputedField.MakeFunction(cfield.script.originalScript);
-                } else if (field instanceof ObjectField) {
-                    copy[key] =
-                        doc[key] instanceof Doc
-                            ? key.includes('layout[')
-                                ? undefined
-                                : doc[key] // reference documents except remove documents that are expanded teplate fields
-                            : ObjectField.MakeCopy(field);
-                } else if (field instanceof Promise) {
-                    debugger; //This shouldn't happend...
+        Object.keys(doc)
+            .filter(key => !exclude.includes(key))
+            .forEach(key => {
+                if (key === 'proto' && copyProto) {
+                    if (doc.proto instanceof Doc) {
+                        copy[key] = Doc.MakeCopy(doc.proto, false);
+                    }
                 } else {
-                    copy[key] = field;
+                    const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
+                    const field = key === 'author' ? Doc.CurrentUserEmail : ProxyField.WithoutProxy(() => doc[key]);
+                    if (field instanceof RefField) {
+                        copy[key] = field;
+                    } else if (cfield instanceof ComputedField) {
+                        copy[key] = cfield[Copy](); // ComputedField.MakeFunction(cfield.script.originalScript);
+                    } else if (field instanceof ObjectField) {
+                        copy[key] =
+                            doc[key] instanceof Doc && key.includes('layout[')
+                                ? undefined // remove expanded template field documents
+                                : ObjectField.MakeCopy(field);
+                    } else if (field instanceof Promise) {
+                        debugger; //This shouldn't happend...
+                    } else {
+                        copy[key] = field;
+                    }
                 }
-            }
-        });
+            });
         if (copyProto) {
             Doc.GetProto(copy).embedContainer = undefined;
             Doc.GetProto(copy).proto_embeddings = new List<Doc>([copy]);
         } else {
-            Doc.AddDocToList(Doc.GetProto(copy)[DataSym], 'proto_embeddings', copy);
+            Doc.AddDocToList(Doc.GetProto(copy)[DocData], 'proto_embeddings', copy);
         }
         copy.embedContainer = undefined;
         Doc.defaultAclPrivate && (copy['acl-Public'] = 'Not Shared');
@@ -1045,7 +1039,7 @@ export namespace Doc {
             Object.keys(doc)
                 .filter(key => key.startsWith('acl'))
                 .forEach(key => (delegate[key] = doc[key]));
-            if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DataSym], 'proto_embeddings', delegate);
+            if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DocData], 'proto_embeddings', delegate);
             title && (delegate.title = title);
             delegate[Initializing] = false;
             Doc.AddFileOrphan(delegate);
@@ -1069,7 +1063,7 @@ export namespace Doc {
         delegate[Initializing] = true;
         delegate.proto = delegateProto;
         delegate.author = Doc.CurrentUserEmail;
-        Doc.AddDocToList(delegateProto[DataSym], 'proto_embeddings', delegate);
+        Doc.AddDocToList(delegateProto[DocData], 'proto_embeddings', delegate);
         delegate[Initializing] = false;
         delegateProto[Initializing] = false;
         return delegate;
@@ -1173,7 +1167,7 @@ export namespace Doc {
     }
     export const brushManager = new DocBrush();
 
-    export class DocData {
+    export class UserDocData {
         @observable _user_doc: Doc = undefined!;
         @observable _sharing_doc: Doc = undefined!;
         @observable _searchQuery: string = '';
@@ -1183,7 +1177,7 @@ export namespace Doc {
     // a layout field or 'layout' is given.
     export function Layout(doc: Doc, layout?: Doc): Doc {
         const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, 'data')}-layout[` + layout[Id] + ']'], Doc, null);
-        return overrideLayout || doc[LayoutSym] || doc;
+        return overrideLayout || doc[DocLayout] || doc;
     }
     export function SetLayout(doc: Doc, layout: Doc | string) {
         doc[StrCast(doc.layout_fieldKey, 'layout')] = layout;
@@ -1198,12 +1192,12 @@ export namespace Doc {
         return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1);
     }
     export function NativeWidth(doc?: Doc, dataDoc?: Doc, useWidth?: boolean) {
-        return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeWidth'], useWidth ? doc[WidthSym]() : 0));
+        return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeWidth'], useWidth ? doc[Width]() : 0));
     }
     export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) {
         if (!doc) return 0;
-        const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[HeightSym]()) / doc[WidthSym]();
-        const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? doc[HeightSym]() : 0);
+        const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[Height]()) / doc[Width]();
+        const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? doc[Height]() : 0);
         return NumCast(doc._nativeHeight, nheight || dheight);
     }
     export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) {
@@ -1213,7 +1207,7 @@ export namespace Doc {
         doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeHeight'] = height;
     }
 
-    const manager = new DocData();
+    const manager = new UserDocData();
     export function SearchQuery(): string {
         return manager._searchQuery;
     }
@@ -1348,16 +1342,16 @@ export namespace Doc {
     export var highlightedDocs = new ObservableSet<Doc>();
     export function IsHighlighted(doc: Doc) {
         if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return false;
-        return doc[HighlightSym] || Doc.GetProto(doc)[HighlightSym];
+        return doc[Highlight] || Doc.GetProto(doc)[Highlight];
     }
     export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presEffect?: Doc) {
         runInAction(() => {
             highlightedDocs.add(doc);
-            doc[HighlightSym] = true;
-            doc[AnimationSym] = presEffect;
+            doc[Highlight] = true;
+            doc[Animation] = presEffect;
             if (dataAndDisplayDocs) {
                 highlightedDocs.add(Doc.GetProto(doc));
-                Doc.GetProto(doc)[HighlightSym] = true;
+                Doc.GetProto(doc)[Highlight] = true;
             }
         });
     }
@@ -1367,8 +1361,8 @@ export namespace Doc {
             (doc ? [doc] : Array.from(highlightedDocs)).forEach(doc => {
                 highlightedDocs.delete(doc);
                 highlightedDocs.delete(Doc.GetProto(doc));
-                doc[HighlightSym] = Doc.GetProto(doc)[HighlightSym] = false;
-                doc[AnimationSym] = undefined;
+                doc[Highlight] = Doc.GetProto(doc)[Highlight] = false;
+                doc[Animation] = undefined;
             });
         });
     }
diff --git a/src/fields/DocSymbols.ts b/src/fields/DocSymbols.ts
new file mode 100644
index 000000000..65decc147
--- /dev/null
+++ b/src/fields/DocSymbols.ts
@@ -0,0 +1,26 @@
+export const Update = Symbol('DocUpdate');
+export const Self = Symbol('DocSelf');
+export const SelfProxy = Symbol('DocSelfProxy');
+export const FieldKeys = Symbol('DocFieldKeys');
+export const FieldTuples = Symbol('DocFieldTuples');
+export const Width = Symbol('DocWidth');
+export const Height = Symbol('DocHeight');
+export const Animation = Symbol('DocAnimation');
+export const Highlight = Symbol('DocHighlight');
+export const DocData = Symbol('DocData');
+export const DocLayout = Symbol('DocLayout');
+export const DocFields = Symbol('DocFields');
+export const DocCss = Symbol('DocCss');
+export const DocAcl = Symbol('DocAcl');
+export const DirectLinks = Symbol('DocDirectLinks');
+export const AclUnset = Symbol('DocAclUnset');
+export const AclPrivate = Symbol('DocAclOwnerOnly');
+export const AclReadonly = Symbol('DocAclReadOnly');
+export const AclAugment = Symbol('DocAclAugment');
+export const AclSelfEdit = Symbol('DocAclSelfEdit');
+export const AclEdit = Symbol('DocAclEdit');
+export const AclAdmin = Symbol('DocAclAdmin');
+export const UpdatingFromServer = Symbol('DocUpdatingFromServer');
+export const Initializing = Symbol('DocInitializing');
+export const ForceServerWrite = Symbol('DocForceServerWrite');
+export const CachedUpdates = Symbol('DocCachedUpdates');
diff --git a/src/fields/FieldSymbols.ts b/src/fields/FieldSymbols.ts
index e50c2856f..c381f14f5 100644
--- a/src/fields/FieldSymbols.ts
+++ b/src/fields/FieldSymbols.ts
@@ -1,12 +1,9 @@
-export const Update = Symbol('Update');
-export const Self = Symbol('Self');
-export const SelfProxy = Symbol('SelfProxy');
-export const HandleUpdate = Symbol('HandleUpdate');
-export const Id = Symbol('Id');
-export const OnUpdate = Symbol('OnUpdate');
-export const Parent = Symbol('Parent');
-export const Copy = Symbol('Copy');
-export const ToValue = Symbol('ToValue');
-export const ToScriptString = Symbol('ToScriptString');
-export const ToPlainText = Symbol('ToPlainText');
-export const ToString = Symbol('ToString');
+export const HandleUpdate = Symbol('FieldHandleUpdate');
+export const Id = Symbol('FieldId');
+export const OnUpdate = Symbol('FieldOnUpdate');
+export const Parent = Symbol('FieldParent');
+export const Copy = Symbol('FieldCopy');
+export const ToValue = Symbol('FieldToValue');
+export const ToScriptString = Symbol('FieldToScriptString');
+export const ToPlainText = Symbol('FieldToPlainText');
+export const ToString = Symbol('FieldToString');
diff --git a/src/fields/List.ts b/src/fields/List.ts
index dfd24cf7a..033fa569b 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -3,8 +3,9 @@ import { alias, list, serializable } from 'serializr';
 import { DocServer } from '../client/DocServer';
 import { ScriptingGlobals } from '../client/util/ScriptingGlobals';
 import { afterDocDeserialize, autoObject, Deserializable } from '../client/util/SerializationHelper';
+import { FieldTuples, Self, SelfProxy, Update } from './DocSymbols';
 import { Field } from './Doc';
-import { Copy, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from './FieldSymbols';
+import { Copy, OnUpdate, Parent, ToScriptString, ToString } from './FieldSymbols';
 import { ObjectField } from './ObjectField';
 import { ProxyField } from './Proxy';
 import { RefField } from './RefField';
@@ -21,12 +22,12 @@ const listHandlers: any = {
         if (value instanceof RefField) {
             throw new Error('fill with RefFields not supported yet');
         }
-        const res = this[Self].__fields.fill(value, start, end);
+        const res = this[Self].__fieldTuples.fill(value, start, end);
         this[Update]();
         return res;
     },
     pop(): any {
-        const field = toRealField(this[Self].__fields.pop());
+        const field = toRealField(this[Self].__fieldTuples.pop());
         this[Update]();
         return field;
     },
@@ -34,7 +35,7 @@ const listHandlers: any = {
         items = items.map(toObjectField);
 
         const list = this[Self];
-        const length = list.__fields.length;
+        const length = list.__fieldTuples.length;
         for (let i = 0; i < items.length; i++) {
             const item = items[i];
             //TODO Error checking to make sure parent doesn't already exist
@@ -43,23 +44,23 @@ const listHandlers: any = {
                 item[OnUpdate] = updateFunction(list, i + length, item, this);
             }
         }
-        const res = list.__fields.push(...items);
+        const res = list.__fieldTuples.push(...items);
         this[Update]({ op: '$addToSet', items, length: length + items.length });
         return res;
     }),
     reverse() {
-        const res = this[Self].__fields.reverse();
+        const res = this[Self].__fieldTuples.reverse();
         this[Update]();
         return res;
     },
     shift() {
-        const res = toRealField(this[Self].__fields.shift());
+        const res = toRealField(this[Self].__fieldTuples.shift());
         this[Update]();
         return res;
     },
     sort(cmpFunc: any) {
         this[Self].__realFields(); // coerce retrieving entire array
-        const res = this[Self].__fields.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined);
+        const res = this[Self].__fieldTuples.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined);
         this[Update]();
         return res;
     },
@@ -67,7 +68,7 @@ const listHandlers: any = {
         this[Self].__realFields(); // coerce retrieving entire array
         items = items.map(toObjectField);
         const list = this[Self];
-        const removed = list.__fields.filter((item: any, i: number) => i >= start && i < start + deleteCount);
+        const removed = list.__fieldTuples.filter((item: any, i: number) => i >= start && i < start + deleteCount);
         for (let i = 0; i < items.length; i++) {
             const item = items[i];
             //TODO Error checking to make sure parent doesn't already exist
@@ -77,18 +78,18 @@ const listHandlers: any = {
                 item[OnUpdate] = updateFunction(list, i + start, item, this);
             }
         }
-        let hintArray: {val : any, index : number}[] = [];
-        for(let i = start; i < start + deleteCount; i++) {
-            hintArray.push({val : list.__fields[i], index : i});
+        let hintArray: { val: any; index: number }[] = [];
+        for (let i = start; i < start + deleteCount; i++) {
+            hintArray.push({ val: list.__fieldTuples[i], index: i });
         }
-        const res = list.__fields.splice(start, deleteCount, ...items);
+        const res = list.__fieldTuples.splice(start, deleteCount, ...items);
         // the hint object sends the starting index of the slice and the number
-        // of elements to delete. 
+        // of elements to delete.
         this[Update](
             items.length === 0 && deleteCount
-                ? { op: '$remFromSet', items: removed, hint : { start : start, deleteCount : deleteCount }, length: list.__fields.length }
-                : items.length && !deleteCount && start === list.__fields.length
-                ? { op: '$addToSet', items, length: list.__fields.length }
+                ? { op: '$remFromSet', items: removed, hint: { start: start, deleteCount: deleteCount }, length: list.__fieldTuples.length }
+                : items.length && !deleteCount && start === list.__fieldTuples.length
+                ? { op: '$addToSet', items, length: list.__fieldTuples.length }
                 : undefined
         );
         return res.map(toRealField);
@@ -96,7 +97,7 @@ const listHandlers: any = {
     unshift(...items: any[]) {
         items = items.map(toObjectField);
         const list = this[Self];
-        const length = list.__fields.length;
+        const length = list.__fieldTuples.length;
         for (let i = 0; i < items.length; i++) {
             const item = items[i];
             //TODO Error checking to make sure parent doesn't already exist
@@ -106,32 +107,32 @@ const listHandlers: any = {
                 item[OnUpdate] = updateFunction(list, i, item, this);
             }
         }
-        const res = this[Self].__fields.unshift(...items);
+        const res = this[Self].__fieldTuples.unshift(...items);
         this[Update]();
         return res;
     },
     /// Accessor methods
     concat: action(function (this: any, ...items: any[]) {
         this[Self].__realFields();
-        return this[Self].__fields.map(toRealField).concat(...items);
+        return this[Self].__fieldTuples.map(toRealField).concat(...items);
     }),
     includes(valueToFind: any, fromIndex: number) {
         if (valueToFind instanceof RefField) {
             return this[Self].__realFields().includes(valueToFind, fromIndex);
         } else {
-            return this[Self].__fields.includes(valueToFind, fromIndex);
+            return this[Self].__fieldTuples.includes(valueToFind, fromIndex);
         }
     },
     indexOf(valueToFind: any, fromIndex: number) {
         if (valueToFind instanceof RefField) {
             return this[Self].__realFields().indexOf(valueToFind, fromIndex);
         } else {
-            return this[Self].__fields.indexOf(valueToFind, fromIndex);
+            return this[Self].__fieldTuples.indexOf(valueToFind, fromIndex);
         }
     },
     join(separator: any) {
         this[Self].__realFields();
-        return this[Self].__fields.map(toRealField).join(separator);
+        return this[Self].__fieldTuples.map(toRealField).join(separator);
     },
     lastElement() {
         return this[Self].__realFields().lastElement();
@@ -140,12 +141,12 @@ const listHandlers: any = {
         if (valueToFind instanceof RefField) {
             return this[Self].__realFields().lastIndexOf(valueToFind, fromIndex);
         } else {
-            return this[Self].__fields.lastIndexOf(valueToFind, fromIndex);
+            return this[Self].__fieldTuples.lastIndexOf(valueToFind, fromIndex);
         }
     },
     slice(begin: number, end: number) {
         this[Self].__realFields();
-        return this[Self].__fields.slice(begin, end).map(toRealField);
+        return this[Self].__fieldTuples.slice(begin, end).map(toRealField);
     },
 
     /// Iteration methods
@@ -156,55 +157,55 @@ const listHandlers: any = {
         return this[Self].__realFields().every(callback, thisArg);
         // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
         // If we don't want to support the array parameter, we should use this version instead
-        // return this[Self].__fields.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+        // return this[Self].__fieldTuples.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
     },
     filter(callback: any, thisArg: any) {
         return this[Self].__realFields().filter(callback, thisArg);
         // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
         // If we don't want to support the array parameter, we should use this version instead
-        // return this[Self].__fields.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+        // return this[Self].__fieldTuples.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
     },
     find(callback: any, thisArg: any) {
         return this[Self].__realFields().find(callback, thisArg);
         // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
         // If we don't want to support the array parameter, we should use this version instead
-        // return this[Self].__fields.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+        // return this[Self].__fieldTuples.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
     },
     findIndex(callback: any, thisArg: any) {
         return this[Self].__realFields().findIndex(callback, thisArg);
         // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
         // If we don't want to support the array parameter, we should use this version instead
-        // return this[Self].__fields.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+        // return this[Self].__fieldTuples.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
     },
     forEach(callback: any, thisArg: any) {
         return this[Self].__realFields().forEach(callback, thisArg);
         // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
         // If we don't want to support the array parameter, we should use this version instead
-        // return this[Self].__fields.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+        // return this[Self].__fieldTuples.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
     },
     map(callback: any, thisArg: any) {
         return this[Self].__realFields().map(callback, thisArg);
         // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
         // If we don't want to support the array parameter, we should use this version instead
-        // return this[Self].__fields.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+        // return this[Self].__fieldTuples.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
     },
     reduce(callback: any, initialValue: any) {
         return this[Self].__realFields().reduce(callback, initialValue);
         // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
         // If we don't want to support the array parameter, we should use this version instead
-        // return this[Self].__fields.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
+        // return this[Self].__fieldTuples.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
     },
     reduceRight(callback: any, initialValue: any) {
         return this[Self].__realFields().reduceRight(callback, initialValue);
         // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
         // If we don't want to support the array parameter, we should use this version instead
-        // return this[Self].__fields.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
+        // return this[Self].__fieldTuples.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
     },
     some(callback: any, thisArg: any) {
         return this[Self].__realFields().some(callback, thisArg);
         // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
         // If we don't want to support the array parameter, we should use this version instead
-        // return this[Self].__fields.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+        // return this[Self].__fieldTuples.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
     },
     values() {
         return this[Self].__realFields().values();
@@ -246,7 +247,7 @@ type ListUpdate<T> = ListSpliceUpdate<T> | ListIndexUpdate<T>;
 
 type StoredType<T extends Field> = T extends RefField ? ProxyField<T> : T;
 
-export const ListFieldName="fields";
+export const ListFieldName = 'fields';
 @Deserializable('list')
 class ListImpl<T extends Field> extends ObjectField {
     constructor(fields?: T[]) {
@@ -254,9 +255,9 @@ class ListImpl<T extends Field> extends ObjectField {
         const list = new Proxy<this>(this, {
             set: setter,
             get: listGetter,
-            ownKeys: target => Object.keys(target.__fields),
+            ownKeys: target => Object.keys(target.__fieldTuples),
             getOwnPropertyDescriptor: (target, prop) => {
-                if (prop in target.__fields) {
+                if (prop in target[FieldTuples]) {
                     return {
                         configurable: true, //TODO Should configurable be true?
                         enumerable: true,
@@ -281,7 +282,7 @@ class ListImpl<T extends Field> extends ObjectField {
     // this requests all ProxyFields at the same time to avoid the overhead
     // of separate network requests and separate updates to the React dom.
     private __realFields() {
-        const unrequested = this.__fields.filter(f => f instanceof ProxyField && f.needsRequesting).map(f => f as ProxyField<RefField>);
+        const unrequested = this[FieldTuples].filter(f => f instanceof ProxyField && f.needsRequesting).map(f => f as ProxyField<RefField>);
         // if we find any ProxyFields that don't have a current value, then
         // start the server request for all of them
         if (unrequested.length) {
@@ -293,17 +294,16 @@ class ListImpl<T extends Field> extends ObjectField {
             // will await the batch request and return the requested field value.
             unrequested.forEach(p => p.setExternalValuePromise(allSetPromise));
         }
-        return this.__fields.map(toRealField);
+        return this[FieldTuples].map(toRealField);
     }
 
-    public static FieldDataName = 'fields';
     @serializable(alias(ListFieldName, list(autoObject(), { afterDeserialize: afterDocDeserialize })))
-    private get __fields() {
-        return this.___fields;
+    private get __fieldTuples() {
+        return this[FieldTuples];
     }
 
-    private set __fields(value) {
-        this.___fields = value;
+    private set __fieldTuples(value) {
+        this[FieldTuples] = value;
         for (const key in value) {
             const field = value[key];
             if (field instanceof ObjectField) {
@@ -314,14 +314,14 @@ class ListImpl<T extends Field> extends ObjectField {
     }
 
     [Copy]() {
-        const copiedData = this[Self].__fields.map(f => (f instanceof ObjectField ? f[Copy]() : f));
+        const copiedData = this[Self].__fieldTuples.map(f => (f instanceof ObjectField ? f[Copy]() : f));
         const deepCopy = new ListImpl<T>(copiedData as any);
         return deepCopy;
     }
 
     // @serializable(alias("fields", list(autoObject())))
     @observable
-    private ___fields: StoredType<T>[] = [];
+    private [FieldTuples]: StoredType<T>[] = [];
 
     private [Update] = (diff: any) => {
         // console.log(diff);
diff --git a/src/fields/util.ts b/src/fields/util.ts
index a2b445d6c..62f27c7d2 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -7,28 +7,9 @@ import { SerializationHelper } from '../client/util/SerializationHelper';
 import { UndoManager } from '../client/util/UndoManager';
 import { returnZero } from '../Utils';
 import CursorField from './CursorField';
-import {
-    AclAdmin,
-    AclEdit,
-    aclLevel,
-    AclPrivate,
-    AclSelfEdit,
-    AclSym,
-    DataSym,
-    Doc,
-    DocListCast,
-    DocListCastAsync,
-    ForceServerWrite,
-    HeightSym,
-    HierarchyMapping,
-    Initializing,
-    LayoutSym,
-    ReverseHierarchyMap,
-    updateCachedAcls,
-    UpdatingFromServer,
-    WidthSym,
-} from './Doc';
-import { Id, OnUpdate, Parent, SelfProxy, ToValue, Update } from './FieldSymbols';
+import { aclLevel, Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap, updateCachedAcls } from './Doc';
+import { AclAdmin, AclEdit, AclPrivate, AclSelfEdit, DocAcl, DocData, DocLayout, FieldKeys, ForceServerWrite, Height, Initializing, SelfProxy, Update, UpdatingFromServer, Width } from './DocSymbols';
+import { Id, OnUpdate, Parent, ToValue } from './FieldSymbols';
 import { List } from './List';
 import { ObjectField } from './ObjectField';
 import { PrefetchProxy, ProxyField } from './Proxy';
@@ -56,7 +37,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
     if (value !== undefined) {
         value = value[SelfProxy] || value;
     }
-    const curValue = target.__fields[prop];
+    const curValue = target.__fieldTuples[prop];
     if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) {
         // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically
         // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way
@@ -88,11 +69,11 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
 
     if (writeToDoc) {
         if (value === undefined) {
-            target.__fieldKeys && delete target.__fieldKeys[prop];
-            delete target.__fields[prop];
+            delete target[FieldKeys][prop];
+            delete target.__fieldTuples[prop];
         } else {
-            target.__fieldKeys && (target.__fieldKeys[prop] = true);
-            target.__fields[prop] = value;
+            target[FieldKeys][prop] = true;
+            target.__fieldTuples[prop] = value;
         }
 
         if (writeToServer) {
@@ -148,12 +129,12 @@ export function denormalizeEmail(email: string) {
  */
 export function inheritParentAcls(parent: Doc, child: Doc) {
     return;
-    const dataDoc = parent[DataSym];
-    for (const key of Object.keys(dataDoc)) {
-        // if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private.
-        const permission = key === 'acl-Public' && Doc.defaultAclPrivate ? AclPrivate : dataDoc[key];
-        key.startsWith('acl') && distributeAcls(key, permission, child);
-    }
+    // const dataDoc = parent[DataSym];
+    // for (const key of Object.keys(dataDoc)) {
+    //     // if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private.
+    //     const permission = key === 'acl-Public' && Doc.defaultAclPrivate ? AclPrivate : dataDoc[key];
+    //     key.startsWith('acl') && distributeAcls(key, permission, child);
+    // }
 }
 
 /**
@@ -212,7 +193,7 @@ export function SetCachedGroups(groups: string[]) {
     runInAction(() => cachedGroups.push(...groups));
 }
 function getEffectiveAcl(target: any, user?: string): symbol {
-    const targetAcls = target[AclSym];
+    const targetAcls = target[DocAcl];
     if (targetAcls?.['acl-Me'] === AclAdmin || GetCachedGroupByName('Admin')) return AclAdmin;
 
     const userChecked = user || Doc.CurrentUserEmail; // if the current user is the author of the document / the current user is a member of the admin group
@@ -237,7 +218,7 @@ function getEffectiveAcl(target: any, user?: string): symbol {
         return DocServer?.Control?.isReadOnly?.() && HierarchyMapping.get(effectiveAcl)!.level < aclLevel.editable ? AclEdit : effectiveAcl;
     }
     // authored documents are private until an ACL is set.
-    const targetAuthor = target.__fields?.author || target.author; // target may be a Doc of Proxy, so check __fields.author and .author
+    const targetAuthor = target.__fieldTuples?.author || target.author; // target may be a Doc of Proxy, so check __fieldTuples.author and .author
     if (targetAuthor && targetAuthor !== userChecked) return AclPrivate;
     return AclAdmin;
 }
@@ -277,7 +258,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
     }
 
     let dataDocChanged = false;
-    const dataDoc = target[DataSym];
+    const dataDoc = target[DocData];
     if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || ReverseHierarchyMap.get(StrCast(dataDoc[key]))! > ReverseHierarchyMap.get(acl)!)) {
         if (GetEffectiveAcl(dataDoc) === AclAdmin) {
             dataDoc[key] = acl;
@@ -290,13 +271,13 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
         // maps over the children of the document
         DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).forEach(d => {
             distributeAcls(key, acl, d, inheritingFromCollection, visited);
-            distributeAcls(key, acl, d[DataSym], inheritingFromCollection, visited);
+            distributeAcls(key, acl, d[DocData], inheritingFromCollection, visited);
         });
 
         // maps over the annotations of the document
         DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + '_annotations']).forEach(d => {
             distributeAcls(key, acl, d, inheritingFromCollection, visited);
-            distributeAcls(key, acl, d[DataSym], inheritingFromCollection, visited);
+            distributeAcls(key, acl, d[DocData], inheritingFromCollection, visited);
         });
     }
 
@@ -311,16 +292,16 @@ export function setter(target: any, in_prop: string | symbol | number, value: an
     // if you're trying to change an acl but don't have Admin access / you're trying to change it to something that isn't an acceptable acl, you can't
     if (typeof prop === 'string' && prop.startsWith('acl') && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined].includes(value))) return true;
 
-    if (typeof prop === 'string' && prop !== '__id' && prop !== '__fields' && prop.startsWith('_')) {
+    if (typeof prop === 'string' && prop !== '__id' && prop !== '__fieldTuples' && prop.startsWith('_')) {
         if (!prop.startsWith('__')) prop = prop.substring(1);
         if (target.__LAYOUT__) {
             target.__LAYOUT__[prop] = value;
             return true;
         }
     }
-    if (target.__fields[prop] instanceof ComputedField) {
-        if (target.__fields[prop].setterscript && value !== undefined && !(value instanceof ComputedField)) {
-            return ScriptCast(target.__fields[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false;
+    if (target.__fieldTuples[prop] instanceof ComputedField) {
+        if (target.__fieldTuples[prop].setterscript && value !== undefined && !(value instanceof ComputedField)) {
+            return ScriptCast(target.__fieldTuples[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false;
         }
     }
     return _setter(target, prop, value, receiver);
@@ -330,14 +311,13 @@ export function getter(target: any, prop: string | symbol, proxy: any): any {
     // prettier-ignore
     switch (prop) {
         case 'then' :   return undefined;
-        case '__fields' :   case '__id':  
-        case 'constructor': case 'toString': case 'valueOf':  
-        case 'factory':     case 'serializeInfo': 
+        case 'constructor':   case 'toString': case 'valueOf':  
+        case 'serializeInfo': case 'factory':     
                         return target[prop];
-        case AclSym :   return target[AclSym];
-        case $mobx:     return target.__fields[prop];
-        case LayoutSym: return target.__LAYOUT__;
-        case HeightSym: case WidthSym: if (GetEffectiveAcl(target) === AclPrivate) return returnZero;
+        case DocAcl :   return target[DocAcl];
+        case $mobx:     return target.__fieldTuples[prop];
+        case DocLayout: return target.__LAYOUT__;
+        case Height: case Width: if (GetEffectiveAcl(target) === AclPrivate) return returnZero;
         default :
             if (typeof prop === 'symbol')  return target[prop];
             if (prop.startsWith('isMobX')) return target[prop];
@@ -351,7 +331,7 @@ export function getter(target: any, prop: string | symbol, proxy: any): any {
 }
 
 function getFieldImpl(target: any, prop: string | number, proxy: any, ignoreProto: boolean = false): any {
-    const field = target.__fields[prop];
+    const field = target.__fieldTuples[prop];
     const value = field?.[ToValue]?.(proxy); // converts ComputedFields to values, or unpacks ProxyFields into Proxys
     if (value) return value.value;
     if (field === undefined && !ignoreProto && prop !== 'proto') {
-- 
cgit v1.2.3-70-g09d2


From bf16eca7a84adfdf1c5970e7e4793568ee70325d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 13 Jun 2023 22:14:29 -0400
Subject: fixed updating cached docs when opening a backlinks collection. 
 added some FieldInfo types and added 'enumeration' field display in schema
 view.  fixed bug in schema view column sizing.   updated a bunch of standard
 field names to be more consistent.

---
 src/client/documents/Documents.ts                  | 471 +++++++++++----------
 src/client/util/CurrentUserUtils.ts                | 115 ++---
 src/client/util/DocumentManager.ts                 |   2 +-
 src/client/util/DragManager.ts                     |   2 +-
 src/client/util/LinkManager.ts                     |   2 +-
 src/client/util/TrackMovements.ts                  |   3 +-
 src/client/views/DashboardView.tsx                 |   9 +-
 src/client/views/DocComponent.tsx                  |   2 -
 src/client/views/DocumentButtonBar.tsx             |   2 +-
 src/client/views/DocumentDecorations.tsx           |  16 +-
 src/client/views/FilterPanel.tsx                   |  12 +-
 src/client/views/GestureOverlay.tsx                |   8 +-
 src/client/views/LightboxView.tsx                  |  12 +-
 src/client/views/MainView.tsx                      |  20 +-
 src/client/views/MarqueeAnnotator.tsx              |   2 +-
 src/client/views/OverlayView.tsx                   |   4 +-
 src/client/views/Palette.tsx                       |   4 +-
 src/client/views/PropertiesButtons.tsx             |   4 +-
 .../views/PropertiesDocBacklinksSelector.tsx       |   4 +-
 src/client/views/PropertiesView.tsx                |  44 +-
 src/client/views/SidebarAnnos.tsx                  |  12 +-
 src/client/views/StyleProvider.tsx                 |  23 +-
 src/client/views/TemplateMenu.tsx                  |   4 +-
 src/client/views/collections/CollectionMenu.tsx    |  10 +-
 .../views/collections/CollectionNoteTakingView.tsx | 104 ++---
 .../views/collections/CollectionPileView.tsx       |  21 +-
 .../collections/CollectionStackedTimeline.tsx      |  14 +-
 .../views/collections/CollectionStackingView.tsx   |  12 +-
 src/client/views/collections/CollectionSubView.tsx |  29 +-
 .../views/collections/CollectionTimeView.tsx       |  18 +-
 .../views/collections/CollectionTreeView.tsx       |  12 +-
 src/client/views/collections/TabDocView.tsx        |   8 +-
 src/client/views/collections/TreeView.tsx          |  24 +-
 .../CollectionFreeFormLinkView.tsx                 |  16 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  14 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   2 +-
 .../collectionLinear/CollectionLinearView.tsx      |  18 +-
 .../CollectionMulticolumnView.tsx                  |   4 +-
 .../CollectionMultirowView.tsx                     |   4 +-
 .../collectionSchema/CollectionSchemaView.scss     |   2 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  56 +--
 .../collectionSchema/SchemaColumnHeader.tsx        |   3 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |  10 +-
 .../collectionSchema/SchemaTableCell.tsx           |  55 ++-
 src/client/views/linking/LinkMenuGroup.tsx         |   2 +-
 src/client/views/linking/LinkPopup.tsx             |   4 +-
 .../views/nodes/DataVizBox/components/TableBox.tsx |   2 +-
 src/client/views/nodes/DocumentLinksButton.tsx     |   6 +-
 src/client/views/nodes/DocumentView.tsx            |  43 +-
 src/client/views/nodes/KeyValuePair.tsx            |   4 +-
 src/client/views/nodes/LabelBox.tsx                |   4 +-
 src/client/views/nodes/LinkAnchorBox.tsx           |   4 +-
 src/client/views/nodes/LinkDocPreview.tsx          |   4 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |   8 +-
 src/client/views/nodes/MapBox/MapBox2.tsx          |   8 +-
 src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx |   2 +-
 src/client/views/nodes/PDFBox.tsx                  |   4 +-
 src/client/views/nodes/QueryBox.scss               |   5 -
 src/client/views/nodes/QueryBox.tsx                |  38 --
 src/client/views/nodes/VideoBox.tsx                |   4 +-
 src/client/views/nodes/WebBox.tsx                  |   8 +-
 src/client/views/nodes/button/FontIconBox.tsx      |   2 +-
 .../views/nodes/formattedText/DashDocView.tsx      |   4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  22 +-
 src/client/views/nodes/trails/PresBox.tsx          |  14 +-
 src/client/views/nodes/trails/PresElementBox.tsx   |  10 +-
 src/client/views/pdf/PDFViewer.tsx                 |  10 +-
 src/fields/Doc.ts                                  |  44 +-
 src/fields/documentSchemas.ts                      |  10 +-
 src/fields/util.ts                                 |   8 +-
 src/mobile/AudioUpload.tsx                         |  10 +-
 src/mobile/MobileInterface.tsx                     |   4 +-
 72 files changed, 740 insertions(+), 761 deletions(-)
 delete mode 100644 src/client/views/nodes/QueryBox.scss
 delete mode 100644 src/client/views/nodes/QueryBox.tsx

(limited to 'src/client/views/nodes/LinkDocPreview.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index c1abd6e71..a91d5806c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -110,18 +110,28 @@ class DocInfo extends FInfo {
     }
 }
 class DimInfo extends FInfo {
-    fieldType? = 'DimUnit';
+    fieldType? = 'enumeration';
     values? = [DimUnit.Pixel, DimUnit.Ratio];
-    readOnly = true;
+    readOnly = false;
 }
 class PEInfo extends FInfo {
-    fieldType? = 'pointerEvents';
+    fieldType? = 'enumeration';
     values? = ['all', 'none'];
-    readOnly = true;
+    readOnly = false;
 }
 class DAInfo extends FInfo {
-    fieldType? = 'dropActionType';
+    fieldType? = 'enumeration';
     values? = ['embed', 'copy', 'move', 'same', 'proto', 'none'];
+    readOnly = false;
+}
+class CTypeInfo extends FInfo {
+    fieldType? = 'enumeration';
+    values? = Array.from(Object.keys(CollectionViewType));
+    readOnly = false;
+}
+class DTypeInfo extends FInfo {
+    fieldType? = 'enumeration';
+    values? = Array.from(Object.keys(DocumentType));
     readOnly = true;
 }
 class DateInfo extends FInfo {
@@ -134,272 +144,267 @@ type STRt = StrInfo | string;
 type DOCt = DocInfo | Doc;
 type DIMt = DimInfo | typeof DimUnit.Pixel | typeof DimUnit.Ratio;
 type PEVt = PEInfo | 'none' | 'all';
+type COLLt = CTypeInfo | CollectionViewType;
 type DROPt = DAInfo | dropActionType;
 type DATEt = DateInfo | number;
+type DTYPEt = DTypeInfo | string;
 export class DocumentOptions {
+    // coordinate and dimensions depending on view
     x?: NUMt = new NumInfo('x coordinate of document in a freeform view');
     y?: NUMt = new NumInfo('y coordinage of document in a freeform view');
     z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, [1, 0]);
-    isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
-    type?: STRt = new StrInfo('type of document', true, Array.from(Object.keys(DocumentType)));
-    title?: string;
-    author_date?: DATEt = new DateInfo('date the document was created', true);
-    _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
-    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
-    childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
-    targetDropAction?: DROPt = new DAInfo('what should happen to the source document when ??? ');
-    userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
-    color?: STRt = new StrInfo('foreground color data doc');
-    backgroundColor?: STRt = new StrInfo('background color for data doc');
-    _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
-    _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title');
-    _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes');
-    _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume');
-    _freeform_panX?: NUMt = new NumInfo('horizontal pan location of a freeform view');
-    _freeform_panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
+    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height");
+    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
+    lat?: NUMt = new NumInfo('latitude coordinate for map views');
+    lng?: NUMt = new NumInfo('longitude coordinate for map views');
+    _timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)');
+    _timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden');
     _width?: NUMt = new NumInfo('displayed width of a document');
     _height?: NUMt = new NumInfo('displayed height of document');
     data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)');
     data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)');
+    linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)');
     _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)');
     _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)');
     _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers');
     _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
-    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height");
-    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
+
+    'acl-Public'?: string; // public permissions
+    '_acl-Public'?: string; // public permissions
+    type?: DTYPEt = new DTypeInfo('type of document', true);
+    _type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
+    title?: STRt = new StrInfo('title of document');
+    caption?: RichTextField;
+    author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable
+    author_date?: DATEt = new DateInfo('date the document was created', true);
+    annotationOn?: DOCt = new DocInfo('document annotated by this document');
+    color?: STRt = new StrInfo('foreground color data doc');
+    hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection');
+    backgroundColor?: STRt = new StrInfo('background color for data doc');
+    opacity?: NUMt = new NumInfo('document opacity');
+    viewTransitionTime?: NUMt = new NumInfo('transition duration for view parameters');
+    dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc');
+    dontUndo?: BOOLt = new BoolInfo('whether button clicks should be undoable (true for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)');
+    _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title');
+    _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes');
+    _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume');
+    _lockedPosition?: BOOLt = new BoolInfo("lock the x,y coordinates of the document so that it can't be dragged");
+    _lockedTransform?: BOOLt = new BoolInfo('lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed');
+
+    layout?: string | Doc; // default layout string or template document
+    layout_keyValue?: STRt = new StrInfo('layout definition for showing keyValue view of document');
+    layout_explainer?: STRt = new StrInfo('explanation displayed at top of a collection to describe its purpose');
+    layout_headerButton?: DOCt = new DocInfo('the (button) Doc to display at the top of a collection.');
+    layout_disableBrushing?: BOOLt = new BoolInfo('whether to suppress border highlighting');
+    layout_unrendered?: BOOLt = new BoolInfo('denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf)');
+    layout_hideOpenButton?: BOOLt = new BoolInfo('whether to hide the open full screen button when selected');
+    layout_hideDocumentButtonBar?: BOOLt = new BoolInfo('whether to hide the document decorations lower button bar when selected');
+    layout_hideLinkAnchors?: BOOLt = new BoolInfo('suppresses link anchor dots from being displayed');
+    layout_hideAllLinks?: BOOLt = new BoolInfo('whether all individual blue anchor dots should be hidden');
+    layout_hideResizeHandles?: BOOLt = new BoolInfo('whether to hide the resize handles when selected');
+    layout_hideLinkButton?: BOOLt = new BoolInfo('whether the blue link counter button should be hidden');
+    layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected');
+    layout_borderRounding?: string;
+    layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
+    layout_maxAutoHeight?: NUMt = new NumInfo('maximum height for newly created (eg, from pasting) text documents');
+    _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
+    _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document');
+    _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video)  value is in seconds');
+    _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
     _layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
-    _layoutFitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
-    _contentBounds?: List<number>; // the (forced) bounds of the document to display. format is: [left, top, right, bottom]
-    _lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged
-    _lockedTransform?: boolean; // lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed
-    _followLinkToggle?: boolean; // whether document, when clicked, toggles display of its link target
+    _layout_fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
+    _layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition');
+    _layout_enableAltContentUI?: BOOLt = new BoolInfo('whether to show alternate content button');
     _layout_showTitle?: string; // field name to display in header (:hover is an optional suffix)
-    _layout_altContentUI?: boolean; // whether to show alternate content button
-    _isLightbox?: boolean; // whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target
+    _layout_showSidebar?: BOOLt = new BoolInfo('whether an annotationsidebar should be displayed for text docuemnts');
     _layout_showCaption?: string; // which field to display in the caption area.  leave empty to have no caption
-    _layoutScrollTop?: 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
-    _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)
-    enableDragWhenActive?: boolean; // allow dragging even if document contentts are active (e.g., tree, groups)
-    _stayInCollection?: boolean; // whether the document should remain in its collection when someone tries to drag and drop it elsewhere
-    _raiseWhenDragged?: boolean; // whether a document is brought to front when dragged.
-    _hideContextMenu?: boolean; // whether the context menu can be shown
-    _type_collection?: string; // sub type of a collection
-    type_collection?: string; // sub type of a collection
-    _gridGap?: number; // gap between items in masonry view
-    freeform?: string; // placeholder just so that the key value pane has a divider to render for freeform view data
-    _freeform_scale?: number; // how much a freeform view has been scaled (zoomed)
-    _overflow?: string; // set overflow behavior
-    _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts
-    _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts
-    _xPadding?: number;
-    _yPadding?: number;
-    _carousel_index?: number; // which item index the carousel viewer is showing
-    _layout_showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts
+
+    _chromeHidden?: BOOLt = new BoolInfo('whether the editing chrome for a document is hidden');
+    _gridGap?: NUMt = new NumInfo('gap between items in masonry view');
+    _xMargin?: NUMt = new NumInfo('gap between left edge of document and start of masonry/stacking layouts');
+    _yMargin?: NUMt = new NumInfo('gap between top edge of dcoument and start of masonry/stacking layouts');
+    _xPadding?: NUMt = new NumInfo('x padding');
+    _yPadding?: NUMt = new NumInfo('y padding');
     _singleLine?: boolean; // whether label box is restricted to one line of text
     _createDocOnCR?: boolean; // whether carriage returns and tabs create new text documents
-    _minFontSize?: number; // minimum font size for labelBoxes
-    _maxFontSize?: number; // maximum font size for labelBoxes
-    _columnWidth?: number;
-    _columnsHideIfEmpty?: boolean; // whether stacking view column headings should be hidden
-    _text_fontSize?: string;
-    _text_fontFamily?: string;
-    _text_fontWeight?: string;
-    _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
-    _layout_curPage?: number; // current page of a PDF or other? paginated document
-    _layout_currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video)  value is in seconds
-    _currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide)
-    _timecodeToShow?: number; // the time that a document should be displayed (e.g., when an annotation shows up as a video plays)
-    _timecodeToHide?: number; // the time that a document should be hidden
-    _timelineLabel?: boolean; // whether the document exists on a timeline
+    _columnWidth?: NUMt = new NumInfo('width of table column');
+    _columnsHideIfEmpty?: BOOLt = new BoolInfo('whether stacking view column headings should be hidden');
     _caption_xMargin?: NUMt = new NumInfo('x margin of caption inside of a carousel collection', true);
     _caption_yMargin?: NUMt = new NumInfo('y margin of caption inside of a carousel collection', true);
     icon_nativeWidth?: NUMt = new NumInfo('native width of icon view', true);
     icon_nativeHeight?: NUMt = new NumInfo('native height of icon view', true);
-    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
-    openFactoryLocation?: string; // an OpenWhere value to place the factory created document
-    openFactoryAsDelegate?: boolean; //
-    lat?: number;
-    lng?: number;
-    infoWindowOpen?: boolean;
-    author?: string;
-    _layout_fieldKey?: string;
-    fieldValues?: List<any>; // possible field values used by fieldInfos
-    fieldType?: string; // type of afield used by fieldInfos
-    layout_unrendered?: boolean; // denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf)
-    'acl-Public'?: string; // public permissions
-    '_acl-Public'?: string; // public permissions
-    version?: string; // version identifier for a document
-    label?: string;
-    hidden?: boolean;
-    _hidden?: boolean;
-    pointerEvents?: string; // pointer events that the documentview should have
-    mediaState?: string; // status of audio/video media document: "pendingRecording", "recording", "paused", "playing"
-    recording?: boolean; // whether WebCam is recording or not
-    autoPlayAnchors?: boolean; // whether to play audio/video when an anchor is clicked in a stackedTimeline.
-    dontPlayLinkOnSelect?: boolean; // whether an audio/video should start playing when a link is followed to it.
-    linkSource?: Doc; // the source document for a collection of backlinks
+    _text_fontSize?: string;
+    _text_fontFamily?: string;
+    _text_fontWeight?: string;
+    _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
+
+    infoWindowOpen?: BOOLt = new BoolInfo('whether info window corresponding to pin is open (on MapDocuments)');
+    _carousel_index?: NUMt = new NumInfo('which item index the carousel viewer is showing');
+    _label_minFontSize?: NUMt = new NumInfo('minimum font size for labelBoxes');
+    _label_maxFontSize?: NUMt = new NumInfo('maximum font size for labelBoxes');
+    stroke_width?: NUMt = new NumInfo('width of an ink stroke');
+    icon_label?: STRt = new StrInfo('label to use for a fontIcon doc (otherwise, the title is used)');
+    mediaState?: STRt = new StrInfo('status of audio/video media document: "pendingRecording", "recording", "paused", "playing"');
+    recording?: BOOLt = new BoolInfo('whether WebCam is recording or not');
+    autoPlayAnchors?: BOOLt = new BoolInfo('whether to play audio/video when an anchor is clicked in a stackedTimeline.');
+    dontPlayLinkOnSelect?: BOOLt = new BoolInfo('whether an audio/video should start playing when a link is followed to it.');
     updateContentsScript?: ScriptField; // reactive script invoked when viewing a document that can update contents of a collection (or do anything)
     toolTip?: string; // tooltip to display on hover
     toolType?: string; // type of pen tool
-    expertMode?: boolean; // something available only in expert (not novice) mode
+    expertMode?: BOOLt = new BoolInfo('something available only in expert (not novice) mode');
+
+    contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
     contextMenuFilters?: List<ScriptField>;
     contextMenuScripts?: List<ScriptField>;
     contextMenuLabels?: List<string>;
     contextMenuIcons?: List<string>;
-    defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
-    waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
-    dontUndo?: boolean; // whether button clicks should be undoable ( true for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)
-    layout?: string | Doc; // default layout string for a document
-    contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
-    childLimitHeight?: number; // whether to limit the height of collection children.  0 - means  height can be no bigger than width
+    childFilters_boolean?: string;
+    childFilters?: List<string>;
+    childLimitHeight?: NUMt = new NumInfo('whether to limit the height of collection children.  0 - means  height can be no bigger than width');
     childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view)
     childLayoutString?: string; // template string for collection to use to render its children
-    childDocumentsActive?: boolean; // whether child documents are active when parent is document active
-    childDontRegisterViews?: boolean;
-    childHideLinkButton?: boolean; // hide link buttons on all children
+    childDocumentsActive?: BOOLt = new BoolInfo('whether child documents are active when parent is document active');
+    childDontRegisterViews?: BOOLt = new BoolInfo('whether child document views should be registered so that they can be found when following links, etc');
+    childHideLinkButton?: BOOLt = new BoolInfo('hide link buttons on all children');
     childContextMenuFilters?: List<ScriptField>;
     childContextMenuScripts?: List<ScriptField>;
     childContextMenuLabels?: List<string>;
     childContextMenuIcons?: List<string>;
-    followLinkZoom?: boolean; // whether to zoom to the target of a link
-    layout_hideLinkButton?: boolean; // whether the blue link counter button should be hidden
-    disableDocBrushing?: boolean; // whether to suppress border highlighting
-    layout_hideDecorationTitle?: boolean;
-    hideOpenButton?: boolean;
-    layout_hideResizeHandles?: boolean;
-    hideDocumentButtonBar?: boolean;
-    hideAllLinks?: boolean; // whether all individual blue anchor dots should be hidden
-    isTemplateForField?: string; // the field key for which the containing document is a rendering template
-    isTemplateDoc?: boolean;
     targetScriptKey?: string; // where to write a template script (used by collections with click templates which need to target onClick, onDoubleClick, etc)
-    templates?: List<string>;
-    hero?: ImageField; // primary image that best represents a compound document (e.g., for a buxton device document that has multiple images)
-    caption?: RichTextField;
-    opacity?: number;
-    defaultBackgroundColor?: string;
-    _layout_autoMoveAnchors?: boolean; // whether link endpoint should move around the edges of a document to make shortest path to other link endpoint
-    layout_hideLinkAnchors?: boolean; // suppresses link anchor dots from being displayed
-    isFolder?: boolean;
-    lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide)
-    activeFrame?: number; // the active frame of a document in a frame base collection
-    appearFrame?: number; // the frame in which the document appears
-    viewTransitionTime?: number; // transition duration for view parameters
-    presPanX?: number; // panX saved as a view spec
-    presPanY?: number; // panY saved as a view spec
-    presViewScale?: number; // viewScale saved as a view Spec
-    presTransition?: number; //the time taken for the transition TO a document
-    presDuration?: number; //the duration of the slide in presentation view
-    presZoomText?: boolean; // whether text anchors should shown in a larger box when following links to make them stand out
-    borderRounding?: string;
-    boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
+
+    lastFrame?: NUMt = new NumInfo('the last frame of a frame-based collection (e.g., progressive slide)');
+    activeFrame?: NUMt = new NumInfo('the active frame of a document in a frame base collection');
+    appearFrame?: NUMt = new NumInfo('the frame in which the document appears');
+    _currentFrame?: NUMt = new NumInfo('the current frame of a frame-based collection (e.g., progressive slide)');
+
+    isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
+    isBaseProto?: BOOLt = new BoolInfo('is doc a base level prototype for data documents as opposed to data documents which are prototypes for layout documents.  base protos are not cloned during a deep');
+    isTemplateForField?: string; // the field key for which the containing document is a rendering template
+    isTemplateDoc?: BOOLt = new BoolInfo('is the document a template for creating other documents');
+    isGroup?: BOOLt = new BoolInfo('should collection use a grouping UI behavior');
+    isFolder?: BOOLt = new BoolInfo('is document a tree view folder');
+    _isTimelineLabel?: BOOLt = new BoolInfo('is document a timeline label');
+    _isLightbox?: BOOLt = new BoolInfo('whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target');
+
+    presPanX?: NUMt = new NumInfo('panX saved as a view spec');
+    presPanY?: NUMt = new NumInfo('panY saved as a view spec');
+    presViewScale?: NUMt = new NumInfo('viewScale saved as a view Spec');
+    presTransition?: NUMt = new NumInfo('the time taken for the transition TO a document');
+    presDuration?: NUMt = new NumInfo('the duration of the slide in presentation view');
+    presZoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out');
+
     data?: any;
-    isBaseProto?: boolean; // this Doc is base level prototype for data documents as opposed to data documents which are prototypes for layout documents.  base protos are not cloned during a deep
-    dontRegisterView?: boolean;
-    lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document.  see PresBox.
+    data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page');
     columnHeaders?: List<SchemaHeaderField>; // headers for stacking views
     schemaHeaders?: List<SchemaHeaderField>; // headers for schema view
-    dockingConfig?: string;
-    annotationOn?: Doc;
-    followLinkToggle?: 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
+    dockingConfig?: STRt = new StrInfo('configuration of golden layout windows (applies only if doc is rendered as a CollectionDockingView)');
+    icon?: string; // icon used by fonticonbox to render button
     noteType?: string;
-    // BACKGROUND GRID
+
+    // freeform properties
     _freeform_backgroundGrid?: boolean;
+    _freeform_scale?: NUMt = new NumInfo('how much a freeform view has been scaled (zoomed)');
+    _freeform_panX?: NUMt = new NumInfo('horizontal pan location of a freeform view');
+    _freeform_panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
+    _freeform_noAutoPan?: BOOLt = new BoolInfo('disables autopanning when this item is dragged');
+    _freeform_noZoom?: BOOLt = new BoolInfo('disables zooming');
 
     //BUTTONS
     buttonText?: string;
-    iconShape?: string; // shapes of the fonticon border
     btnType?: string;
     btnList?: List<string>;
     docColorBtn?: string;
     userColorBtn?: string;
-    canClick?: string;
     script?: ScriptField;
-    numBtnMax?: number;
-    numBtnMin?: number;
+    numBtnMax?: NUMt = new NumInfo('maximum value of a number button');
+    numBtnMin?: NUMt = new NumInfo('minimum value of a number button');
     switchToggle?: boolean;
     badgeValue?: ScriptField;
 
     //LINEAR VIEW
-    linearViewIsExpanded?: boolean; // is linear view expanded
-    linearViewExpandable?: boolean; // can linear view be expanded
-    linearViewToggleButton?: string; // button to open close linear view group
-    linearViewSubMenu?: boolean;
-    linearBtnWidth?: number;
-    flexGap?: number; // Linear view flex gap
+    linearView_IsExpanded?: BOOLt = new BoolInfo('is linear view expanded');
+    linearView_Expandable?: BOOLt = new BoolInfo('can linear view be expanded');
+    linearView_SubMenu?: BOOLt = new BoolInfo('is doc a sub menu of more linear views');
+    flexGap?: NUMt = new NumInfo('Linear view flex gap');
     flexDirection?: 'unset' | 'row' | 'column' | 'row-reverse' | 'column-reverse';
 
-    layout_linkView?: Doc; // view template for a link document
-    layout_keyValue?: string; // view tempalte for key value docs
     link_description?: string; // added for links
     link_relationship?: string; // type of relatinoship a link represents
-    layout_linkDisplay?: boolean; // whether a link line should be dipslayed between the two link anchors
-    layout_linkDisplayArrow?: boolean; // whether to display link's directional arrowhead
+    link_displayLine?: BOOLt = new BoolInfo('whether a link line should be dipslayed between the two link anchors');
+    link_displayArrow?: BOOLt = new BoolInfo("whether to display link's directional arrowhead");
     link_anchor_1?: Doc;
     link_anchor_2?: Doc;
-    link_anchor_1_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
-    link_anchor_2_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
-    ignoreClick?: boolean;
+    link_autoMoveAnchors?: BOOLt = new BoolInfo('whether link endpoint should move around the edges of a document to make shortest path to other link endpoint');
+    link_anchor_1_useSmallAnchor?: BOOLt = new BoolInfo('whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)');
+    link_anchor_2_useSmallAnchor?: BOOLt = new BoolInfo('whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)');
+    link_relationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
+    link_relationshipSizes?: List<number>; //stores number of links contained in each relationship
+    link_colorList?: List<string>; // colors of links corresponding to specific link relationships
+    followLinkZoom?: BOOLt = new BoolInfo('whether to zoom to the target of a link');
+    followLinkToggle?: BOOLt = new BoolInfo('whether target of link should be toggled on and off when following a link to it');
+    followLinkLocation?: STRt = new StrInfo('where to open link target when following link');
+    followLinkAnimEffect?: STRt = new StrInfo('animation effect triggered on target of link');
+    followLinkAnimDirection?: STRt = new StrInfo('direction modifier for animation effect');
+
+    ignoreClick?: BOOLt = new BoolInfo('whether clicks on document should be ignored');
     onClick?: ScriptField;
     onDoubleClick?: ScriptField;
     onChildClick?: ScriptField; // script given to children of a collection to execute when they are clicked
     onChildDoubleClick?: ScriptField; // script given to children of a collection to execute when they are double clicked
+    defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
+    waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
+    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
+    openFactoryLocation?: string; // an OpenWhere value to place the factory created document
+    openFactoryAsDelegate?: BOOLt = new BoolInfo('create a delegate of the factory');
+    _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)');
+    enableDragWhenActive?: BOOLt = new BoolInfo('allow dragging even if document contentts are active (e.g., tree, groups)');
+    _stayInCollection?: BOOLt = new BoolInfo('whether the document should remain in its collection when someone tries to drag and drop it elsewhere');
+    _raiseWhenDragged?: BOOLt = new BoolInfo('whether a document is brought to front when dragged.');
+    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
+    childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
+    targetDropAction?: DROPt = new DAInfo('what should happen to the source document when ??? ');
+    _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
+    _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
+    cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
     dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
     dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
     clickFactory?: Doc; // document to create when clicking on a button with a suitable onClick script
     onDragStart?: ScriptField; //script to execute at start of drag operation --  e.g., when a "creator" button is dragged this script generates a different document to drop
-    cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
-    filterBoolean?: string;
-    data_useCors?: boolean;
-    icon?: string; // icon used by fonticonbox to render button
-    target?: Doc; // available for use in scripts as the primary target document
-    sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script
-    targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script
-    searchFileTypes?: List<string>; // file types allowed in a search query
-    stroke_width?: 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
-    treeViewHideUnrendered?: boolean; // tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeViewFieldKey tag (presBox)
-    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.
+    target?: Doc; // available for use in scripts.  used to provide a document parameter to the script (Note, this is a convenience entry since any field could be used for parameterizing a script)
+
+    treeViewHideTitle?: BOOLt = new BoolInfo('whether to hide the top document title of a tree view');
+    treeViewHideUnrendered?: BOOLt = new BoolInfo("tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeViewFieldKey tag (presBox)");
+    treeViewHideHeaderIfTemplate?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)');
+    treeViewHideHeader?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view');
+    treeViewHideHeaderFields?: BOOLt = new BoolInfo('whether to hide the drop down options for tree view items.');
     treeViewChildDoubleClick?: ScriptField; //
-    // Action Button
-    buttonMenu?: boolean; // whether a action button should be displayed
-    buttonMenuDoc?: Doc;
-    explainer?: string;
-
-    treeViewOpenIsTransient?: boolean; // ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view
-    _treeViewOpen?: boolean; // whether this document is expanded in a tree view  (note: need _ and regular versions since this can be specified for both proto and layout docs)
-    treeViewOpen?: boolean; // whether this document is expanded in a tree view
+    treeViewOpenIsTransient?: BOOLt = new BoolInfo("ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view");
+    treeViewOpen?: BOOLt = new BoolInfo('whether this document is expanded in a tree view');
     treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view
-    treeViewExpandedViewLock?: boolean; // whether the expanded view can be changed
+    treeViewExpandedViewLock?: BOOLt = new BoolInfo('whether the expanded view can be changed');
     treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked
-    treeViewTruncateTitleWidth?: number;
-    treeViewHasOverlay?: boolean; // whether the treeview has an overlay for freeform annotations
+    treeViewTruncateTitleWidth?: NUMt = new NumInfo('maximum width of a treew view title before truncation');
+    treeViewHasOverlay?: BOOLt = new BoolInfo('whether the treeview has an overlay for freeform annotations');
     treeViewType?: string; // whether treeview is a Slide, file system, or (default) collection hierarchy
-    sidebarColor?: string; // background color of text sidebar
-    sidebarViewType?: string; // collection type of text sidebar
-    docMaxAutoHeight?: number; // maximum height for newly created (eg, from pasting) text documents
+    treeViewFreezeChildren?: STRt = new StrInfo('set (add, remove, add|remove) to disable adding, removing or both from collection');
+
+    sidebar_color?: string; // background color of text sidebar
+    sidebar_collectionType?: string; // collection type of text sidebar
+
     text?: string;
-    textTransform?: string; // is linear view expanded
-    letterSpacing?: string; // is linear view expanded
+    textTransform?: string;
+    letterSpacing?: string;
     iconTemplate?: string; // name of icon template style
-    selectedIndex?: number; // which item in a linear view has been selected using the "thumb doc" ui
+    selectedIndex?: NUMt = new NumInfo("which item in a linear view has been selected using the 'thumb doc' ui");
+
+    fieldValues?: List<any>; // possible values a field can have (used by FieldInfo's only)
+    fieldType?: string; // display type of a field, e.g. string, number, enumeration (used by FieldInfo's only)
+
     clipboard?: Doc;
-    searchQuery?: string; // for quersyBox
-    useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox
-    border?: string; //for searchbox
     hoverBackgroundColor?: string; // background color of a label when hovered
-    link_relationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
-    link_relationshipSizes?: List<number>; //stores number of links contained in each relationship
-    linkColorList?: List<string>; // colors of links corresponding to specific link relationships
+    userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
 }
 export namespace Docs {
     export let newAccount: boolean = false;
@@ -986,7 +991,7 @@ export namespace Docs {
             I.layout = InkingStroke.LayoutString('stroke');
             I.layout_fitWidth = true;
             I.layout_hideDecorationTitle = true; // don't show title when selected
-            // I.hideOpenButton = true; // don't show open full screen button when selected
+            // I.layout_hideOpenButton = true; // don't show open full screen button when selected
             I.color = color;
             I.fillColor = fillColor;
             I.stroke = new InkField(points);
@@ -1088,7 +1093,12 @@ export namespace Docs {
         }
 
         export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
-            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _overflow: 'visible', enableDragWhenActive: true, _forceActive: true, _noAutoscroll: true, ...options, _type_collection: CollectionViewType.Pile }, id);
+            return InstanceFromProto(
+                Prototypes.get(DocumentType.COL),
+                new List(documents),
+                { enableDragWhenActive: true, _forceActive: true, _freeform_noZoom: true, _freeform_noAutoPan: true, ...options, _type_collection: CollectionViewType.Pile },
+                id
+            );
         }
 
         export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
@@ -1177,12 +1187,7 @@ export namespace Docs {
         }
 
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
-            return InstanceFromProto(
-                Prototypes.get(DocumentType.COL),
-                new List(documents),
-                { freezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, _type_collection: CollectionViewType.Docking, dockingConfig: config },
-                id
-            );
+            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, _type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
         }
 
         export function DirectoryImportDocument(options: DocumentOptions = {}) {
@@ -1227,18 +1232,18 @@ export namespace Docs {
 export namespace DocUtils {
     /**
      * @param docs
-     * @param docFilters
-     * @param docRangeFilters
+     * @param childFilters
+     * @param childFiltersByRanges
      * @param parentCollection
-     * Given a list of docs and docFilters, @returns the list of Docs that match those filters
+     * Given a list of docs and childFilters, @returns the list of Docs that match those filters
      */
-    export function FilterDocs(childDocs: Doc[], docFilters: string[], docRangeFilters: string[], parentCollection?: Doc) {
-        if (!docFilters?.length && !docRangeFilters?.length) {
+    export function FilterDocs(childDocs: Doc[], childFilters: string[], childFiltersByRanges: string[], parentCollection?: Doc) {
+        if (!childFilters?.length && !childFiltersByRanges?.length) {
             return childDocs.filter(d => !d.cookies); // remove documents that need a cookie if there are no filters to provide one
         }
 
         const filterFacets: { [key: string]: { [value: string]: string } } = {}; // maps each filter key to an object with value=>modifier fields
-        docFilters.forEach(filter => {
+        childFilters.forEach(filter => {
             const fields = filter.split(':');
             const key = fields[0];
             const value = fields[1];
@@ -1249,7 +1254,7 @@ export namespace DocUtils {
             filterFacets[key][value] = modifiers;
         });
 
-        const filteredDocs = docFilters.length
+        const filteredDocs = childFilters.length
             ? childDocs.filter(d => {
                   if (d.z) return true;
                   // if the document needs a cookie but no filter provides the cookie, then the document does not pass the filter
@@ -1293,7 +1298,7 @@ export namespace DocUtils {
                                 return Field.toString(d[facetKey] as Field).includes(value);
                             });
                       // if we're ORing them together, the default return is false, and we return true for a doc if it satisfies any one set of criteria
-                      if (parentCollection?.filterBoolean === 'OR') {
+                      if (parentCollection?.childFilters_boolean === 'OR') {
                           if (satisfiesUnsetsFacets && satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true;
                       }
                       // if we're ANDing them together, the default return is true, and we return false for a doc if it doesn't satisfy any set of criteria
@@ -1301,14 +1306,14 @@ export namespace DocUtils {
                           if (!satisfiesUnsetsFacets || !satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
                       }
                   }
-                  return (parentCollection?.currentFilter as Doc)?.filterBoolean === 'OR' ? false : true;
+                  return (parentCollection?.currentFilter as Doc)?.childFilters_boolean === 'OR' ? false : true;
               })
             : childDocs;
         const rangeFilteredDocs = filteredDocs.filter(d => {
-            for (let i = 0; i < docRangeFilters.length; i += 3) {
-                const key = docRangeFilters[i];
-                const min = Number(docRangeFilters[i + 1]);
-                const max = Number(docRangeFilters[i + 2]);
+            for (let i = 0; i < childFiltersByRanges.length; i += 3) {
+                const key = childFiltersByRanges[i];
+                const min = Number(childFiltersByRanges[i + 1]);
+                const max = Number(childFiltersByRanges[i + 2]);
                 const val = typeof d[key] === 'string' ? (Number(StrCast(d[key])).toString() === StrCast(d[key]) ? Number(StrCast(d[key])) : undefined) : Cast(d[key], 'number', null);
                 if (val === undefined) {
                     //console.log("Should 'undefined' pass range filter or not?")
@@ -1325,11 +1330,11 @@ export namespace DocUtils {
         broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1));
         return DocUtils.ActiveRecordings.map(audio => {
             const sourceDoc = getSourceDoc();
-            return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { layout_linkDisplay: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
+            return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { link_displayLine: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
         });
     }
 
-    export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; layout_linkDisplay?: boolean }, id?: string, showPopup?: number[]) {
+    export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; link_displayLine?: boolean }, id?: string, showPopup?: number[]) {
         if (!linkSettings.link_relationship) linkSettings.link_relationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
         const sv = DocumentManager.Instance.getDocumentView(source);
         if (target.doc === Doc.UserDoc()) return undefined;
@@ -1370,15 +1375,15 @@ export namespace DocUtils {
                 source,
                 target,
                 {
-                    title: ComputedField.MakeFunction('generateLinkTitle(self)') as any,
-                    link_anchor_1_useLinkSmallAnchor: source.useLinkSmallAnchor ? true : undefined,
-                    link_anchor_2_useLinkSmallAnchor: target.useLinkSmallAnchor ? true : undefined,
                     'acl-Public': SharingPermissions.Augment,
                     '_acl-Public': SharingPermissions.Augment,
-                    layout_linkDisplay: linkSettings.layout_linkDisplay,
+                    title: ComputedField.MakeFunction('generateLinkTitle(self)') as any,
+                    link_anchor_1_useSmallAnchor: source.useSmallAnchor ? true : undefined,
+                    link_anchor_2_useSmallAnchor: target.useSmallAnchor ? true : undefined,
+                    link_displayLine: linkSettings.link_displayLine,
                     link_relationship: linkSettings.link_relationship,
                     link_description: linkSettings.link_description,
-                    _layout_autoMoveAnchors: true,
+                    link_autoMoveAnchors: true,
                     _layout_showCaption: 'link_description',
                     _layout_showTitle: 'link_relationship',
                 },
@@ -1706,14 +1711,14 @@ export namespace DocUtils {
         if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) {
             const pushpin = Docs.Create.FontIconDocument({
                 title: 'pushpin',
-                label: '',
+                icon_label: '',
                 annotationOn: Cast(doc.annotationOn, Doc, null),
                 followLinkToggle: true,
                 icon: 'map-pin',
                 x: Cast(doc.x, 'number', null),
                 y: Cast(doc.y, 'number', null),
                 backgroundColor: '#ACCEF7',
-                hideAllLinks: true,
+                layout_hideAllLinks: true,
                 _width: 15,
                 _height: 15,
                 _xPadding: 0,
@@ -1804,7 +1809,7 @@ export namespace DocUtils {
             _xMargin: noMargins ? 0 : undefined,
             _yMargin: noMargins ? 0 : undefined,
             annotationOn,
-            docMaxAutoHeight: maxHeight,
+            layout_maxAutoHeight: maxHeight,
             backgroundColor,
             _width: width || 200,
             _height: 35,
@@ -1812,7 +1817,7 @@ export namespace DocUtils {
             y: y,
             _layout_fitWidth: true,
             _layout_autoHeight: true,
-            _layout_altContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
+            _layout_enableAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
             title,
         });
         const template = Doc.UserDoc().defaultTextLayout;
@@ -1842,18 +1847,18 @@ export namespace DocUtils {
     }
 
     /**
-     * uploadFilesToDocs will take in an array of Files, and creates documents for the 
-     * new files. 
-     * 
+     * uploadFilesToDocs will take in an array of Files, and creates documents for the
+     * new files.
+     *
      * @param files an array of files that will be uploaded
      * @param options options to use while uploading
-     * @returns 
+     * @returns
      */
     export async function uploadFilesToDocs(files: File[], options: DocumentOptions) {
         const generatedDocuments: Doc[] = [];
 
-        // These files do not have overwriteDocs, so we do not set the guid and let the client generate one. 
-        const fileNoGuidPairs: Networking.FileGuidPair[] = files.map(file => ({file}));
+        // These files do not have overwriteDocs, so we do not set the guid and let the client generate one.
+        const fileNoGuidPairs: Networking.FileGuidPair[] = files.map(file => ({ file }));
 
         const upfiles = await Networking.UploadFilesToServer(fileNoGuidPairs);
         for (const {
@@ -1867,8 +1872,8 @@ export namespace DocUtils {
 
     export function uploadFileToDoc(file: File, options: DocumentOptions, overwriteDoc: Doc) {
         const generatedDocuments: Doc[] = [];
-        // Since this file has an overwriteDoc, we can set the client tracking guid to the overwriteDoc's guid. 
-        Networking.UploadFilesToServer([{file, guid: overwriteDoc[Id]}]).then(upfiles => {
+        // Since this file has an overwriteDoc, we can set the client tracking guid to the overwriteDoc's guid.
+        Networking.UploadFilesToServer([{ file, guid: overwriteDoc[Id] }]).then(upfiles => {
             const {
                 source: { name, type },
                 result,
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 6f6ac2d4a..59041862f 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -23,7 +23,7 @@ import { MainView } from "../views/MainView";
 import { ButtonType } from "../views/nodes/button/FontIconBox";
 import { OpenWhere } from "../views/nodes/DocumentView";
 import { OverlayView } from "../views/OverlayView";
-import { DragManager } from "./DragManager";
+import { DragManager, dropActionType } from "./DragManager";
 import { MakeTemplate } from "./DropConverter";
 import { FollowLinkScript } from "./LinkFollower";
 import { LinkManager } from "./LinkManager";
@@ -97,7 +97,7 @@ export class CurrentUserUtils {
 
         const reqdOpts:DocumentOptions = {
             title: "Experimental Tools", _xMargin: 0, _layout_showTitle: "title", _chromeHidden: true,
-            _stayInCollection: true, _hideContextMenu: true, _forceActive: true, isSystem: true,
+            _stayInCollection: true, _layout_hideContextMenu: true, _forceActive: true, isSystem: true,
             _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
         };
         const reqdScripts = { dropConverter : "convertToButtons(dragData)" };
@@ -136,7 +136,7 @@ export class CurrentUserUtils {
         const reqdClickList = reqdTempOpts.map(opts => {
             const allOpts = {...reqdClickOpts, ...opts.opts};
             const clickDoc = tempClicks ? DocListCast(tempClicks.data).find(doc => doc.title === opts.opts.title): undefined;
-            return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title);
+            return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title?.toString());
         });
 
         const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, isSystem: true};
@@ -192,7 +192,7 @@ export class CurrentUserUtils {
                 {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", });
         };
         const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({
-            textTransform: "unset", letterSpacing: "unset", _singleLine: false, _minFontSize: 14, _maxFontSize: 24, borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
+            textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 24, layout_borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
         });
         const imageBox = (opts: DocumentOptions, url?:string) => Docs.Create.ImageDocument(url ?? "http://www.cs.brown.edu/~bcz/noImage.png", { "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG,  _width: 360 / 4, _height: 270 / 4,  _layout_showTitle: "title", ...opts });
         const fontBox = (opts:DocumentOptions, data?:string) => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts  });
@@ -260,10 +260,11 @@ export class CurrentUserUtils {
         const emptyThings:{key:string,  // the field name where the empty thing will be stored
                           opts:DocumentOptions,   // the document options that are required for the empty thing
                           funcs?:{[key:string]: any},  // computed fields that are rquired for the empth thing
+                          scripts?:{[key:string]: any},
                           creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist
               }[] = [
             {key: "Note",       creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true }},
-            {key: "Flashcard",  creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true, _layout_altContentUI: true}},
+            {key: "Flashcard",  creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true, _layout_enableAltContentUI: true}},
             {key: "Equation",   creator: opts => Docs.Create.EquationDocument(opts),        opts: { _width: 300, _height: 35, }},
             {key: "Noteboard",  creator: opts => Docs.Create.NoteTakingDocument([], opts),  opts: { _width: 250, _height: 200, _layout_fitWidth: true}},
             {key: "Simulation", creator: opts => Docs.Create.SimulationDocument(opts),      opts: { _width: 300, _height: 300, }},
@@ -274,11 +275,11 @@ export class CurrentUserUtils {
             {key: "Map",        creator: opts => Docs.Create.MapDocument([], opts),         opts: { _width: 800, _height: 600, _layout_fitWidth: true, _layout_showSidebar: true,  }},
             {key: "Screengrab", creator: Docs.Create.ScreenshotDocument,                    opts: { _width: 400, _height: 200 }},
             {key: "WebCam",     creator: opts => Docs.Create.WebCamDocument("", opts),      opts: { _width: 400, _height: 200, recording:true, isSystem: true, cloneFieldFilter: new List<string>(["isSystem"]) }},
-            {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, onClick: FollowLinkScript()}},
+            {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}},
             {key: "Script",     creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
             {key: "DataViz",    creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts),   opts: { _width: 300, _height: 300 }},
             {key: "Header",     creator: headerTemplate,                                    opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeViewHideUnrendered: true}},
-            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, targetDropAction: "embed" as any, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, boxShadow: "0 0" }},
+            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, targetDropAction: "embed" as dropActionType, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, layout_boxShadow: "0 0" }},
             {key: "Tab",        creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }},
             {key: "Slide",      creator: opts => Docs.Create.TreeDocument([], opts),        opts: { _width: 300, _height: 200, _type_collection: CollectionViewType.Tree, 
                                                                                                 treeViewHasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, 
@@ -287,7 +288,7 @@ export class CurrentUserUtils {
                                                                                             }, funcs: {title: 'self.text?.Text'}},
             ];
 
-        emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, undefined, thing.funcs));
+        emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs));
         
         return [
             { toolTip: "Tap or drag to create a note",            title: "Note", icon: "sticky-note",   dragFactory: doc.emptyNote as Doc,       clickFactory: DocCast(doc.emptyNote)},
@@ -321,7 +322,7 @@ export class CurrentUserUtils {
         const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => {
             const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined;
             const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, 
-                _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, 
+                _width: 35, _height: 35, _layout_hideContextMenu: true, _stayInCollection: true, 
                 btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, isSystem: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
                 };
@@ -329,7 +330,7 @@ export class CurrentUserUtils {
         });
 
         const reqdOpts:DocumentOptions = {
-            title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, isSystem: true,
+            title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _stayInCollection: true, _layout_hideContextMenu: true, _chromeHidden: true, isSystem: true,
             _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true,
              childDropAction: 'embed' 
         };
@@ -367,14 +368,14 @@ export class CurrentUserUtils {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
             const reqdBtnOpts:DocumentOptions = {
                 title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, dontUndo: true, dontRegisterView: true,
-                _width: 60, _height: 60,  _stayInCollection: true, _hideContextMenu: true,
+                _width: 60, _height: 60,  _stayInCollection: true, _layout_hideContextMenu: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
             };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
         });
 
         const reqdStackOpts:DocumentOptions ={
-            title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
+            title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, layout_boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
             _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true,
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" });
@@ -413,14 +414,14 @@ export class CurrentUserUtils {
     static mobileButton = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MulticolumnDocument(docs, {
         ...opts,
          _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15,
-        borderRounding: "5px", boxShadow: "0 0", isSystem: true
+        layout_borderRounding: "5px", layout_boxShadow: "0 0", isSystem: true
     }) as any as Doc
 
     // sets up the text container for the information contained within the mobile button
     static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MultirowDocument(docs, {
         ...opts,
         _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25,
-        backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", ignoreClick: true, isSystem: true
+        backgroundColor: "rgba(0,0,0,0)", layout_borderRounding: "0", layout_boxShadow: "0 0", ignoreClick: true, isSystem: true
     }) as any as Doc
 
     // Sets up the title of the button
@@ -458,7 +459,7 @@ export class CurrentUserUtils {
     static setupSearcher(doc: Doc, field:string) {
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.SearchDocument(opts), {
                 dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", isSystem: true, childDropAction: "embed", 
-                _lockedPosition: true, _type_collection: CollectionViewType.Schema, _searchDoc: true,  });
+                _lockedPosition: true, _type_collection: CollectionViewType.Schema  });
     }
 
     /// Initializes the panel of draggable tools that is opened from the left sidebar.
@@ -467,8 +468,8 @@ export class CurrentUserUtils {
         const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, DocListCast(myTools?.data)?.length ? DocListCast(myTools.data)[0]:undefined);
         const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined);
         const reqdToolOps:DocumentOptions = {
-            title: "My Tools", isSystem: true, ignoreClick: true, boxShadow: "0 0",
-            _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, 
+            title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0",
+            _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, _chromeHidden: true, 
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, templateBtns]);
     }
@@ -480,10 +481,10 @@ export class CurrentUserUtils {
         const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`;
         const newDashboard = `createNewDashboard()`;
 
-        const reqdBtnOpts:DocumentOptions = { _forceActive: true,  _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true,
+        const reqdBtnOpts:DocumentOptions = { _forceActive: true,  _width: 30, _height: 30, _stayInCollection: true, _layout_hideContextMenu: true,
              title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", isSystem: true };
         const reqdBtnScript = {onClick: newDashboard,}
-        const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
+        const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.layout_headerButton), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
        
         const contextMenuScripts = [/*newDashboard*/] as string[];
         const contextMenuLabels = [/*"Create New Dashboard"*/]  as string[];
@@ -493,15 +494,15 @@ export class CurrentUserUtils {
         const childContextMenuLabels =  ["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters
         const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
         const reqdOpts:DocumentOptions = {
-            title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true,
+            title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
             targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
-            buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "embed",
+            layout_headerButton: newDashboardButton, childDropAction: "embed",
             _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
             contextMenuLabels:new List<string>(contextMenuLabels),
             contextMenuIcons:new List<string>(contextMenuIcons),
             childContextMenuLabels:new List<string>(childContextMenuLabels),
             childContextMenuIcons:new List<string>(childContextMenuIcons),
-            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."
+            layout_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."
         };
         myDashboards = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
         if (Cast(myDashboards.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
@@ -523,19 +524,19 @@ export class CurrentUserUtils {
         
         const newFolder = `TreeView_addNewFolder()`;
         const newFolderOpts: DocumentOptions = {
-            _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _width: 30, _height: 30,
+            _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, _width: 30, _height: 30,
             title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true
         };
         const newFolderScript = { onClick: newFolder};
-        const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.buttonMenuDoc), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
+        const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
         
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, 
-            title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", isSystem: true,
-            isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, boxShadow: "0 0", childDontRegisterViews: true, 
+            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", isSystem: true,
+            isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, 
             treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "embed",
             childContextMenuLabels: new List<string>(["Create new folder"]),
             childContextMenuIcons: new List<string>(["plus"]),
-            explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
+            layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
         };
         myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [myFileOrphans]);
         const childContextMenuScripts = [newFolder];
@@ -548,21 +549,21 @@ export class CurrentUserUtils {
     /// initializes the panel displaying docs that have been recently closed
     static setupRecentlyClosed(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
-            title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "embed", isSystem: true,
-            treeViewTruncateTitleWidth: 350, ignoreClick: true,  boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
+            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "embed", isSystem: true,
+            treeViewTruncateTitleWidth: 350, ignoreClick: true,  layout_boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
             contextMenuLabels: new List<string>(["Empty recently closed"]),
             contextMenuIcons:new List<string>(["trash"]),
-            explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list."
+            layout_explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list."
         };
         const recentlyClosed = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
 
         const clearAll = (target:string) => `getProto(${target}).data = new List([])`;
-        const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, 
+        const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, 
             title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton,  buttonText: "Empty", icon: "trash", isSystem: true,
             toolTip: "Empty recently closed",};
-        const clearDocsButton = DocUtils.AssignDocField(recentlyClosed, "clearDocsBtn", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
+        DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
 
-        if (recentlyClosed.buttonMenuDoc !== clearDocsButton) Doc.GetProto(recentlyClosed).buttonMenuDoc = clearDocsButton;
+        //if (recentlyClosed.layout_headerButton !== clearDocsButton) Doc.GetProto(recentlyClosed).layout_headerButton = clearDocsButton;
         
         if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) {
             recentlyClosed.contextMenuScripts = new List<ScriptField>([ScriptField.MakeScript(clearAll("self"))!])
@@ -574,7 +575,7 @@ export class CurrentUserUtils {
     static setupUserDocView(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = {
             _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view",
-            boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, isSystem: true,
+            layout_boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, isSystem: true,
             treeViewHideTitle: true, treeViewTruncateTitleWidth: 350
         };
         if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" });
@@ -582,14 +583,14 @@ export class CurrentUserUtils {
     }
 
     static linearButtonList = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.LinearDocument(docs, {
-        ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, boxShadow: "0 0", _forceActive: true,
+        ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, layout_boxShadow: "0 0", _forceActive: true,
         dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
         _lockedPosition: true, isSystem: true, flexDirection: "row"
     })
 
     static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({
-        btnType: ButtonType.ToolButton, _forceActive: true, _hideContextMenu: true, 
-        _removeDropProperties: new List<string>([ "_hideContextMenu", "stayInCollection"]), 
+        btnType: ButtonType.ToolButton, _forceActive: true, _layout_hideContextMenu: true, 
+        _removeDropProperties: new List<string>([ "_layout_hideContextMenu", "stayInCollection"]), 
         _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, isSystem: true, ...opts,
     })
 
@@ -609,8 +610,8 @@ export class CurrentUserUtils {
         ];
         const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts));
         const dockBtnsReqdOpts:DocumentOptions = {
-            title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", childDropAction: 'embed',
-            childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true
+            title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDropAction: 'embed',
+            childDontRegisterViews: true, linearView_IsExpanded: true, linearView_Expandable: true, ignoreClick: true
         };
         reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
         reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
@@ -701,12 +702,12 @@ export class CurrentUserUtils {
             { title: "Back",    icon: "chevron-left",  toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 20,  scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
             { title: "Num", icon:"",toolTip: "Frame Number (click to toggle edit mode)",btnType: ButtonType.TextButton,          expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
             { title: "Fwd",     icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 20,  scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
-            { title: "Text",    icon: "Text",          toolTip: "Text functions",       subMenu: CurrentUserUtils.textTools(),   expertMode: false, toolType:DocumentType.RTF,            funcs: {                                                                             linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "Ink",     icon: "Ink",           toolTip: "Ink functions",        subMenu: CurrentUserUtils.inkTools(),    expertMode: false, toolType:DocumentType.INK,            funcs: {                                                                             linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
-            { title: "Doc",     icon: "Doc",           toolTip: "Freeform Doc tools",   subMenu: CurrentUserUtils.freeTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "View",    icon: "View",          toolTip: "View tools",           subMenu: CurrentUserUtils.viewTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "Web",     icon: "Web",           toolTip: "Web functions",        subMenu: CurrentUserUtils.webTools(),    expertMode: false, toolType:DocumentType.WEB,            funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
-            { title: "Schema",  icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",    subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema,   funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected
+            { title: "Text",    icon: "Text",          toolTip: "Text functions",       subMenu: CurrentUserUtils.textTools(),   expertMode: false, toolType:DocumentType.RTF,            funcs: {                                                                             linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "Ink",     icon: "Ink",           toolTip: "Ink functions",        subMenu: CurrentUserUtils.inkTools(),    expertMode: false, toolType:DocumentType.INK,            funcs: {                                                                             linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
+            { title: "Doc",     icon: "Doc",           toolTip: "Freeform Doc tools",   subMenu: CurrentUserUtils.freeTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "View",    icon: "View",          toolTip: "View tools",           subMenu: CurrentUserUtils.viewTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "Web",     icon: "Web",           toolTip: "Web functions",        subMenu: CurrentUserUtils.webTools(),    expertMode: false, toolType:DocumentType.WEB,            funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
+            { title: "Schema",  icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema,   funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected
         ];
     }
 
@@ -719,7 +720,7 @@ export class CurrentUserUtils {
             _nativeWidth: params.width ?? 30, _width: params.width ?? 30,
             _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
             toolType: params.toolType, expertMode: params.expertMode,
-            _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true,
+            _stayInCollection: true, _layout_hideContextMenu: true, _lockedPosition: true,
             _removeDropProperties: new List<string>([ "_stayInCollection"]),
         };
         const reqdFuncs:{[key:string]:any} = {
@@ -731,7 +732,7 @@ export class CurrentUserUtils {
 
     /// Initializes all the default buttons for the top bar context menu
     static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") {
-        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", dontUndo:true, flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 };
+        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", dontUndo:true, flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearView_IsExpanded: true, ignoreClick: true, linearView_Expandable: false, _height: 35 };
         const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
         const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => {
             const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title);
@@ -740,7 +741,7 @@ export class CurrentUserUtils {
             } else {
                 const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, dontUndo: true,
                     childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true,
-                    linearViewSubMenu: true, linearViewExpandable: true, };
+                    linearView_SubMenu: true, linearView_Expandable: true, };
                 const items = params.subMenu?.map(sub =>
                     this.setupContextMenuButton(sub, DocListCast(menuBtnDoc?.data).find(doc => doc.title === sub.title))
                 );
@@ -793,8 +794,8 @@ export class CurrentUserUtils {
             "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,
             childDropAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
             // NOTE: treeViewHideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar
-            _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
-            explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
+            _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
+            layout_explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
         };
         
         DocUtils.AssignDocField(doc, "mySharedDocs", opts => Docs.Create.TreeDocument([], opts, sharingDocumentId + "layout", sharingDocumentId), sharedDocOpts, undefined, sharedScripts);
@@ -803,17 +804,17 @@ export class CurrentUserUtils {
     /// Import option on the left side button panel 
     static setupImportSidebar(doc: Doc, field:string) {   
         const reqdOpts:DocumentOptions = {
-            title: "My Imports", _forceActive: true, buttonMenu: true, ignoreClick: true, _layout_showTitle: "title", 
-            _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0,
-            childDropAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true,
-            dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go."
+            title: "My Imports", _forceActive: true, ignoreClick: true, _layout_showTitle: "title", 
+            _stayInCollection: true, _layout_hideContextMenu: true, childLimitHeight: 0,
+            childDropAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, layout_boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true,
+            dontRegisterView: true, layout_explainer: "This is where documents that are Imported into Dash will go."
         };
         const myImports = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.StackingDocument([], opts), reqdOpts);
     
         const reqdBtnOpts:DocumentOptions = { _forceActive: true, toolTip: "Import from computer",
-            _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, 
+            _width: 30, _height: 30, _stayInCollection: true, _layout_hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, 
             buttonText: "Import", icon: "upload", isSystem: true };
-        DocUtils.AssignDocField(myImports, "buttonMenuDoc", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" });
+        DocUtils.AssignDocField(myImports, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" });
         return myImports;
     }
     /// Updates the UserDoc to have all required fields, docs, etc.  No changes should need to be
@@ -850,7 +851,7 @@ export class CurrentUserUtils {
         doc.defaultAclPrivate ?? (doc.defaultAclPrivate = false);
         doc.savedFilters ?? (doc.savedFilters = new List<Doc>());
         doc.filterDocCount = 0;
-        doc.freezeChildren = "remove|add";
+        doc.treeViewFreezeChildren = "remove|add";
         this.setupLinkDocs(doc, linkDatabaseId);
         this.setupSharedDocs(doc, sharingDocumentId);  // sets up the right sidebar collection for mobile upload documents and sharing
         this.setupDefaultIconTemplates(doc);  // creates a set of icon templates triggered by the document deoration icon
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 7a88ca991..612f16ce9 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -189,7 +189,7 @@ export class DocumentManager {
         while (
             containerDocContext.length &&
             containerDocContext[0]?.embedContainer &&
-            DocCast(containerDocContext[0].embedContainer)?.type_collection !== CollectionViewType.Docking &&
+            DocCast(containerDocContext[0].embedContainer)?._type_collection !== CollectionViewType.Docking &&
             (includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0]))
         ) {
             containerDocContext = [Cast(containerDocContext[0].embedContainer, Doc, null), ...containerDocContext];
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index fb4a8985c..668de5408 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -517,7 +517,7 @@ export namespace DragManager {
 
             const target = document.elementFromPoint(e.x, e.y);
 
-            if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._noAutoscroll)) {
+            if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._freeform_noAutoPan)) {
                 const autoScrollHandler = () => {
                     target.dispatchEvent(
                         new CustomEvent<React.DragEvent>('dashDragAutoScroll', {
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 41c2fa889..dbb05917e 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -134,7 +134,7 @@ export class LinkManager {
     public createlink_relationshipLists = () => {
         //create new lists for link relations and their associated colors if the lists don't already exist
         !Doc.UserDoc().link_relationshipList && (Doc.UserDoc().link_relationshipList = new List<string>());
-        !Doc.UserDoc().linkColorList && (Doc.UserDoc().linkColorList = new List<string>());
+        !Doc.UserDoc().link_ColorList && (Doc.UserDoc().link_ColorList = new List<string>());
         !Doc.UserDoc().link_relationshipSizes && (Doc.UserDoc().link_relationshipSizes = new List<number>());
     };
 
diff --git a/src/client/util/TrackMovements.ts b/src/client/util/TrackMovements.ts
index f83b6af0e..0e56ee1bc 100644
--- a/src/client/util/TrackMovements.ts
+++ b/src/client/util/TrackMovements.ts
@@ -3,6 +3,7 @@ import { NumCast } from '../../fields/Types';
 import { Doc, DocListCast } from '../../fields/Doc';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
 import { Id } from '../../fields/FieldSymbols';
+import { CollectionViewType } from '../documents/DocumentTypes';
 
 export type Movement = {
     time: number;
@@ -89,7 +90,7 @@ export class TrackMovements {
         if (this.recordingFFViews === null) return;
 
         // so that the size comparisons are correct, we must filter to only the FFViews
-        const isFFView = (doc: Doc) => doc && 'type_collection' in doc && doc.type_collection === 'freeform';
+        const isFFView = (doc: Doc) => doc && doc._type_collection === CollectionViewType.Freeform;
         const tabbedFFViews = new Set<Doc>();
         for (const DashDoc of tabbedDocs) {
             if (isFFView(DashDoc)) tabbedFFViews.add(DashDoc);
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 94dd010c3..50cf2226e 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -390,7 +390,7 @@ export class DashboardView extends React.Component {
             _width: 30,
             _height: 30,
             _stayInCollection: true,
-            _hideContextMenu: true,
+            _layout_hideContextMenu: true,
             title: 'New trail',
             toolTip: 'Create new trail',
             btnType: ButtonType.ClickButton,
@@ -415,16 +415,15 @@ export class DashboardView extends React.Component {
             childDropAction: 'embed',
             treeViewTruncateTitleWidth: 150,
             ignoreClick: true,
-            buttonMenu: true,
-            buttonMenuDoc: myTrailsBtn,
+            layout_headerButton: myTrailsBtn,
             contextMenuIcons: new List<string>(['plus']),
             contextMenuLabels: new List<string>(['Create New Trail']),
             _lockedPosition: true,
-            boxShadow: '0 0',
+            layout_boxShadow: '0 0',
             childDontRegisterViews: true,
             targetDropAction: 'same',
             isSystem: true,
-            explainer: 'All of the trails that you have created will appear here.',
+            layout_explainer: 'All of the trails that you have created will appear here.',
         };
         const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeViewChildDoubleClick: 'openPresentation(documentView.rootDoc)' });
         dashboardDoc.myTrails = new PrefetchProxy(myTrails);
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 6fab4430d..db24229dc 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -128,8 +128,6 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
 
         isAnyChildContentActive = () => this._isAnyChildContentActive;
 
-        lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
-
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
         @computed public get annotationKey() {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 547d844ca..35b0b22a8 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -589,7 +589,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                         <LinkPopup
                             key="popup"
                             showPopup={this._showLinkPopup}
-                            linkCreated={link => (link.layout_linkDisplay = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
+                            linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
                             linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
                             linkFrom={() => this.props.views().lastElement()?.rootDoc}
                         />
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e4d50b143..528b82e3e 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -332,7 +332,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                         const docMax = Math.min(NumCast(doc.width) / 2, NumCast(doc.height) / 2);
                         const ratio = dist / maxDist;
                         const radius = Math.min(1, ratio) * docMax;
-                        doc.borderRounding = `${radius}px`;
+                        doc.layout_borderRounding = `${radius}px`;
                     });
                 return false;
             }, // moveEvent
@@ -588,7 +588,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                     let dW = docwidth * (dWin / refWidth);
                     let dH = docheight * (dHin / refHeight);
                     const scale = docView.props.ScreenToLocalTransform().Scale;
-                    const modifyNativeDim = (e.ctrlKey || doc.layout_forceReflow) && doc.nativeDimModifiable && ((!dragBottom && !dragTop) || e.ctrlKey || doc.nativeHeightUnfrozen);
+                    const modifyNativeDim = (e.ctrlKey && doc.nativeDimModifiable) || (doc.layout_forceReflow && !dragBottom && !dragTop) || (doc.nativeHeightUnfrozen && (dragBottom || dragTop || e.ctrlKey));
                     if (nwidth && nheight) {
                         if (nwidth / nheight !== docwidth / docheight && !dragBottom && !dragTop) {
                             docheight = (nheight / nwidth) * docwidth;
@@ -636,7 +636,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                 }
                             }
                             if (!modifyNativeDim) {
-                                actualdH = Math.min((nheight / nwidth) * docwidth, actualdH);
+                                actualdH = (nheight / nwidth) * docwidth; //, actualdH);
                             }
                             doc._height = actualdH;
                         }
@@ -750,13 +750,13 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations;
         const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
         const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating;
-        const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.hideDocumentButtonBar || this._isRounding || this._isRotating;
+        const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.layout_hideDocumentButtonBar || this._isRounding || this._isRotating;
         // if multiple documents have been opened at the same time, then don't show open button
         const hideOpenButton =
             hideDecorations ||
             seldocview.props.hideOpenButton ||
-            seldocview.rootDoc.hideOpenButton ||
-            SelectionManager.Views().some(docView => docView.props.Document._stayInCollection || docView.props.Document.isGroup || docView.props.Document.hideOpenButton) ||
+            seldocview.rootDoc.layout_hideOpenButton ||
+            SelectionManager.Views().some(docView => docView.rootDoc._stayInCollection || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) ||
             this._isRounding ||
             this._isRotating;
         const hideDeleteButton =
@@ -767,7 +767,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             seldocview.rootDoc.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
                 const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit;
-                return (docView.rootDoc.stayInCollection && !docView.rootDoc.timelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
+                return (docView.rootDoc.stayInCollection && !docView.rootDoc._isTimelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
             });
 
         const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
@@ -796,7 +796,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
         // Radius constants
         const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView;
-        const borderRadius = numberValue(StrCast(seldocview.rootDoc.borderRounding));
+        const borderRadius = numberValue(StrCast(seldocview.rootDoc.layout_borderRounding));
         const docMax = Math.min(NumCast(seldocview.rootDoc.width) / 2, NumCast(seldocview.rootDoc.height) / 2);
         const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2);
         const radiusHandle = (borderRadius / docMax) * maxDist;
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 53c1f1018..fe42628cd 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -64,7 +64,7 @@ export class FilterPanel extends React.Component<filterProps> {
      * The current attributes selected to filter based on
      */
     @computed get activeFilters() {
-        return StrListCast(this.targetDoc?._docFilters);
+        return StrListCast(this.targetDoc?._childFilters);
     }
 
     /**
@@ -108,8 +108,8 @@ export class FilterPanel extends React.Component<filterProps> {
     @observable _chosenFacets = new ObservableMap<string, 'text' | 'checkbox' | 'slider' | 'range'>();
     @computed get activeFacets() {
         const facets = new Map<string, 'text' | 'checkbox' | 'slider' | 'range'>(this._chosenFacets);
-        StrListCast(this.targetDoc?._docFilters).map(filter => facets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'));
-        setTimeout(() => StrListCast(this.targetDoc?._docFilters).map(action(filter => this._chosenFacets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'))));
+        StrListCast(this.targetDoc?._childFilters).map(filter => facets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'));
+        setTimeout(() => StrListCast(this.targetDoc?._childFilters).map(action(filter => this._chosenFacets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'))));
         return facets;
     }
     /**
@@ -174,7 +174,7 @@ export class FilterPanel extends React.Component<filterProps> {
                         <Select placeholder="Add a filter..." options={options} isMulti={false} onChange={val => this.facetClick((val as UserOptions).value)} onKeyDown={e => e.stopPropagation()} value={null} closeMenuOnSelect={true} />
                     </div>
                     <div className="filterBox-select-bool">
-                        <select className="filterBox-selection" onChange={action(e => this.targetDoc && (this.targetDoc._filterBoolean = (e.target as any).value))} defaultValue={StrCast(this.targetDoc?.filterBoolean)}>
+                        <select className="filterBox-selection" onChange={action(e => this.targetDoc && (this.targetDoc._childFilters_boolean = (e.target as any).value))} defaultValue={StrCast(this.targetDoc?.childFilters_boolean)}>
                             {['AND', 'OR'].map(bool => (
                                 <option value={bool} key={bool}>
                                     {bool}
@@ -202,7 +202,7 @@ export class FilterPanel extends React.Component<filterProps> {
                 return (
                     <input
                         placeholder={
-                            StrListCast(this.targetDoc._docFilters)
+                            StrListCast(this.targetDoc._childFilters)
                                 .find(filter => filter.split(':')[0] === facetHeader)
                                 ?.split(':')[1] ?? '-empty-'
                         }
@@ -218,7 +218,7 @@ export class FilterPanel extends React.Component<filterProps> {
                             <input
                                 style={{ width: 20, marginLeft: 20 }}
                                 checked={
-                                    StrListCast(this.targetDoc._docFilters)
+                                    StrListCast(this.targetDoc._childFilters)
                                         .find(filter => filter.split(':')[0] === facetHeader && filter.split(':')[1] == facetValue)
                                         ?.split(':')[2] === 'check'
                                 }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 141e99c66..0951bff22 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -140,7 +140,7 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 title: 'buttons',
                 _layout_autoHeight: true,
                 _yMargin: 5,
-                linearViewIsExpanded: true,
+                linearView_IsExpanded: true,
                 backgroundColor: 'white',
                 isSystem: true,
             });
@@ -148,7 +148,7 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 _width: 300,
                 _height: 25,
                 _layout_autoHeight: true,
-                linearViewIsExpanded: true,
+                linearView_IsExpanded: true,
                 flexDirection: 'column',
                 isSystem: true,
             });
@@ -1013,8 +1013,8 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 focus={emptyFunction}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
-                docRangeFilters={returnEmptyFilter}
-                docFilters={returnEmptyFilter}
+                childFiltersByRanges={returnEmptyFilter}
+                childFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
             />
         );
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 1b309a6be..286d39943 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -43,7 +43,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
     @observable private static _layoutTemplateString: Opt<string>;
     @observable private static _doc: Opt<Doc>;
     @observable private static _docTarget: Opt<Doc>;
-    @observable private static _docFilters: string[] = []; // filters
+    @observable private static _childFilters: string[] = []; // filters
     private static _savedState: Opt<LightboxSavedState>;
     private static _history: Opt<{ doc: Doc; target?: Doc }[]> = [];
     @observable private static _future: Opt<Doc[]> = [];
@@ -58,7 +58,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             this.LightboxDoc.layout_fieldKey = this._savedState.layout_fieldKey;
         }
         if (!doc) {
-            this._docFilters && (this._docFilters.length = 0);
+            this._childFilters && (this._childFilters.length = 0);
             this._future = this._history = [];
             Doc.ActiveTool = InkTool.None;
             MainView.Instance._exploreMode = false;
@@ -134,7 +134,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
     @action
     public static SetCookie(cookie: string) {
         if (this.LightboxDoc && cookie) {
-            this._docFilters = (f => (this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f]))(`cookies:${cookie}:provide`);
+            this._childFilters = (f => (this._childFilters ? [this._childFilters.push(f) as any, this._childFilters][1] : [f]))(`cookies:${cookie}:provide`);
         }
     }
     public static AddDocTab = (doc: Doc, location: OpenWhere, layoutTemplate?: Doc | string) => {
@@ -148,7 +148,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             layoutTemplate
         );
     };
-    docFilters = () => LightboxView._docFilters || [];
+    childFilters = () => LightboxView._childFilters || [];
     addDocTab = LightboxView.AddDocTab;
     @action public static Next() {
         const doc = LightboxView._doc!;
@@ -261,8 +261,8 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             renderDepth={0}
                             rootSelected={returnTrue}
                             docViewPath={returnEmptyDoclist}
-                            docFilters={this.docFilters}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={this.childFilters}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                             addDocument={undefined}
                             removeDocument={undefined}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8e112dddb..b0e992cb6 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -608,8 +608,8 @@ export class MainView extends React.Component {
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>
@@ -637,8 +637,8 @@ export class MainView extends React.Component {
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     suppressSetHeight={true}
                     renderDepth={this._hideUI ? 0 : -1}
@@ -736,8 +736,8 @@ export class MainView extends React.Component {
                         focus={emptyFunction}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                     />
                 </div>
@@ -767,8 +767,8 @@ export class MainView extends React.Component {
                     isContentActive={returnTrue}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     scriptContext={this}
                 />
@@ -903,8 +903,8 @@ export class MainView extends React.Component {
                     renderDepth={0}
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
                 {['watching', 'recording'].includes(String(this.userDoc?.presentationMode) ?? '') ? <div style={{ border: '.5rem solid green', padding: '5px' }}>{StrCast(this.userDoc?.presentationMode)}</div> : <></>}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 6c36d39b9..a4a2c1df9 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -126,7 +126,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
                           if (!e.aborted && e.linkDocument) {
                               Doc.GetProto(e.linkDocument).link_relationship = 'cropped image';
                               Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView.rootDoc.title;
-                              Doc.GetProto(e.linkDocument).layout_linkDisplay = false;
+                              Doc.GetProto(e.linkDocument).link_displayLine = false;
                           }
                       },
                   });
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 59865cba3..339507f65 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -228,8 +228,8 @@ export class OverlayView extends React.Component {
                             docViewPath={returnEmptyDoclist}
                             addDocTab={DocumentViewInternal.addDocTabFunc}
                             pinToPres={emptyFunction}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                         />
                     </div>
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 3ad28c418..749eb08a2 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -56,8 +56,8 @@ export default class Palette extends React.Component<PaletteProps> {
                             styleProvider={returnEmptyString}
                             whenChildContentsActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                         />
                         <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 76828a576..11b89fd69 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -133,14 +133,14 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                     const containerDoc = dv.rootDoc;
                     //containerDoc.followAllLinks =
                     // containerDoc.noShadow =
-                    // containerDoc.disableDocBrushing =
+                    // containerDoc.layout_disableBrushing =
                     // containerDoc._forceActive =
                     //containerDoc._freeform_fitContentsToBox =
                     containerDoc._isLightbox = !containerDoc._isLightbox;
                     //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
                     const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
                     //dv.rootDoc.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
-                    containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false)));
+                    containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.link_displayLine = false)));
                 });
             }
         );
diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx
index 7b21629da..3e69bcba6 100644
--- a/src/client/views/PropertiesDocBacklinksSelector.tsx
+++ b/src/client/views/PropertiesDocBacklinksSelector.tsx
@@ -19,8 +19,8 @@ type PropertiesDocBacklinksSelectorProps = {
 @observer
 export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDocBacklinksSelectorProps> {
     getOnClick = (link: Doc) => {
-        const linkSource = this.props.Document;
-        const other = LinkManager.getOppositeAnchor(link, linkSource);
+        const linkAnchor = this.props.Document;
+        const other = LinkManager.getOppositeAnchor(link, linkAnchor);
         const otherdoc = !other ? undefined : other.annotationOn && other.type !== DocumentType.RTF ? Cast(other.annotationOn, Doc, null) : other;
 
         if (otherdoc) {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 00e077f96..1f2e21dd5 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -276,8 +276,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         PanelHeight={panelHeight}
                         focus={emptyFunction}
                         ScreenToLocalTransform={this.getTransform}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                         addDocument={returnFalse}
                         moveDocument={undefined}
@@ -941,26 +941,26 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     /**
-     * Updates this.filterDoc's currentFilter and saves the docFilters on the currentFilter
+     * Updates this.filterDoc's currentFilter and saves the childFilters on the currentFilter
      */
     updateFilterDoc = (doc: Doc) => {
         if (this.selectedDoc) {
             if (doc === this.selectedDoc.currentFilter) return; // causes problems if you try to reapply the same doc
-            const savedDocFilters = doc._docFiltersList;
-            const currentDocFilters = this.selectedDoc._docFilters;
-            this.selectedDoc._docFilters = new List<string>();
-            (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters;
+            const savedDocFilters = doc._childFiltersList;
+            const currentDocFilters = this.selectedDoc._childFilters;
+            this.selectedDoc._childFilters = new List<string>();
+            (this.selectedDoc.currentFilter as Doc)._childFiltersList = currentDocFilters;
             this.selectedDoc.currentFilter = doc;
-            doc._docFiltersList = new List<string>();
-            this.selectedDoc._docFilters = savedDocFilters;
+            doc._childFiltersList = new List<string>();
+            this.selectedDoc._childFilters = savedDocFilters;
 
-            const savedDocRangeFilters = doc._docRangeFiltersList;
-            const currentDocRangeFilters = this.selectedDoc._docRangeFilters;
-            this.selectedDoc._docRangeFilters = new List<string>();
-            (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters;
+            const savedDocRangeFilters = doc._childFiltersByRangesList;
+            const currentDocRangeFilters = this.selectedDoc._childFiltersByRanges;
+            this.selectedDoc._childFiltersByRanges = new List<string>();
+            (this.selectedDoc.currentFilter as Doc)._childFiltersByRangesList = currentDocRangeFilters;
             this.selectedDoc.currentFilter = doc;
-            doc._docRangeFiltersList = new List<string>();
-            this.selectedDoc._docRangeFilters = savedDocRangeFilters;
+            doc._childFiltersByRangesList = new List<string>();
+            this.selectedDoc._childFiltersByRanges = savedDocRangeFilters;
         }
     };
 
@@ -1117,7 +1117,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             Doc.GetProto(LinkManager.currentLink).link_relationship = value;
             const linkRelationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
             const linkRelationshipSizes = NumListCast(Doc.UserDoc().link_relationshipSizes);
-            const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
+            const linkColorList = StrListCast(Doc.UserDoc().link_ColorList);
 
             // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color
             if (!linkRelationshipList?.includes(value)) {
@@ -1328,8 +1328,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline">
                                         <p>Show link</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.layout_linkDisplay ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_linkDisplay')}
+                                            style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
@@ -1338,8 +1338,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
                                         <p>Auto-move anchors</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.layout_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_autoMoveAnchors')}
+                                            style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
@@ -1348,8 +1348,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
                                         <p>Display arrow</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.layout_linkDisplayArrow ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_linkDisplayArrow')}
+                                            style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 498e2ccba..db273cc88 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -63,11 +63,11 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         return Array.from(keys.keys()).sort();
     }
     get filtersKey() {
-        return '_' + this.sidebarKey + '_docFilters';
+        return '_' + this.sidebarKey + '_childFilters';
     }
 
     anchorMenuClick = (anchor: Doc) => {
-        const startup = StrListCast(this.props.rootDoc.docFilters)
+        const startup = StrListCast(this.props.rootDoc.childFilters)
             .map(filter => filter.split(':')[0])
             .join(' ');
         const target = Docs.Create.TextDocument(startup, {
@@ -83,9 +83,9 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         FormattedTextBox.SelectOnLoad = target[Id];
         FormattedTextBox.DontSelectInitialText = true;
         const link = DocUtils.MakeLink(anchor, target, { link_relationship: 'inline comment:comment on' });
-        link && (link.layout_linkDisplay = false);
+        link && (link.link_displayLine = false);
 
-        const taggedContent = this.docFilters()
+        const taggedContent = this.childFilters()
             .filter(data => data.split(':')[0])
             .map(data => {
                 const key = data.split(':')[0];
@@ -177,7 +177,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     addDocument = (doc: Doc | Doc[]) => this.props.sidebarAddDocument(doc, this.sidebarKey);
     moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(doc, targetCollection, addDocument, this.sidebarKey);
     removeDocument = (doc: Doc | Doc[]) => this.props.removeDocument(doc, this.sidebarKey);
-    docFilters = () => [...StrListCast(this.props.layoutDoc._docFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])];
+    childFilters = () => [...StrListCast(this.props.layoutDoc._childFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])];
     layout_showTitle = () => 'title';
     setHeightCallback = (height: number) => this.props.setHeight?.(height + this.filtersHeight());
     sortByLinkAnchorY = (a: Doc, b: Doc) => {
@@ -238,7 +238,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                         ref={this._stackRef}
                         PanelHeight={this.panelHeight}
                         PanelWidth={this.panelWidth}
-                        docFilters={this.docFilters}
+                        childFilters={this.childFilters}
                         sortFunc={this.sortByLinkAnchorY}
                         setHeight={this.setHeightCallback}
                         isAnnotationOverlay={false}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index cf0177f4b..9199bf931 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -115,7 +115,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             allSorts[TreeSort.None] = { color: 'darkgray', label: '\u00A0\u00A0\u00A0' };
             return allSorts;
         case StyleProp.Highlighting:
-            if (doc && !doc.disableDocBrushing && !props?.disableDocBrushing) {
+            if (doc && !doc.layout_disableBrushing && !props?.disableBrushing) {
                 const selected = SelectionManager.Views().some(dv => dv.rootDoc === doc);
                 const highlightIndex = Doc.isBrushedHighlightedDegree(doc) || (selected ? Doc.DocBrushStatus.selfBrushed : 0);
                 const highlightColor = ['transparent', 'rgb(68, 118, 247)', selected ? 'black' : 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex];
@@ -166,7 +166,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             if (!backColor) return undefined;
             return lightOrDark(backColor);
         case StyleProp.BorderRounding:
-            return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : ''));
+            return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : ''));
         case StyleProp.BorderPath:
             const borderPath = Doc.IsComicStyle(doc) &&
                 props?.renderDepth &&
@@ -235,38 +235,37 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         }
         case StyleProp.BoxShadow: {
             if (!doc || opacity() === 0 || doc.noShadow) return undefined; // if it's not visible, then no shadow)
-            if (doc.boxShadow === 'standard') return Shadows.STANDARD_SHADOW;
+            if (doc.layout_boxShadow === 'standard') return Shadows.STANDARD_SHADOW;
             if (IsFollowLinkScript(doc?.onClick) && LinkManager.Links(doc).length && ![DocumentType.LINK, DocumentType.INK].includes(doc.type as any)) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em');
             switch (doc?.type) {
                 case DocumentType.COL:
                     return StrCast(
-                        doc?.boxShadow,
+                        doc?.layout_borderRounding,
                         doc?._type_collection === CollectionViewType.Pile
                             ? '4px 4px 10px 2px'
                             : lockedPosition() || doc?._isGroup || docProps?.LayoutTemplateString
                             ? undefined // groups have no drop shadow -- they're supposed to be "invisible".  LayoutString's imply collection is being rendered as something else (e.g., title of a Slide)
-                            : `${darkScheme() ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY} ${StrCast(doc.boxShadow, '0.2vw 0.2vw 0.8vw')}`
+                            : `${darkScheme() ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY} ${StrCast(doc.layout_borderRounding, '0.2vw 0.2vw 0.8vw')}`
                     );
 
                 case DocumentType.LABEL:
                     if (doc?.annotationOn !== undefined) return 'black 2px 2px 1px';
                 default:
                     return doc.z
-                        ? `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
+                        ? `#9c9396  ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
                         : props?.docViewPath().lastElement()?.rootDoc._freeform_useClusters
-                        ? `${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                        ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : NumCast(doc.group, -1) !== -1
-                        ? `gray ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                        ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : lockedPosition()
                         ? undefined // if it's a background & has a cluster color, make the shadow spread really big
-                        : StrCast(doc.boxShadow, '');
+                        : StrCast(doc.layout_boxShadow, '');
             }
         }
         case StyleProp.PointerEvents:
             const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name) && !props?.LayoutTemplateString;
             if (docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.() !== undefined) return docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.();
             if (MainView.Instance._exploreMode || doc?.layout_unrendered) return isInk ? 'visiblePainted' : 'all';
-            if (doc?.pointerEvents) return StrCast(doc.pointerEvents);
             if (props?.contentPointerEvents) return StrCast(props.contentPointerEvents);
             if (props?.pointerEvents?.() === 'none') return 'none';
             if (opacity() === 0) return 'none';
@@ -284,9 +283,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             };
             const filter = () => {
                 const showFilterIcon =
-                    StrListCast(doc?._docFilters).length || StrListCast(doc?._docRangeFilters).length
+                    StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length
                         ? '#18c718bd' //'hasFilter'
-                        : docProps?.docFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragsDocFilter).length || docProps?.docRangeFilters().length
+                        : docProps?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragsDocFilter).length || docProps?.childFiltersByRanges().length
                         ? 'orange' //'inheritsFilter'
                         : undefined;
                 return !showFilterIcon ? null : (
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 814a95ab8..62f47ba71 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -116,8 +116,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                     styleProvider={DefaultStyleProvider}
                     setHeight={returnFalse}
                     docViewPath={returnEmptyDoclist}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     rootSelected={returnFalse}
                     onCheckedClick={this.scriptField}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index dc430667b..fc3f713ce 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -130,8 +130,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                     renderDepth={0}
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>
@@ -277,16 +277,16 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
     _saveFilterCommand = {
         params: ['target'],
         title: 'save filter',
-        script: `self.target._docFilters = compareLists(self['target-docFilters'],self.target._docFilters) ? undefined : copyField(self['target-docFilters']); 
+        script: `self.target._childFilters = compareLists(self['target-childFilters'],self.target._childFilters) ? undefined : copyField(self['target-childFilters']); 
                  self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`,
         immediate: undoBatch((source: Doc[]) => {
-            this.target._docFilters = undefined;
+            this.target._childFilters = undefined;
             this.target._searchFilterDocs = undefined;
         }),
         initialize: (button: Doc) => {
             const activeDash = Doc.ActiveDashboard;
             if (activeDash) {
-                button['target-docFilters'] = (Doc.MySearcher._docFilters || activeDash._docFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._docFilters || activeDash._docFilters) as any as ObjectField) : undefined;
+                button['target-childFilters'] = (Doc.MySearcher._childFilters || activeDash._childFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._childFilters || activeDash._childFilters) as any as ObjectField) : undefined;
                 button['target-searchFilterDocs'] = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs as any as ObjectField) : undefined;
             }
         },
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index fc265e2b9..675f23970 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -201,13 +201,17 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     };
 
     styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => {
-        if (property === StyleProp.BoxShadow && doc && DragManager.docsBeingDragged.includes(doc)) {
-            return `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}`;
-        }
-        if (property === StyleProp.Opacity && doc) {
-            if (this.props.childOpacity) {
-                return this.props.childOpacity();
-            }
+        switch (property) {
+            case StyleProp.BoxShadow:
+                if (doc && DragManager.docsBeingDragged.includes(doc)) {
+                    return `#9c9396 ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}`;
+                }
+                break;
+            case StyleProp.Opacity:
+                if (doc && this.props.childOpacity) {
+                    return this.props.childOpacity();
+                }
+                break;
         }
         return this.props.styleProvider?.(doc, props, property);
     };
@@ -251,11 +255,11 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={noteTakingDocTransform}
                 focus={this.focusDocument}
-                docFilters={this.childDocFilters}
+                childFilters={this.childDocFilters}
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 hideResizeHandles={this.props.childHideResizeHandles?.()}
                 hideTitle={this.props.childHideTitle?.()}
-                docRangeFilters={this.childDocRangeFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
@@ -603,42 +607,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         return eles;
     }
 
-    @computed get buttonMenu() {
-        const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
-        if (menuDoc) {
-            const width = NumCast(menuDoc._width, 30);
-            const height = NumCast(menuDoc._height, 30);
-            return (
-                <div className="buttonMenu-docBtn" style={{ width, height }}>
-                    <DocumentView
-                        Document={menuDoc}
-                        DataDoc={menuDoc}
-                        isContentActive={this.props.isContentActive}
-                        isDocumentActive={returnTrue}
-                        addDocument={this.props.addDocument}
-                        moveDocument={this.props.moveDocument}
-                        addDocTab={this.props.addDocTab}
-                        pinToPres={emptyFunction}
-                        rootSelected={this.props.isSelected}
-                        removeDocument={this.props.removeDocument}
-                        ScreenToLocalTransform={Transform.Identity}
-                        PanelWidth={() => 35}
-                        PanelHeight={() => 35}
-                        renderDepth={this.props.renderDepth}
-                        focus={emptyFunction}
-                        styleProvider={this.props.styleProvider}
-                        docViewPath={returnEmptyDoclist}
-                        whenChildContentsActiveChanged={emptyFunction}
-                        bringToFront={emptyFunction}
-                        docFilters={this.props.docFilters}
-                        docRangeFilters={this.props.docRangeFilters}
-                        searchFilterDocs={this.props.searchFilterDocs}
-                    />
-                </div>
-            );
-        }
-    }
-
     @computed get nativeWidth() {
         return Doc.NativeWidth(this.layoutDoc);
     }
@@ -658,35 +626,25 @@ export class CollectionNoteTakingView extends CollectionSubView() {
 
     render() {
         TraceMobx();
-        const buttonMenu = this.rootDoc.buttonMenu;
-        const noviceExplainer = StrCast(this.rootDoc.explainer);
         return (
-            <>
-                {buttonMenu || noviceExplainer ? (
-                    <div className="documentButtonMenu" key="buttons">
-                        {buttonMenu ? this.buttonMenu : null}
-                        {Doc.UserDoc().noviceMode && noviceExplainer ? <div className="documentExplanation">{noviceExplainer}</div> : null}
-                    </div>
-                ) : null}
-                <div
-                    className="collectionNoteTakingView"
-                    ref={this.createRef}
-                    key="notes"
-                    style={{
-                        overflowY: this.props.isContentActive() ? 'auto' : 'hidden',
-                        background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
-                        pointerEvents: this.backgroundEvents ? 'all' : undefined,
-                    }}
-                    onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
-                    onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))}
-                    onPointerMove={e => e.buttons && this.onPointerMove(false, e.clientX, e.clientY)}
-                    onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)}
-                    onDrop={this.onExternalDrop.bind(this)}
-                    onContextMenu={this.onContextMenu}
-                    onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}>
-                    {this.renderedSections}
-                </div>
-            </>
+            <div
+                className="collectionNoteTakingView"
+                ref={this.createRef}
+                key="notes"
+                style={{
+                    overflowY: this.props.isContentActive() ? 'auto' : 'hidden',
+                    background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
+                    pointerEvents: this.backgroundEvents ? 'all' : undefined,
+                }}
+                onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
+                onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))}
+                onPointerMove={e => e.buttons && this.onPointerMove(false, e.clientX, e.clientY)}
+                onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)}
+                onDrop={this.onExternalDrop.bind(this)}
+                onContextMenu={this.onContextMenu}
+                onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}>
+                {this.renderedSections}
+            </div>
         );
     }
 }
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index bbc91aa6e..57d9bbb49 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -23,7 +23,7 @@ export class CollectionPileView extends CollectionSubView() {
 
     componentDidMount() {
         if (this.layoutEngine() !== computePassLayout.name && this.layoutEngine() !== computeStarburstLayout.name) {
-            this.Document._pileLayoutEngine = computePassLayout.name;
+            this.Document._freeform_pileEngine = computePassLayout.name;
         }
         this._originalChrome = this.layoutDoc._chromeHidden;
         this.layoutDoc._chromeHidden = true;
@@ -33,7 +33,7 @@ export class CollectionPileView extends CollectionSubView() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
-    layoutEngine = () => StrCast(this.Document._pileLayoutEngine);
+    layoutEngine = () => StrCast(this.Document._freeform_pileEngine);
 
     @undoBatch
     addPileDoc = (doc: Doc | Doc[]) => {
@@ -73,28 +73,29 @@ export class CollectionPileView extends CollectionSubView() {
 
     // toggles the pileup between starburst to compact
     toggleStarburst = action(() => {
+        this.layoutDoc._freeform_scale = undefined;
         if (this.layoutEngine() === computeStarburstLayout.name) {
             if (this.rootDoc[Width]() !== NumCast(this.rootDoc._starburstDiameter, 500)) {
                 this.rootDoc._starburstDiameter = this.rootDoc[Width]();
             }
             const defaultSize = 110;
-            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2;
-            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2;
-            this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize);
-            this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize);
+            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2;
+            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2;
+            this.layoutDoc._width = NumCast(this.layoutDoc._freeform_pileWidth, defaultSize);
+            this.layoutDoc._height = NumCast(this.layoutDoc._freeform_pileHeight, defaultSize);
             DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false);
             this.layoutDoc._freeform_panX = 0;
             this.layoutDoc._freeform_panY = -10;
-            this.props.Document._pileLayoutEngine = computePassLayout.name;
+            this.props.Document._freeform_pileEngine = computePassLayout.name;
         } else {
             const defaultSize = NumCast(this.rootDoc._starburstDiameter, 500);
             this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - defaultSize / 2;
             this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - defaultSize / 2;
-            this.layoutDoc._starburstPileWidth = this.layoutDoc[Width]();
-            this.layoutDoc._starburstPileHeight = this.layoutDoc[Height]();
+            this.layoutDoc._freeform_pileWidth = this.layoutDoc[Width]();
+            this.layoutDoc._freeform_pileHeight = this.layoutDoc[Height]();
             this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0;
             this.layoutDoc._width = this.layoutDoc._height = defaultSize;
-            this.props.Document._pileLayoutEngine = computeStarburstLayout.name;
+            this.props.Document._freeform_pileEngine = computeStarburstLayout.name;
         }
     });
 
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index b131d38d8..9d5cb257a 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -404,15 +404,15 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
             docAnchor ??
             Docs.Create.LabelDocument({
                 title: ComputedField.MakeFunction(`self["${endTag}"] ? "#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"]) : "#" + formatToTime(self["${startTag}"])`) as any,
-                _minFontSize: 12,
-                _maxFontSize: 24,
+                _label_minFontSize: 12,
+                _label_maxFontSize: 24,
                 _stayInCollection: true,
                 backgroundColor: 'rgba(128, 128, 128, 0.5)',
                 layout_hideLinkButton: true,
                 onClick: FollowLinkScript(),
                 annotationOn: rootDoc,
-                _timelineLabel: true,
-                borderRounding: anchorEndTime === undefined ? '100%' : undefined,
+                _isTimelineLabel: true,
+                layout_borderRounding: anchorEndTime === undefined ? '100%' : undefined,
             });
         Doc.GetProto(anchor)[startTag] = anchorStartTime;
         Doc.GetProto(anchor)[endTag] = anchorEndTime;
@@ -752,7 +752,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
             if (timelineOnly) {
                 if (!left && time !== undefined && time <= NumCast(anchor[this.props.startTag])) time = undefined;
                 Doc.SetInPlace(anchor, left ? this.props.startTag : this.props.endTag, time, true);
-                if (!left) Doc.SetInPlace(anchor, 'borderRounding', time !== undefined ? undefined : '100%', true);
+                if (!left) Doc.SetInPlace(anchor, 'layout_borderRounding', time !== undefined ? undefined : '100%', true);
             } else {
                 anchor[left ? '_timecodeToShow' : '_timecodeToHide'] = time;
             }
@@ -820,8 +820,8 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     focus={focusFunc}
                     isContentActive={returnFalse}
                     searchFilterDocs={returnEmptyDoclist}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     rootSelected={returnFalse}
                     onClick={script}
                     onDoubleClick={this.props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 56f53afe6..3c0d8cbc3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -346,11 +346,11 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={stackedDocTransform}
                 focus={this.focusDocument}
-                docFilters={this.childDocFilters}
+                childFilters={this.childDocFilters}
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 hideResizeHandles={this.props.childHideResizeHandles?.()}
                 hideTitle={this.props.childHideTitle?.()}
-                docRangeFilters={this.childDocRangeFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 xPadding={NumCast(this.layoutDoc._childXPadding, this.props.childXPadding)}
                 yPadding={NumCast(this.layoutDoc._childYPadding, this.props.childYPadding)}
@@ -650,7 +650,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
 
     return35 = () => 35;
     @computed get buttonMenu() {
-        const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
+        const menuDoc: Doc = Cast(this.rootDoc.layout_headerButton, Doc, null);
         // TODO:glr Allow support for multiple buttons
         if (menuDoc) {
             const width: number = NumCast(menuDoc._width, 30);
@@ -679,8 +679,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        docFilters={this.props.docFilters}
-                        docRangeFilters={this.props.docRangeFilters}
+                        childFilters={this.props.childFilters}
+                        childFiltersByRanges={this.props.childFiltersByRanges}
                         searchFilterDocs={this.props.searchFilterDocs}
                     />
                 </div>
@@ -711,7 +711,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             contents: '+ ADD A GROUP',
         };
         const buttonMenu = this.rootDoc.buttonMenu;
-        const noviceExplainer = this.rootDoc.explainer;
+        const noviceExplainer = this.rootDoc.layout_explainer;
         return (
             <>
                 {buttonMenu || noviceExplainer ? (
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 967d1d40e..d1b7f6ff6 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -28,8 +28,8 @@ export function CollectionSubView<X>(moreProps?: X) {
         private gestureDisposer?: GestureUtils.GestureEventDisposer;
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
         protected _mainCont?: HTMLDivElement;
-        @observable _focusFilters: Opt<string[]>; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it
-        @observable _focusRangeFilters: Opt<string[]>; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it
+        @observable _focusFilters: Opt<string[]>; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it
+        @observable _focusRangeFilters: Opt<string[]>; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it
         protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
             //used for stacking and masonry view
             this.dropDisposer?.();
@@ -81,13 +81,13 @@ export function CollectionSubView<X>(moreProps?: X) {
         get childDocList() {
             return Cast(this.dataField, listSpec(Doc));
         }
-        collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._docFilters);
-        collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec('string'), []);
+        collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._childFilters);
+        collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._childFiltersByRanges, listSpec('string'), []);
         // child filters apply to the descendants of the documents in this collection
-        childDocFilters = () => [...(this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
+        childDocFilters = () => [...(this.props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
         // unrecursive filters apply to the documents in the collection, but no their children.  See Utils.noRecursionHack
-        unrecursiveDocFilters = () => [...(this.props.docFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
-        childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
+        unrecursiveDocFilters = () => [...(this.props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
+        childDocRangeFilters = () => [...(this.props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()];
         searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
         @computed.struct get childDocs() {
             TraceMobx();
@@ -109,20 +109,20 @@ export function CollectionSubView<X>(moreProps?: X) {
             const childDocs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this.props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc);
 
             const childDocFilters = this.childDocFilters();
-            const docRangeFilters = this.childDocRangeFilters();
+            const childFiltersByRanges = this.childDocRangeFilters();
             const searchDocs = this.searchFilterDocs();
-            if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !docRangeFilters.length && !searchDocs.length)) {
+            if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) {
                 return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
             }
 
             const docsforFilter: Doc[] = [];
             childDocs.forEach(d => {
                 // dragging facets
-                const dragged = this.props.docFilters?.().some(f => f.includes(Utils.noDragsDocFilter));
+                const dragged = this.props.childFilters?.().some(f => f.includes(Utils.noDragsDocFilter));
                 if (dragged && DragManager.docsBeingDragged.includes(d)) return false;
-                let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), docRangeFilters, this.props.Document).length > 0;
+                let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.props.Document).length > 0;
                 if (notFiltered) {
-                    notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, this.props.Document).length > 0;
+                    notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.props.Document).length > 0;
                     const fieldKey = Doc.LayoutFieldKey(d);
                     const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name);
                     const data = d[annos ? fieldKey + '_annotations' : fieldKey];
@@ -131,13 +131,14 @@ export function CollectionSubView<X>(moreProps?: X) {
                         let subDocs = [...DocListCast(data), ...DocListCast(side)];
                         if (subDocs.length > 0) {
                             let newarray: Doc[] = [];
-                            notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, docRangeFilters, d).length);
+                            notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, childFiltersByRanges, d).length);
                             while (subDocs.length > 0 && !notFiltered) {
                                 newarray = [];
                                 subDocs.forEach(t => {
                                     const fieldKey = Doc.LayoutFieldKey(t);
                                     const annos = !Field.toString(Doc.LayoutField(t) as Field).includes(CollectionView.name);
-                                    notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, d).length));
+                                    notFiltered =
+                                        notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !childFiltersByRanges.length) || DocUtils.FilterDocs([t], childDocFilters, childFiltersByRanges, d).length));
                                     DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
                                     annos && DocListCast(t[fieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc));
                                 });
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 49a90d828..60e6815e5 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -125,8 +125,8 @@ export class CollectionTimeView extends CollectionSubView() {
 
     goTo = (prevFilterIndex: number) => {
         this.layoutDoc._pivotField = this.layoutDoc['_prevPivotFields' + prevFilterIndex];
-        this.layoutDoc._docFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField);
-        this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField);
+        this.layoutDoc._childFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField);
+        this.layoutDoc._childFiltersByRanges = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField);
         this.layoutDoc._prevFilterIndex = prevFilterIndex;
     };
 
@@ -136,7 +136,7 @@ export class CollectionTimeView extends CollectionSubView() {
         if (prevFilterIndex > 0) {
             this.goTo(prevFilterIndex - 1);
         } else {
-            this.layoutDoc._docFilters = new List([]);
+            this.layoutDoc._childFilters = new List([]);
         }
     };
 
@@ -145,7 +145,7 @@ export class CollectionTimeView extends CollectionSubView() {
             <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.isContentActive() ? undefined : 'none' }} onClick={this.contentsDown}>
                 <CollectionFreeFormView
                     {...this.props}
-                    engineProps={{ pivotField: this.pivotField, docFilters: this.childDocFilters, docRangeFilters: this.childDocRangeFilters }}
+                    engineProps={{ pivotField: this.pivotField, childFilters: this.childDocFilters, childFiltersByRanges: this.childDocRangeFilters }}
                     fitContentsToBox={returnTrue}
                     childClickScript={this._childClickedScript}
                     viewDefDivClick={this.layoutEngine() === computeTimelineLayout.name ? undefined : this._viewDefDivClick}
@@ -276,12 +276,12 @@ export class CollectionTimeView extends CollectionSubView() {
 ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
     const pivotField = StrCast(pivotDoc._pivotField, 'author');
     let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex);
-    const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField));
-    pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField);
-    pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField);
+    const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField));
+    pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField);
+    pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFiltersByRanges as ObjectField);
     pivotDoc['_prevPivotFields' + prevFilterIndex] = pivotField;
     pivotDoc._prevFilterIndex = ++prevFilterIndex;
-    pivotDoc._docFilters = new List();
+    pivotDoc._childFilters = new List();
     setTimeout(
         action(() => {
             const filterVals = bounds.payload as string[];
@@ -292,7 +292,7 @@ ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBou
                     pivotDoc._pivotField = filterVals[0];
                 }
             }
-            const newFilters = StrListCast(pivotDoc._docFilters);
+            const newFilters = StrListCast(pivotDoc._childFilters);
             if (newFilters.length && originalFilter.length && newFilters.lastElement() === originalFilter.lastElement()) {
                 pivotDoc._prevFilterIndex = --prevFilterIndex;
                 pivotDoc['_prevDocFilter' + prevFilterIndex] = undefined;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 969658238..ed1e0c067 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -240,8 +240,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 PanelHeight={this.documentTitleHeight}
                 NativeDimScaling={returnOne}
                 onKey={this.onKey}
-                docFilters={returnEmptyFilter}
-                docRangeFilters={returnEmptyFilter}
+                childFilters={returnEmptyFilter}
+                childFiltersByRanges={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 addDocument={returnFalse}
                 moveDocument={returnFalse}
@@ -314,12 +314,12 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     }
 
     @computed get noviceExplainer() {
-        return !Doc.noviceMode || !this.rootDoc.explainer ? null : <div className="documentExplanation"> {StrCast(this.rootDoc.explainer)} </div>;
+        return !Doc.noviceMode || !this.rootDoc.layout_explainer ? null : <div className="documentExplanation"> {StrCast(this.rootDoc.layout_explainer)} </div>;
     }
 
     return35 = () => 35;
     @computed get buttonMenu() {
-        const menuDoc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
+        const menuDoc = Cast(this.rootDoc.layout_headerButton, Doc, null);
         // To create a multibutton menu add a CollectionLinearView
         return !menuDoc ? null : (
             <div className="buttonMenu-docBtn" style={{ width: NumCast(menuDoc._width, 30), height: NumCast(menuDoc._height, 30) }}>
@@ -343,8 +343,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
+                    childFilters={this.props.childFilters}
+                    childFiltersByRanges={this.props.childFiltersByRanges}
                     searchFilterDocs={this.props.searchFilterDocs}
                 />
             </div>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 710e33b1c..75e4e8abf 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -432,8 +432,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     PanelWidth={this.PanelWidth}
                     PanelHeight={this.PanelHeight}
                     styleProvider={DefaultStyleProvider}
-                    docFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
-                    docRangeFilters={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
+                    childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
+                    childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
                     searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
                     addDocument={undefined}
                     removeDocument={this.remDocTab}
@@ -602,8 +602,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     styleProvider={TabMinimapView.miniStyleProvider}
                     addDocTab={this.props.addDocTab}
                     pinToPres={TabDocView.PinDoc}
-                    docFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
-                    docRangeFilters={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
+                    childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
+                    childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
                     searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
                     fitContentsToBox={returnTrue}
                 />
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ca9471f6f..9039875c1 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -119,7 +119,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return 'TreeView(' + this.props.document.title + ')';
     } // this makes mobx trace() statements more descriptive
     get defaultExpandedView() {
-        return this.doc.type_collection === CollectionViewType.Docking
+        return this.doc._type_collection === CollectionViewType.Docking
             ? this.fieldKey
             : this.props.treeView.dashboardMode
             ? this.fieldKey
@@ -388,7 +388,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         };
         const addDoc = inside ? localAdd : parentAddDoc;
         const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument;
-        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.freezeChildren).includes('add')) || forceAdd;
+        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeViewFreezeChildren).includes('add')) || forceAdd;
         if (canAdd) {
             this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
             const res = UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false));
@@ -714,7 +714,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const data = () => (this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : '');
         const embeddings = () => (this.props.treeView.dashboardMode ? '' : 'embeddings');
         const fields = () => (Doc.noviceMode ? '' : 'fields');
-        const layout = Doc.noviceMode || this.doc.type_collection === CollectionViewType.Docking ? [] : ['layout'];
+        const layout = Doc.noviceMode || this.doc._type_collection === CollectionViewType.Docking ? [] : ['layout'];
         return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [embeddings(), links(), annos()] : []), fields()].filter(m => m);
     }
     @action
@@ -732,7 +732,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : (
             <>
                 {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */}
-                {this.doc.hideContextMenu ? null : (
+                {this.doc._layout_hideContextMenu ? null : (
                     <FontAwesomeIcon
                         title="context menu"
                         key="bars"
@@ -772,7 +772,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 ? []
                 : this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc)
                 ? [openEmbedding, makeFolder]
-                : this.doc.type_collection === CollectionViewType.Docking
+                : this.doc._type_collection === CollectionViewType.Docking
                 ? []
                 : [deleteItem, openEmbedding, focusDoc]),
         ];
@@ -930,13 +930,13 @@ export class TreeView extends React.Component<TreeViewProps> {
                 focus={this.refocus}
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                 bringToFront={emptyFunction}
-                disableDocBrushing={this.props.treeView.props.disableDocBrushing}
+                disableBrushing={this.props.treeView.props.disableBrushing}
                 hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
                 dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
                 xPadding={NumCast(this.props.treeView.props.Document.childXPadding, this.props.treeView.props.childXPadding)}
                 yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)}
-                docFilters={returnEmptyFilter}
-                docRangeFilters={returnEmptyFilter}
+                childFilters={returnEmptyFilter}
+                childFiltersByRanges={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
             />
         );
@@ -1010,8 +1010,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                     treeViewDoc={this.props.treeView?.props.Document}
                     rootSelected={returnTrue}
                     docViewPath={this.props.treeView.props.docViewPath}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     addDocument={this.props.addDocument}
                     moveDocument={this.move}
@@ -1021,7 +1021,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)}
                     addDocTab={this.props.addDocTab}
                     pinToPres={this.props.treeView.props.pinToPres}
-                    disableDocBrushing={this.props.treeView.props.disableDocBrushing}
+                    disableBrushing={this.props.treeView.props.disableBrushing}
                     bringToFront={returnFalse}
                     scriptContext={this}
                 />
@@ -1211,7 +1211,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         onCheckedClick={onCheckedClick}
                         onChildClick={onChildClick}
                         renderDepth={renderDepth}
-                        removeDoc={StrCast(treeViewParent.freezeChildren).includes('remove') ? undefined : remove}
+                        removeDoc={StrCast(treeViewParent.treeViewFreezeChildren).includes('remove') ? undefined : remove}
                         addDocument={addDocument}
                         styleProvider={styleProvider}
                         panelWidth={rowWidth}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 6202dcacc..f1d98d22a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -59,7 +59,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             0
         ); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
         setTimeout(
-            action(() => (!LinkDocs.length || !linkDoc.layout_linkDisplay) && (this._opacity = 0.05)),
+            action(() => (!LinkDocs.length || !linkDoc.link_displayLine) && (this._opacity = 0.05)),
             750
         ); // this will unhighlight the link line.
         const a = A.ContentDiv.getBoundingClientRect();
@@ -77,7 +77,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const targetBhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.link_anchor_2 as Doc)[Id])).lastElement();
         if ((!targetAhyperlink && !a.width) || (!targetBhyperlink && !b.width)) return;
         if (!targetAhyperlink) {
-            if (linkDoc.layout_autoMoveAnchors) {
+            if (linkDoc.link_autoMoveAnchors) {
                 linkDoc.link_anchor_1_x = ((apt.point.x - aleft) / awidth) * 100;
                 linkDoc.link_anchor_1_y = ((apt.point.y - atop) / aheight) * 100;
             }
@@ -92,7 +92,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             else linkDoc.opacity = 1;
         }
         if (!targetBhyperlink) {
-            if (linkDoc.layout_autoMoveAnchors) {
+            if (linkDoc.link_autoMoveAnchors) {
                 linkDoc.link_anchor_2_x = ((bpt.point.x - bleft) / bwidth) * 100;
                 linkDoc.link_anchor_2_y = ((bpt.point.y - btop) / bheight) * 100;
             }
@@ -247,7 +247,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
         const linkRelationship = Field.toString(link?.link_relationship as any as Field); //get string representing relationship
         const linkRelationshipList = Doc.UserDoc().link_relationshipList as List<string>;
-        const linkColorList = Doc.UserDoc().linkColorList as List<string>;
+        const linkColorList = Doc.UserDoc().link_ColorList as List<string>;
         const linkRelationshipSizes = Doc.UserDoc().link_relationshipSizes as List<number>;
         const currRelationshipIndex = linkRelationshipList.indexOf(linkRelationship);
         const linkDescription = Field.toString(link.link_description as any as Field);
@@ -262,11 +262,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         //thickness varies linearly from 3px to 12px for increasing link count
         const strokeWidth = linkSize === -1 ? '3px' : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + 'px';
 
-        if (link.layout_linkDisplayArrow === undefined) {
-            link.layout_linkDisplayArrow = false;
+        if (link.link_displayArrow === undefined) {
+            link.link_displayArrow = false;
         }
 
-        return link.opacity === 0 || !a.width || !b.width || (!link.layout_linkDisplay && !aActive && !bActive) ? null : (
+        return link.opacity === 0 || !a.width || !b.width || (!link.link_displayLine && !aActive && !bActive) ? null : (
             <>
                 <defs>
                     <marker id={`${link[Id] + 'arrowhead'}`} markerWidth="4" markerHeight="3" refX="0" refY="1.5" orient="auto">
@@ -295,7 +295,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
                     style={{ pointerEvents: 'visibleStroke', opacity: this._opacity, stroke, strokeWidth }}
                     onClick={this.onClickLine}
                     d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`}
-                    markerEnd={link.layout_linkDisplayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
+                    markerEnd={link.link_displayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
                 />
                 {textX === undefined || !linkDescription ? null : (
                     <text filter={`url(#${link[Id] + 'background'})`} className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown}>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 811a77fa8..11151e74e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1021,7 +1021,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     zoom = (pointX: number, pointY: number, deltaY: number): void => {
-        if (this.Document._isGroup) return;
+        if (this.Document._isGroup || this.Document._freeform_noZoom) return;
         let deltaScale = deltaY > 0 ? 1 / 1.05 : 1.05;
         if (deltaScale < 0) deltaScale = -deltaScale;
         const [x, y] = this.getTransform().transformPoint(pointX, pointY);
@@ -1294,8 +1294,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 ScreenToLocalTransform={childLayout.z ? this.getContainerTransform : this.getTransform}
                 PanelWidth={childLayout[Width]}
                 PanelHeight={childLayout[Height]}
-                docFilters={this.childDocFilters}
-                docRangeFilters={this.childDocRangeFilters}
+                childFilters={this.childDocFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
                 isContentActive={this.props.childContentsActive ?? emptyFunction}
@@ -1317,7 +1317,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView}
                 pointerEvents={this.pointerEvents}
                 //rotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0}
-                //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
+                //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.treeViewFreezeChildDimensions)} // bcz: check this
             />
         );
     }
@@ -1692,7 +1692,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if ((e as any).handlePan || this.props.isAnnotationOverlay) return;
         (e as any).handlePan = true;
 
-        if (!this.layoutDoc._noAutoscroll && !this.props.renderDepth && this._marqueeRef) {
+        if (!this.layoutDoc._freeform_noAutoPan && !this.props.renderDepth && this._marqueeRef) {
             const dragX = e.detail.clientX;
             const dragY = e.detail.clientY;
             const bounds = this._marqueeRef?.getBoundingClientRect();
@@ -2007,8 +2007,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                             onKey={this.onKeyDown}
                             onDoubleClick={this.onChildDoubleClickHandler}
                             onBrowseClick={this.onBrowseClickHandler}
-                            docFilters={this.childDocFilters}
-                            docRangeFilters={this.childDocRangeFilters}
+                            childFilters={this.childDocFilters}
+                            childFiltersByRanges={this.childDocRangeFilters}
                             searchFilterDocs={this.searchFilterDocs}
                             isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
                             isContentActive={this.props.childContentsActive ?? emptyFunction}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index d50c8d2c4..534275610 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -522,7 +522,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             followLinkToggle: true,
             _width: 200,
             _height: 200,
-            _layoutFitContentsToBox: true,
+            _layout_fitContentsToBox: true,
             _layout_showSidebar: true,
             title: 'overview',
         });
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index ca6b8705d..65578f214 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -24,7 +24,7 @@ import './CollectionLinearView.scss';
 /**
  * CollectionLinearView is the class for rendering the horizontal collection
  * of documents, it useful for horizontal menus. It can either be expandable
- * or not using the linearViewExpandable field.
+ * or not using the linearView_Expandable field.
  * It is used in the following locations:
  * - It is used in the popup menu on the bottom left (see docButtons() in MainView.tsx)
  * - It is used for the context sensitive toolbar at the top (see contMenuButtons() in CollectionMenu.tsx)
@@ -46,7 +46,7 @@ export class CollectionLinearView extends CollectionSubView() {
 
     componentDidMount() {
         this._widthDisposer = reaction(
-            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0),
+            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0),
             width => this.childDocs.length && (this.layoutDoc._width = width),
             { fireImmediately: true }
         );
@@ -214,8 +214,8 @@ export class CollectionLinearView extends CollectionSubView() {
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
+                    childFilters={this.props.childFilters}
+                    childFiltersByRanges={this.props.childFiltersByRanges}
                     searchFilterDocs={this.props.searchFilterDocs}
                     hideResizeHandles={true}
                 />
@@ -226,7 +226,7 @@ export class CollectionLinearView extends CollectionSubView() {
     render() {
         const flexDir = StrCast(this.Document.flexDirection); // Specify direction of linear view content
         const flexGap = NumCast(this.Document.flexGap); // Specify the gap between linear view content
-        const isExpanded = BoolCast(this.layoutDoc.linearViewIsExpanded);
+        const isExpanded = BoolCast(this.layoutDoc.linearView_IsExpanded);
 
         const menuOpener = (
             <label
@@ -239,9 +239,9 @@ export class CollectionLinearView extends CollectionSubView() {
         );
 
         return (
-            <div className={`collectionLinearView-outer ${this.layoutDoc.linearViewSubMenu}`} style={{ backgroundColor: this.layoutDoc.linearViewIsExpanded ? undefined : 'transparent' }}>
+            <div className={`collectionLinearView-outer ${this.layoutDoc.linearView_SubMenu}`} style={{ backgroundColor: this.layoutDoc.linearView_IsExpanded ? undefined : 'transparent' }}>
                 <div className="collectionLinearView" ref={this.createDashEventsTarget} onContextMenu={this.myContextMenu} style={{ minHeight: this.dimension() }}>
-                    {!this.props.Document.linearViewExpandable ? null : (
+                    {!this.props.Document.linearView_Expandable ? null : (
                         <Tooltip title={<div className="dash-tooltip">{isExpanded ? 'Close' : 'Open'}</div>} placement="top">
                             {menuOpener}
                         </Tooltip>
@@ -259,11 +259,11 @@ export class CollectionLinearView extends CollectionSubView() {
                                 scriptContext: this.props.scriptContext,
                                 documentView: this.props.DocumentView?.(),
                             });
-                            this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked;
+                            this.layoutDoc.linearView_IsExpanded = this.addMenuToggle.current!.checked;
                         })}
                     />
 
-                    {!this.layoutDoc.linearViewIsExpanded ? null : (
+                    {!this.layoutDoc.linearView_IsExpanded ? null : (
                         <div
                             className="collectionLinearView-content"
                             style={{
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 78d3d1b6e..34fa0343d 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -259,8 +259,8 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 fitContentsToBox={this.props.fitContentsToBox}
                 focus={this.props.focus}
-                docFilters={this.childDocFilters}
-                docRangeFilters={this.childDocRangeFilters}
+                childFilters={this.childDocFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 4d61dc272..bab77ed48 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -258,8 +258,8 @@ export class CollectionMultirowView extends CollectionSubView() {
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 fitContentsToBox={this.props.fitContentsToBox}
                 focus={this.props.focus}
-                docFilters={this.childDocFilters}
-                docRangeFilters={this.childDocRangeFilters}
+                childFilters={this.childDocFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 3a0c2c85c..52ebb7763 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -104,7 +104,7 @@
 
 .schema-header-row {
     cursor: grab;
-    justify-content: flex-end;
+    //justify-content: flex-end;
 
     .row-menu {
         display: flex;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 36abad87e..15424de98 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -32,6 +32,7 @@ export enum ColumnType {
     Date,
     Image,
     RTF,
+    Enumeration,
     Any,
 }
 
@@ -42,6 +43,7 @@ export const FInfotoColType: { [key: string]: ColumnType } = {
     date: ColumnType.Date,
     image: ColumnType.Image,
     rtf: ColumnType.RTF,
+    enumeration: ColumnType.Enumeration,
 };
 
 const defaultColumnKeys: string[] = ['title', 'type', 'author', 'author_date', 'text'];
@@ -54,6 +56,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _makeNewColumn: boolean = false;
     private _documentOptions: DocumentOptions = new DocumentOptions();
     private _tableContentRef: HTMLDivElement | null = null;
+    private _menuTarget = React.createRef<HTMLDivElement>();
 
     static _rowHeight: number = 50;
     static _rowSingleLineHeight: number = 32;
@@ -77,6 +80,11 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _filterSearchValue: string = '';
     @observable _selectedCell: [Doc, number] | undefined;
 
+    // target HTMLelement portal for showing a popup menu to edit cell values.
+    public get MenuTarget() {
+        return this._menuTarget.current;
+    }
+
     @computed get _selectedDocs() {
         return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc));
     }
@@ -336,9 +344,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     dragColumn = (e: PointerEvent, index: number) => {
         const dragData = new DragManager.ColumnDragData(index);
         const dragEles = [this._colEles[index]];
-        this.childDocs.forEach(doc => {
-            dragEles.push(this._rowEles.get(doc).children[1].children[index]);
-        });
+        this.childDocs.forEach(doc => dragEles.push(this._rowEles.get(doc).children[1].children[index]));
         DragManager.StartColumnDrag(dragEles, dragData, e.x, e.y);
 
         document.removeEventListener('pointermove', this.highlightDropColumn);
@@ -352,24 +358,28 @@ export class CollectionSchemaView extends CollectionSubView() {
         return true;
     };
 
-    @action
-    highlightDropColumn = (e: PointerEvent) => {
-        e.stopPropagation();
-        const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+    findDropIndex = (mouseX: number) => {
         let index: number | undefined;
         this.displayColumnWidths.reduce((total, curr, i) => {
             if (total <= mouseX && total + curr >= mouseX) {
-                if (mouseX <= total + curr / 2) index = i;
+                if (mouseX <= total + curr) index = i;
                 else index = i + 1;
             }
             return total + curr;
         }, CollectionSchemaView._rowMenuWidth);
+        return index;
+    };
 
+    @action
+    highlightDropColumn = (e: PointerEvent) => {
+        e.stopPropagation();
+        const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+        const index = this.findDropIndex(mouseX);
         this._colEles.forEach((colRef, i) => {
             let leftStyle = '';
             let rightStyle = '';
-            if (i + 1 === index) rightStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
-            if (i === index && i === 0) leftStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
+            if (i + 1 === index) rightStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
+            if (i === index && i === 0) leftStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
             colRef.style.borderLeft = leftStyle;
             colRef.style.borderRight = rightStyle;
             this.childDocs.forEach(doc => {
@@ -426,15 +436,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         if (de.complete.columnDragData) {
             e.stopPropagation();
             const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0];
-            let index = de.complete.columnDragData.colIndex;
-            this.displayColumnWidths.reduce((total, curr, i) => {
-                if (total <= mouseX && total + curr >= mouseX) {
-                    if (mouseX <= total + curr / 2) index = i;
-                    else index = i + 1;
-                }
-                return total + curr;
-            }, CollectionSchemaView._rowMenuWidth);
-            this.moveColumn(de.complete.columnDragData.colIndex, index);
+            const index = this.findDropIndex(mouseX);
+            this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex);
 
             this._colEles.forEach((colRef, i) => {
                 colRef.style.borderLeft = '';
@@ -607,7 +610,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._menuKeys = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
-    getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
+    getFieldFilters = (field: string) => StrListCast(this.Document._childFilters).filter(filter => filter.split(':')[0] == field);
 
     removeFieldFilters = (field: string) => {
         this.getFieldFilters(field).forEach(filter => Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove'));
@@ -760,7 +763,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             }
         });
 
-        const filters = StrListCast(this.Document._docFilters);
+        const filters = StrListCast(this.Document._childFilters);
         return keyOptions.map(key => {
             let bool = false;
             if (filters !== undefined) {
@@ -832,6 +835,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     render() {
         return (
             <div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)}>
+                <div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }}></div>
                 <div
                     className="schema-table"
                     onWheel={e => this.props.isContentActive() && e.stopPropagation()}
@@ -860,6 +864,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 openContextMenu={this.openContextMenu}
                                 dragColumn={this.dragColumn}
                                 setColRef={this.setColRef}
+                                isContentActive={this.props.isContentActive}
                             />
                         ))}
                     </div>
@@ -894,8 +899,8 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 isContentActive={returnTrue}
                                 isDocumentActive={returnFalse}
                                 ScreenToLocalTransform={this.screenToLocal}
-                                docFilters={this.childDocFilters}
-                                docRangeFilters={this.childDocRangeFilters}
+                                childFilters={this.childDocFilters}
+                                childFiltersByRanges={this.childDocRangeFilters}
                                 searchFilterDocs={this.searchFilterDocs}
                                 styleProvider={DefaultStyleProvider}
                                 docViewPath={returnEmptyDoclist}
@@ -940,6 +945,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 LayoutTemplateString={SchemaRowBox.LayoutString(this.props.schema.props.fieldKey)}
                                 Document={doc}
                                 DataDoc={dataDoc}
+                                yPadding={index}
                                 renderDepth={this.props.schema.props.renderDepth + 1}
                                 PanelWidth={this.tableWidthFunc}
                                 PanelHeight={this.props.rowHeight}
@@ -949,8 +955,8 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 enableDragWhenActive={true}
                                 onClickScriptDisable="always"
                                 focus={this.props.schema.focusDocument}
-                                docFilters={this.props.schema.childDocFilters}
-                                docRangeFilters={this.props.schema.childDocRangeFilters}
+                                childFilters={this.props.schema.childDocFilters}
+                                childFiltersByRanges={this.props.schema.childDocRangeFilters}
                                 searchFilterDocs={this.props.schema.searchFilterDocs}
                                 rootSelected={this.props.schema.rootSelected}
                                 ScreenToLocalTransform={this.childScreenToLocal(index)}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 46c2f622b..65e47f441 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -12,6 +12,7 @@ export interface SchemaColumnHeaderProps {
     columnIndex: number;
     sortField: string;
     sortDesc: boolean;
+    isContentActive: (outsideReaction?: boolean | undefined) => boolean | undefined;
     setSort: (field: string | undefined, desc?: boolean) => void;
     removeColumn: (index: number) => void;
     rowHeight: () => number;
@@ -44,7 +45,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
 
     @action
     onPointerDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction, false);
+        this.props.isContentActive(true) && setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction, false);
     };
 
     render() {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 978b65053..4f3503751 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -7,7 +7,7 @@ import { Doc } from '../../../../fields/Doc';
 import { BoolCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
-import { undoable, undoBatch } from '../../../util/UndoManager';
+import { undoable } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
 import { OpenWhere } from '../../nodes/DocumentView';
@@ -15,6 +15,7 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
+import { Transform } from '../../../util/Transform';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -143,6 +144,13 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             selectedCell={this.selectedCell}
                             setColumnValues={this.setColumnValues}
                             oneLine={BoolCast(this.schemaDoc?._singleLine)}
+                            menuTarget={this.schemaView.MenuTarget}
+                            transform={() => {
+                                const ind = index === this.schemaView.columnKeys.length - 1 ? this.schemaView.columnKeys.length - 3 : index;
+                                const x = this.schemaView?.displayColumnWidths.reduce((p, c, i) => (i <= ind ? p + c : p), 0);
+                                const y = (this.props.yPadding ?? 0) * this.props.PanelHeight();
+                                return new Transform(x + CollectionSchemaView._rowMenuWidth, y, 1);
+                            }}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 876693474..97264508c 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,4 +1,5 @@
-import React = require('react');
+import * as React from 'react';
+import Select, { MenuPlacement } from 'react-select';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { extname } from 'path';
@@ -6,12 +7,11 @@ import DatePicker from 'react-datepicker';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field } from '../../../../fields/Doc';
 import { RichTextField } from '../../../../fields/RichTextField';
-import { BoolCast, Cast, DateCast, DocCast, FieldValue } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast, DocCast, FieldValue, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
 import { FInfo } from '../../../documents/Documents';
 import { DocFocusOrOpen } from '../../../util/DocumentManager';
-import { dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoable, undoBatch } from '../../../util/UndoManager';
 import { EditableView } from '../../EditableView';
@@ -21,7 +21,7 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
-import { ColumnType, FInfotoColType } from './CollectionSchemaView';
+import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 
 export interface SchemaTableCellProps {
@@ -41,6 +41,9 @@ export interface SchemaTableCellProps {
     oneLine?: boolean; // whether all input should fit on one line vs allowing textare multiline inputs
     allowCRs?: boolean; // allow carriage returns in text input (othewrise CR ends the edit)
     finishEdit?: () => void; // notify container that edit is over (eg. to hide view in DashFieldView)
+    options?: string[];
+    menuTarget: HTMLDivElement | null;
+    transform: () => Transform;
 }
 
 @observer
@@ -64,8 +67,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue';
         const textDecoration = color !== 'black' && parenCount ? 'underline' : '';
         const fieldProps: FieldViewProps = {
-            docFilters: returnEmptyFilter,
-            docRangeFilters: returnEmptyFilter,
+            childFilters: returnEmptyFilter,
+            childFiltersByRanges: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
@@ -129,15 +132,15 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
+        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         const cellValue = this.props.Document[this.props.fieldKey];
         if (cellValue instanceof ImageField) return ColumnType.Image;
         if (cellValue instanceof DateField) return ColumnType.Date;
         if (cellValue instanceof RichTextField) return ColumnType.RTF;
         if (typeof cellValue === 'number') return ColumnType.Any;
-        if (typeof cellValue === 'string') return ColumnType.Any;
+        if (typeof cellValue === 'string' && columnTypeStr !== 'enumeration') return ColumnType.Any;
         if (typeof cellValue === 'boolean') return ColumnType.Boolean;
 
-        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         if (columnTypeStr && columnTypeStr in FInfotoColType) {
             return FInfotoColType[columnTypeStr];
         }
@@ -152,6 +155,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             case ColumnType.Image: return <SchemaImageCell {...this.props} />;
             case ColumnType.Boolean: return <SchemaBoolCell {...this.props} />;
             case ColumnType.RTF: return <SchemaRTFCell {...this.props} />;
+            case ColumnType.Enumeration: return <SchemaEnumerationCell {...this.props} options={this.props.getFinfo(this.props.fieldKey)?.values?.map(val => val.toString())} />;
             case ColumnType.Date: // return <SchemaDateCell {...this.props} />;
             default:  return this.defaultCellContent;
         }
@@ -311,3 +315,38 @@ export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
         );
     }
 }
+@observer
+export class SchemaEnumerationCell extends React.Component<SchemaTableCellProps> {
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+    render() {
+        const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
+        const options = this.props.options?.map(facet => ({ value: facet, label: facet }));
+        return (
+            <div className="schemaSelectionCell" style={{ display: 'flex', color, textDecoration, cursor, pointerEvents }}>
+                <div style={{ width: '100%' }}>
+                    <Select
+                        styles={{
+                            menuPortal: base => ({
+                                ...base,
+                                left: 0,
+                                top: 0,
+                                transform: `translate(${this.props.transform().TranslateX}px, ${this.props.transform().TranslateY}px)`,
+                                width: Number(base.width) * this.props.transform().Scale,
+                                zIndex: 9999,
+                            }),
+                        }}
+                        menuPortalTarget={this.props.menuTarget}
+                        menuPosition={'absolute'}
+                        placeholder={StrCast(this.props.Document[this.props.fieldKey], 'select...')}
+                        options={options}
+                        isMulti={false}
+                        onChange={val => KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), `"${val?.value ?? ''}"`)}
+                    />
+                </div>
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index b9d56541a..8324a97d9 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -25,7 +25,7 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
 
     getBackgroundColor = (): string => {
         const link_relationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
-        const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
+        const linkColorList = StrListCast(Doc.UserDoc().link_ColorList);
         let color = 'white';
         // if this link's relationship property is not default "link", set its color
         if (link_relationshipList) {
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 5f2d4a7b6..664a0fa4f 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -89,8 +89,8 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                     />
                 </div>
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 60480ac33..d84e34d52 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -57,7 +57,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                             DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
                                                                 dragComplete: e => {
                                                                     if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
-                                                                        e.linkDocument.layout_linkDisplay = true;
+                                                                        e.linkDocument.link_displayLine = true;
                                                                         // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
                                                                         // e.annoDragData.linkSourceDoc.followLinkZoom = false;
                                                                     }
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index bd1952ecb..7723a088d 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -71,7 +71,9 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             e,
             this.onLinkButtonMoved,
             emptyFunction,
-            action((e, doubleTap) => doubleTap && DocumentView.showBackLinks(this.props.View.rootDoc)),
+            action((e, doubleTap) => {
+                doubleTap && DocumentView.showBackLinks(this.props.View.rootDoc);
+            }),
             undefined,
             undefined,
             action(() => (DocumentLinksButton.LinkEditorDocView = this.props.View))
@@ -191,7 +193,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
 
     @computed get filteredLinks() {
         const results = [] as Doc[];
-        const filters = this.props.View.props.docFilters();
+        const filters = this.props.View.props.childFilters();
         Array.from(new Set<Doc>(this.props.View.allLinks)).forEach(link => {
             if (DocUtils.FilterDocs([link], filters, []).length || DocUtils.FilterDocs([link.link_anchor_2 as Doc], filters, []).length || DocUtils.FilterDocs([link.link_anchor_1 as Doc], filters, []).length) {
                 results.push(link);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 687683e6e..461066b1b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -168,8 +168,8 @@ export interface DocumentViewSharedProps {
     setTitleFocus?: () => void;
     focus: DocFocusFunc;
     layout_fitWidth?: (doc: Doc) => boolean | undefined;
-    docFilters: () => string[];
-    docRangeFilters: () => string[];
+    childFilters: () => string[];
+    childFiltersByRanges: () => string[];
     searchFilterDocs: () => Doc[];
     layout_showTitle?: () => string;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
@@ -192,7 +192,7 @@ export interface DocumentViewSharedProps {
     hideCaptions?: boolean;
     ignoreAutoHeight?: boolean;
     forceAutoHeight?: boolean;
-    disableDocBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
+    disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
     onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected
     enableDragWhenActive?: boolean;
     waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
@@ -664,7 +664,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     @action
     onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => {
-        if (e && this.rootDoc._hideContextMenu && Doc.noviceMode) {
+        if (e && this.rootDoc._layout_hideContextMenu && Doc.noviceMode) {
             e.preventDefault();
             e.stopPropagation();
             //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false);
@@ -880,7 +880,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             ? true
             : false;
     };
-    docFilters = () => [...this.props.docFilters(), ...StrListCast(this.layoutDoc.docFilters)];
+    childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
     contentPointerEvents = () => (!this.disableClickScriptFunc && this.onClickHandler ? 'none' : this.pointerEvents);
     @computed get contents() {
         TraceMobx();
@@ -912,7 +912,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     docViewPath={this.props.viewPath}
                     thumbShown={this.thumbShown}
                     setContentView={this.setContentView}
-                    docFilters={this.docFilters}
+                    childFilters={this.childFilters}
                     NativeDimScaling={this.props.NativeDimScaling}
                     PanelHeight={this.panelHeight}
                     setHeight={!this.props.suppressSetHeight ? this.setHeight : undefined}
@@ -924,7 +924,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     setTitleFocus={this.setTitleFocus}
                     layout_fieldKey={this.finalLayoutKey}
                 />
-                {this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints}
+                {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints}
             </div>
         );
     }
@@ -960,12 +960,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         TraceMobx();
         return LinkManager.Instance.getAllRelatedLinks(this.rootDoc);
     }
-    hideLink = computedFn((link: Doc) => () => (link.layout_linkDisplay = false));
+    hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false));
     @computed get allLinkEndpoints() {
         // the small blue dots that mark the endpoints of links
         TraceMobx();
         if (this.props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.layout_unrendered) return null;
-        const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => d.layout_linkDisplay);
+        const filtered = DocUtils.FilterDocs(this.directLinks, this.props.childFilters?.() ?? [], []).filter(d => d.link_displayLine);
         return filtered.map(link => (
             <div className="documentView-anchorCont" key={link[Id]}>
                 <DocumentView
@@ -1013,7 +1013,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 gumStream = stream;
                 recorder = new MediaRecorder(stream);
                 recorder.ondataavailable = async (e: any) => {
-                    const [{ result }] = await Networking.UploadFilesToServer({file: e.data});
+                    const [{ result }] = await Networking.UploadFilesToServer({ file: e.data });
                     if (!(result instanceof Error)) {
                         const audioField = new AudioField(result.accessPaths.agnostic.client);
                         const audioAnnos = Cast(dataDoc[field + '-audioAnnotations'], listSpec(AudioField), null);
@@ -1296,13 +1296,13 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 
     // shows a stacking view collection (by default, but the user can change) of all documents linked to the source
-    public static showBackLinks(linkSource: Doc) {
-        const docId = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + '-pivotish';
+    public static showBackLinks(linkAnchor: Doc) {
+        const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish';
         // prettier-ignore
-        DocServer.GetRefField(docId).then(docx => docx instanceof Doc &&
+        DocServer.GetRefField(docId).then(docx =>
             LightboxView.SetLightboxDoc(
-                docx || // reuse existing pivot view of documents, or else create a new collection
-                Docs.Create.StackingDocument([], { title: linkSource.title + '-pivot', _width: 500, _height: 500, linkSource, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self)') }, docId)
+                (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection
+                Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self, self.target)') }, docId)
             )
         );
     }
@@ -1490,8 +1490,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             // increase max auto height if document has been resized to be greater than current max
             () => NumCast(this.layoutDoc._height),
             action(height => {
-                const docMax = NumCast(this.layoutDoc.docMaxAutoHeight);
-                if (docMax && docMax < height) this.layoutDoc.docMaxAutoHeight = height;
+                const docMax = NumCast(this.layoutDoc.layout_maxAutoHeight);
+                if (docMax && docMax < height) this.layoutDoc.layout_maxAutoHeight = height;
             })
         );
         !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.AddView(this);
@@ -1577,16 +1577,16 @@ ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuff
     else dv.switchViews(true, detailLayoutKeySuffix, undefined, true);
 });
 
-ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
-    const linkSource = Cast(linkCollection.linkSource, Doc, null);
+ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSource: Doc) {
     const collectedLinks = DocListCast(Doc.GetProto(linkCollection).data);
     let wid = linkSource[Width]();
+    let embedding:Doc|undefined;
     const links = LinkManager.Links(linkSource);
     links.forEach(link => {
         const other = LinkManager.getOppositeAnchor(link, linkSource);
-        const otherdoc = !other ? undefined : other.annotationOn ? Cast(other.annotationOn, Doc, null) : other;
+        const otherdoc = DocCast(other?.annotationOn ?? other);
         if (otherdoc && !collectedLinks?.some(d => Doc.AreProtosEqual(d, otherdoc))) {
-            const embedding = Doc.MakeEmbedding(otherdoc);
+            embedding = Doc.MakeEmbedding(otherdoc);
             embedding.x = wid;
             embedding.y = 0;
             embedding._lockedPosition = false;
@@ -1594,5 +1594,6 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
             Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', embedding);
         }
     });
+    embedding && DocServer.UPDATE_SERVER_CACHE();// if a new embedding was made, update the client's server cache so that it will not come back as a promise
     return links;
 });
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 4e348c67c..64f25cb22 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -57,8 +57,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
         const props: FieldViewProps = {
             Document: this.props.doc,
             DataDoc: this.props.doc,
-            docFilters: returnEmptyFilter,
-            docRangeFilters: returnEmptyFilter,
+            childFilters: returnEmptyFilter,
+            childFiltersByRanges: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 73823041c..52f3575cb 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -87,8 +87,8 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
         const params = {
             rotateText: null,
             fontSizeFactor: 1,
-            minimumFontSize: NumCast(this.rootDoc._minFontSize, 8),
-            maximumFontSize: NumCast(this.rootDoc._maxFontSize, 1000),
+            minimumFontSize: NumCast(this.rootDoc._label_minFontSize, 8),
+            maximumFontSize: NumCast(this.rootDoc._label_maxFontSize, 1000),
             limitingDimension: 'both',
             horizontalAlign: 'center',
             verticalAlign: 'center',
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index f38ef634c..e86b881a8 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -53,7 +53,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
             } else {
                 this.rootDoc[this.fieldKey + '_x'] = ((pt[0] - bounds.left) / bounds.width) * 100;
                 this.rootDoc[this.fieldKey + '_y'] = ((pt[1] - bounds.top) / bounds.height) * 100;
-                this.rootDoc.layout_autoMoveAnchors = false;
+                this.rootDoc.link_autoMoveAnchors = false;
             }
         }
         return false;
@@ -68,7 +68,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const y = NumCast(this.rootDoc[this.fieldKey + '_y'], 100);
         const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor + ':anchor');
         const anchor = this.fieldKey === 'link_anchor_1' ? 'link_anchor_2' : 'link_anchor_1';
-        const anchorScale = !this.dataDoc[this.fieldKey + '_useLinkSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25;
+        const anchorScale = !this.dataDoc[this.fieldKey + '_useSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25;
         const targetTitle = StrCast((this.dataDoc[anchor] as Doc)?.title);
         const selView = SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('link_anchor_1')
             ? 'link_anchor_1'
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 079e1b56d..86191de63 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -268,8 +268,8 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             addDocTab={returnFalse}
                             pinToPres={returnFalse}
                             dontRegisterView={true}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                             renderDepth={0}
                             suppressSetHeight={true}
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index f03954789..93e54ffb7 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -394,7 +394,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
 
     /**
@@ -550,8 +550,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.IsOpaqueFilter()];
     infoWidth = () => this.props.PanelWidth() / 5;
     infoHeight = () => this.props.PanelHeight() / 5;
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
@@ -601,7 +601,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
     bingMapReady = (map: any) => (this._bingMap = map.map);
     render() {
-        const renderAnnotations = (docFilters?: () => string[]) => null;
+        const renderAnnotations = (childFilters?: () => string[]) => null;
         return (
             <div className="mapBox" ref={this._ref}>
                 <div
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 18fcc951a..72f37b62c 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -391,7 +391,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
 
     /**
@@ -547,8 +547,8 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.IsOpaqueFilter()];
     infoWidth = () => this.props.PanelWidth() / 5;
     infoHeight = () => this.props.PanelHeight() / 5;
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
@@ -558,7 +558,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return (window as any).Microsoft.Maps;
     }
     render() {
-        const renderAnnotations = (docFilters?: () => string[]) => null;
+        const renderAnnotations = (childFilters?: () => string[]) => null;
         return (
             <div className="MapBox2" ref={this._ref}>
                 <div
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 6b26f494b..577101445 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -59,7 +59,7 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
                             fieldKey="data"
                             NativeWidth={returnZero}
                             NativeHeight={returnZero}
-                            docFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
                             setHeight={emptyFunction}
                             isAnnotationOverlay={false}
                             select={emptyFunction}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 6ee1b67f2..c210176b0 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -441,7 +441,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return PDFBox.sidebarResizerWidth + nativeDiff * (this.props.NativeDimScaling?.() || 1);
     };
     @undoBatch
-    toggleSidebarType = () => (this.rootDoc.sidebarViewType = this.rootDoc.sidebarViewType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform);
+    toggleSidebarType = () => (this.rootDoc.sidebar_collectionType = this.rootDoc.sidebar_collectionType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform);
     specificContextMenu = (e: React.MouseEvent): void => {
         const cm = ContextMenu.Instance;
         const options = cm.findByDescription('Options...');
@@ -557,7 +557,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         };
         return (
             <div className={'formattedTextBox-sidebar' + (Doc.ActiveTool !== InkTool.None ? '-inking' : '')} style={{ width: '100%', right: 0, backgroundColor: `white` }}>
-                {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
+                {renderComponent(StrCast(this.layoutDoc.sidebar_collectionType))}
             </div>
         );
     }
diff --git a/src/client/views/nodes/QueryBox.scss b/src/client/views/nodes/QueryBox.scss
deleted file mode 100644
index b5f90aa1e..000000000
--- a/src/client/views/nodes/QueryBox.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-.queryBox, .queryBox-dragging {
-    width: 100%;
-    height: 100%; 
-    position: absolute;
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx
deleted file mode 100644
index 1b6056be6..000000000
--- a/src/client/views/nodes/QueryBox.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-// import React = require("react");
-// import { IReactionDisposer } from "mobx";
-// import { observer } from "mobx-react";
-// import { documentSchema } from "../../../new_fields/documentSchemas";
-// import { Id } from '../../../new_fields/FieldSymbols';
-// import { makeInterface, listSpec } from "../../../new_fields/Schema";
-// import { StrCast, Cast } from "../../../new_fields/Types";
-// import { ViewBoxAnnotatableComponent } from '../DocComponent';
-// import { SearchBox } from "../search/SearchBox";
-// import { FieldView, FieldViewProps } from './FieldView';
-// import "./QueryBox.scss";
-// import { List } from "../../../new_fields/List";
-// import { SnappingManager } from "../../util/SnappingManager";
-
-// type QueryDocument = makeInterface<[typeof documentSchema]>;
-// const QueryDocument = makeInterface(documentSchema);
-
-// @observer
-// export class QueryBox extends ViewBoxAnnotatableComponent<FieldViewProps, QueryDocument>(QueryDocument) {
-//     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(QueryBox, fieldKey); }
-//     _docListChangedReaction: IReactionDisposer | undefined;
-//     componentDidMount() {
-//     }
-
-//     componentWillUnmount() {
-//         this._docListChangedReaction?.();
-//     }
-
-//     render() {
-//         const dragging = !SnappingManager.GetIsDragging() ? "" : "-dragging";
-//         return <div className={`queryBox${dragging}`} onWheel={(e) => e.stopPropagation()} >
-            
-//             <SearchBox  Document={this.props.Document}  />
-//         </div >;
-//     }
-// }
-
-// //<SearchBox id={this.props.Document[Id]} sideBar={side} Document={this.props.Document} searchQuery={StrCast(this.dataDoc.searchQuery)} filterQuery={this.dataDoc.filterQuery} />
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 34dcde23b..1f52c2d92 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -913,7 +913,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     marqueeFitScaling = () => ((this.props.NativeDimScaling?.() || 1) * this.heightPercent) / 100;
     marqueeOffset = () => [((this.panelWidth() / 2) * (1 - this.heightPercent / 100)) / (this.heightPercent / 100), 0];
 
-    timelineDocFilter = () => [`_timelineLabel:true,${Utils.noRecursionHack}:x`];
+    timelineDocFilter = () => [`_isTimelineLabel:true,${Utils.noRecursionHack}:x`];
 
     // renders video controls
     componentUI = (boundsLeft: number, boundsTop: number) => {
@@ -1082,7 +1082,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             PanelHeight={this.panelHeight}
                             isAnyChildContentActive={returnFalse}
                             ScreenToLocalTransform={this.screenToLocalTransform}
-                            docFilters={this.timelineDocFilter}
+                            childFilters={this.timelineDocFilter}
                             select={emptyFunction}
                             focus={emptyFunction}
                             NativeDimScaling={returnOne}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 48f77469f..2ff0245d2 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -900,7 +900,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any);
         const scale = previewScale * (this.props.NativeDimScaling?.() || 1);
-        const renderAnnotations = (docFilters: () => string[]) => (
+        const renderAnnotations = (childFilters: () => string[]) => (
             <CollectionFreeFormView
                 {...this.props}
                 setContentView={this.setInnerContent}
@@ -919,7 +919,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 NativeDimScaling={returnOne}
                 focus={this.focus}
                 dropAction="embed"
-                docFilters={docFilters}
+                childFilters={childFilters}
                 select={emptyFunction}
                 isAnyChildContentActive={returnFalse}
                 bringToFront={emptyFunction}
@@ -995,8 +995,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
     childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
             if (this.inlineTextAnnotations.includes(doc)) return 'none';
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 601759dbb..5bba51ec8 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -95,7 +95,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
 
     // Determining UI Specs
     @computed get label() {
-        return StrCast(this.rootDoc.label, StrCast(this.rootDoc.title));
+        return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title));
     }
     Icon = (color: string) => {
         const icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any;
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 1d41eb379..48f4c2afd 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -217,8 +217,8 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     whenChildContentsActiveChanged={returnFalse}
                     bringToFront={emptyFunction}
                     dontRegisterView={false}
-                    docFilters={this.props.tbox?.props.docFilters}
-                    docRangeFilters={this.props.tbox?.props.docRangeFilters}
+                    childFilters={this.props.tbox?.props.childFilters}
+                    childFiltersByRanges={this.props.tbox?.props.childFiltersByRanges}
                     searchFilterDocs={this.props.tbox?.props.searchFilterDocs}
                 />
             </div>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 105fb9003..115777c18 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -132,7 +132,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
     @computed get layout_autoHeight() {
         return (this.props.forceAutoHeight || this.layoutDoc._layout_autoHeight) && !this.props.ignoreAutoHeight;
@@ -811,9 +811,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             icon: !this.Document._layout_noSidebar ? 'eye-slash' : 'eye',
         });
         uicontrols.push({
-            description: (this.Document._layout_altContentUI ? 'Hide' : 'Show') + ' Alt Content UI',
-            event: () => (this.layoutDoc._layout_altContentUI = !this.layoutDoc._layout_altContentUI),
-            icon: !this.Document._layout_altContentUI ? 'eye-slash' : 'eye',
+            description: (this.Document._layout_enableAltContentUI ? 'Hide' : 'Show') + ' Alt Content UI',
+            event: () => (this.layoutDoc._layout_enableAltContentUI = !this.layoutDoc._layout_enableAltContentUI),
+            icon: !this.Document._layout_enableAltContentUI ? 'eye-slash' : 'eye',
         });
         uicontrols.push({ description: 'Show Highlights...', noexpand: true, subitems: highlighting, icon: 'hand-point-right' });
         !Doc.noviceMode &&
@@ -1741,7 +1741,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
 
         const state = this._editorView!.state;
         const curText = state.doc.textBetween(0, state.doc.content.size, ' \n');
-        if (this.layoutDoc.sidebarViewType === 'translation' && !this.fieldKey.includes('translation') && curText.endsWith(' ') && curText !== this._lastText) {
+        if (this.layoutDoc.sidebar_collectionType === 'translation' && !this.fieldKey.includes('translation') && curText.endsWith(' ') && curText !== this._lastText) {
             try {
                 translateGoogleApi(curText, { from: 'en', to: 'es' }).then((result1: any) => {
                     setTimeout(
@@ -1837,7 +1837,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 return toNum(height) + Math.max(0, toNum(marginTop)) + Math.max(0, toNum(marginBottom));
             };
             const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + toHgt(child), margins);
-            const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
+            const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.layout_maxAutoHeight, proseHeight), proseHeight);
             if (this.props.setHeight && scrollHeight && !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);
@@ -1949,19 +1949,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         fitContentsToBox={this.fitContentsToBox}
                         noSidebar={true}
                         treeViewHideTitle={true}
-                        fieldKey={this.layoutDoc.sidebarViewType === 'translation' ? `${this.fieldKey}_translation` : `${this.fieldKey}_sidebar`}
+                        fieldKey={this.layoutDoc.sidebar_collectionType === 'translation' ? `${this.fieldKey}_translation` : `${this.fieldKey}_sidebar`}
                     />
                 </div>
             );
         };
         return (
             <div className={'formattedTextBox-sidebar' + (Doc.ActiveTool !== InkTool.None ? '-inking' : '')} style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
-                {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
+                {renderComponent(StrCast(this.layoutDoc.sidebar_collectionType))}
             </div>
         );
     }
     cycleAlternateText = () => {
-        if (this.layoutDoc._layout_altContentUI) {
+        if (this.layoutDoc._layout_enableAltContentUI) {
             const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
             this.rootDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
         }
@@ -2016,7 +2016,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         const active = this.props.isContentActive() || this.props.isSelected();
         const selected = active;
         const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
-        const rounded = StrCast(this.layoutDoc.borderRounding) === '100%' ? '-rounded' : '';
+        const rounded = StrCast(this.layoutDoc.layout_borderRounding) === '100%' ? '-rounded' : '';
         const interactive = (Doc.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
         if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
         const minimal = this.props.ignoreAutoHeight;
@@ -2096,7 +2096,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     {this.noSidebar || this.props.dontSelectOnLoad || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection}
                     {this.noSidebar || this.Document._layout_noSidebar || this.props.dontSelectOnLoad || this.Document._createDocOnCR ? null : this.sidebarHandle}
                     {this.audioHandle}
-                    {this.layoutDoc._layout_altContentUI ? this.overlayAlternateIcon : null}
+                    {this.layoutDoc._layout_enableAltContentUI ? this.overlayAlternateIcon : null}
                 </div>
             </div>
         );
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 884811317..ac20126f1 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -488,8 +488,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
 
         if ((pinDataTypes?.filters && activeItem.presDocFilters !== undefined) || (!pinDataTypes && activeItem.presDocFilters !== undefined)) {
-            if (bestTarget.docFilters !== activeItem.presDocFilters) {
-                bestTarget.docFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List<string>([]);
+            if (bestTarget.childFilters !== activeItem.presDocFilters) {
+                bestTarget.childFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List<string>([]);
                 changed = true;
             }
         }
@@ -651,7 +651,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     )
                 );
             if (pinProps.pinData.type_collection) pinDoc.presViewType = targetDoc._type_collection;
-            if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.docFilters as ObjectField);
+            if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField);
             if (pinProps.pinData.pivot) pinDoc.presPivotField = targetDoc._pivotField;
             if (pinProps.pinData.pannable) {
                 pinDoc.presPanX = NumCast(targetDoc._freeform_panX);
@@ -2078,10 +2078,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         // prettier-ignore
         switch (layout) {
             case 'blank': return Docs.Create.FreeformDocument([], { title: input ? input : 'Blank slide', _width: 400, _height: 225, x, y });
-            case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
-            case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
-            case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
-            case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y })
+            case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y });
+            case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y });
+            case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y });
+            case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y })
         }
     };
 
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 154c879a0..34e069046 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -107,8 +107,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     ScreenToLocalTransform={Transform.Identity}
                     renderDepth={this.props.renderDepth + 1}
                     docViewPath={returnEmptyDoclist}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
+                    childFilters={this.props.childFilters}
+                    childFiltersByRanges={this.props.childFiltersByRanges}
                     searchFilterDocs={this.props.searchFilterDocs}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
@@ -377,9 +377,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const recording = Docs.Create.WebCamDocument('', {
                 _width: 384,
                 _height: 216,
-                hideDocumentButtonBar: true,
+                layout_hideDocumentButtonBar: true,
                 layout_hideDecorationTitle: true,
-                hideOpenButton: true,
+                layout_hideOpenButton: true,
                 // hideDeleteButton: true,
                 cloneFieldFilter: new List<string>(['isSystem']),
             });
@@ -522,7 +522,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         style={{
                             display: 'infline-block',
                             backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
-                            //boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined,
+                            //layout_boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined,
                             border: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? presBoxColor + ' solid 2.5px' : undefined) : undefined,
                         }}>
                         <div
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index bc0cad636..dd202418b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -91,7 +91,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
     @observable isAnnotating = false;
     // key where data is stored
     @computed get allAnnotations() {
-        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.props.docFilters(), this.props.docRangeFilters());
+        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.props.childFilters(), this.props.childFiltersByRanges());
     }
     @computed get inlineTextAnnotations() {
         return this.allAnnotations.filter(a => a.textInlineAnnotations);
@@ -513,8 +513,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
     overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._freeform_scale, 1));
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1);
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
     childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
             if (this.inlineTextAnnotations.includes(doc)) return 'none';
@@ -523,7 +523,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         return this.props.styleProvider?.(doc, props, property);
     };
 
-    renderAnnotations = (docFilters: () => string[], mixBlendMode?: any, display?: string) => (
+    renderAnnotations = (childFilters: () => string[], mixBlendMode?: any, display?: string) => (
         <div
             className="pdfViewerDash-overlay"
             style={{
@@ -550,7 +550,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 isAnyChildContentActive={returnFalse}
                 isAnnotationOverlayScrollable={true}
                 dropAction="embed"
-                docFilters={docFilters}
+                childFilters={childFilters}
                 select={emptyFunction}
                 bringToFront={emptyFunction}
                 styleProvider={this.childStyleProvider}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 72eeedcff..92ae64567 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1415,18 +1415,18 @@ export namespace Doc {
     }
     export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: number[]) {
         if (!container) return;
-        const docRangeFilters = Cast(container._docRangeFilters, listSpec('string'), []);
-        for (let i = 0; i < docRangeFilters.length; i += 3) {
-            if (docRangeFilters[i] === key) {
-                docRangeFilters.splice(i, 3);
+        const childFiltersByRanges = Cast(container._childFiltersByRanges, listSpec('string'), []);
+        for (let i = 0; i < childFiltersByRanges.length; i += 3) {
+            if (childFiltersByRanges[i] === key) {
+                childFiltersByRanges.splice(i, 3);
                 break;
             }
         }
         if (range !== undefined) {
-            docRangeFilters.push(key);
-            docRangeFilters.push(range[0].toString());
-            docRangeFilters.push(range[1].toString());
-            container._docRangeFilters = new List<string>(docRangeFilters);
+            childFiltersByRanges.push(key);
+            childFiltersByRanges.push(range[0].toString());
+            childFiltersByRanges.push(range[1].toString());
+            container._childFiltersByRanges = new List<string>(childFiltersByRanges);
         }
     }
 
@@ -1435,35 +1435,35 @@ export namespace Doc {
     // based on the modifiers :"check", "x", undefined
     export function setDocFilter(container: Opt<Doc>, key: string, value: any, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) {
         if (!container) return;
-        const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'docFilters';
-        const docFilters = StrListCast(container[filterField]);
+        const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'childFilters';
+        const childFilters = StrListCast(container[filterField]);
         runInAction(() => {
-            for (let i = 0; i < docFilters.length; i++) {
-                const fields = docFilters[i].split(':'); // split key:value:modifier
+            for (let i = 0; i < childFilters.length; i++) {
+                const fields = childFilters[i].split(':'); // split key:value:modifier
                 if (fields[0] === key && (fields[1] === value || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
                     if (fields[2] === modifiers && modifiers && fields[1] === value) {
                         if (toggle) modifiers = 'remove';
                         else return;
                     }
-                    docFilters.splice(i, 1);
-                    container[filterField] = new List<string>(docFilters);
+                    childFilters.splice(i, 1);
+                    container[filterField] = new List<string>(childFilters);
                     break;
                 }
             }
-            if (!docFilters.length && modifiers === 'match' && value === undefined) {
+            if (!childFilters.length && modifiers === 'match' && value === undefined) {
                 container[filterField] = undefined;
             } else if (modifiers !== 'remove') {
-                !append && (docFilters.length = 0);
-                docFilters.push(key + ':' + value + ':' + modifiers);
-                container[filterField] = new List<string>(docFilters);
+                !append && (childFilters.length = 0);
+                childFilters.push(key + ':' + value + ':' + modifiers);
+                container[filterField] = new List<string>(childFilters);
             }
         });
     }
     export function readDocRangeFilter(doc: Doc, key: string) {
-        const docRangeFilters = Cast(doc._docRangeFilters, listSpec('string'), []);
-        for (let i = 0; i < docRangeFilters.length; i += 3) {
-            if (docRangeFilters[i] === key) {
-                return [Number(docRangeFilters[i + 1]), Number(docRangeFilters[i + 2])];
+        const childFiltersByRanges = Cast(doc._childFiltersByRanges, listSpec('string'), []);
+        for (let i = 0; i < childFiltersByRanges.length; i += 3) {
+            if (childFiltersByRanges[i] === key) {
+                return [Number(childFiltersByRanges[i + 1]), Number(childFiltersByRanges[i + 2])];
             }
         }
     }
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index 7a0a18929..757d507be 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -55,8 +55,8 @@ export const documentSchema = createSchema({
 
     // appearance properties on the data document
     backgroundColor: 'string', // background color of document
-    borderRounding: 'string', // border radius rounding of document
-    boxShadow: 'string', // the amount of shadow around the perimeter of a document
+    layout_borderRounding: 'string', // border radius rounding of document
+    layout_boxShadow: 'string', // the amount of shadow around the perimeter of a document
     color: 'string', // foreground color of document
     freeform_fitContentsToBox: 'boolean', // whether freeform view contents should be zoomed/panned to fill the area of the document view box
     fontSize: 'string',
@@ -86,13 +86,13 @@ export const documentSchema = createSchema({
     onDragStart: ScriptField, // script to run when document is dragged (without being selected).  the script should return the Doc to be dropped.
     followLinkLocation: 'string', // flag for where to place content when following a click interaction (e.g., add:right, lightbox, default, )
     hideLinkButton: 'boolean', // whether the blue link counter button should be hidden
-    hideAllLinks: 'boolean', // whether all individual blue anchor dots should be hidden
-    layout_linkDisplay: 'boolean', // whether a link connection should be shown between link anchor endpoints.
+    layout_hideAllLinks: 'boolean', // whether all individual blue anchor dots should be hidden
+    link_displayLine: 'boolean', // whether a link connection should be shown between link anchor endpoints.
     isLightbox: 'boolean', // whether the marked object will display addDocTab() calls that target "lightbox" destinations
     layers: listSpec('string'), // which layers the document is part of
     _lockedPosition: 'boolean', // whether the document can be moved (dragged)
     _lockedTransform: 'boolean', // whether a freeformview can pan/zoom
-    layout_linkDisplayArrow: 'boolean', // toggles directed arrows
+    link_displayArrow: 'boolean', // toggles directed arrows
 
     // drag drop properties
     _stayInCollection: 'boolean', // whether document can be dropped into a different collection
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 62f27c7d2..f365adf4b 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -16,7 +16,7 @@ import { PrefetchProxy, ProxyField } from './Proxy';
 import { RefField } from './RefField';
 import { RichTextField } from './RichTextField';
 import { SchemaHeaderField } from './SchemaHeaderField';
-import { ComputedField } from './ScriptField';
+import { ComputedField, ScriptField } from './ScriptField';
 import { ScriptCast, StrCast } from './Types';
 
 function _readOnlySetter(): never {
@@ -69,10 +69,12 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
 
     if (writeToDoc) {
         if (value === undefined) {
-            delete target[FieldKeys][prop];
+            target[FieldKeys] && delete target[FieldKeys][prop]; // Lists don't have a FieldKeys field
             delete target.__fieldTuples[prop];
         } else {
-            target[FieldKeys][prop] = true;
+            // bcz: uncomment to see if server is being updated
+            // console.log(prop + ' = ' + value + '(' + curValue + ')');
+            target[FieldKeys] && (target[FieldKeys][prop] = true); // Lists don't have a FieldKeys field
             target.__fieldTuples[prop] = value;
         }
 
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index c3423e2a5..7a1dde9fb 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -25,8 +25,8 @@ export class AudioUpload extends React.Component {
                 title: 'mobile audio',
                 _width: 300,
                 _height: 300,
-                _layoutFitContentsToBox: true,
-                boxShadow: '0 0',
+                _layout_fitContentsToBox: true,
+                layout_boxShadow: '0 0',
             }),
             Doc
         )
@@ -54,7 +54,7 @@ export class AudioUpload extends React.Component {
                             Doc
                         ) as Doc,
                     ],
-                    { title: 'mobile audio', _width: 300, _height: 300, _layoutFitContentsToBox: true, boxShadow: '0 0' }
+                    { title: 'mobile audio', _width: 300, _height: 300, _layout_fitContentsToBox: true, layout_boxShadow: '0 0' }
                 ),
                 Doc
             )
@@ -110,8 +110,8 @@ export class AudioUpload extends React.Component {
                         pinToPres={emptyFunction}
                         rootSelected={returnTrue}
                         removeDocument={undefined}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                         ScreenToLocalTransform={Transform.Identity}
                         PanelWidth={() => 600}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 471dc568b..584a7b432 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -402,8 +402,8 @@ export class MobileInterface extends React.Component {
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>
-- 
cgit v1.2.3-70-g09d2


From 4c8eee9811abd072d2a6adfe24eaf04f980ccf21 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 9 Aug 2023 15:21:20 -0400
Subject: updated file system to include recentlyClosed, Shared, and Dashboards
 and fixed drag drop to make sense for the filesystem.   Fixed loading
 documents to happen in one batch by fixing UPDATE_CACHED_DOCS to save only
 documents accessible from current dashboard.

---
 src/Utils.ts                                       |   2 +-
 src/client/DocServer.ts                            |  60 +-
 src/client/documents/DocumentTypes.ts              |   4 -
 src/client/documents/Documents.ts                  |  12 +-
 src/client/util/CurrentUserUtils.ts                |  37 +-
 src/client/util/DocumentManager.ts                 |   5 +-
 src/client/util/DragManager.ts                     |   4 +-
 src/client/util/GroupManager.tsx                   |   5 +-
 src/client/util/GroupMemberView.tsx                |   3 +-
 src/client/util/LinkManager.ts                     |   4 +-
 src/client/util/ReplayMovements.ts                 |   1 -
 src/client/util/ServerStats.tsx                    |  26 +-
 src/client/util/SettingsManager.tsx                |  11 +-
 src/client/util/SharingManager.tsx                 |  11 +-
 src/client/util/reportManager/ReportManager.tsx    |   5 +-
 src/client/views/DashboardView.tsx                 |  83 +--
 src/client/views/DocComponent.tsx                  |   4 +-
 src/client/views/FilterPanel.tsx                   |  18 +-
 src/client/views/LightboxView.tsx                  |   4 +-
 src/client/views/Main.tsx                          |   5 +-
 src/client/views/MainView.tsx                      |  12 +-
 src/client/views/PropertiesButtons.tsx             |   1 -
 src/client/views/PropertiesDocContextSelector.tsx  |   1 -
 src/client/views/PropertiesSection.tsx             |  80 ++-
 src/client/views/PropertiesView.tsx                | 758 ++++++++++-----------
 src/client/views/StyleProvider.tsx                 |   8 +-
 src/client/views/UndoStack.tsx                     |  43 +-
 .../views/collections/CollectionDockingView.tsx    |   7 +-
 src/client/views/collections/CollectionMenu.tsx    |   2 +-
 .../views/collections/CollectionStackingView.tsx   |   1 -
 .../views/collections/CollectionTreeView.tsx       |   1 +
 src/client/views/collections/TabDocView.tsx        |   2 +-
 src/client/views/collections/TreeView.tsx          |   2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   1 -
 src/client/views/global/globalScripts.ts           |   1 -
 .../views/newlightbox/ExploreView/ExploreView.tsx  |   3 -
 .../components/Recommendation/Recommendation.tsx   |   1 -
 src/client/views/nodes/DataVizBox/utils/D3Utils.ts |   1 -
 src/client/views/nodes/DocumentView.tsx            |   3 +-
 src/client/views/nodes/LinkDocPreview.tsx          |   2 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |   1 -
 src/client/views/nodes/ScreenshotBox.tsx           |   5 +-
 src/client/views/nodes/ScriptingBox.tsx            |   2 -
 .../views/nodes/formattedText/FormattedTextBox.tsx |  20 +-
 .../views/nodes/formattedText/RichTextRules.ts     |  26 +-
 src/client/views/pdf/AnchorMenu.tsx                |   5 +-
 src/client/views/search/SearchBox.tsx              |  78 ++-
 src/client/views/topbar/TopBar.tsx                 |  38 +-
 src/fields/Doc.ts                                  |  81 ++-
 src/fields/FieldLoader.tsx                         |   5 +-
 src/server/DashUploadUtils.ts                      |   3 +-
 51 files changed, 727 insertions(+), 771 deletions(-)

(limited to 'src/client/views/nodes/LinkDocPreview.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index 8b9fe2aab..7f83ab8f5 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -76,7 +76,7 @@ export namespace Utils {
             });
             return returnedUri;
         } catch (e) {
-            console.log('VideoBox :' + e);
+            console.log('ConvertDataURI :' + e);
         }
     }
 
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index ad5a73598..40979d631 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,16 +1,18 @@
 import { runInAction } from 'mobx';
 import * as rp from 'request-promise';
 import * as io from 'socket.io-client';
-import { Doc, Opt } from '../fields/Doc';
+import { Doc, DocListCast, Opt } from '../fields/Doc';
 import { UpdatingFromServer } from '../fields/DocSymbols';
 import { FieldLoader } from '../fields/FieldLoader';
 import { HandleUpdate, Id, Parent } from '../fields/FieldSymbols';
 import { ObjectField } from '../fields/ObjectField';
 import { RefField } from '../fields/RefField';
-import { StrCast } from '../fields/Types';
+import { DocCast, StrCast } from '../fields/Types';
 import MobileInkOverlay from '../mobile/MobileInkOverlay';
 import { emptyFunction, Utils } from '../Utils';
 import { GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, YoutubeQueryTypes } from './../server/Message';
+import { DocumentType } from './documents/DocumentTypes';
+import { LinkManager } from './util/LinkManager';
 import { SerializationHelper } from './util/SerializationHelper';
 import { GestureOverlay } from './views/GestureOverlay';
 
@@ -30,35 +32,44 @@ import { GestureOverlay } from './views/GestureOverlay';
 export namespace DocServer {
     let _cache: { [id: string]: RefField | Promise<Opt<RefField>> } = {};
 
-    export function QUERY_SERVER_CACHE(title: string) {
+    export function FindDocByTitle(title: string) {
         const foundDocId = Array.from(Object.keys(_cache))
             .filter(key => _cache[key] instanceof Doc)
             .find(key => (_cache[key] as Doc).title === title);
 
         return foundDocId ? (_cache[foundDocId] as Doc) : undefined;
     }
-    let lastCacheUpdate = 0;
-    export function UPDATE_SERVER_CACHE(print: boolean = false) {
-        if (print) {
-            const strings: string[] = [];
-            Array.from(Object.keys(_cache)).forEach(key => {
-                const doc = _cache[key];
-                if (doc instanceof Doc) strings.push(StrCast(doc.author) + ' ' + StrCast(doc.title) + ' ' + StrCast(Doc.GetT(doc, 'title', 'string', true)));
-            });
-            strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
-        }
-        const filtered = Array.from(Object.keys(_cache)).filter(key => {
-            const doc = _cache[key] as Doc;
-            return true;
-            if (!(StrCast(doc.author).includes('.edu') || StrCast(doc.author).includes('.com')) || doc.author === Doc.CurrentUserEmail) return true;
-            return false;
+    let cacheDocumentIds = ''; // ; separate string of all documents ids in the user's working set (cached on the server)
+    export let CacheNeedsUpdate = false;
+    export function UPDATE_SERVER_CACHE() {
+        const prototypes = Object.values(DocumentType)
+            .filter(type => type !== DocumentType.NONE)
+            .map(type => _cache[type + 'Proto'])
+            .filter(doc => doc instanceof Doc)
+            .map(doc => doc as Doc);
+        const references = new Set<Doc>(prototypes);
+        Doc.FindReferences(Doc.UserDoc(), references, undefined);
+        DocListCast(DocCast(Doc.UserDoc().myLinkDatabase).data).forEach(link => {
+            if (!references.has(DocCast(link.link_anchor_1)) && !references.has(DocCast(link.link_anchor_2))) {
+                Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myLinkDatabase), 'data', link);
+            }
         });
-        if (filtered.length === lastCacheUpdate) return;
-        lastCacheUpdate = filtered.length;
+        LinkManager.userLinkDBs.forEach(linkDb => Doc.FindReferences(linkDb, references, undefined));
+        const filtered = Array.from(references);
+
+        const newCacheUpdate = filtered.map(doc => doc[Id]).join(';');
+        if (newCacheUpdate === cacheDocumentIds) return;
+        cacheDocumentIds = newCacheUpdate;
+
+        // print out cached docs
+        console.log('Set cached docs = ');
+        const is_filtered = filtered.filter(doc => !Doc.IsSystem(doc));
+        const strings = is_filtered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)'));
+        strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
 
         rp.post(Utils.prepend('/setCacheDocumentIds'), {
             body: {
-                cacheDocumentIds: filtered.join(';'),
+                cacheDocumentIds,
             },
             json: true,
         });
@@ -353,7 +364,7 @@ export namespace DocServer {
         // i) which documents need to be fetched
         // ii) which are already in the process of being fetched
         // iii) which already exist in the cache
-        for (const id of ids) {
+        for (const id of ids.filter(id => id)) {
             const cached = _cache[id];
             if (cached === undefined) {
                 defaultPromises.push({
@@ -382,7 +393,7 @@ export namespace DocServer {
             // fields for the given ids. This returns a promise, which, when resolved, indicates that all the JSON serialized versions of
             // the fields have been returned from the server
             console.log('Requesting ' + requestedIds.length);
-            FieldLoader.active && runInAction(() => (FieldLoader.ServerLoadStatus.requested = requestedIds.length));
+            setTimeout(() => runInAction(() => (FieldLoader.ServerLoadStatus.requested = requestedIds.length)));
             const serializedFields = await Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds);
 
             // 3) when the serialized RefFields have been received, go head and begin deserializing them into objects.
@@ -392,7 +403,7 @@ export namespace DocServer {
             console.log('deserializing ' + serializedFields.length + ' fields');
             for (const field of serializedFields) {
                 processed++;
-                if (FieldLoader.active && processed % 150 === 0) {
+                if (processed % 150 === 0) {
                     runInAction(() => (FieldLoader.ServerLoadStatus.retrieved = processed));
                     await new Promise(res => setTimeout(res)); // force loading to yield to splash screen rendering to update progress
                 }
@@ -478,6 +489,7 @@ export namespace DocServer {
      * @param field the [RefField] to be serialized and sent to the server to be stored in the database
      */
     export function CreateField(field: RefField) {
+        CacheNeedsUpdate = true;
         _CreateField(field);
     }
 
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index b629d9b8c..1d0ddce40 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -14,13 +14,11 @@ export enum DocumentType {
     INK = 'ink',
     SCREENSHOT = 'screenshot',
     FONTICON = 'fonticonbox',
-    FILTER = 'filter',
     SEARCH = 'search', // search query
     LABEL = 'label', // simple text label
     BUTTON = 'button', // onClick button
     WEBCAM = 'webcam', // webcam
     CONFIG = 'config', // configuration document intended to specify a view layout configuration, but not be directly rendered (e.g., for saving the page# of a PDF, or view transform of a collection)
-    DATE = 'date', // calendar view of a date
     SCRIPTING = 'script', // script editor
     EQUATION = 'equation', // equation editor
     FUNCPLOT = 'funcplot', // function plotter
@@ -31,14 +29,12 @@ export enum DocumentType {
 
     // special purpose wrappers that either take no data or are compositions of lower level types
     LINK = 'link',
-    LINKANCHOR = 'linkanchor',
     IMPORT = 'import',
     SLIDER = 'slider',
     PRES = 'presentation',
     PRESELEMENT = 'preselement',
     COLOR = 'color',
     YOUTUBE = 'youtube',
-    SEARCHITEM = 'searchitem',
     COMPARISON = 'comparison',
     GROUP = 'group',
 
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8eeceaa15..fccad80ee 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,5 +1,5 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { action, runInAction } from 'mobx';
+import { action, reaction, runInAction } from 'mobx';
 import { basename } from 'path';
 import { DateField } from '../../fields/DateField';
 import { Doc, DocListCast, Field, Opt, updateCachedAcls } from '../../fields/Doc';
@@ -744,6 +744,10 @@ export namespace Docs {
                 // an entry dedicated to the given DocumentType)
                 target && PrototypeMap.set(type, target);
             });
+            reaction(
+                () => (proto => StrCast(proto?.BROADCAST_MESSAGE))(DocServer.GetCachedRefField('rtfProto') as Doc),
+                msg => msg && alert(msg)
+            );
         }
 
         /**
@@ -887,8 +891,6 @@ export namespace Docs {
                 DocUtils.MakeLinkToActiveAudio(() => viewDoc);
             }
 
-            Doc.AddFileOrphan(dataDoc);
-
             updateCachedAcls(dataDoc);
             updateCachedAcls(viewDoc);
 
@@ -1150,9 +1152,6 @@ export namespace Docs {
         export function FontIconDocument(options?: DocumentOptions) {
             return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { ...(options || {}) });
         }
-        export function FilterDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.FILTER), undefined, { ...(options || {}) });
-        }
 
         export function PresElementBoxDocument() {
             return Prototypes.get(DocumentType.PRESELEMENT);
@@ -1872,7 +1871,6 @@ export namespace DocUtils {
     export function copyDragFactory(dragFactory: Doc) {
         if (!dragFactory) return undefined;
         const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true);
-        ndoc && Doc.AddFileOrphan(Doc.GetProto(ndoc));
         if (ndoc && dragFactory['dragFactory_count'] !== undefined) {
             dragFactory['dragFactory_count'] = NumCast(dragFactory['dragFactory_count']) + 1;
             Doc.SetInPlace(ndoc, 'title', ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString(), true);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 21bcec6d1..e8262ff3b 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -152,7 +152,7 @@ export class CurrentUserUtils {
             { noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" },
             { noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
         const reqdNoteList = reqdTempOpts.map(opts => {
-            const reqdOpts = {...opts, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
+            const reqdOpts = {...opts, isSystem:true, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
             const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined;
             return DocUtils.AssignOpts(noteType, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts), true, opts.noteType??"Note");
         });
@@ -339,7 +339,7 @@ export class CurrentUserUtils {
     }
 
     /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents
-    static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] {
+    static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] {
       const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; 
       const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails";
         return [
@@ -348,7 +348,7 @@ export class CurrentUserUtils {
             { title: "Files",           toolTip: "Files",           target: this.setupFilesystem(doc, "myFilesystem"),         ignoreClick: true, icon: "folder-open", },
             { title: "Tools",           toolTip: "Tools",           target: this.setupToolsBtnPanel(doc, "myTools"),           ignoreClick: true, icon: "wrench",      funcs: {hidden: "IsNoviceMode()"} },
             { title: "Imports",         toolTip: "Imports ⌘I",      target: this.setupImportSidebar(doc, "myImports"),         ignoreClick:false, icon: "upload",      },
-            { title: "Closed",          toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive",     },
+            { title: "Closed",          toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive",     hidden: true }, // this doc is hidden from the Sidebar, but it's still being used in MyFilesystem which ignores the hidden field
             { title: "Shared",          toolTip: "Shared Docs",     target: Doc.MySharedDocs,                                  ignoreClick: true, icon: "users",       funcs: {badgeValue: badgeValue}},
             { title: "Trails",          toolTip: "Trails ⌘R",       target: Doc.UserDoc(),                                     ignoreClick: true, icon: "pres-trail",  funcs: {target: getActiveDashTrails}},
             { title: "User Doc",        toolTip: "User Doc",        target: this.setupUserDocView(doc, "myUserDocView"),       ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
@@ -357,17 +357,17 @@ export class CurrentUserUtils {
 
     /// the empty panel that is filled with whichever left menu button's panel has been selected
     static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") {
-        DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
+        DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {title:"leftSidebarPanel", isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
     }
 
     /// Initializes the left sidebar menu buttons and the panels they open up
     static setupLeftSidebarMenu(doc: Doc, field="myLeftSidebarMenu") {
         this.setupLeftSidebarPanel(doc);
         const myLeftSidebarMenu = DocCast(doc[field]);
-        const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, toolTip, scripts, funcs }) => {
+        const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, toolTip, hidden, scripts, funcs }) => {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
             const reqdBtnOpts:DocumentOptions = {
-                title, icon, target, toolTip, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
+                title, icon, target, toolTip, hidden, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
                 _width: 60, _height: 60,  _dragOnlyWithinContainer: true, _layout_hideContextMenu: true,
             };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
@@ -495,7 +495,7 @@ export class CurrentUserUtils {
         const reqdOpts:DocumentOptions = {
             title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
             dropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
-            layout_headerButton: newDashboardButton, childDragAction: "embed",
+            layout_headerButton: newDashboardButton, childDragAction: "none",
             _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
             contextMenuLabels:new List<string>(contextMenuLabels),
             contextMenuIcons:new List<string>(contextMenuIcons),
@@ -519,7 +519,6 @@ export class CurrentUserUtils {
     /// initializes the left sidebar File system pane
     static setupFilesystem(doc: Doc, field:string) {
         var myFilesystem = DocCast(doc[field]);
-        const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", undoIgnoreFields:new List<string>(['treeViewSortCriterion']), _dragOnlyWithinContainer: true, isSystem: true, isFolder: true });
         
         const newFolder = `TreeView_addNewFolder()`;
         const newFolderOpts: DocumentOptions = {
@@ -530,14 +529,15 @@ export class CurrentUserUtils {
         const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
         
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, 
-            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: "proto", isSystem: true,
+            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: 'add', isSystem: true,
             isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, 
             treeViewTruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed",
             childContextMenuLabels: new List<string>(["Create new folder"]),
             childContextMenuIcons: new List<string>(["plus"]),
             layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
         };
-        myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [myFileOrphans]);
+        const fileFolders = new Set(DocListCast(DocCast(doc[field])?.data));
+        myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, Array.from(fileFolders));
         const childContextMenuScripts = [newFolder];
         if (Cast(myFilesystem.childContextMenuScripts, listSpec(ScriptField), null)?.length !== childContextMenuScripts.length) {
             myFilesystem.childContextMenuScripts = new List<ScriptField>(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
@@ -547,8 +547,8 @@ export class CurrentUserUtils {
 
     /// initializes the panel displaying docs that have been recently closed
     static setupRecentlyClosed(doc: Doc, field:string) {
-        const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
-            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "embed", isSystem: true,
+        const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, isFolder: true,
+            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "move", isSystem: true,
             treeViewTruncateTitleWidth: 350, ignoreClick: true,  layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same",
             contextMenuLabels: new List<string>(["Empty recently closed"]),
             contextMenuIcons:new List<string>(["trash"]),
@@ -562,8 +562,6 @@ export class CurrentUserUtils {
             toolTip: "Empty recently closed",};
         DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
 
-        //if (recentlyClosed.layout_headerButton !== clearDocsButton) Doc.GetProto(recentlyClosed).layout_headerButton = clearDocsButton;
-        
         if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) {
             recentlyClosed.contextMenuScripts = new List<ScriptField>([ScriptField.MakeScript(clearAll("self"))!])
         }
@@ -777,6 +775,7 @@ export class CurrentUserUtils {
             const linkDocs = new Doc(linkDatabaseId, true);
             linkDocs.title = "LINK DATABASE: " + Doc.CurrentUserEmail;
             linkDocs.author = Doc.CurrentUserEmail;
+            linkDocs.isSystem = true;
             linkDocs.data = new List<Doc>([]);
             linkDocs["acl-Guest"] = SharingPermissions.Augment;
             doc.myLinkDatabase = new PrefetchProxy(linkDocs);
@@ -877,11 +876,13 @@ export class CurrentUserUtils {
         this.setupDockedButtons(doc);  // the bottom bar of font icons
         this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left
         this.setupDocTemplates(doc); // sets up the template menu of templates
-        this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
+        //this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
         DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) =>  Docs.Prototypes.MainScriptDocument(), {});
-        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents
+        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents
         
+        Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards)
         Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs)
+        Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyRecentlyClosed)
 
         if (doc.activeDashboard instanceof Doc) {
             // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss)
@@ -889,7 +890,7 @@ export class CurrentUserUtils {
         }
         new LinkManager();
 
-        setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500);
+        DocServer.CacheNeedsUpdate && setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500);
         setInterval(DocServer.UPDATE_SERVER_CACHE, 120000);
         return doc;
     }
@@ -923,11 +924,9 @@ export class CurrentUserUtils {
                 {
                     const ids = result.cacheDocumentIds.split(";");
                     const batch = 30000;
-                    FieldLoader.active = true;
                     for (let i = 0; i < ids.length; i = Math.min(ids.length, i+batch)) {
                         await DocServer.GetRefFields(ids.slice(i, i+batch));
                     }
-                    FieldLoader.active = false;
                 }
                 return result;
             } else {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 8e4e0d8f3..42132c2d7 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -75,7 +75,7 @@ export class DocumentManager {
 
     @action
     public AddView = (view: DocumentView) => {
-        //console.log("MOUNT " + view.props.Document.title + "/" + view.props.LayoutTemplateString);
+        if (view.props.LayoutTemplateString?.includes(KeyValueBox.name)) return;
         if (view.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
             const viewAnchorIndex = view.props.LayoutTemplateString.includes('link_anchor_2') ? 'link_anchor_2' : 'link_anchor_1';
             const link = view.rootDoc;
@@ -251,6 +251,7 @@ export class DocumentManager {
         options: DocFocusOptions, // options for how to navigate to target
         finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
     ) => {
+        Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc);
         const docContextPath = DocumentManager.GetContextPath(targetDoc, true);
         if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false;
         let rootContextView =
@@ -335,7 +336,7 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe
         if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
             DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
         } else {
-            const container = DocCast(containingDoc ?? doc.embedContainer ?? doc);
+            const container = DocCast(containingDoc ?? doc.embedContainer ?? Doc.BestEmbedding(doc));
             const showDoc = !Doc.IsSystem(container) ? container : doc;
             options.toggleTarget = undefined;
             DocumentManager.Instance.showDocument(showDoc, options, () => DocumentManager.Instance.showDocument(doc, { ...options, openLocation: undefined })).then(() => {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 85101fcab..f4ff38515 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -15,7 +15,7 @@ import { SelectionManager } from './SelectionManager';
 import { SnappingManager } from './SnappingManager';
 import { UndoManager } from './UndoManager';
 
-export type dropActionType = 'embed' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
+export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
 
 /**
  * Initialize drag
@@ -213,6 +213,8 @@ export namespace DragManager {
                                 ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result)
                                 : docDragData.dropAction === 'embed'
                                 ? Doc.BestEmbedding(d)
+                                : docDragData.dropAction === 'add'
+                                ? d
                                 : docDragData.dropAction === 'proto'
                                 ? Doc.GetProto(d)
                                 : docDragData.dropAction === 'copy'
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index e406d89e7..f35844020 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -16,6 +16,7 @@ import { listSpec } from '../../fields/Schema';
 import { DateField } from '../../fields/DateField';
 import { Id } from '../../fields/FieldSymbols';
 import { Button, IconButton, Size, Type } from 'browndash-components';
+import { SettingsManager } from './SettingsManager';
 
 /**
  * Interface for options for the react-select component
@@ -281,7 +282,7 @@ export class GroupManager extends React.Component<{}> {
      */
     private get groupCreationModal() {
         const contents = (
-            <div className="group-create" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+            <div className="group-create" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                 <div className="group-heading" style={{ marginBottom: 0 }}>
                     <p>
                         <b>New Group</b>
@@ -366,7 +367,7 @@ export class GroupManager extends React.Component<{}> {
         const groups = this.groupSort === 'ascending' ? this.allGroups.sort(sortGroups) : this.groupSort === 'descending' ? this.allGroups.sort(sortGroups).reverse() : this.allGroups;
 
         return (
-            <div className="group-interface" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+            <div className="group-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                 {this.groupCreationModal}
                 {this.currentGroup ? <GroupMemberView group={this.currentGroup} onCloseButtonClick={action(() => (this.currentGroup = undefined))} /> : null}
                 <div className="group-heading">
diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx
index 057f94f64..535d8ccc2 100644
--- a/src/client/util/GroupMemberView.tsx
+++ b/src/client/util/GroupMemberView.tsx
@@ -9,6 +9,7 @@ import { MainViewModal } from '../views/MainViewModal';
 import { GroupManager, UserOptions } from './GroupManager';
 import './GroupMemberView.scss';
 import { Button, IconButton, Size, Type } from 'browndash-components';
+import { SettingsManager } from './SettingsManager';
 
 interface GroupMemberViewProps {
     group: Doc;
@@ -28,7 +29,7 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> {
         const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group);
 
         return !this.props.group ? null : (
-            <div className="editing-interface" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+            <div className="editing-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                 <div className="editing-header">
                     <input
                         className="group-title"
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index c7f092565..ef4b21b05 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,7 +1,8 @@
-import { action, observable, observe } from 'mobx';
+import { action, observable, observe, runInAction } from 'mobx';
 import { computedFn } from 'mobx-utils';
 import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc';
 import { DirectLinks } from '../../fields/DocSymbols';
+import { FieldLoader } from '../../fields/FieldLoader';
 import { List } from '../../fields/List';
 import { ProxyField } from '../../fields/Proxy';
 import { Cast, DocCast, PromiseValue, StrCast } from '../../fields/Types';
@@ -132,6 +133,7 @@ export class LinkManager {
             },
             true
         );
+        runInAction(() => (FieldLoader.ServerLoadStatus.message = 'links'));
         LinkManager.addLinkDB(Doc.LinkDBDoc());
     }
 
diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts
index cbc465d6a..d99630f82 100644
--- a/src/client/util/ReplayMovements.ts
+++ b/src/client/util/ReplayMovements.ts
@@ -187,7 +187,6 @@ export class ReplayMovements {
                 } else {
                     // tab wasn't open - open it and play the movement
                     const openedColFFView = this.openTab(movement.doc);
-                    console.log('openedColFFView', openedColFFView);
                     openedColFFView && this.zoomAndPan(movement, openedColFFView);
                 }
 
diff --git a/src/client/util/ServerStats.tsx b/src/client/util/ServerStats.tsx
index 6a6ec158e..3c7c35a7e 100644
--- a/src/client/util/ServerStats.tsx
+++ b/src/client/util/ServerStats.tsx
@@ -6,6 +6,7 @@ import './SharingManager.scss';
 import { PingManager } from './PingManager';
 import { StrCast } from '../../fields/Types';
 import { Doc } from '../../fields/Doc';
+import { SettingsManager } from './SettingsManager';
 
 @observer
 export class ServerStats extends React.Component<{}> {
@@ -42,21 +43,22 @@ export class ServerStats extends React.Component<{}> {
      */
     @computed get sharingInterface() {
         return (
-            <div style={{
-                display: "flex",
-                height: 300,
-                width: 400,
-                background: StrCast(Doc.UserDoc().userBackgroundColor),
-                opacity: 0.6}}>
-                    <div style={{width: 300,height: 100,margin: "auto",display: "flex",flexDirection: "column"}}>
-                        {PingManager.Instance.IsBeating ? 'The server connection is active' :
-                            'The server connection has been interrupted.NOTE: Any changes made will appear to persist but will be lost after a browser refreshes.'}
-                          
-                    <br/>
+            <div
+                style={{
+                    display: 'flex',
+                    height: 300,
+                    width: 400,
+                    background: SettingsManager.Instance?.userBackgroundColor,
+                    opacity: 0.6,
+                }}>
+                <div style={{ width: 300, height: 100, margin: 'auto', display: 'flex', flexDirection: 'column' }}>
+                    {PingManager.Instance.IsBeating ? 'The server connection is active' : 'The server connection has been interrupted.NOTE: Any changes made will appear to persist but will be lost after a browser refreshes.'}
+
+                    <br />
                     <span>Active users:{this._stats?.socketMap.length}</span>
                     {this._stats?.socketMap.map((user: any) => (
                         <p>{user.username}</p>
-                    ))}  
+                    ))}
                 </div>
             </div>
         );
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index b8e327968..573900825 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -1,10 +1,11 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
 import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { ColorState, SketchPicker } from 'react-color';
+import { BsGoogle } from 'react-icons/bs';
+import { FaFillDrip, FaPalette } from 'react-icons/fa';
 import { Doc } from '../../fields/Doc';
-import { Id } from '../../fields/FieldSymbols';
 import { BoolCast, Cast, StrCast } from '../../fields/Types';
 import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
@@ -12,13 +13,9 @@ import { DocServer } from '../DocServer';
 import { Networking } from '../Network';
 import { MainViewModal } from '../views/MainViewModal';
 import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
-import { DragManager } from './DragManager';
 import { GroupManager } from './GroupManager';
 import './SettingsManager.scss';
 import { undoBatch } from './UndoManager';
-import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
-import { BsGoogle } from 'react-icons/bs';
-import { FaFillDrip, FaPalette } from 'react-icons/fa';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -39,6 +36,7 @@ export enum freeformScrollMode {
 
 @observer
 export class SettingsManager extends React.Component<{}> {
+    static Version = 'v0.5';
     public static Instance: SettingsManager;
     static _settingsStyle = addStyleSheet();
     @observable public isOpen = false;
@@ -452,6 +450,7 @@ export class SettingsManager extends React.Component<{}> {
                     </div>
 
                     <div className="settings-user">
+                        <div style={{ color: 'black' }}>{SettingsManager.Version}</div>
                         <div className="settings-username" style={{ color: this.userBackgroundColor }}>
                             {Doc.CurrentUserEmail}
                         </div>
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index cadcb1f8a..6171c01d7 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -8,6 +8,7 @@ import Select from 'react-select';
 import * as RequestPromise from 'request-promise';
 import { Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
 import { AclAdmin, AclPrivate, DocAcl, DocData } from '../../fields/DocSymbols';
+import { FieldLoader } from '../../fields/FieldLoader';
 import { Id } from '../../fields/FieldSymbols';
 import { StrCast } from '../../fields/Types';
 import { distributeAcls, GetEffectiveAcl, normalizeEmail, SharingPermissions, TraceMobx } from '../../fields/util';
@@ -23,6 +24,7 @@ import { GroupManager, UserOptions } from './GroupManager';
 import { GroupMemberView } from './GroupMemberView';
 import { LinkManager } from './LinkManager';
 import { SelectionManager } from './SelectionManager';
+import { SettingsManager } from './SettingsManager';
 import './SharingManager.scss';
 import { undoable } from './UndoManager';
 
@@ -136,6 +138,7 @@ export class SharingManager extends React.Component<{}> {
             this.populating = true;
             const userList = await RequestPromise.get(Utils.prepend('/getUsers'));
             const raw = (JSON.parse(userList) as User[]).filter(user => user.email !== 'guest' && user.email !== Doc.CurrentUserEmail);
+            runInAction(() => (FieldLoader.ServerLoadStatus.message = 'users'));
             const docs = await DocServer.GetRefFields(raw.reduce((list, user) => [...list, user.sharingDocumentId, user.linkDatabaseId], [] as string[]));
             raw.map(
                 action((newUser: User) => {
@@ -144,7 +147,7 @@ export class SharingManager extends React.Component<{}> {
                     if (sharingDoc instanceof Doc && linkDatabase instanceof Doc) {
                         if (!this.users.find(user => user.user.email === newUser.email)) {
                             this.users.push({ user: newUser, sharingDoc, linkDatabase, userColor: StrCast(sharingDoc.userColor) });
-                            LinkManager.addLinkDB(linkDatabase);
+                            //LinkManager.addLinkDB(linkDatabase);
                         }
                     }
                 })
@@ -525,10 +528,10 @@ export class SharingManager extends React.Component<{}> {
             const permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
 
             return !permissions ? null : (
-                <div key={groupKey} className={'container'} style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+                <div key={groupKey} className={'container'} style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
                     <div className={'padding'}>{StrCast(group.title)}</div>
                     &nbsp;
-                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
+                    {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={SettingsManager.Instance.userColor} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
                     <div className={'edit-actions'}>
                         {admin || this.myDocAcls ? (
                             <select className={`permissions-dropdown-${permissions}`} value={permissions} onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}>
@@ -550,7 +553,7 @@ export class SharingManager extends React.Component<{}> {
                 <div
                     className="sharing-contents"
                     style={{
-                        background: StrCast(Doc.UserDoc().userBackgroundColor),
+                        background: SettingsManager.Instance.userBackgroundColor,
                         color: StrCast(Doc.UserDoc().userColor),
                     }}>
                     <p className="share-title" style={{ color: StrCast(Doc.UserDoc().userColor) }}>
diff --git a/src/client/util/reportManager/ReportManager.tsx b/src/client/util/reportManager/ReportManager.tsx
index e684bd637..7aad0f2b1 100644
--- a/src/client/util/reportManager/ReportManager.tsx
+++ b/src/client/util/reportManager/ReportManager.tsx
@@ -19,6 +19,7 @@ import { BugType, FileData, Priority, ReportForm, ViewState, bugDropdownItems, d
 import { Filter, FormInput, FormTextArea, IssueCard, IssueView, Tag } from './ReportManagerComponents';
 import { StrCast } from '../../../fields/Types';
 import { MdRefresh } from 'react-icons/md';
+import { SettingsManager } from '../SettingsManager';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -213,11 +214,11 @@ export class ReportManager extends React.Component<{}> {
      * @returns the component that dispays all issues
      */
     private viewIssuesComponent = () => {
-        const darkMode = isDarkMode(StrCast(Doc.UserDoc().userBackgroundColor));
+        const darkMode = isDarkMode(SettingsManager.Instance.userBackgroundColor);
         const colors = darkMode ? darkColors : lightColors;
 
         return (
-            <div className="view-issues" style={{ backgroundColor: StrCast(Doc.UserDoc().userBackgroundColor), color: colors.text }}>
+            <div className="view-issues" style={{ backgroundColor: SettingsManager.Instance.userBackgroundColor, color: colors.text }}>
                 <div className="left" style={{ display: this.rightExpanded ? 'none' : 'flex' }}>
                     <div className="report-header">
                         <h2 style={{ color: colors.text }}>Open Issues</h2>
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index ae55c8ebf..21808d6e0 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -43,7 +43,7 @@ export class DashboardView extends React.Component {
     @observable private selectedDashboardGroup = DashboardGroup.MyDashboards;
 
     @observable private newDashboardName: string | undefined = undefined;
-    @observable private newDashboardColor: string | undefined = "#AFAFAF";
+    @observable private newDashboardColor: string | undefined = '#AFAFAF';
     @action abortCreateNewDashboard = () => {
         this.newDashboardName = undefined;
     };
@@ -100,30 +100,15 @@ export class DashboardView extends React.Component {
         const dashboardCount = DocListCast(Doc.MyDashboards.data).length + 1;
         const placeholder = `Dashboard ${dashboardCount}`;
         return (
-            <div className="new-dashboard"
-                style={{ 
+            <div
+                className="new-dashboard"
+                style={{
                     background: StrCast(Doc.UserDoc().userBackgroundColor),
-                    color: StrCast(Doc.UserDoc().userColor)
-                }}
-            >
+                    color: StrCast(Doc.UserDoc().userColor),
+                }}>
                 <div className="header">Create New Dashboard</div>
-                <EditableText 
-                    formLabel='Title'
-                    placeholder={placeholder}
-                    type={Type.SEC}
-                    color={StrCast(Doc.UserDoc().userColor)}
-                    setVal={val => this.setNewDashboardName(val as string)}
-                    fillWidth
-                />
-                <ColorPicker
-                    formLabel='Background'
-                    colorPickerType='github'
-                    type={Type.TERT}
-                    selectedColor={this.newDashboardColor}
-                    setSelectedColor={color => {
-                        this.setNewDashboardColor(color);
-                    }}
-                />
+                <EditableText formLabel="Title" placeholder={placeholder} type={Type.SEC} color={StrCast(Doc.UserDoc().userColor)} setVal={val => this.setNewDashboardName(val as string)} fillWidth />
+                <ColorPicker formLabel="Background" colorPickerType="github" type={Type.TERT} selectedColor={this.newDashboardColor} setSelectedColor={this.setNewDashboardColor} />
                 <div className="button-bar">
                     <Button text="Cancel" color={StrCast(Doc.UserDoc().userColor)} onClick={this.abortCreateNewDashboard} />
                     <Button type={Type.TERT} text="Create" color={StrCast(Doc.UserDoc().userVariantColor)} onClick={() => this.createNewDashboard(this.newDashboardName!, this.newDashboardColor)} />
@@ -165,21 +150,14 @@ export class DashboardView extends React.Component {
     };
 
     render() {
-        const color = StrCast(Doc.UserDoc().userColor)
-        const variant = StrCast(Doc.UserDoc().userVariantColor)
+        const color = StrCast(Doc.UserDoc().userColor);
+        const variant = StrCast(Doc.UserDoc().userVariantColor);
         return (
             <>
                 <div className="dashboard-view">
                     <div className="left-menu">
-                        <Button 
-                            text={'My Dashboards'}
-                            active={this.selectedDashboardGroup === DashboardGroup.MyDashboards}
-                            color={color}
-                            align={'flex-start'}
-                            onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)}
-                            fillWidth
-                        />
-                        <Button 
+                        <Button text={'My Dashboards'} active={this.selectedDashboardGroup === DashboardGroup.MyDashboards} color={color} align={'flex-start'} onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)} fillWidth />
+                        <Button
                             text={'Shared Dashboards' + ' (' + this.getDashboards(DashboardGroup.SharedDashboards).length + ')'}
                             active={this.selectedDashboardGroup === DashboardGroup.SharedDashboards}
                             color={this.getDashboards(DashboardGroup.SharedDashboards).some(dash => !DocListCast(Doc.MySharedDocs.viewed).includes(dash)) ? 'green' : color}
@@ -196,11 +174,11 @@ export class DashboardView extends React.Component {
                                 .filter(key => key !== `acl-${Doc.CurrentUserEmailNormalized}` && !['acl-Me', 'acl-Guest'].includes(key))
                                 .some(key => dashboard[DocAcl][key] !== AclPrivate);
                             return (
-                                <div 
-                                    className="dashboard-container" 
-                                    key={dashboard[Id]} 
+                                <div
+                                    className="dashboard-container"
+                                    key={dashboard[Id]}
                                     style={{ background: this.isUnviewedSharedDashboard(dashboard) && this.selectedDashboardGroup === DashboardGroup.SharedDashboards ? '#6CB982' : shared ? variant : '' }}
-                                    onContextMenu={e => this.onContextMenu(dashboard, e)} 
+                                    onContextMenu={e => this.onContextMenu(dashboard, e)}
                                     onClick={e => this.clickDashboard(e, dashboard)}>
                                     <img
                                         src={
@@ -208,12 +186,7 @@ export class DashboardView extends React.Component {
                                         }
                                     />
                                     <div className="info">
-                                        <EditableText 
-                                            type={Type.PRIM}
-                                            color={color}
-                                            val={StrCast(dashboard.title)} 
-                                            setVal={val => (Doc.GetProto(dashboard).title = val)}
-                                        />
+                                        <EditableText type={Type.PRIM} color={color} val={StrCast(dashboard.title)} setVal={val => (Doc.GetProto(dashboard).title = val)} />
                                         {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ? <div>unviewed</div> : <div></div>}
                                         <div
                                             className="more"
@@ -229,10 +202,13 @@ export class DashboardView extends React.Component {
                                             <Button size={Size.SMALL} color={color} icon={<FontAwesomeIcon color={color} icon="bars" />} />
                                         </div>
                                     </div>
-                                    <div className={`background`} style={{
-                                        background: StrCast(Doc.UserDoc().userColor),
-                                        filter: 'opacity(0.2)'
-                                    }}/>
+                                    <div
+                                        className={`background`}
+                                        style={{
+                                            background: StrCast(Doc.UserDoc().userColor),
+                                            filter: 'opacity(0.2)',
+                                        }}
+                                    />
                                     <div className={'dashboard-status' + (shared ? '-shared' : '')}>{shared ? 'shared' : ''}</div>
                                 </div>
                             );
@@ -243,10 +219,13 @@ export class DashboardView extends React.Component {
                                 this.setNewDashboardName('');
                             }}>
                             +
-                            <div className={`background`} style={{
-                                background: StrCast(Doc.UserDoc().userColor),
-                                filter: 'opacity(0.2)'
-                            }}/>
+                            <div
+                                className={`background`}
+                                style={{
+                                    background: StrCast(Doc.UserDoc().userColor),
+                                    filter: 'opacity(0.2)',
+                                }}
+                            />
                         </div>
                     </div>
                 </div>
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 8fe5c2e01..e076e69ca 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -3,7 +3,7 @@ import { DateField } from '../../fields/DateField';
 import { Doc, DocListCast, HierarchyMapping, Opt, ReverseHierarchyMap } from '../../fields/Doc';
 import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocAcl, DocData } from '../../fields/DocSymbols';
 import { List } from '../../fields/List';
-import { Cast, StrCast } from '../../fields/Types';
+import { Cast, DocCast, StrCast } from '../../fields/Types';
 import { distributeAcls, GetEffectiveAcl, inheritParentAcls, SharingPermissions } from '../../fields/util';
 import { returnFalse } from '../../Utils';
 import { DocUtils } from '../documents/Documents';
@@ -149,9 +149,9 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                 toRemove.forEach(doc => {
                     leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
                     Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
+                    Doc.RemoveDocFromList(Doc.GetProto(doc), 'proto_embeddings', doc);
                     doc.embedContainer = undefined;
                     if (recent) {
-                        Doc.RemoveDocFromList(recent, 'data', doc);
                         doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true);
                     }
                 });
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 68d29942b..63bd01b19 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -169,8 +169,6 @@ export class FilterPanel extends React.Component<filterProps> {
 
     render() {
         const options = this._allFacets.filter(facet => this.currentFacets.indexOf(facet) === -1).map(facet => ({ value: facet, label: facet }));
-        console.log("this is option " + options)
-        console.log("this is alll facets " + this._allFacets)
         return (
             <div className="filterBox-treeView">
                 <div className="filterBox-select">
@@ -192,17 +190,15 @@ export class FilterPanel extends React.Component<filterProps> {
                 <div className="filterBox-tree" key="tree">
                     {Array.from(this.activeFacets.keys()).map(facetHeader => (
                         <div>
-                            <div className  = "filterBox-facetHeader">
-                                <div className = "filterBox-facetHeader-Header"> </div>
+                            <div className="filterBox-facetHeader">
+                                <div className="filterBox-facetHeader-Header"> </div>
                                 {facetHeader.charAt(0).toUpperCase() + facetHeader.slice(1)}
-                                
-                                <div className = "filterBox-facetHeader-collapse"> 
-                                 <AiOutlineMinusSquare/>
-                                 {/* <CiCircleRemove/> */}
-                                  </div>
-                               
+
+                                <div className="filterBox-facetHeader-collapse">
+                                    <AiOutlineMinusSquare />
+                                    {/* <CiCircleRemove/> */}
+                                </div>
                             </div>
-                           
 
                             {this.displayFacetValueFilterUIs(this.activeFacets.get(facetHeader), facetHeader)}
                         </div>
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 286d39943..f79a30ad3 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -313,8 +313,10 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                     className="lightboxView-tabBtn"
                     title="open in tab"
                     onClick={e => {
+                        const lightdoc = LightboxView._docTarget || LightboxView._doc!;
                         e.stopPropagation();
-                        CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, OpenWhereMod.none);
+                        Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', lightdoc);
+                        CollectionDockingView.AddSplit(lightdoc, OpenWhereMod.none);
                         SelectionManager.DeselectAll();
                         LightboxView.SetLightboxDoc(undefined);
                     }}>
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 2fa42d091..2a73d77ed 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -6,10 +6,7 @@ import * as React from 'react';
 import * as ReactDOM from 'react-dom/client';
 import { AssignAllExtensions } from '../../extensions/General/Extensions';
 import { FieldLoader } from '../../fields/FieldLoader';
-import { DocServer } from '../DocServer';
-import { Docs } from '../documents/Documents';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { LinkManager } from '../util/LinkManager'; // this must come before importing Docs and CurrentUserUtils
 import { ReplayMovements } from '../util/ReplayMovements';
 import { TrackMovements } from '../util/TrackMovements';
 import { CollectionView } from './collections/CollectionView';
@@ -20,7 +17,7 @@ import './global/globalScripts';
 dotenv.config();
 
 AssignAllExtensions();
-FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0 }; // bcz: not sure why this is needed to get the code loaded properly...
+FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; // bcz: not sure why this is needed to get the code loaded properly...
 
 (async () => {
     MainView.Live = window.location.search.includes('live');
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index cbaa763f5..dc236b603 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -4,7 +4,7 @@ import * as far from '@fortawesome/free-regular-svg-icons';
 import * as fa from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import 'browndash-components/dist/styles/global.min.css';
-import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
+import { action, computed, configure, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import 'normalize.css';
 import * as React from 'react';
@@ -182,14 +182,6 @@ export class MainView extends React.Component {
                 'currentFrame',
             ]); // can play with these fields on someone else's
         }
-        DocServer.GetRefField('rtfProto').then(
-            proto =>
-                proto instanceof Doc &&
-                reaction(
-                    () => StrCast(proto.BROADCAST_MESSAGE),
-                    msg => msg && alert(msg)
-                )
-        );
 
         const tag = document.createElement('script');
         tag.src = 'https://www.youtube.com/iframe_api';
@@ -527,7 +519,7 @@ export class MainView extends React.Component {
     });
 
     initEventListeners = () => {
-        window.addEventListener('beforeunload', () => DocServer.UPDATE_SERVER_CACHE());
+        window.addEventListener('beforeunload', DocServer.UPDATE_SERVER_CACHE);
         window.addEventListener('drop', e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page
         window.addEventListener('dragover', e => e.preventDefault(), false);
         // document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined));
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index b74eabcc3..8cae34d7d 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -375,7 +375,6 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 val: value[1],
             };
         });
-        console.log('click val: ', this.onClickVal);
         return !this.selectedDoc ? null : (
             <Dropdown
                 tooltip={'Choose onClick behavior'}
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 395aa2b61..d157e7b1c 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -38,7 +38,6 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
                 }, new Set<Doc>())
                 .keys()
         );
-        console.log('embeddings ' + embeddings.length);
 
         return doclayouts
             .filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance?.props.Document))
diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx
index ec8043ffe..6fab0168b 100644
--- a/src/client/views/PropertiesSection.tsx
+++ b/src/client/views/PropertiesSection.tsx
@@ -1,19 +1,19 @@
 import React = require('react');
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
-import { action, computed, observable } from "mobx"
-import { observer } from "mobx-react"
-import './PropertiesSection.scss'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import './PropertiesSection.scss';
 import { Doc } from '../../fields/Doc';
 import { StrCast } from '../../fields/Types';
 
 export interface PropertiesSectionProps {
-    title: string, 
-    content?: JSX.Element | string | null, 
-    isOpen: boolean,
-    setIsOpen: (bool: boolean) => any 
-    inSection?: boolean,
-    setInSection?: (bool: boolean) => any
-    onDoubleClick?: () => void
+    title: string;
+    content?: JSX.Element | string | null;
+    isOpen: boolean;
+    setIsOpen: (bool: boolean) => any;
+    inSection?: boolean;
+    setInSection?: (bool: boolean) => any;
+    onDoubleClick?: () => void;
 }
 
 @observer
@@ -33,34 +33,32 @@ export class PropertiesSection extends React.Component<PropertiesSectionProps> {
     @observable isDouble: boolean = false;
 
     render() {
-        console.log(this.props.title, this.props.content)
-        if (this.props.content === undefined || this.props.content === null) return null
-        else return <div className="propertiesView-section" onPointerEnter={action(() => (this.props.setInSection && this.props.setInSection(true)))} onPointerLeave={action(() => (this.props.setInSection && this.props.setInSection(false)))}>
-        <div className="propertiesView-sectionTitle" 
-            onDoubleClick={action((e) => {
-                this.isDouble = true;
-                this.props.onDoubleClick && this.props.onDoubleClick()
-                console.log("open options")
-                this.props.setIsOpen(true)
-                setTimeout(() => this.isDouble = false, 300)
-            })}
-            onClick={action((e) => {
-                this.props.setIsOpen(!this.props.isOpen)
-            })} 
-            style={{ 
-                background: this.props.isOpen ?  this.variantColor : this.backgroundColor,
-                color: this.color
-            }}>
-            {this.props.title}
-            <div className="propertiesView-sectionTitle-icon">
-                <FontAwesomeIcon icon={this.props.isOpen ? 'caret-down' : 'caret-right'} size="lg"  />
-            </div>
-        </div>
-        {!this.props.isOpen ? null :
-            <div className="propertiesView-content">
-                {this.props.content}
-            </div>
-        }
-    </div>
+        if (this.props.content === undefined || this.props.content === null) return null;
+        else
+            return (
+                <div className="propertiesView-section" onPointerEnter={action(() => this.props.setInSection && this.props.setInSection(true))} onPointerLeave={action(() => this.props.setInSection && this.props.setInSection(false))}>
+                    <div
+                        className="propertiesView-sectionTitle"
+                        onDoubleClick={action(e => {
+                            this.isDouble = true;
+                            this.props.onDoubleClick && this.props.onDoubleClick();
+                            this.props.setIsOpen(true);
+                            setTimeout(() => (this.isDouble = false), 300);
+                        })}
+                        onClick={action(e => {
+                            this.props.setIsOpen(!this.props.isOpen);
+                        })}
+                        style={{
+                            background: this.props.isOpen ? this.variantColor : this.backgroundColor,
+                            color: this.color,
+                        }}>
+                        {this.props.title}
+                        <div className="propertiesView-sectionTitle-icon">
+                            <FontAwesomeIcon icon={this.props.isOpen ? 'caret-down' : 'caret-right'} size="lg" />
+                        </div>
+                    </div>
+                    {!this.props.isOpen ? null : <div className="propertiesView-content">{this.props.content}</div>}
+                </div>
+            );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 27b9c3c7a..872f1c6ab 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -8,7 +8,7 @@ import { concat } from 'lodash';
 import { Lambda, action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { ColorState, SketchPicker } from 'react-color';
-import * as Icons from "react-icons/bs"; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs"
+import * as Icons from 'react-icons/bs'; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs"
 import { GrCircleInformation } from 'react-icons/gr';
 import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../Utils';
 import { Doc, DocListCast, Field, FieldResult, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc';
@@ -51,7 +51,6 @@ interface PropertiesViewProps {
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
 }
 
-
 @observer
 export class PropertiesView extends React.Component<PropertiesViewProps> {
     private _widthUndo?: UndoManager.Batch;
@@ -191,7 +190,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             });
 
             rows.push(
-                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: "white", textAlign: "center" }}>
+                <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: 'white', textAlign: 'center' }}>
                     <EditableView key="editableView" oneLine contents={'add key:value or #tags'} height={13} fontSize={10} GetValue={() => ''} SetValue={this.setKeyValue} />
                 </div>
             );
@@ -249,14 +248,12 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return !this.selectedDoc ? null : <PropertiesDocContextSelector DocView={this.selectedDocumentView} hideTitle={true} addDocTab={this.props.addDocTab} />;
     }
 
-    @computed get contextCount(){
-        console.log("in context count");
-        if (this.selectedDocumentView){ 
-            const target = (this.selectedDocumentView.props.Document)
-            const embeddings = DocListCast(target.proto_embeddings)
-            console.log(embeddings.length -1 );
-            return (embeddings.length - 1)
-        } else{
+    @computed get contextCount() {
+        if (this.selectedDocumentView) {
+            const target = this.selectedDocumentView.props.Document;
+            const embeddings = DocListCast(target.proto_embeddings);
+            return embeddings.length - 1;
+        } else {
             return 0;
         }
     }
@@ -266,13 +263,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return !selAnchor ? null : <PropertiesDocBacklinksSelector Document={selAnchor} hideTitle={true} addDocTab={this.props.addDocTab} />;
     }
 
-    @computed get linkCount(){
-        const selAnchor =  this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor ?? this.selectedDoc;
+    @computed get linkCount() {
+        const selAnchor = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor ?? this.selectedDoc;
         var counter = 0;
 
-        LinkManager.Links(selAnchor).forEach((l, i) =>
-                counter ++
-            );
+        LinkManager.Links(selAnchor).forEach((l, i) => counter++);
 
         return counter;
     }
@@ -356,7 +351,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return (
             <Tooltip title={<div className="dash-tooltip">Notify with message</div>}>
                 <div className="notify-button">
-                    <FontAwesomeIcon className="notify-button-icon" icon="bell"  size="sm" />
+                    <FontAwesomeIcon className="notify-button-icon" icon="bell" size="sm" />
                 </div>
             </Tooltip>
         );
@@ -367,16 +362,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
      */
     @computed get expansionIcon() {
         return (
-            <div className="expansion-button" >
-                <IconButton 
-                    icon={<FontAwesomeIcon icon={'ellipsis-h'} />} 
-                    size={Size.XSMALL} 
-                    color={StrCast(Doc.UserDoc().userColor)} 
+            <div className="expansion-button">
+                <IconButton
+                    icon={<FontAwesomeIcon icon={'ellipsis-h'} />}
+                    size={Size.XSMALL}
+                    color={StrCast(Doc.UserDoc().userColor)}
                     onClick={action(() => {
                         if (this.selectedDocumentView || this.selectedDoc) {
                             SharingManager.Instance.open(this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined, this.selectedDoc);
                         }
-                    })} 
+                    })}
                 />
             </div>
         );
@@ -418,7 +413,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             <div>
                 <div className={'propertiesView-shareDropDown'}>
                     <div className={`propertiesView-shareDropDown${permission}`}>
-                        <div >{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div>
+                        <div>{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div>
                     </div>
                 </div>
             </div>
@@ -450,7 +445,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         const target = docs[0];
 
         const showAdmin = GetEffectiveAcl(target) == AclAdmin;
-        console.log(GetEffectiveAcl(target), Doc.GetProto(target)[`acl-${normalizeEmail(Doc.CurrentUserEmail)}`])
         const individualTableEntries = [];
         const usersAdded: string[] = []; // all shared users being added - organized by denormalized email
 
@@ -522,7 +516,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <div>
                     <br></br> Individuals with Access to this Document
                 </div>
-                <div className="propertiesView-sharingTable" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}>
+                <div className="propertiesView-sharingTable" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                     {<div> {individualTableEntries}</div>}
                 </div>
                 {groupTableEntries.length > 0 ? (
@@ -530,7 +524,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <div>
                             <br></br> Groups with Access to this Document
                         </div>
-                        <div className="propertiesView-sharingTable" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}>
+                        <div className="propertiesView-sharingTable" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
                             {<div> {groupTableEntries}</div>}
                         </div>
                     </div>
@@ -562,68 +556,43 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get editableTitle() {
-
         const titles = new Set<string>();
         const title = Array.from(titles.keys()).length > 1 ? '--multiple selected--' : StrCast(this.selectedDoc?.title);
         SelectionManager.Views().forEach(dv => titles.add(StrCast(dv.rootDoc.title)));
-        return (
-            <EditableText
-                val={title}
-                setVal={this.setTitle}
-                color={this.color}
-                type={Type.SEC}
-                formLabel={"Title"}
-                fillWidth
-            />
-        );
+        return <EditableText val={title} setVal={this.setTitle} color={this.color} type={Type.SEC} formLabel={'Title'} fillWidth />;
     }
 
     @computed get currentType() {
-        // console.log("current type " + this.selectedDoc?.type)
- 
-         const documentType = StrCast(this.selectedDoc?.type)
-         var currentType: string = documentType;
-         var capitalizedDocType = Utils.cleanDocumentType(currentType as DocumentType);
- 
-         return (
-             <div>
-                 <div className = "propertiesView-wordType">Type</div>  
-                 <div className= "currentType"> 
-                 <div className='currentType-icon'>
-                      {this.currentComponent}
-                 </div>
-                
-                   {capitalizedDocType} 
-                
-                 </div>
-                
-             </div>
-           
-         )
-     }
+        const documentType = StrCast(this.selectedDoc?.type);
+        var currentType: string = documentType;
+        var capitalizedDocType = Utils.cleanDocumentType(currentType as DocumentType);
 
-    @computed get currentComponent() {
+        return (
+            <div>
+                <div className="propertiesView-wordType">Type</div>
+                <div className="currentType">
+                    <div className="currentType-icon">{this.currentComponent}</div>
 
-        var iconName = StrCast(this.selectedDoc?.systemIcon)
+                    {capitalizedDocType}
+                </div>
+            </div>
+        );
+    }
 
-        // if (this.selectedDoc?.type === DocumentType.COL){
-        //     console.log("i did it!")
-        // }
-       
+    @computed get currentComponent() {
+        var iconName = StrCast(this.selectedDoc?.systemIcon);
 
-        if (iconName){
+        if (iconName) {
             const Icon = Icons[iconName as keyof typeof Icons];
             return <Icon />;
-        } else{
-          return <Icons.BsFillCollectionFill/>
-
+        } else {
+            return <Icons.BsFillCollectionFill />;
         }
     }
 
     @undoBatch
     @action
     setTitle = (value: string | number) => {
-        console.log(value)
         if (SelectionManager.Views().length > 1) {
             SelectionManager.Views().map(dv => Doc.SetInPlace(dv.rootDoc, 'title', value, true));
         } else if (this.dataDoc) {
@@ -687,7 +656,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         className="inking-button-points"
                         style={{ backgroundColor: InkStrokeProperties.Instance._controlButton ? 'black' : '' }}
                         onPointerDown={action(() => (InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton))}>
-                        <FontAwesomeIcon icon="bezier-curve"  size="lg" />
+                        <FontAwesomeIcon icon="bezier-curve" size="lg" />
                     </div>
                 </Tooltip>
             </div>
@@ -706,10 +675,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} onKeyPress={e => e.stopPropagation()} />
                 <div className="inputBox-button">
                     <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
-                        <FontAwesomeIcon icon="caret-up"  size="sm" />
+                        <FontAwesomeIcon icon="caret-up" size="sm" />
                     </div>
                     <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}>
-                        <FontAwesomeIcon icon="caret-down"  size="sm" />
+                        <FontAwesomeIcon icon="caret-down" size="sm" />
                     </div>
                 </div>
             </div>
@@ -963,10 +932,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} />
                 <div className="inputBox-button">
                     <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
-                        <FontAwesomeIcon icon="caret-up"  size="sm" />
+                        <FontAwesomeIcon icon="caret-up" size="sm" />
                     </div>
                     <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}>
-                        <FontAwesomeIcon icon="caret-down"  size="sm" />
+                        <FontAwesomeIcon icon="caret-down" size="sm" />
                     </div>
                 </div>
             </div>
@@ -983,7 +952,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         this.openSharing = false;
         this.openLayout = false;
         this.openFilters = false;
-    }
+    };
 
     @computed get widthAndDash() {
         return (
@@ -1065,64 +1034,45 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any) => {
-        return <div>
-            <NumberInput
-                formLabel={label}
-                formLabelPlacement={'left'}
-                type={Type.SEC}
-                unit={unit}
-                fillWidth
-                color={this.color}
-                number={number}
-                setNumber={setNumber} 
-                min={min}
-                max={max}            
-            />
-            <Slider 
-                multithumb={false}
-                color={this.color}
-                size={Size.XSMALL} 
-                min={min} 
-                max={max}
-                unit={unit} 
-                number={number}
-                setNumber={setNumber}
-                fillWidth
-            />
-        </div>
-    }
+        return (
+            <div>
+                <NumberInput formLabel={label} formLabelPlacement={'left'} type={Type.SEC} unit={unit} fillWidth color={this.color} number={number} setNumber={setNumber} min={min} max={max} />
+                <Slider multithumb={false} color={this.color} size={Size.XSMALL} min={min} max={max} unit={unit} number={number} setNumber={setNumber} fillWidth />
+            </div>
+        );
+    };
 
     @computed get transformEditor() {
         return (
             <div className="transform-editor">
                 {this.isInk ? this.controlPointsButton : null}
                 {this.getNumber(
-                    "Height",
-                    " px",
+                    'Height',
+                    ' px',
                     0,
                     1000,
                     Number(this.shapeHgt),
                     undoable((val: string) => !isNaN(Number(val)) && (this.shapeHgt = val), 'set height')
                 )}
                 {this.getNumber(
-                    "Width",
-                    " px",
+                    'Width',
+                    ' px',
                     0,
                     1000,
                     Number(this.shapeWid),
                     undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = val), 'set width')
                 )}
                 {this.getNumber(
-                    "X Coordinate",
-                    " px",
+                    'X Coordinate',
+                    ' px',
                     -2000,
                     2000,
                     Number(this.shapeXps),
                     undoable((val: string) => !isNaN(Number(val)) && (this.shapeXps = val), 'set x coord')
                 )}
                 {this.getNumber(
-                    "Y Coordinate",
-                    " px",
+                    'Y Coordinate',
+                    ' px',
                     -2000,
                     2000,
                     Number(this.shapeYps),
@@ -1133,38 +1083,44 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get optionsSubMenu() {
-        return <PropertiesSection
-            title="Options"
-            content={<PropertiesButtons />}
-            inSection={this.inOptions}
-            isOpen={this.openOptions}
-            setInSection={(bool) => this.inOptions = bool}
-            setIsOpen={(bool) => this.openOptions = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Options"
+                content={<PropertiesButtons />}
+                inSection={this.inOptions}
+                isOpen={this.openOptions}
+                setInSection={bool => (this.inOptions = bool)}
+                setIsOpen={bool => (this.openOptions = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     @computed get sharingSubMenu() {
-        return <PropertiesSection
-            title="Sharing & Permissions"
-            content={<>
-            {/* <div className="propertiesView-buttonContainer"> */}
-                    <div className="propertiesView-acls-checkbox">
-                        Layout Permissions
-                        <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
-                    </div>
-                    {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
+        return (
+            <PropertiesSection
+                title="Sharing & Permissions"
+                content={
+                    <>
+                        {/* <div className="propertiesView-buttonContainer"> */}
+                        <div className="propertiesView-acls-checkbox">
+                            Layout Permissions
+                            <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
+                        </div>
+                        {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
                         <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}>
                             <FontAwesomeIcon icon="redo-alt"  size="1x" />
                         </button>
                     </Tooltip> */}
-                {/* </div> */}
-                {this.sharingTable}
-            </>}
-            isOpen={this.openSharing}
-            setIsOpen={(bool) => this.openSharing = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+                        {/* </div> */}
+                        {this.sharingTable}
+                    </>
+                }
+                isOpen={this.openSharing}
+                setIsOpen={bool => (this.openSharing = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     /**
@@ -1192,15 +1148,19 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     };
 
     @computed get filtersSubMenu() {
-        return <PropertiesSection 
-            title="Filters"
-            content={<div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
-                <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
-            </div>}
-            isOpen={this.openFilters}
-            setIsOpen={(bool) => this.openFilters = bool}
-             onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Filters"
+                content={
+                    <div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
+                        <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
+                    </div>
+                }
+                isOpen={this.openFilters}
+                setIsOpen={bool => (this.openFilters = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     @computed get inkSubMenu() {
@@ -1208,68 +1168,42 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
         return (
             <>
-                <PropertiesSection
-                    title="Appearance"
-                    content={this.isInk ? this.appearanceEditor : null}
-                    isOpen={this.openAppearance}
-                    setIsOpen={(bool) => this.openAppearance = bool}
-                     onDoubleClick={() => this.onDoubleClick()}
-                />
-                <PropertiesSection
-                    title="Transform"
-                    content={this.transformEditor}
-                    isOpen={this.openTransform}
-                    setIsOpen={(bool) => this.openTransform = bool}
-                    onDoubleClick={() => this.onDoubleClick()}
-                />
+                <PropertiesSection title="Appearance" content={this.isInk ? this.appearanceEditor : null} isOpen={this.openAppearance} setIsOpen={bool => (this.openAppearance = bool)} onDoubleClick={() => this.onDoubleClick()} />
+                <PropertiesSection title="Transform" content={this.transformEditor} isOpen={this.openTransform} setIsOpen={bool => (this.openTransform = bool)} onDoubleClick={() => this.onDoubleClick()} />
             </>
         );
     }
 
     @computed get fieldsSubMenu() {
-        return <PropertiesSection
-            title="Fields & Tags"
-            content={<div className="propertiesView-content fields">{
-                Doc.noviceMode ? this.noviceFields : this.expandedField}
-            </div>}
-            isOpen={this.openFields}
-            setIsOpen={(bool) => this.openFields = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Fields & Tags"
+                content={<div className="propertiesView-content fields">{Doc.noviceMode ? this.noviceFields : this.expandedField}</div>}
+                isOpen={this.openFields}
+                setIsOpen={bool => (this.openFields = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
     @computed get contextsSubMenu() {
-        return <PropertiesSection
-            title="Other Contexts"
-            content={this.contextCount > 0 ? this.contexts : "There are no other contexts."}
-            isOpen={this.openContexts}
-            setIsOpen={(bool) => this.openContexts = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return (
+            <PropertiesSection
+                title="Other Contexts"
+                content={this.contextCount > 0 ? this.contexts : 'There are no other contexts.'}
+                isOpen={this.openContexts}
+                setIsOpen={bool => (this.openContexts = bool)}
+                onDoubleClick={() => this.onDoubleClick()}
+            />
+        );
     }
 
-
-
-
-
     @computed get linksSubMenu() {
-        return <PropertiesSection
-            title="Linked To"
-            content={this.linkCount > 0 ? this.links : "There are no current links." }
-            isOpen={this.openLinks}
-            setIsOpen={(bool) => this.openLinks = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return <PropertiesSection title="Linked To" content={this.linkCount > 0 ? this.links : 'There are no current links.'} isOpen={this.openLinks} setIsOpen={bool => (this.openLinks = bool)} onDoubleClick={() => this.onDoubleClick()} />;
     }
 
     @computed get layoutSubMenu() {
-        return <PropertiesSection
-            title="Layout"
-            content={this.layoutPreview}
-            isOpen={this.openLayout}
-            setIsOpen={(bool) => this.openLayout = bool}
-            onDoubleClick={() => this.onDoubleClick()}
-        />
+        return <PropertiesSection title="Layout" content={this.layoutPreview} isOpen={this.openLayout} setIsOpen={bool => (this.openLayout = bool)} onDoubleClick={() => this.onDoubleClick()} />;
     }
 
     @computed get description() {
@@ -1470,224 +1404,226 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         if (scale > 1) scale = 1;
         this.sourceAnchor && (this.sourceAnchor.followLinkZoomScale = scale);
     };
-    
+
     @computed get linkProperties() {
         const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3));
         const targZoom = this.sourceAnchor?.followLinkZoom;
         const indent = 30;
         const hasSelectedAnchor = LinkManager.Links(this.sourceAnchor).includes(LinkManager.currentLink!);
 
-        return <>
-        <div className="propertiesView-section" style={{ background: 'darkgray' }}>
-            <div className="propertiesView-input first" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
-                <p>Relationship</p>
-                {this.editRelationship}
-            </div>
-            <div className="propertiesView-input" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
-                <p>Description</p>
-                {this.editDescription}
-            </div>
-            <div className="propertiesView-input inline">
-                <p>Show link</p>
-                <button
-                    style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
-                    onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
-                    onClick={e => e.stopPropagation()}
-                    className="propertiesButton">
-                    <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                </button>
-            </div>
-            <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
-                <p>Auto-move anchors</p>
-                <button
-                    style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
-                    onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
-                    onClick={e => e.stopPropagation()}
-                    className="propertiesButton">
-                    <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                </button>
-            </div>
-            <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
-                <p>Display arrow</p>
-                <button
-                    style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
-                    onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
-                    onClick={e => e.stopPropagation()}
-                    className="propertiesButton">
-                    <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                </button>
-            </div>
-        </div>
-        {!hasSelectedAnchor ? null : (
-            <div className="propertiesView-section">
-                <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 84px)' }}>
-                    <p>Follow by</p>
-                    <select onChange={e => this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}>
-                        <option value={undefined}>Default</option>
-                        <option value={OpenWhere.addLeft}>Opening in new left pane</option>
-                        <option value={OpenWhere.addRight}>Opening in new right pane</option>
-                        <option value={OpenWhere.replaceLeft}>Replacing left tab</option>
-                        <option value={OpenWhere.replaceRight}>Replacing right tab</option>
-                        <option value={OpenWhere.lightbox}>Opening in lightbox</option>
-                        <option value={OpenWhere.add}>Opening in new tab</option>
-                        <option value={OpenWhere.replace}>Replacing current tab</option>
-                        <option value={OpenWhere.inParent}>Opening in same collection</option>
-                        {LinkManager.currentLink?.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
-                    </select>
-                </div>
-                <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 134px) 50px' }}>
-                    <p>Animation</p>
-                    <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
-                        <option value="default">Default</option>
-                        {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
-                            <option key={effect.toString()} value={effect.toString()}>
-                                {effect.toString()}
-                            </option>
-                        ))}
-                    </select>
-                    <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
-                        {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
-                        {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
-                        {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
-                        {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
-                        {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
+        return (
+            <>
+                <div className="propertiesView-section" style={{ background: 'darkgray' }}>
+                    <div className="propertiesView-input first" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+                        <p>Relationship</p>
+                        {this.editRelationship}
+                    </div>
+                    <div className="propertiesView-input" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+                        <p>Description</p>
+                        {this.editDescription}
+                    </div>
+                    <div className="propertiesView-input inline">
+                        <p>Show link</p>
+                        <button
+                            style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
+                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
+                            onClick={e => e.stopPropagation()}
+                            className="propertiesButton">
+                            <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                        </button>
+                    </div>
+                    <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+                        <p>Auto-move anchors</p>
+                        <button
+                            style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
+                            onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
+                            onClick={e => e.stopPropagation()}
+                            className="propertiesButton">
+                            <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                        </button>
+                    </div>
+                    <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+                        <p>Display arrow</p>
+                        <button
+                            style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
+                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
+                            onClick={e => e.stopPropagation()}
+                            className="propertiesButton">
+                            <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                        </button>
                     </div>
                 </div>
-                {PresBox.inputter(
-                    '0.1',
-                    '0.1',
-                    '10',
-                    NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000,
-                    true,
-                    (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)),
-                    indent
-                )}{' '}
-                <div
-                    className={'slider-headers'}
-                    style={{
-                        display: 'grid',
-                        justifyContent: 'space-between',
-                        width: `calc(100% - ${indent * 2}px)`,
-                        marginLeft: indent,
-                        marginRight: indent,
-                        gridTemplateColumns: 'auto auto',
-                        borderTop: 'solid',
-                    }}>
-                    <div className="slider-text">Fast</div>
-                    <div className="slider-text">Slow</div>
-                </div>{' '}
-                <div className="propertiesView-input inline">
-                    <p>Play Target Audio</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkAudio ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkAudio', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Zoom Text Selections</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Toggle Follow to Outer Context</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Toggle Target (Show/Hide)</p>
-                    <button
-                        style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToggle', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Ease Transitions</p>
-                    <button
-                        style={{ background: this.sourceAnchor?.followLinkEase === 'linear' ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkEase', this.sourceAnchor, 'ease', 'linear')}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Capture Offset to Target</p>
-                    <button
-                        style={{ background: this.sourceAnchor?.followLinkXoffset === undefined ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => {
-                            this.toggleAnchorProp(e, 'followLinkXoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.x) - NumCast(this.sourceAnchor?.x), undefined);
-                            this.toggleAnchorProp(e, 'followLinkYoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.y) - NumCast(this.sourceAnchor?.y), undefined);
-                        }}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline">
-                    <p>Center Target (no zoom)</p>
-                    <button
-                        style={{ background: this.sourceAnchor?.followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
-                    </button>
-                </div>
-                <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
-                    <p>Zoom %</p>
-                    <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
-                        <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
-                        <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
-                            <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
-                                <FontAwesomeIcon icon={'caret-up'} />
+                {!hasSelectedAnchor ? null : (
+                    <div className="propertiesView-section">
+                        <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 84px)' }}>
+                            <p>Follow by</p>
+                            <select onChange={e => this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}>
+                                <option value={undefined}>Default</option>
+                                <option value={OpenWhere.addLeft}>Opening in new left pane</option>
+                                <option value={OpenWhere.addRight}>Opening in new right pane</option>
+                                <option value={OpenWhere.replaceLeft}>Replacing left tab</option>
+                                <option value={OpenWhere.replaceRight}>Replacing right tab</option>
+                                <option value={OpenWhere.lightbox}>Opening in lightbox</option>
+                                <option value={OpenWhere.add}>Opening in new tab</option>
+                                <option value={OpenWhere.replace}>Replacing current tab</option>
+                                <option value={OpenWhere.inParent}>Opening in same collection</option>
+                                {LinkManager.currentLink?.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
+                            </select>
+                        </div>
+                        <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 134px) 50px' }}>
+                            <p>Animation</p>
+                            <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
+                                <option value="default">Default</option>
+                                {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
+                                    <option key={effect.toString()} value={effect.toString()}>
+                                        {effect.toString()}
+                                    </option>
+                                ))}
+                            </select>
+                            <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
+                                {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
+                                {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
+                                {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
+                                {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
+                                {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
                             </div>
-                            <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
-                                <FontAwesomeIcon icon={'caret-down'} />
+                        </div>
+                        {PresBox.inputter(
+                            '0.1',
+                            '0.1',
+                            '10',
+                            NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000,
+                            true,
+                            (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)),
+                            indent
+                        )}{' '}
+                        <div
+                            className={'slider-headers'}
+                            style={{
+                                display: 'grid',
+                                justifyContent: 'space-between',
+                                width: `calc(100% - ${indent * 2}px)`,
+                                marginLeft: indent,
+                                marginRight: indent,
+                                gridTemplateColumns: 'auto auto',
+                                borderTop: 'solid',
+                            }}>
+                            <div className="slider-text">Fast</div>
+                            <div className="slider-text">Slow</div>
+                        </div>{' '}
+                        <div className="propertiesView-input inline">
+                            <p>Play Target Audio</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkAudio ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkAudio', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Zoom Text Selections</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Toggle Follow to Outer Context</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Toggle Target (Show/Hide)</p>
+                            <button
+                                style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToggle', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Ease Transitions</p>
+                            <button
+                                style={{ background: this.sourceAnchor?.followLinkEase === 'linear' ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkEase', this.sourceAnchor, 'ease', 'linear')}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Capture Offset to Target</p>
+                            <button
+                                style={{ background: this.sourceAnchor?.followLinkXoffset === undefined ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => {
+                                    this.toggleAnchorProp(e, 'followLinkXoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.x) - NumCast(this.sourceAnchor?.x), undefined);
+                                    this.toggleAnchorProp(e, 'followLinkYoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.y) - NumCast(this.sourceAnchor?.y), undefined);
+                                }}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline">
+                            <p>Center Target (no zoom)</p>
+                            <button
+                                style={{ background: this.sourceAnchor?.followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+                            </button>
+                        </div>
+                        <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
+                            <p>Zoom %</p>
+                            <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
+                                <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
+                                <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
+                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
+                                        <FontAwesomeIcon icon={'caret-up'} />
+                                    </div>
+                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
+                                        <FontAwesomeIcon icon={'caret-down'} />
+                                    </div>
+                                </div>
                             </div>
+                            <button
+                                style={{ background: !targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? '' : '#4476f7', borderRadius: 3, gridColumn: 3 }}
+                                onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+                                onClick={e => e.stopPropagation()}
+                                className="propertiesButton">
+                                <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+                            </button>
                         </div>
+                        {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
+                        <div
+                            className={'slider-headers'}
+                            style={{
+                                display: !targZoom ? 'none' : 'grid',
+                                justifyContent: 'space-between',
+                                width: `calc(100% - ${indent * 2}px)`,
+                                marginLeft: indent,
+                                marginRight: indent,
+                                gridTemplateColumns: 'auto auto',
+                                borderTop: 'solid',
+                            }}>
+                            <div className="slider-text">0%</div>
+                            <div className="slider-text">100%</div>
+                        </div>{' '}
                     </div>
-                    <button
-                        style={{ background: !targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? '' : '#4476f7', borderRadius: 3, gridColumn: 3 }}
-                        onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
-                        onClick={e => e.stopPropagation()}
-                        className="propertiesButton">
-                        <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
-                    </button>
-                </div>
-                {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
-                <div
-                    className={'slider-headers'}
-                    style={{
-                        display: !targZoom ? 'none' : 'grid',
-                        justifyContent: 'space-between',
-                        width: `calc(100% - ${indent * 2}px)`,
-                        marginLeft: indent,
-                        marginRight: indent,
-                        gridTemplateColumns: 'auto auto',
-                        borderTop: 'solid',
-                    }}>
-                    <div className="slider-text">0%</div>
-                    <div className="slider-text">100%</div>
-                </div>{' '}
-            </div>
-        )}
-    </>
+                )}
+            </>
+        );
     }
 
     /**
@@ -1723,23 +1659,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             width: this.props.width,
                             minWidth: this.props.width,
                         }}>
-                        <div className = "propertiesView-propAndInfoGrouping">
+                        <div className="propertiesView-propAndInfoGrouping">
                             <div className="propertiesView-title" style={{ width: this.props.width }}>
                                 Properties
                             </div>
-                            <div className = "propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/')}>
-                                 <GrCircleInformation/> </div>
-
+                            <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/')}>
+                                <GrCircleInformation />{' '}
+                            </div>
                         </div>
 
-                        
                         <div className="propertiesView-name">{this.editableTitle}</div>
-                        <div className = "propertiesView-type"> {this.currentType} </div>
+                        <div className="propertiesView-type"> {this.currentType} </div>
                         {this.contextsSubMenu}
                         {this.linksSubMenu}
-                        {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : (
-                            this.linkProperties
-                        )}
+                        {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : this.linkProperties}
                         {this.inkSubMenu}
                         {this.optionsSubMenu}
                         {this.fieldsSubMenu}
@@ -1760,7 +1693,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             Presentation
                         </div>
                         <div className="propertiesView-name" style={{ borderBottom: 0 }}>
-                         
                             {this.editableTitle}
                             <div className="propertiesView-presSelected">
                                 <div className="propertiesView-selectedCount">{PresBox.Instance.selectedArray.size} selected</div>
@@ -1772,7 +1704,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Transitions
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openPresTransitions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.transitionDropdown}</div> : null}
@@ -1786,7 +1718,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Visibilty
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openPresVisibilityAndDuration ? <div className="propertiesView-presTrails-content">{PresBox.Instance.visibiltyDurationDropdown}</div> : null}
@@ -1797,7 +1729,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Progressivize
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">{PresBox.Instance.progressivizeDropdown}</div> : null}
@@ -1808,7 +1740,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                 <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>
                                     &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> &nbsp; {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
                                     <div className="propertiesView-presTrails-title-icon">
-                                        <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg"  />
+                                        <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg" />
                                     </div>
                                 </div>
                                 {this.openSlideOptions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.mediaOptionsDropdown}</div> : null}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index bbbad3690..94748e884 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -22,7 +22,7 @@ import { DocumentViewProps } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
 import { KeyValueBox } from './nodes/KeyValueBox';
 import { SliderBox } from './nodes/SliderBox';
-import { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs'
+import { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs';
 import './StyleProvider.scss';
 import React = require('react');
 
@@ -161,7 +161,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 ''
             );
         case StyleProp.Color:
-            if (MainView.Instance.LastButton === doc) return Doc.UserDoc().userBackgroundColor;
+            if (MainView.Instance.LastButton === doc) return SettingsManager.Instance.userBackgroundColor;
             if (Doc.IsSystem(doc!)) return StrCast(Doc.UserDoc().userColor)
             if (doc?.type === DocumentType.FONTICON) return Doc.UserDoc().userColor;
             const docColor: Opt<string> = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color));
@@ -208,12 +208,10 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 case DocumentType.PRES:        docColor = docColor || (darkScheme() ? 'transparent' : 'transparent'); break;
                 case DocumentType.FONTICON:    docColor = boxBackground ? undefined : docColor || Colors.DARK_GRAY; break;
                 case DocumentType.RTF:         docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
-                case DocumentType.FILTER:      docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : 'rgba(105, 105, 105, 0.432)'); break;
                 case DocumentType.INK:         docColor = doc?.stroke_isInkMask ? 'rgba(0,0,0,0.7)' : undefined; break;
                 case DocumentType.EQUATION:    docColor = docColor || 'transparent'; break;
                 case DocumentType.LABEL:       docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
                 case DocumentType.BUTTON:      docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
-                case DocumentType.LINKANCHOR:  docColor = isAnchor ? Colors.LIGHT_BLUE : 'transparent'; break;
                 case DocumentType.LINK:        docColor = (isAnchor ? docColor : '') || 'transparent'; break;
                 case DocumentType.IMG:
                 case DocumentType.WEB:
@@ -224,7 +222,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 case DocumentType.COL:
                     if (StrCast(Doc.LayoutField(doc)).includes(SliderBox.name)) break;
                     docColor = docColor || (Doc.IsSystem(doc)
-                            ? StrCast(Doc.UserDoc().userBackgroundColor)
+                            ? SettingsManager.Instance.userBackgroundColor
                             : doc.annotationOn
                             ? '#00000010' // faint interior for collections on PDFs, images, etc
                             : doc?._isGroup
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index caf04cc1b..a551e5332 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -7,6 +7,7 @@ import { StrCast } from '../../fields/Types';
 import { Doc } from '../../fields/Doc';
 import { Popup, Type, isDark } from 'browndash-components';
 import { Colors } from './global/globalEnums';
+import { SettingsManager } from '../util/SettingsManager';
 
 interface UndoStackProps {
     width?: number;
@@ -18,35 +19,37 @@ export class UndoStack extends React.Component<UndoStackProps> {
     @observable static HideInline: boolean;
     @observable static Expand: boolean;
     render() {
-        const background = UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userBackgroundColor)
+        const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.Instance.userBackgroundColor;
         return this.props.inline && UndoStack.HideInline ? null : (
             <div className="undoStack-outerContainer">
-                <Popup 
+                <Popup
                     text={'Undo/Redo Stack'}
                     color={UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userVariantColor)}
                     placement={`top-start`}
                     type={Type.TERT}
                     popup={
-                    <div className="undoStack-commandsContainer" ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} 
-                        style={{ 
-                            background: background,
-                            color: isDark(background) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY
-                        }}>
-                        {UndoManager.undoStackNames.map((name, i) => (
-                            <div className="undoStack-resultContainer" key={i}>
-                                <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
-                            </div>
-                        ))}
-                        {Array.from(UndoManager.redoStackNames)
-                            .reverse()
-                            .map((name, i) => (
+                        <div
+                            className="undoStack-commandsContainer"
+                            ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })}
+                            style={{
+                                background: background,
+                                color: isDark(background) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY,
+                            }}>
+                            {UndoManager.undoStackNames.map((name, i) => (
                                 <div className="undoStack-resultContainer" key={i}>
-                                    <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
-                                        {name.replace(/[^\.]*\./, '')}
-                                    </div>
+                                    <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
                                 </div>
-                        ))}
-                    </div>    
+                            ))}
+                            {Array.from(UndoManager.redoStackNames)
+                                .reverse()
+                                .map((name, i) => (
+                                    <div className="undoStack-resultContainer" key={i}>
+                                        <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
+                                            {name.replace(/[^\.]*\./, '')}
+                                        </div>
+                                    </div>
+                                ))}
+                        </div>
                     }
                 />
             </div>
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 16982595d..0052c4196 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -164,7 +164,7 @@ export class CollectionDockingView extends CollectionSubView() {
     public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
         if (document?._type_collection === CollectionViewType.Docking && !keyValue) return DashboardView.openDashboard(document);
         if (!CollectionDockingView.Instance) return false;
-        const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !keyValue);
+        const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !tab.contentItem.config.props.keyValue && !keyValue);
         if (tab) {
             tab.header.parent.setActiveContentItem(tab.contentItem);
             return true;
@@ -466,7 +466,10 @@ export class CollectionDockingView extends CollectionSubView() {
         this._flush = this._flush ?? UndoManager.StartBatch('tab movement');
         if (tab.DashDoc && ![DocumentType.PRES].includes(tab.DashDoc?.type) && !tab.contentItem.config.props.keyValue) {
             Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc);
-            Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
+            // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed
+            if (tab.DashDoc.embedContainer === this.rootDoc) tab.DashDoc.embedContainer = undefined;
+            if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
+            Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc);
         }
         if (CollectionDockingView.Instance) {
             const dview = CollectionDockingView.Instance.props.Document;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5135cfb57..f65e8698f 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -181,7 +181,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
             <div
                 className="collectionMenu-container"
                 style={{
-                    background: StrCast(Doc.UserDoc().userBackgroundColor),
+                    background: SettingsManager.Instance.userBackgroundColor,
                     // borderColor: StrCast(Doc.UserDoc().userColor)
                 }}>
                 {this.contMenuButtons}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a5c276125..056204ad3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -669,7 +669,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         if (menuDoc) {
             const width: number = NumCast(menuDoc._width, 30);
             const height: number = NumCast(menuDoc._height, 30);
-            console.log(menuDoc.title, width, height);
             return (
                 <div className="buttonMenu-docBtn" style={{ width: width, height: height }}>
                     <DocumentView
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 00137736d..ea3b5065f 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -150,6 +150,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 console.log('WHAAAT');
             }
             dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree ? 'same' : dragData.dropAction;
+            e.stopPropagation();
         }
     };
 
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 67b7b39dd..d787f5262 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -396,7 +396,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         return NumCast(Cast(PresBox.Instance.activeItem.presentationTargetDoc, Doc, null)._currentFrame);
     };
     static Activate = (tabDoc: Doc) => {
-        const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc);
+        const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc && !tab.contentItem.config.props.keyValue);
         tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
         return tab !== undefined;
     };
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index fb23fc7f1..6e0ccd4be 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -127,7 +127,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             : this.props.treeView.fileSysMode
             ? this.doc.isFolder
                 ? this.fieldKey
-                : 'embeddings' // for displaying
+                : 'data' // file system folders display their contents (data).  used to be they displayed their embeddings but now its a tree structure and not a flat list
             : this.props.treeView.outlineMode || this.childDocs
             ? this.fieldKey
             : Doc.noviceMode
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 090cf356c..7c53bfdbe 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -377,7 +377,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             : ((doc: Doc) => {
                   Doc.GetProto(doc).data = new List<Doc>(selected);
                   Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform';
-                  !this.props.isAnnotationOverlay && Doc.AddFileOrphan(Doc.GetProto(doc));
                   doc._freeform_panX = doc._freeform_panY = 0;
                   return doc;
               })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 79842047b..256377758 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -197,7 +197,6 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?:
 });
 
 export function checkInksToGroup() {
-    // console.log("getting here to inks group");
     if (Doc.ActiveTool === InkTool.Write) {
         CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => {
             // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those
diff --git a/src/client/views/newlightbox/ExploreView/ExploreView.tsx b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
index 44a0bcd5f..a1d6375c4 100644
--- a/src/client/views/newlightbox/ExploreView/ExploreView.tsx
+++ b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
@@ -12,14 +12,11 @@ export const ExploreView = (props: IExploreView) => {
         <div className={`exploreView-container`}>
             {recs &&
                 recs.map(rec => {
-                    console.log(rec.embedding, bounds);
                     const x_bound: number = Math.max(Math.abs(bounds.max_x), Math.abs(bounds.min_x));
                     const y_bound: number = Math.max(Math.abs(bounds.max_y), Math.abs(bounds.min_y));
-                    console.log(x_bound, y_bound);
                     if (rec.embedding) {
                         const x = (rec.embedding.x / x_bound) * 50;
                         const y = (rec.embedding.y / y_bound) * 50;
-                        console.log(x, y);
                         return (
                             <div className={`exploreView-doc`} onClick={() => {}} style={{ top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)` }}>
                                 {rec.title}
diff --git a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
index b9d05c531..2c2f04b9f 100644
--- a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
+++ b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
@@ -22,7 +22,6 @@ export const Recommendation = (props: IRecommendation) => {
                         doc = docView.rootDoc;
                     }
                 } else if (data) {
-                    console.log(data, type);
                     switch (type) {
                         case 'YouTube':
                             console.log('create ', type, 'document');
diff --git a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
index e1ff6f8eb..10bfb0c64 100644
--- a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
+++ b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
@@ -34,7 +34,6 @@ export const createLineGenerator = (xScale: d3.ScaleLinear<number, number, never
 };
 
 export const xAxisCreator = (g: d3.Selection<SVGGElement, unknown, null, undefined>, height: number, xScale: d3.ScaleLinear<number, number, never>) => {
-    console.log('x axis creator being called');
     g.attr('class', 'x-axis').attr('transform', `translate(0,${height})`).call(d3.axisBottom(xScale).tickSize(15));
 };
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 70d2f95ea..d379b2b52 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,5 +1,5 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-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 { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
@@ -47,7 +47,6 @@ import { DocumentLinksButton } from './DocumentLinksButton';
 import './DocumentView.scss';
 import { FieldViewProps } from './FieldView';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
-import { KeyValueBox } from './KeyValueBox';
 import { LinkAnchorBox } from './LinkAnchorBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 86191de63..d69009415 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -4,7 +4,7 @@ import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import wiki from 'wikijs';
 import { Doc, DocCastAsync, Opt } from '../../../fields/Doc';
-import { Height, Width } from '../../../fields/DocSymbols';
+import { DirectLinks, Height, Width } from '../../../fields/DocSymbols';
 import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils';
 import { DocServer } from '../../DocServer';
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index de0b57fd7..4919ee94c 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -61,7 +61,6 @@ const script = document.createElement('script');
 script.defer = true;
 script.async = true;
 script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places,drawing`;
-console.log(script.src);
 document.head.appendChild(script);
 
 /**
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 312b3c619..bbf56bdf9 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -224,7 +224,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             const aud_chunks: any = [];
             this._audioRec.ondataavailable = (e: any) => aud_chunks.push(e.data);
             this._audioRec.onstop = async (e: any) => {
-                const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({file})));
+                const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({ file })));
                 if (!(result instanceof Error)) {
                     this.dataDoc[this.props.fieldKey + '-audio'] = new AudioField(result.accessPaths.agnostic.client);
                 }
@@ -235,9 +235,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             this._videoRec.onstart = () => (this.dataDoc[this.props.fieldKey + '-recordingStart'] = new DateField(new Date()));
             this._videoRec.ondataavailable = (e: any) => vid_chunks.push(e.data);
             this._videoRec.onstop = async (e: any) => {
-                console.log('screenshotbox: upload');
                 const file = new File(vid_chunks, `${this.rootDoc[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() });
-                const [{ result }] = await Networking.UploadFilesToServer({file});
+                const [{ result }] = await Networking.UploadFilesToServer({ file });
                 this.dataDoc[this.fieldKey + '_duration'] = (new Date().getTime() - this.recordingStart!) / 1000;
                 if (!(result instanceof Error)) {
                     // convert this screenshotBox into normal videoBox
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 3ad3c911d..7c8a1849e 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -610,7 +610,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         ' ': {
                             dataProvider: (token: any) => this.handleToken(token),
                             component: (blob: any) => {
-                                console.log('Blob', blob);
                                 return this.renderFuncListElement(blob.entity);
                             },
                             output: (item: any, trigger: any) => {
@@ -621,7 +620,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         '.': {
                             dataProvider: (token: any) => this.handleToken(token),
                             component: (blob: any) => {
-                                console.log('Blob', blob);
                                 return this.renderFuncListElement(blob.entity);
                             },
                             output: (item: any, trigger: any) => {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 895bb80f0..1dcc445e8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -96,6 +96,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     private _scrollRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _editorView: Opt<EditorView>;
     public _applyingChange: string = '';
+    private _finishingLink = false;
     private _searchIndex = 0;
     private _lastTimedMark: Mark | undefined = undefined;
     private _cachedLinks: Doc[] = [];
@@ -245,7 +246,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         if (!pinProps && this._editorView?.state.selection.empty) return this.rootDoc;
         const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.rootDoc.title), annotationOn: this.rootDoc });
         this.addDocument(anchor);
+        this._finishingLink = true;
         this.makeLinkAnchor(anchor, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation);
+        this._finishingLink = false;
         PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true } }, this.rootDoc);
         return anchor;
     };
@@ -326,7 +329,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
                     if ((!prevData && !protoData) || newText || (!newText && !templateData)) {
                         // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
-                        if (this.props.isContentActive() && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
+                        if ((this._finishingLink || this.props.isContentActive()) && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
                             const numstring = NumCast(dataDoc[this.fieldKey], null);
                             dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
                             dataDoc[this.fieldKey + '_noTemplate'] = true; // mark the data field as being split from the template if it has been edited
@@ -457,8 +460,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
                             alink =
                                 alink ??
-                                (LinkManager.Links(this.Document).find(link => Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target)) ||
-                                    DocUtils.MakeLink(this.props.Document, target, { link_relationship: LinkManager.AutoKeywords })!);
+                                (LinkManager.Links(this.rootDoc).find(
+                                    link =>
+                                        Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && //
+                                        Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target)
+                                ) ||
+                                    DocUtils.MakeLink(this.rootDoc, target, { link_relationship: LinkManager.AutoKeywords })!);
                             newAutoLinks.add(alink);
                             const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.props.Document[Id] }];
                             allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? []));
@@ -840,7 +847,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
 
         const appearance = cm.findByDescription('Appearance...');
         const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : [];
-        appearanceItems.push({ description: 'Change Perspective...', noexpand: true, subitems: changeItems, icon: 'external-link-alt' });
+        appearanceItems.push({ description: 'Change Style...', noexpand: true, subitems: changeItems, icon: 'external-link-alt' });
         // this.rootDoc.isTemplateDoc && appearanceItems.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" });
 
         !Doc.noviceMode &&
@@ -1996,12 +2003,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     }
     cycleAlternateText = () => {
         if (this.layoutDoc._layout_enableAltContentUI) {
-            const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
+            const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`];
             this.rootDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
         }
     };
     @computed get overlayAlternateIcon() {
-        const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
+        const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`];
         return (
             <Tooltip
                 title={
@@ -2080,7 +2087,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         ? {}
                         : {
                               transform: `scale(${scale})`,
-                              transformOrigin: 'top left',
                               width: `${100 / scale}%`,
                               height: `${100 / scale}%`,
                           }),
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index ac1e7ce5d..8bafc2cef 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -243,13 +243,13 @@ export class RichTextRules {
 
             // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
             // [[<fieldKey> : <Doc>]]
-            // [[:Doc]] => hyperlink
+            // [[:docTitle]] => hyperlink
             // [[fieldKey]] => show field
             // [[fieldKey=value]] => show field and also set its value
-            // [[fieldKey:Doc]] => show field of doc
+            // [[fieldKey:docTitle]] => show field of doc
             new InputRule(new RegExp(/\[\[([a-zA-Z_\? \-0-9]*)(=[a-zA-Z_@\? /\-0-9]*)?(:[a-zA-Z_@:\.\? \-0-9]+)?\]\]$/), (state, match, start, end) => {
                 const fieldKey = match[1];
-                const docId = match[3]?.replace(':', '');
+                const docTitle = match[3]?.replace(':', '');
                 const value = match[2]?.substring(1);
                 const linkToDoc = (target: Doc) => {
                     const rstate = this.TextBox.EditorView?.state;
@@ -266,12 +266,12 @@ export class RichTextRules {
                     }
                 };
                 if (!fieldKey) {
-                    if (docId) {
-                        const target = DocServer.QUERY_SERVER_CACHE(docId);
-                        if (target) setTimeout(() => linkToDoc(target));
-                        else DocServer.GetRefField(docId).then(docx => linkToDoc((docx instanceof Doc && docx) || Docs.Create.FreeformDocument([], { title: docId + '(auto)', _width: 500, _height: 500 }, docId)));
-
-                        return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3);
+                    if (docTitle) {
+                        const target = DocServer.FindDocByTitle(docTitle);
+                        if (target) {
+                            setTimeout(() => linkToDoc(target));
+                            return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3);
+                        }
                     }
                     return state.tr;
                 }
@@ -279,8 +279,12 @@ export class RichTextRules {
                     const num = value.match(/^[0-9.]$/);
                     this.Document[DocData][fieldKey] = value === 'true' ? true : value === 'false' ? false : num ? Number(value) : value;
                 }
-                const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId, hideKey: false });
-                return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true);
+                const target = DocServer.FindDocByTitle(docTitle);
+                if (target) {
+                    const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId: target[Id], hideKey: false });
+                    return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true);
+                }
+                return state.tr;
             }),
 
             // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index b877cc36a..e35e011e2 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -17,6 +17,7 @@ import { EditorView } from 'prosemirror-view';
 import './AnchorMenu.scss';
 import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
 import { StrCast } from '../../../fields/Types';
+import { DocumentType } from '../../documents/DocumentTypes';
 
 @observer
 export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -262,7 +263,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                     colorPicker={this.highlightColor}
                     color={StrCast(Doc.UserDoc().userColor)}
                 />
-                <ColorPicker colorPickerType={'github'} selectedColor={this.highlightColor} setSelectedColor={color => this.changeHighlightColor(color)} size={Size.XSMALL} />
+                <ColorPicker selectedColor={this.highlightColor} setSelectedColor={this.changeHighlightColor} size={Size.XSMALL} />
             </Group>
         );
     }
@@ -287,7 +288,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     canSummarize = (): boolean => {
         const docs = SelectionManager.Docs();
         if (docs.length > 0) {
-            return docs.some(doc => doc.type === 'pdf' || doc.type === 'web');
+            return docs.some(doc => doc.type === DocumentType.PDF || doc.type === DocumentType.WEB);
         }
         return false;
     };
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index e911bd283..a28561107 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -18,6 +18,7 @@ import './SearchBox.scss';
 import { fetchRecommendations } from '../newlightbox/utils';
 import { IRecommendation, Recommendation } from '../newlightbox/components';
 import { Colors } from '../global/globalEnums';
+import { SettingsManager } from '../../util/SettingsManager';
 
 const DAMPENING_FACTOR = 0.9;
 const MAX_ITERATIONS = 25;
@@ -218,7 +219,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     }
     @action
     static staticSearchCollection(rootDoc: Opt<Doc>, query: string) {
-        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
+        const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.SEARCH, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
         const blockedKeys = [
             'x',
             'y',
@@ -398,22 +399,21 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
 
         if (query) {
             this.searchCollection(query);
-            const response = await fetchRecommendations('', query, [], true)
-            const recs = response.recommendations
-            const recommendations:IRecommendation[] = []
+            const response = await fetchRecommendations('', query, [], true);
+            const recs = response.recommendations;
+            const recommendations: IRecommendation[] = [];
             for (const key in recs) {
                 const title = recs[key].title;
-                console.log(title);
-                const url = recs[key].url
-                const type = recs[key].type
-                const text = recs[key].text
-                const transcript = recs[key].transcript
-                const previewUrl = recs[key].previewUrl
-                const embedding = recs[key].embedding
-                const distance = recs[key].distance
-                const source = recs[key].source
-                const related_concepts = recs[key].related_concepts
-                const docId = recs[key].doc_id
+                const url = recs[key].url;
+                const type = recs[key].type;
+                const text = recs[key].text;
+                const transcript = recs[key].transcript;
+                const previewUrl = recs[key].previewUrl;
+                const embedding = recs[key].embedding;
+                const distance = recs[key].distance;
+                const source = recs[key].source;
+                const related_concepts = recs[key].related_concepts;
+                const docId = recs[key].doc_id;
                 recommendations.push({
                     title: title,
                     data: url,
@@ -425,11 +425,11 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                     distance: Math.round(distance * 100) / 100,
                     source: source,
                     related_concepts: related_concepts,
-                    docId: docId
-                })
+                    docId: docId,
+                });
             }
-            const setRecommendations = action(() => this._recommendations = recommendations)
-            setRecommendations()
+            const setRecommendations = action(() => (this._recommendations = recommendations));
+            setRecommendations();
         }
     };
 
@@ -461,7 +461,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      */
     @computed
     public get selectOptions() {
-        const selectValues = ['all', 'rtf', 'image', 'pdf', 'web', 'video', 'audio', 'collection'];
+        const selectValues = ['all', DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.WEB, DocumentType.VID, DocumentType.AUDIO, DocumentType.COL];
 
         return selectValues.map(value => (
             <option key={value} value={value}>
@@ -517,19 +517,19 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                             className={className}>
                             <div className="searchBox-result-title">{title as string}</div>
                             <div className="searchBox-result-type">{formattedType}</div>
-                            <div className="searchBox-result-keys">{result[1].join(', ')}</div>
+                            <div className="searchBox-result-keys" style={{ color: SettingsManager.Instance.userVariantColor }}>
+                                {result[1].join(', ')}
+                            </div>
                         </div>
                     </Tooltip>
                 );
             }
         });
 
-        const recommendationsJSX: JSX.Element[] = this._recommendations.map((props) => (
-            <Recommendation {...props}/>
-        ))
+        const recommendationsJSX: JSX.Element[] = this._recommendations.map(props => <Recommendation {...props} />);
 
         return (
-            <div className="searchBox-container" style={{pointerEvents: 'all', background: StrCast(Doc.UserDoc().userBackgroundColor)}}>
+            <div className="searchBox-container" style={{ pointerEvents: 'all', color: SettingsManager.Instance.userColor, background: SettingsManager.Instance.userBackgroundColor }}>
                 <div className="searchBox-bar">
                     {isLinkSearch ? null : (
                         <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
@@ -552,20 +552,24 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                         ref={this._inputRef}
                     />
                 </div>
-                {resultsJSX.length > 0 && <div className="searchBox-results-container">
-                    <div className="section-header" style={{background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)}}>
-                        <div className="section-title">Results</div>
-                        <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                {resultsJSX.length > 0 && (
+                    <div className="searchBox-results-container">
+                        <div className="section-header" style={{ background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE) }}>
+                            <div className="section-title">Results</div>
+                            <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                        </div>
+                        <div className="searchBox-results-view">{resultsJSX}</div>
                     </div>
-                    <div className="searchBox-results-view">{resultsJSX}</div>
-                </div>}
-                {recommendationsJSX.length > 0 && <div className="searchBox-recommendations-container">
-                    <div className="section-header" style={{background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)}}>
-                        <div className="section-title">Recommendations</div>
-                        <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                )}
+                {recommendationsJSX.length > 0 && (
+                    <div className="searchBox-recommendations-container">
+                        <div className="section-header" style={{ background: StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE) }}>
+                            <div className="section-title">Recommendations</div>
+                            <div className="section-subtitle">{`${validResults}` + ' result' + (validResults === 1 ? '' : 's')}</div>
+                        </div>
+                        <div className="searchBox-recommendations-view">{recommendationsJSX}</div>
                     </div>
-                    <div className="searchBox-recommendations-view">{recommendationsJSX}</div>
-                </div>}
+                )}
             </div>
         );
     }
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index cb8eda9de..8caba930d 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -35,10 +35,14 @@ export class TopBar extends React.Component {
         });
     };
 
-    @computed get color() { return StrCast(Doc.UserDoc().userColor, Colors.LIGHT_GRAY); }
-    @computed get variantColor() { return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE); }
+    @computed get color() {
+        return StrCast(Doc.UserDoc().userColor, Colors.LIGHT_GRAY);
+    }
+    @computed get variantColor() {
+        return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE);
+    }
     @computed get backgroundColor() {
-        return PingManager.Instance.IsBeating ? StrCast(Doc.UserDoc().userBackgroundColor, Colors.DARK_GRAY) : Colors.MEDIUM_GRAY;
+        return PingManager.Instance.IsBeating ? SettingsManager.Instance.userBackgroundColor : Colors.MEDIUM_GRAY;
     }
 
     @observable happyHeart: boolean = PingManager.Instance.IsBeating;
@@ -102,7 +106,7 @@ export class TopBar extends React.Component {
                     tooltip="Open Dashboards"
                     size={Size.SMALL}
                     color={this.color}
-                    style={{fontWeight: 700, fontSize: '1rem'}}
+                    style={{ fontWeight: 700, fontSize: '1rem' }}
                     onClick={(e: React.MouseEvent) => {
                         const dashView = Doc.ActiveDashboard && DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard);
                         ContextMenu.Instance.addItem({ description: 'Open Dashboard View', event: this.navigateToHome, icon: 'edit' });
@@ -134,7 +138,7 @@ export class TopBar extends React.Component {
     @computed get topbarRight() {
         return (
             <div className="topbar-right">
-                {Doc.ActiveDashboard ? 
+                {Doc.ActiveDashboard ? (
                     <Button
                         text={GetEffectiveAcl(Doc.ActiveDashboard) === AclAdmin ? 'Share' : 'View Original'}
                         type={Type.TERT}
@@ -143,15 +147,15 @@ export class TopBar extends React.Component {
                             SharingManager.Instance.open(undefined, Doc.ActiveDashboard);
                         }}
                     />
-                : null }
-                <IconButton tooltip={"Issue Reporter ⌘I"} size={Size.SMALL} color={this.color} onClick={ReportManager.Instance.open} icon={<FaBug />} />
-                <IconButton tooltip={"Documentation ⌘D"} size={Size.SMALL} color={this.color} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
-                <IconButton tooltip={"Settings ⌘⇧S"} size={Size.SMALL} color={this.color} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} />
+                ) : null}
+                <IconButton tooltip={'Issue Reporter ⌘I'} size={Size.SMALL} color={this.color} onClick={ReportManager.Instance.open} icon={<FaBug />} />
+                <IconButton tooltip={'Documentation ⌘D'} size={Size.SMALL} color={this.color} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
+                <IconButton tooltip={'Settings ⌘⇧S'} size={Size.SMALL} color={this.color} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} />
                 <IconButton
                     size={Size.SMALL}
                     onClick={ServerStats.Instance.open}
                     type={Type.TERT}
-                    tooltip={'Server is ' + (PingManager.Instance.IsBeating ? '' : 'NOT ') + 'running'}
+                    tooltip={'Server is ' + (PingManager.Instance.IsBeating ? '' : 'NOT ') + 'running ' + SettingsManager.Version}
                     color={this.happyHeart ? Colors.LIGHT_BLUE : Colors.ERROR_RED}
                     icon={<FontAwesomeIcon icon={this.happyHeart ? 'heart' : 'heart-broken'} />}
                 />
@@ -163,12 +167,14 @@ export class TopBar extends React.Component {
     render() {
         return (
             //TODO:glr Add support for light / dark mode
-            <div style={{ 
-                pointerEvents: 'all',
-                color: this.color,
-                background: this.backgroundColor,
-                // borderColor: this.color
-            }} className="topbar-container">
+            <div
+                style={{
+                    pointerEvents: 'all',
+                    color: this.color,
+                    background: this.backgroundColor,
+                    // borderColor: this.color
+                }}
+                className="topbar-container">
                 <div className="topbar-inner-container">
                     {this.topbarLeft}
                     {this.topbarCenter}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 5a411a201..eb52cff88 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -238,22 +238,6 @@ export class Doc extends RefField {
     public static get MyFilesystem() {
         return DocCast(Doc.UserDoc().myFilesystem);
     }
-    public static get MyFileOrphans() {
-        return DocCast(Doc.UserDoc().myFileOrphans);
-    }
-    public static AddFileOrphan(doc: Doc) {
-        if (
-            doc &&
-            Doc.MyFileOrphans instanceof Doc &&
-            Doc.IsDataProto(doc) &&
-            !Doc.IsSystem(doc) &&
-            ![DocumentType.CONFIG, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR].includes(doc.type as any) &&
-            !doc.isFolder &&
-            !doc.annotationOn
-        ) {
-            Doc.AddDocToList(Doc.MyFileOrphans, undefined, doc);
-        }
-    }
     public static get MyTools() {
         return DocCast(Doc.UserDoc().myTools);
     }
@@ -388,7 +372,7 @@ export class Doc extends RefField {
             } else {
                 return Cast(layoutField, Doc, null);
             }
-            return Cast(self[renderFieldKey + '-layout[' + templateLayoutDoc[Id] + ']'], Doc, null) || templateLayoutDoc;
+            return Cast(self[renderFieldKey + '_layout[' + templateLayoutDoc[Id] + ']'], Doc, null) || templateLayoutDoc;
         }
         return undefined;
     }
@@ -701,7 +685,8 @@ export namespace Doc {
     }
 
     export function BestEmbedding(doc: Doc) {
-        const bestEmbedding = Doc.GetProto(doc) ? DocListCast(doc.proto_embeddings).find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail) : doc;
+        const bestEmbedding = Doc.GetProto(doc) ? [doc, ...DocListCast(doc.proto_embeddings)].find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail) : doc;
+        bestEmbedding && Doc.AddDocToList(Doc.GetProto(doc), 'protoEmbeddings', doc);
         return bestEmbedding ?? Doc.MakeEmbedding(doc);
     }
 
@@ -782,7 +767,6 @@ export namespace Doc {
         copy.cloneOf = doc;
         cloneMap.set(doc[Id], copy);
 
-        Doc.AddFileOrphan(copy);
         return copy;
     }
     export function repairClone(clone: Doc, cloneMap: Map<string, Doc>, visited: Set<Doc>) {
@@ -917,7 +901,7 @@ export namespace Doc {
         // If it doesn't find the expanded layout, then it makes a delegate of the template layout and
         // saves it on the data doc indexed by the template layout's id.
         //
-        const expandedLayoutFieldKey = templateField + '-layout[' + templateLayoutDoc[Id] + ']';
+        const expandedLayoutFieldKey = templateField + '_layout[' + templateLayoutDoc[Id] + ']';
         let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey];
 
         if (templateLayoutDoc.resolvedDataDoc instanceof Promise) {
@@ -985,6 +969,59 @@ export namespace Doc {
         return overwrite;
     }
 
+    export function FindReferences(infield: Doc | List<any>, references: Set<Doc>, system: boolean | undefined) {
+        if (infield instanceof List<any>) {
+            infield.forEach(val => (val instanceof Doc || val instanceof List) && FindReferences(val, references, system));
+            return;
+        }
+        const doc = infield as Doc;
+        if (references.has(doc)) {
+            references.add(doc);
+            return;
+        }
+        const excludeLists = doc.title === 'My Recently Closed' || doc.title === 'My Header Bar' || doc.title === 'My Dashboards';
+        if (system !== undefined && ((system && !Doc.IsSystem(doc)) || (!system && Doc.IsSystem(doc)))) return;
+        references.add(doc);
+        Object.keys(doc).forEach(key => {
+            if (key === 'proto') {
+                if (doc.proto instanceof Doc) {
+                    Doc.FindReferences(doc.proto, references, system);
+                }
+            } else {
+                const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
+                const field = key === 'author' ? Doc.CurrentUserEmail : ProxyField.WithoutProxy(() => doc[key]);
+                if (field instanceof RefField) {
+                    if (field instanceof Doc) {
+                        if (key === 'myLinkDatabase') {
+                            field instanceof Doc && references.add(field);
+                            // skip docs that have been closed and are scheduled for garbage collection
+                        } else {
+                            Doc.FindReferences(field, references, system);
+                        }
+                    }
+                } else if (cfield instanceof ComputedField) {
+                } else if (field instanceof ObjectField) {
+                    if (field instanceof Doc) {
+                        Doc.FindReferences(field, references, system);
+                    } else if (field instanceof List) {
+                        !excludeLists && Doc.FindReferences(field, references, system);
+                    } else if (field instanceof ProxyField) {
+                        if (key === 'myLinkDatabase') {
+                            field instanceof Doc && references.add(field);
+                            // skip docs that have been closed and are scheduled for garbage collection
+                        } else {
+                            Doc.FindReferences(field.value, references, system);
+                        }
+                    } else if (field instanceof PrefetchProxy) {
+                        Doc.FindReferences(field.value, references, system);
+                    }
+                } else if (field instanceof Promise) {
+                    debugger; //This shouldn't happend...
+                }
+            }
+        });
+    }
+
     export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string, retitle = false): Doc {
         const copy = new Doc(copyProtoId, true);
         updateCachedAcls(copy);
@@ -1025,7 +1062,6 @@ export namespace Doc {
         if (retitle) {
             copy.title = incrementTitleCopy(StrCast(copy.title));
         }
-        Doc.AddFileOrphan(copy);
         return copy;
     }
 
@@ -1044,7 +1080,6 @@ export namespace Doc {
             if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DocData], 'proto_embeddings', delegate);
             title && (delegate.title = title);
             delegate[Initializing] = false;
-            Doc.AddFileOrphan(delegate);
             return delegate;
         }
         return undefined;
@@ -1177,7 +1212,7 @@ export namespace Doc {
     // the document containing the view layout information - will be the Document itself unless the Document has
     // a layout field or 'layout' is given.
     export function Layout(doc: Doc, layout?: Doc): Doc {
-        const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, 'data')}-layout[` + layout[Id] + ']'], Doc, null);
+        const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, 'data')}_layout[` + layout[Id] + ']'], Doc, null);
         return overrideLayout || doc[DocLayout] || doc;
     }
     export function SetLayout(doc: Doc, layout: Doc | string) {
diff --git a/src/fields/FieldLoader.tsx b/src/fields/FieldLoader.tsx
index 2a7b936f7..a5a71833c 100644
--- a/src/fields/FieldLoader.tsx
+++ b/src/fields/FieldLoader.tsx
@@ -6,10 +6,9 @@ import './FieldLoader.scss';
 
 @observer
 export class FieldLoader extends React.Component {
-    @observable public static ServerLoadStatus = { requested: 0, retrieved: 0 };
-    public static active = false;
+    @observable public static ServerLoadStatus = { requested: 0, retrieved: 0, message: '' };
 
     render() {
-        return <div className="fieldLoader">{`Requested: ${FieldLoader.ServerLoadStatus.requested} ... ${FieldLoader.ServerLoadStatus.retrieved} `}</div>;
+        return <div className="fieldLoader">{`${FieldLoader.ServerLoadStatus.message} request: ${FieldLoader.ServerLoadStatus.requested} ... ${FieldLoader.ServerLoadStatus.retrieved} `}</div>;
     }
 }
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 6764f2727..337bb812f 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -143,7 +143,6 @@ export namespace DashUploadUtils {
 
     export function uploadYoutube(videoId: string): Promise<Upload.FileResponse> {
         return new Promise<Upload.FileResponse<Upload.FileInformation>>((res, rej) => {
-            console.log('Uploading YouTube video: ' + videoId);
             const name = videoId;
             const path = name.replace(/^-/, '__') + '.mp4';
             const finalPath = serverPathToFile(Directory.videos, path);
@@ -523,7 +522,7 @@ export namespace DashUploadUtils {
             try {
                 const response = await axios.post(RESIZE_FUNCTION_URL, {
                     url: requestable,
-                    filename: resolved
+                    filename: resolved,
                 });
                 writtenFiles = response.data.writtenFiles;
             } catch (err) {
-- 
cgit v1.2.3-70-g09d2

