From 5b5730a7df073659cbb6c326f748f7fcbe6625e8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 18 Jan 2024 15:05:53 -0500
Subject: lots of changes to try to simplify API for viewPaths and related

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

(limited to 'src/client/views/PropertiesDocContextSelector.tsx')

diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index a710e7816..54f141a36 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -27,7 +27,7 @@ export class PropertiesDocContextSelector extends ObservableReactComponent<Prope
     @computed get _docs() {
         if (!this._props.DocView) return [];
         const target = this._props.DocView._props.Document;
-        const targetContext = this._props.DocView._props.docViewPath().lastElement()?.Document;
+        const targetContext = this._props.DocView.containerViewPath?.().lastElement()?.Document;
         const embeddings = DocListCast(target.proto_embeddings);
         const containerProtos = embeddings.filter(embedding => embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set<Doc>());
         const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.proto_embeddings));
-- 
cgit v1.2.3-70-g09d2


From 0d8c05db9cbb5a23a94554c65015c347ff8c38b9 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 31 Jan 2024 20:39:47 -0500
Subject: cleaned up accessing/setting proto_embeddings with api on Doc.  fixed
 some css related to IconButtons.  added a paintView toggle button to dec
 decorations for text with code blocks. enabled text with code to modify Docs
 and get this and documentView as params.

---
 package-lock.json                                  |   9 +-
 package.json                                       |   2 +-
 src/client/util/DocumentManager.ts                 |   4 +-
 src/client/util/DropConverter.ts                   |   1 +
 src/client/util/Scripting.ts                       |   3 +-
 src/client/views/DocComponent.tsx                  |   2 +-
 src/client/views/DocumentDecorations.tsx           |   2 +-
 src/client/views/PropertiesDocContextSelector.tsx  |   6 +-
 src/client/views/PropertiesView.tsx                |   5 +-
 src/client/views/StyleProvider.scss                |   4 +
 src/client/views/StyleProvider.tsx                 |  18 +++-
 .../views/collections/CollectionDockingView.tsx    |   2 +-
 src/client/views/collections/TreeView.scss         |   4 +
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  14 ++-
 .../collectionSchema/CollectionSchemaView.scss     |   7 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |   2 +-
 src/client/views/nodes/DocumentView.tsx            |   6 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  55 +++++-----
 .../views/nodes/formattedText/PaintButtonView.tsx  | 113 ---------------------
 .../views/nodes/formattedText/RichTextRules.ts     |  49 +++------
 src/fields/Doc.ts                                  |  25 +++--
 21 files changed, 127 insertions(+), 206 deletions(-)
 delete mode 100644 src/client/views/nodes/formattedText/PaintButtonView.tsx

(limited to 'src/client/views/PropertiesDocContextSelector.tsx')

diff --git a/package-lock.json b/package-lock.json
index aa4108243..aafc14a86 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -154,7 +154,7 @@
                 "prosemirror-commands": "^1.5.2",
                 "prosemirror-find-replace": "^0.9.0",
                 "prosemirror-history": "^1.3.2",
-                "prosemirror-inputrules": "github:bobzel/prosemirror-inputrules#3b3b3e0b1a1dcf80490d81675206369b6be96276",
+                "prosemirror-inputrules": "^1.4.0",
                 "prosemirror-keymap": "^1.2.2",
                 "prosemirror-model": "^1.19.3",
                 "prosemirror-schema-list": "^1.3.0",
@@ -28699,10 +28699,9 @@
             }
         },
         "node_modules/prosemirror-inputrules": {
-            "version": "1.3.0",
-            "resolved": "git+ssh://git@github.com/bobzel/prosemirror-inputrules.git#3b3b3e0b1a1dcf80490d81675206369b6be96276",
-            "integrity": "sha512-l81tcwS7ugPJEvCy78RtEvR2/2mVaTkFHJD9ACRxRDXhrfPWV0FkFYBAO7GolN4XlzIbIsal2MVvq2baLQ2guw==",
-            "license": "MIT",
+            "version": "1.4.0",
+            "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz",
+            "integrity": "sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==",
             "dependencies": {
                 "prosemirror-state": "^1.0.0",
                 "prosemirror-transform": "^1.0.0"
diff --git a/package.json b/package.json
index f8144a0b3..a94f8c9be 100644
--- a/package.json
+++ b/package.json
@@ -237,7 +237,7 @@
         "prosemirror-commands": "^1.5.2",
         "prosemirror-find-replace": "^0.9.0",
         "prosemirror-history": "^1.3.2",
-        "prosemirror-inputrules": "github:bobzel/prosemirror-inputrules#3b3b3e0b1a1dcf80490d81675206369b6be96276",
+        "prosemirror-inputrules": "^1.4.0",
         "prosemirror-keymap": "^1.2.2",
         "prosemirror-model": "^1.19.3",
         "prosemirror-schema-list": "^1.3.0",
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index f730d17fe..53d472c66 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -355,8 +355,8 @@ export function DocFocusOrOpen(doc: Doc, options: FocusViewOptions = { willZoomC
             });
         }
     };
-    if (Doc.IsDataProto(doc) && DocListCast(doc.proto_embeddings).some(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))) {
-        doc = DocListCast(doc.proto_embeddings).find(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))!;
+    if (Doc.IsDataProto(doc) && Doc.GetEmbeddings(doc).some(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))) {
+        doc = Doc.GetEmbeddings(doc).find(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))!;
     }
     if (doc.hidden) {
         doc.hidden = false;
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index ba981145d..54066d267 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -73,6 +73,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
                 _nativeHeight: 100,
                 _width: 100,
                 _height: 100,
+                _layout_hideContextMenu: true,
                 backgroundColor: StrCast(doc.backgroundColor),
                 title: StrCast(layoutDoc.title),
                 btnType: ButtonType.ClickButton,
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index dfaacf318..f5e162d16 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -61,7 +61,8 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an
     const compiledFunction = (() => {
         try {
             return new Function(...paramNames, `return ${script}`);
-        } catch {
+        } catch (e) {
+            console.log(e);
             return undefined;
         }
     })();
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 73fa6709c..58be41f53 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -189,7 +189,7 @@ export function ViewBoxAnnotatableComponent<P extends FieldViewProps>() {
                 toRemove.forEach(doc => {
                     leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
                     Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc, true);
-                    Doc.RemoveDocFromList(doc[DocData], 'proto_embeddings', doc, true);
+                    Doc.RemoveEmbedding(doc, doc);
                     doc.embedContainer = undefined;
                     if (recent && !dontAddToRemoved) {
                         doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true);
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2193acf62..dec109d7b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -283,7 +283,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
             } else {
                 var openDoc = selectedDocs[0].Document;
                 if (openDoc.layout_fieldKey === 'layout_icon') {
-                    openDoc = DocListCast(openDoc.proto_embeddings).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc);
+                    openDoc = Doc.GetEmbeddings(openDoc).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc);
                     Doc.deiconifyView(openDoc);
                 }
                 LightboxView.Instance.SetLightboxDoc(
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 54f141a36..361451c4d 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -28,14 +28,14 @@ export class PropertiesDocContextSelector extends ObservableReactComponent<Prope
         if (!this._props.DocView) return [];
         const target = this._props.DocView._props.Document;
         const targetContext = this._props.DocView.containerViewPath?.().lastElement()?.Document;
-        const embeddings = DocListCast(target.proto_embeddings);
+        const embeddings = Doc.GetEmbeddings(target);
         const containerProtos = embeddings.filter(embedding => embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set<Doc>());
-        const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.proto_embeddings));
+        const containerSets = Array.from(containerProtos.keys()).map(container => Doc.GetEmbeddings(container));
         const containers = containerSets.reduce((p, set) => {
             set.map(s => p.add(s));
             return p;
         }, new Set<Doc>());
-        const doclayoutSets = Array.from(containers.keys()).map(dp => DocListCast(dp.proto_embeddings));
+        const doclayoutSets = Array.from(containers.keys()).map(dp => Doc.GetEmbeddings(dp));
         const doclayouts = Array.from(
             doclayoutSets
                 .reduce((p, set) => {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 208ed56c9..a7a065a95 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -173,7 +173,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
         if (this.dataDoc && this.selectedDoc) {
             const ids = new Set<string>(reqdKeys);
             const docs: Doc[] = SelectionManager.Views.length < 2 ? [this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc] : SelectionManager.Views.map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc));
-            docs.forEach(doc => Object.keys(doc).forEach(key => doc[key] !== ComputedField.undefined && ids.add(key)));
+            docs.forEach(doc => Object.keys(doc).forEach(key => doc[key] !== ComputedField.undefined && key && ids.add(key)));
 
             // prettier-ignore
             Array.from(ids).filter(filter).sort().map(key => {
@@ -263,8 +263,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
     @computed get contextCount() {
         if (this.selectedDocumentView) {
             const target = this.selectedDocumentView.Document;
-            const embeddings = DocListCast(target.proto_embeddings);
-            return embeddings.length - 1;
+            return Doc.GetEmbeddings(target).length - 1;
         } else {
             return 0;
         }
diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss
index 4d3096f71..00bf503f5 100644
--- a/src/client/views/StyleProvider.scss
+++ b/src/client/views/StyleProvider.scss
@@ -1,5 +1,6 @@
 .styleProvider-filter,
 .styleProvider-audio,
+.styleProvider-paint,
 .styleProvider-lock {
     font-size: 10;
     width: 15;
@@ -28,6 +29,9 @@
 .styleProvider-audio {
     right: 30;
 }
+.styleProvider-paint {
+    top: 15;
+}
 .styleProvider-lock:hover,
 .styleProvider-audio:hover,
 .styleProvider-filter:hover {
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 5a0167338..d3d13988f 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -9,7 +9,7 @@ import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs';
 import { FaFilter } from 'react-icons/fa';
 import { Doc, Opt, StrListCast } from '../../fields/Doc';
 import { DocViews } from '../../fields/DocSymbols';
-import { BoolCast, Cast, DocCast, ImageCast, NumCast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../fields/Types';
 import { DashColor, lightOrDark, Utils } from '../../Utils';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
 import { DocFocusOrOpen, DocumentManager } from '../util/DocumentManager';
@@ -53,6 +53,16 @@ export enum StyleProp {
 function toggleLockedPosition(doc: Doc) {
     UndoManager.RunInBatch(() => Doc.toggleLockedPosition(doc), 'toggleBackground');
 }
+function togglePaintView(e: React.MouseEvent, doc: Opt<Doc>, props: Opt<FieldViewProps & DocumentViewProps>) {
+    const scriptProps = {
+        this: doc,
+        _readOnly_: false,
+        documentView: props?.DocumentView?.(),
+        value: undefined,
+    };
+    e.stopPropagation();
+    UndoManager.RunInBatch(() => doc && ScriptCast(doc.onPaint).script.run(scriptProps), 'togglePaintView');
+}
 
 export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) {
     return `M ${pw * 0.5} ${ph * inset}   C ${pw * 0.6} ${ph * inset} ${pw * (1 - 2 * inset)} 0 ${pw * (1 - inset)} ${ph * inset}   C ${pw} ${ph * (2 * inset)} ${pw * (1 - inset)} ${ph * 0.25} ${pw * (1 - inset)} ${ph * 0.3}   C ${
@@ -267,6 +277,11 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
                             <FontAwesomeIcon icon='lock' size="lg" />
                         </div>
                     );
+            const paint = () => !doc?.onPaint ? null : (
+                        <div className="styleProvider-paint" onClick={e => togglePaintView(e, doc, props)}>
+                            <FontAwesomeIcon icon='pen' size="lg" />
+                        </div>
+                    );
             const filter = () => {
                 const dashView = untracked(() => DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard));
                 const showFilterIcon =
@@ -329,6 +344,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
             };
             return (
                 <>
+                    {paint()}
                     {lock()}
                     {filter()}
                     {audio()}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 87973fd81..31ca86f0f 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -490,7 +490,7 @@ export class CollectionDockingView extends CollectionSubView() {
             // 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.Document) tab.DashDoc.embedContainer = undefined;
             if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
-            Doc.RemoveDocFromList(tab.DashDoc[DocData], 'proto_embeddings', tab.DashDoc);
+            Doc.RemoveEmbedding(tab.DashDoc, tab.DashDoc);
         }
         if (CollectionDockingView.Instance) {
             const dview = CollectionDockingView.Instance.Document;
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 0a1946f09..09701ddb5 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -128,6 +128,10 @@
     position: relative;
     z-index: 1;
 
+    .treeView-rightButtons > .iconButton-container {
+        min-height: unset;
+    }
+
     .treeView-background {
         width: 100%;
         height: 100%;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 54e8b08b6..9368560e9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -54,6 +54,7 @@ import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCurso
 import './CollectionFreeFormView.scss';
 import { MarqueeView } from './MarqueeView';
 import { RichTextField } from '../../../../fields/RichTextField';
+import { CompileScript } from '../../../util/Scripting';
 
 export interface collectionFreeformViewProps {
     NativeWidth?: () => number;
@@ -80,8 +81,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const paintFunc = StrCast(Field.toJavascriptString(Cast(field, RichTextField, null)?.Text as Field)).trim();
         return !paintFunc
             ? ''
-            : `const dashDiv = document.querySelector('#${this._paintedId}'); 
-        (async () => {  ${paintFunc} })()`;
+            : paintFunc.includes('dashDiv')
+              ? `const dashDiv = document.querySelector('#${this._paintedId}');
+                    (async () => {  ${paintFunc} })()`
+              : paintFunc;
     }
     constructor(props: any) {
         super(props);
@@ -1496,7 +1499,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         this._disposers.paintFunc = reaction(
             () => ({ code: this.paintFunc, first: this._firstRender, width: this.Document._width, height: this.Document._height }),
-            ({ code, first }) => code && !first && eval(code),
+            ({ code, first }) => {
+                if (!code.includes('dashDiv')) {
+                    const script = CompileScript(code, { params: { docView: 'any' }, typecheck: false, editable: true });
+                    if (script.compiled) script.run({ this: this.Document, docView: this.DocumentView?.() });
+                } else code && !first && eval(code);
+            },
             { fireImmediately: true }
         );
 
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 29d121974..29491569a 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -128,7 +128,7 @@
 
     .row-menu {
         display: flex;
-        justify-content: flex-end;
+        justify-content: center;
     }
 }
 
@@ -224,7 +224,10 @@
         display: flex;
         flex-direction: row;
         min-width: 50px;
-        justify-content: flex-end;
+        justify-content: center;
+        .iconButton-container {
+            min-width: unset !important;
+        }
     }
 
     .row-cells {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index f2fe0dde7..39fea2d2e 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -121,7 +121,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                         pointerEvents: !this._props.isContentActive() ? 'none' : undefined,
                     }}>
                     <IconButton
-                        tooltip="whether document interations are enabled"
+                        tooltip="whether document interactions are enabled"
                         icon={this.Document._lockedPosition ? <CgLockUnlock size="12px" /> : <CgLock size="12px" />}
                         size={Size.XSMALL}
                         onPointerDown={e =>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 51f4b1a68..b5355fb99 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -456,8 +456,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
 
     deleteClicked = undoable(() => this._props.removeDocument?.(this.Document), 'delete doc');
     setToggleDetail = undoable(
-        (defaultLayout: string) =>
-            (this.Document.onClick = ScriptField.MakeScript(
+        (defaultLayout: string, scriptFieldKey: 'onClick') =>
+            (this.Document[scriptFieldKey] = ScriptField.MakeScript(
                 `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey)
                     .replace('layout_', '')
                     .replace(/^layout$/, 'detail')}", "${defaultLayout}")`,
@@ -1212,7 +1212,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
     };
     public noOnClick = () => this._docViewInternal?.noOnClick();
     public toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle);
-    public setToggleDetail = (defaultLayout = '') => this._docViewInternal?.setToggleDetail(defaultLayout);
+    public setToggleDetail = (defaultLayout = '', scriptFieldKey = 'onClick') => this._docViewInternal?.setToggleDetail(defaultLayout, scriptFieldKey);
     public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY);
     public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents();
     public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 973f90501..b82ab4219 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -67,8 +67,6 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu';
 import { RichTextRules } from './RichTextRules';
 import { schema } from './schema_rts';
 import { SummaryView } from './SummaryView';
-import { CollectionView } from '../../collections/CollectionView';
-import { PaintButtonView } from './PaintButtonView';
 // import * as applyDevTools from 'prosemirror-dev-tools';
 @observer
 export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
@@ -488,14 +486,29 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     };
 
     // creates links between terms in a document and published documents (myPublishedDocs) that have titles starting with an '@'
+    /**
+     * Searches the text for occurences of any strings that match the names of 'published' documents.  These document
+     * names will begin with an '@' prefix.  However, valid matches within the text can have any of the following formats:
+     *    name, @<name>, or ^@<name>
+     * The last of these is interpreted as an include directive when converting the text into evaluated code in the paint
+     * function of a freeform view that is driven by the text box's text.  The include directive will copy the code of the published
+     * document into the code being evaluated.
+     */
     hyperlinkTerm = (tr: any, target: Doc, newAutoLinks: Set<Doc>) => {
         const editorView = this._editorView;
         if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.Document)) {
             const autoLinkTerm = StrCast(target.title).replace(/^@/, '');
             var alink: Doc | undefined;
             this.findInNode(editorView, editorView.state.doc, autoLinkTerm).forEach(sel => {
-                const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() });
-                if (!sel.$anchor.pos || [autoLinkTerm, StrCast(target.title)].includes(editorView.state.doc.textBetween(sel.$anchor.pos - 1, sel.$to.pos).trim())) {
+                if (
+                    !sel.$anchor.pos ||
+                    autoLinkTerm ===
+                        editorView.state.doc
+                            .textBetween(sel.$anchor.pos - 1, sel.$to.pos)
+                            .trim()
+                            .replace(/[\^@]+/, '')
+                ) {
+                    const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() });
                     tr = tr.addMark(sel.from, sel.to, splitter);
                     tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => {
                         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)) {
@@ -668,12 +681,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             let index = 0,
                 foundAt;
             const ep = this.getNodeEndpoints(pm.state.doc, node);
-            const regexp = new RegExp(find.replace('*', ''), 'i');
+            const regexp = new RegExp(find, 'i');
             if (regexp) {
-                while (ep && (foundAt = node.textContent.slice(index).search(regexp)) > -1) {
-                    const sel = new TextSelection(pm.state.doc.resolve(ep.from + index + foundAt + 1), pm.state.doc.resolve(ep.from + index + foundAt + find.length + 1));
-                    ret.push(sel);
-                    index = index + foundAt + find.length;
+                var blockOffset = 0;
+                for (var i = 0; i < node.childCount; i++) {
+                    var textContent = '';
+                    while (i < node.childCount && node.child(i).type === pm.state.schema.nodes.text) {
+                        textContent += node.child(i).textContent;
+                        i++;
+                    }
+                    while (ep && (foundAt = textContent.slice(index).search(regexp)) > -1) {
+                        const sel = new TextSelection(pm.state.doc.resolve(ep.from + index + blockOffset + foundAt + 1), pm.state.doc.resolve(ep.from + index + blockOffset + foundAt + find.length + 1));
+                        ret.push(sel);
+                        index = index + foundAt + find.length;
+                    }
+                    blockOffset += textContent.length;
+                    if (i < node.childCount) blockOffset += node.child(i).nodeSize;
                 }
             }
         } else {
@@ -934,17 +957,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR),
                 icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars',
             });
-        optionItems.push({
-            description: 'Make Paint Function',
-            event: () => {
-                this.dataDoc.layout_painted = CollectionView.LayoutString('painted');
-                this.layoutDoc.layout_fieldKey = 'layout_painted';
-                this.layoutDoc.type_collection = CollectionViewType.Freeform;
-                this.DocumentView?.().setToggleDetail();
-                this.dataDoc.paintFunc = ComputedField.MakeFunction(`toJavascriptString(this['${this.fieldKey}']?.Text)`);
-            },
-            icon: !this.Document._layout_enableAltContentUI ? 'eye-slash' : 'eye',
-        });
         !Doc.noviceMode &&
             optionItems.push({
                 description: `${this.Document._layout_autoHeight ? 'Lock' : 'Auto'} Height`,
@@ -1411,9 +1423,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     dashField(node: any, view: any, getPos: any) {
                         return new DashFieldView(node, view, getPos, self);
                     },
-                    paintButton(node: any, view: any, getPos: any) {
-                        return new PaintButtonView(node, view, getPos, self);
-                    },
                     equation(node: any, view: any, getPos: any) {
                         return new EquationView(node, view, getPos, self);
                     },
diff --git a/src/client/views/nodes/formattedText/PaintButtonView.tsx b/src/client/views/nodes/formattedText/PaintButtonView.tsx
deleted file mode 100644
index 74423c772..000000000
--- a/src/client/views/nodes/formattedText/PaintButtonView.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-import { action, computed, IReactionDisposer, makeObservable } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import * as ReactDOM from 'react-dom/client';
-import { Doc } from '../../../../fields/Doc';
-import { ObservableReactComponent } from '../../ObservableReactComponent';
-import './DashFieldView.scss';
-import { FormattedTextBox } from './FormattedTextBox';
-import { CollectionViewType } from '../../../documents/DocumentTypes';
-import { CollectionView } from '../../collections/CollectionView';
-import { StrCast } from '../../../../fields/Types';
-
-export class PaintButtonView {
-    dom: HTMLDivElement; // container for label and value
-    root: any;
-    node: any;
-    tbox: FormattedTextBox;
-
-    constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
-        this.node = node;
-        this.tbox = tbox;
-        this.dom = document.createElement('div');
-        this.dom.style.width = node.attrs.width;
-        this.dom.style.height = node.attrs.height;
-        this.dom.style.position = 'relative';
-        this.dom.style.display = 'inline-block';
-        this.dom.onkeypress = function (e: any) {
-            e.stopPropagation();
-        };
-        this.dom.onkeydown = function (e: any) {
-            e.stopPropagation();
-        };
-        this.dom.onkeyup = function (e: any) {
-            e.stopPropagation();
-        };
-        this.dom.onmousedown = function (e: any) {
-            e.stopPropagation();
-        };
-
-        this.root = ReactDOM.createRoot(this.dom);
-        this.root.render(<PaintButtonViewInternal node={node} getPos={getPos} width={node.attrs.width} height={node.attrs.height} tbox={tbox} />);
-    }
-    destroy() {
-        setTimeout(() => {
-            try {
-                this.root.unmount();
-            } catch {}
-        });
-    }
-    deselectNode() {
-        this.dom.classList.remove('ProseMirror-selectednode');
-    }
-    selectNode() {
-        this.dom.classList.add('ProseMirror-selectednode');
-    }
-}
-
-interface IPaintButtonViewInternal {
-    tbox: FormattedTextBox;
-    width: number;
-    height: number;
-    node: any;
-    getPos: any;
-}
-
-@observer
-export class PaintButtonViewInternal extends ObservableReactComponent<IPaintButtonViewInternal> {
-    _reactionDisposer: IReactionDisposer | undefined;
-    _textBoxDoc: Doc;
-
-    constructor(props: IPaintButtonViewInternal) {
-        super(props);
-        makeObservable(this);
-        this._textBoxDoc = this._props.tbox.Document;
-    }
-
-    return100 = () => 100;
-    @computed get _checked() {
-        return this._props.tbox.Document.onClick ? true : false;
-    }
-
-    onCheckClick = () => {
-        const textView = this._props.tbox.DocumentView?.();
-        if (textView) {
-            const paintedField = 'layout_' + this._props.tbox.fieldKey + 'Painted';
-            const layoutFieldKey = StrCast(textView.layoutDoc.layout_fieldKey, 'layout');
-            if (textView.layoutDoc.onClick) {
-                textView.layoutDoc[paintedField] = undefined;
-                textView.layoutDoc.onClick = undefined;
-            } else {
-                textView.layoutDoc.type_collection = CollectionViewType.Freeform;
-                textView.dataDoc[paintedField] = CollectionView.LayoutString(this._props.tbox.fieldKey);
-                textView.layoutDoc.layout_fieldKey = paintedField;
-                textView.setToggleDetail(layoutFieldKey.replace('layout_', '').replace('layout', ''));
-                textView.layoutDoc.layout_fieldKey = layoutFieldKey;
-            }
-        }
-    };
-
-    render() {
-        return (
-            <div
-                className="dashFieldView"
-                style={{
-                    width: this._props.width,
-                    height: this._props.height,
-                    pointerEvents: this._props.tbox._props.isSelected() || this._props.tbox.isAnyChildContentActive?.() ? undefined : 'none',
-                }}>
-                <input type="checkbox" value="paint" checked={this._checked} onChange={e => this.onCheckClick()} />
-            </div>
-        );
-    }
-}
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 8f7bc5282..ce2c33fb4 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -68,40 +68,21 @@ export class RichTextRules {
             ),
 
             // ``` create code block
-            textblockTypeInputRule(/^```$/, schema.nodes.code_block),
-            new InputRule(
-                new RegExp(/(^|\n)\^@paint/), // for code blocks '^' means the beginning of the block, not the line, so need to test for \n
-                (state, match, start, end) => {
-                    const { dataDoc, layoutDoc, fieldKey } = this.TextBox;
-                    layoutDoc.type_collection = CollectionViewType.Freeform;
-                    const paintedField = 'layout_' + this.TextBox.fieldKey + 'Painted';
-                    dataDoc[paintedField] = CollectionView.LayoutString(this.TextBox.fieldKey);
-                    const layoutFieldKey = StrCast(layoutDoc.layout_fieldKey);
-                    layoutDoc.layout_fieldKey = paintedField;
-                    this.TextBox.DocumentView?.().setToggleDetail(layoutFieldKey.replace('layout_', '').replace('layout', ''));
-                    layoutDoc.layout_fieldKey = layoutFieldKey;
-                    const comment = '/* enable as paint function ';
-                    const endComment = ' */\n';
-                    const inCode = state.tr.selection.$anchor.node().type === schema.nodes.code_block;
-                    if (inCode) {
-                        const tr = state.tr
-                            .deleteRange(start, end)
-                            .insertText(comment)
-                            .insert(start + comment.length, schema.nodes.paintButton.create())
-                            .insertText(endComment);
-                        return tr.setSelection(new TextSelection(tr.doc.resolve(start + comment.length + endComment.length + 1)));
-                    } else {
-                        const tr = state.tr
-                            .deleteRange(start, end)
-                            .insertText(comment)
-                            .insert(start + comment.length, schema.nodes.paintButton.create())
-                            .insertText(endComment)
-                            .insert(start + comment.length + endComment.length + 1, schema.nodes.code_block.create());
-                        return tr.setSelection(new TextSelection(tr.doc.resolve(start + comment.length + endComment.length + 3)));
-                    }
-                },
-                { inCode: true }
-            ),
+            new InputRule(/^```$/, (state, match, start, end) => {
+                let $start = state.doc.resolve(start);
+                if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), schema.nodes.code_block)) return null;
+
+                // this enables text with code blocks to be used as a 'paint' function via a styleprovider button that is added to Docs that have an onPaint script
+                this.TextBox.layoutDoc.type_collection = CollectionViewType.Freeform; // make it a freeform when rendered as a collection since those are the only views that know about the paint function
+                const paintedField = 'layout_' + this.TextBox.fieldKey + 'Painted'; // make a layout field key for storing the CollectionView jsx string pointing to the textbox's text
+                this.TextBox.dataDoc[paintedField] = CollectionView.LayoutString(this.TextBox.fieldKey);
+                const layoutFieldKey = StrCast(this.TextBox.layoutDoc.layout_fieldKey); // save the current layout fieldkey
+                this.TextBox.layoutDoc.layout_fieldKey = paintedField; // setup the paint layout field key
+                this.TextBox.DocumentView?.().setToggleDetail(layoutFieldKey.replace('layout_', '').replace('layout', ''), 'onPaint'); // create the script to toggle between the painted and regular view
+                this.TextBox.layoutDoc.layout_fieldKey = layoutFieldKey; // restore the layout field key to text
+
+                return state.tr.delete(start, end).setBlockType(start, start, schema.nodes.code_block);
+            }),
 
             // %<font-size> set the font size
             new InputRule(new RegExp(/%([0-9]+)\s$/), (state, match, start, end) => {
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 30e3aa5f0..f3fc51671 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -572,6 +572,16 @@ export namespace Doc {
         return false;
     }
 
+    export function RemoveEmbedding(doc: Doc, embedding: Doc) {
+        Doc.RemoveDocFromList(doc[DocData], 'proto_embeddings', embedding);
+    }
+    export function AddEmbedding(doc: Doc, embedding: Doc) {
+        Doc.AddDocToList(doc[DocData], 'proto_embeddings', embedding, undefined, undefined, undefined, undefined, undefined, true);
+    }
+    export function GetEmbeddings(doc: Doc) {
+        return DocListCast(Doc.Get(doc[DocData], 'proto_embeddings', true));
+    }
+
     export function MakeEmbedding(doc: Doc, id?: string) {
         const embedding = (!GetT(doc, 'isDataDoc', 'boolean', true) && doc.proto) || doc.type === DocumentType.CONFIG ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id);
         const layout = Doc.LayoutField(embedding);
@@ -579,20 +589,18 @@ export namespace Doc {
             Doc.SetLayout(embedding, Doc.MakeEmbedding(layout));
         }
         embedding.createdFrom = doc;
-        embedding.proto_embeddingId = doc[DocData].proto_embeddingId = DocListCast(doc[DocData].proto_embeddings).length - 1;
+        embedding.proto_embeddingId = doc[DocData].proto_embeddingId = Doc.GetEmbeddings(doc).length - 1;
         !Doc.GetT(embedding, 'title', 'string', true) && (embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`));
         embedding.author = Doc.CurrentUserEmail;
 
-        Doc.AddDocToList(doc[DocData], 'proto_embeddings', embedding);
-
         return embedding;
     }
 
     export function BestEmbedding(doc: Doc) {
         const dataDoc = doc[DocData];
-        const availableEmbeddings = DocListCast(dataDoc.proto_embeddings);
+        const availableEmbeddings = Doc.GetEmbeddings(dataDoc);
         const bestEmbedding = [...(dataDoc !== doc ? [doc] : []), ...availableEmbeddings].find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail);
-        bestEmbedding && Doc.AddDocToList(dataDoc, 'protoEmbeddings', doc);
+        bestEmbedding && Doc.AddDocToList(dataDoc, 'protoEmbeddings', doc, undefined, undefined, undefined, undefined, undefined, true);
         return bestEmbedding ?? Doc.MakeEmbedding(doc);
     }
 
@@ -951,7 +959,7 @@ export namespace Doc {
             Doc.GetProto(copy).embedContainer = undefined;
             Doc.GetProto(copy).proto_embeddings = new List<Doc>([copy]);
         } else {
-            Doc.AddDocToList(copy[DocData], 'proto_embeddings', copy);
+            Doc.AddEmbedding(copy, copy);
         }
         copy.embedContainer = undefined;
         if (retitle) {
@@ -972,9 +980,10 @@ export namespace Doc {
             Object.keys(doc)
                 .filter(key => key.startsWith('acl'))
                 .forEach(key => (delegate[key] = doc[key]));
-            if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DocData], 'proto_embeddings', delegate);
+            if (!Doc.IsSystem(doc)) Doc.AddEmbedding(doc, delegate);
             title && (delegate.title = title);
             delegate[Initializing] = false;
+            Doc.AddEmbedding(doc, delegate);
             return delegate;
         }
         return undefined;
@@ -995,7 +1004,7 @@ export namespace Doc {
         delegate[Initializing] = true;
         delegate.proto = delegateProto;
         delegate.author = Doc.CurrentUserEmail;
-        Doc.AddDocToList(delegateProto[DocData], 'proto_embeddings', delegate);
+        Doc.AddEmbedding(delegateProto, delegate);
         delegate[Initializing] = false;
         delegateProto[Initializing] = false;
         return delegate;
-- 
cgit v1.2.3-70-g09d2


From ab658feb8d5a0a2c7eb2bd213bff227b7accb23a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 26 Feb 2024 14:45:02 -0500
Subject: fixed tooltips to not grab events - this made moving down a menu a
 problem since the tooltip blocked the next menu item and wouldn't give the
 hover event to the next menu item.  fixed proto_embeddings to update when
 lassoing a collection in marqueeView which made showContexts in property view
 do the right thing.

---
 src/client/views/DocComponent.tsx                      |  8 ++++----
 src/client/views/PropertiesDocContextSelector.tsx      |  4 ++--
 src/client/views/collections/CollectionDockingView.tsx |  6 ++++--
 src/client/views/linking/LinkMenuItem.tsx              | 14 +++++++-------
 src/fields/Doc.ts                                      | 11 ++++++-----
 5 files changed, 23 insertions(+), 20 deletions(-)

(limited to 'src/client/views/PropertiesDocContextSelector.tsx')

diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 3d5a5b945..2a527eca1 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -187,14 +187,14 @@ export function ViewBoxAnnotatableComponent<P extends FieldViewProps>() {
             const toRemove = value.filter(v => docs.includes(v));
 
             if (toRemove.length !== 0) {
-                const recent = this.Document !== Doc.MyRecentlyClosed ? Doc.MyRecentlyClosed : undefined;
+                const recentlyClosed = this.Document !== Doc.MyRecentlyClosed ? Doc.MyRecentlyClosed : undefined;
                 toRemove.forEach(doc => {
                     leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
                     Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc, true);
-                    Doc.RemoveEmbedding(doc, doc);
                     doc.embedContainer = undefined;
-                    if (recent && !dontAddToRemoved) {
-                        doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true);
+                    if (recentlyClosed && !dontAddToRemoved && doc.type !== DocumentType.LOADING) {
+                        Doc.AddDocToList(recentlyClosed, 'data', doc, undefined, true, true);
+                        Doc.RemoveEmbedding(doc, doc);
                     }
                 });
                 if (targetDataDoc.isGroup && DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]).length < 2) {
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 361451c4d..b8bbde9de 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -30,12 +30,12 @@ export class PropertiesDocContextSelector extends ObservableReactComponent<Prope
         const targetContext = this._props.DocView.containerViewPath?.().lastElement()?.Document;
         const embeddings = Doc.GetEmbeddings(target);
         const containerProtos = embeddings.filter(embedding => embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set<Doc>());
-        const containerSets = Array.from(containerProtos.keys()).map(container => Doc.GetEmbeddings(container));
+        const containerSets = Array.from(containerProtos.keys()).map(container => (Doc.GetEmbeddings(container).length ? Doc.GetEmbeddings(container) : [container]));
         const containers = containerSets.reduce((p, set) => {
             set.map(s => p.add(s));
             return p;
         }, new Set<Doc>());
-        const doclayoutSets = Array.from(containers.keys()).map(dp => Doc.GetEmbeddings(dp));
+        const doclayoutSets = Array.from(containers.keys()).map(dp => (Doc.GetEmbeddings(dp).length ? Doc.GetEmbeddings(dp) : [dp]));
         const doclayouts = Array.from(
             doclayoutSets
                 .reduce((p, set) => {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 68de62d93..d9d6a5eb5 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -488,8 +488,10 @@ export class CollectionDockingView extends CollectionSubView() {
             Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc, undefined, undefined, 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.Document) tab.DashDoc.embedContainer = undefined;
-            if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
-            Doc.RemoveEmbedding(tab.DashDoc, tab.DashDoc);
+            if (!tab.DashDoc.embedContainer) {
+                Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
+                Doc.RemoveEmbedding(tab.DashDoc, tab.DashDoc);
+            }
         }
         if (CollectionDockingView.Instance) {
             const dview = CollectionDockingView.Instance.Document;
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index e694806a5..81dd0eb98 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -10,7 +10,7 @@ import { Cast, DocCast, StrCast } from '../../../fields/Types';
 import { WebField } from '../../../fields/URLField';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
-import { DragManager } from '../../util/DragManager';
+import { DragManager, dropActionType } from '../../util/DragManager';
 import { LinkFollower } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
 import { SelectionManager } from '../../util/SelectionManager';
@@ -45,7 +45,7 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume
 
         const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
         dragData.canEmbed = true;
-        dragData.dropAction = 'embed';
+        dragData.dropAction = dropActionType.embed;
 
         DragManager.StartDocumentDrag([dragEle], dragData, downX, downY, undefined);
     }
@@ -89,7 +89,7 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
             this,
             e,
             e => {
-                const dragData = new DragManager.DocumentDragData([this._props.linkDoc], 'embed');
+                const dragData = new DragManager.DocumentDragData([this._props.linkDoc], dropActionType.embed);
                 dragData.dropPropertiesToRemove = ['hidden'];
                 DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y);
                 return true;
@@ -177,12 +177,12 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
                         className="linkMenu-name" //title="drag to view target. click to customize."
                         onPointerDown={this.onLinkButtonDown}>
                         <div className="linkMenu-item-buttons">
-                            <Tooltip title={<div className="dash-tooltip">Edit Link</div>}>
+                            <Tooltip disableInteractive={true} title={<div className="dash-tooltip">Edit Link</div>}>
                                 <div className="linkMenu-icon-wrapper" ref={this._editRef} onPointerDown={this.onEdit} onClick={e => e.stopPropagation()}>
                                     <FontAwesomeIcon className="linkMenu-icon" icon="edit" size="sm" />
                                 </div>
                             </Tooltip>
-                            <Tooltip title={<div className="dash-tooltip">Show/Hide Link</div>}>
+                            <Tooltip disableInteractive={true} title={<div className="dash-tooltip">Show/Hide Link</div>}>
                                 <div title="click to show link" className="linkMenu-icon-wrapper" onPointerDown={this.onIconDown}>
                                     <FontAwesomeIcon className="linkMenu-icon" icon={destinationIcon} size="sm" />
                                 </div>
@@ -211,7 +211,7 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
                                 </p>
                             ) : null}
                             <div className="linkMenu-title-wrapper">
-                                <Tooltip title={<div className="dash-tooltip">Follow Link</div>}>
+                                <Tooltip disableInteractive={true} title={<div className="dash-tooltip">Follow Link</div>}>
                                     <p className="linkMenu-destination-title">
                                         {this._props.linkDoc.linksToAnnotation && Cast(this._props.destinationDoc.data, WebField)?.url.href === this._props.linkDoc.annotationUri ? 'Annotation in' : ''} {StrCast(title)}
                                     </p>
@@ -221,7 +221,7 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
                         </div>
 
                         <div className="linkMenu-item-buttons">
-                            <Tooltip title={<div className="dash-tooltip">Delete Link</div>}>
+                            <Tooltip disableInteractive={true} title={<div className="dash-tooltip">Delete Link</div>}>
                                 <div className="linkMenu-deleteButton" onPointerDown={this.deleteLink} onClick={e => e.stopPropagation()}>
                                     <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" />
                                 </div>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 56d50846a..b1bdd50a7 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -391,7 +391,10 @@ export class Doc extends RefField {
 
 export namespace Doc {
     export function SetContainer(doc: Doc, container: Doc) {
-        container !== Doc.MyRecentlyClosed && (doc.embedContainer = container);
+        if (container !== Doc.MyRecentlyClosed) {
+            doc.embedContainer = container;
+            Doc.AddEmbedding(doc, doc);
+        }
     }
     export function RunCachedUpdate(doc: Doc, field: string) {
         const update = doc[CachedUpdates][field];
@@ -604,7 +607,7 @@ export namespace Doc {
         const dataDoc = doc[DocData];
         const availableEmbeddings = Doc.GetEmbeddings(dataDoc);
         const bestEmbedding = [...(dataDoc !== doc ? [doc] : []), ...availableEmbeddings].find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail);
-        bestEmbedding && Doc.AddDocToList(dataDoc, 'protoEmbeddings', doc, undefined, undefined, undefined, undefined, undefined, true);
+        bestEmbedding && Doc.AddDocToList(dataDoc, 'proto_embeddings', doc, undefined, undefined, undefined, undefined, undefined, true);
         return bestEmbedding ?? Doc.MakeEmbedding(doc);
     }
 
@@ -984,10 +987,9 @@ export namespace Doc {
             Object.keys(doc)
                 .filter(key => key.startsWith('acl'))
                 .forEach(key => (delegate[key] = doc[key]));
-            if (!Doc.IsSystem(doc)) Doc.AddEmbedding(doc, delegate);
             title && (delegate.title = title);
             delegate[Initializing] = false;
-            Doc.AddEmbedding(doc, delegate);
+            if (!Doc.IsSystem(doc)) Doc.AddEmbedding(doc, delegate);
             return delegate;
         }
         return undefined;
@@ -1008,7 +1010,6 @@ export namespace Doc {
         delegate[Initializing] = true;
         delegate.proto = delegateProto;
         delegate.author = Doc.CurrentUserEmail;
-        Doc.AddEmbedding(delegateProto, delegate);
         delegate[Initializing] = false;
         delegateProto[Initializing] = false;
         return delegate;
-- 
cgit v1.2.3-70-g09d2

