From 27d37f7c50978da6f3eca87e1aa5bfea786b19c6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 6 Apr 2022 11:04:53 -0400
Subject: fixed displaying titles on text to not shrink box to 0 height.  fixed
 autoLink to not self link.

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

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 1f7e557d9..dcb312980 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -381,7 +381,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
     // creates links between terms in a document and documents which have a matching Id
     hyperlinkTerm = (tr: any, target: Doc, newAutoLinks: Set<Doc>) => {
-        if (this._editorView && (this._editorView as any).docView) {
+        if (this._editorView && (this._editorView as any).docView && !Doc.AreProtosEqual(target, this.rootDoc)) {
             const flattened1 = this.findInNode(this._editorView, this._editorView.state.doc, StrCast(target.title).replace(/^@/, ""));
             var alink: Doc | undefined;
             flattened1.forEach((flat, i) => {
-- 
cgit v1.2.3-70-g09d2


From aeb636371275ed056d7812447984f71ff90b39e0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 6 Apr 2022 11:44:02 -0400
Subject: set publsihed documents to automatically display a title region

---
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 8 ++++++++
 1 file changed, 8 insertions(+)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index dcb312980..18be30a88 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1443,6 +1443,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             } catch (e: any) { console.log(e.message); }
             this._lastText = curText;
         }
+        if (StrCast(this.rootDoc.title).startsWith("@") && !this.dataDoc["title-custom"]) {
+            UndoManager.RunInBatch(() => {
+                this.dataDoc["title-custom"] = true;
+                this.dataDoc.showTitle = "title";
+                const tr = this._editorView!.state.tr;
+                this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(0), tr.doc.resolve(StrCast(this.rootDoc.title).length + 2))).deleteSelection());
+            }, "titler");
+        }
     }
     onKeyDown = (e: React.KeyboardEvent) => {
         // single line text boxes need to pass through tab/enter/backspace so that their containers can respond (eg, an outline container)
-- 
cgit v1.2.3-70-g09d2


From f05bc3ee02198289dbfbc1b9c8db0b9e0fffd27c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 7 Apr 2022 12:02:04 -0400
Subject: added multiple target capability for autoLinks.   added wiki:<link>

---
 src/client/views/nodes/LinkDocPreview.tsx          | 22 ++++++++++++++++------
 .../views/nodes/formattedText/FormattedTextBox.tsx | 20 +++++++++++++++-----
 .../views/nodes/formattedText/RichTextRules.ts     | 19 +++++++++++++++++++
 src/client/views/nodes/formattedText/marks_rts.ts  | 13 +++++++++----
 4 files changed, 59 insertions(+), 15 deletions(-)

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

diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index f5f773595..d5f3f3b4e 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -84,9 +84,16 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                 anchorDoc && DocServer.GetRefField(anchorDoc).then(action(anchor => {
                     if (anchor instanceof Doc && DocListCast(anchor.links).length) {
                         this._linkDoc = this._linkDoc ?? DocListCast(anchor.links)[0];
-                        this._linkSrc = anchor;
-                        const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc);
-                        this._targetDoc = linkTarget?.type === DocumentType.MARKER && linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget;
+                        const automaticLink = this._linkDoc.linkRelationship === "automatic";
+                        if (automaticLink) { // automatic links specify the target in the link info, not the source
+                            const linkTarget = anchor;
+                            this._linkSrc = LinkManager.getOppositeAnchor(this._linkDoc, linkTarget);
+                            this._targetDoc = linkTarget;
+                        } else {
+                            this._linkSrc = anchor;
+                            const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc);
+                            this._targetDoc = linkTarget?.type === DocumentType.MARKER && linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget;
+                        }
                         this._toolTipText = "";
                     }
                 }));
@@ -99,7 +106,10 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
         setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(() => this._linkDoc && LinkManager.Instance.deleteLink(this._linkDoc)));
     }
     nextHref = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, returnFalse, emptyFunction, action(() => this._hrefInd = (this._hrefInd + 1) % (this.props.hrefs?.length || 1)));
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, action(() => {
+            this._linkDoc = undefined;
+            this._hrefInd = (this._hrefInd + 1) % (this.props.hrefs?.length || 1);
+        }));
     }
 
     followLink = (e: React.PointerEvent) => {
@@ -152,10 +162,10 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
         return (!this._linkDoc || !this._targetDoc || !this._linkSrc) && !this._toolTipText ? (null) :
             <div className="linkDocPreview-inner">
                 {!this.props.showHeader ? (null) : this.previewHeader}
-                <div className="linkDocPreview-preview-wrapper">
+                <div className="linkDocPreview-preview-wrapper" style={{ maxHeight: this._toolTipText ? "100%" : undefined, overflow: "auto" }}>
                     {this._toolTipText ? this._toolTipText :
                         <DocumentView ref={(r) => {
-                            const targetanchor = LinkManager.getOppositeAnchor(this._linkDoc!, this._linkSrc!);
+                            const targetanchor = this._linkDoc && this._linkSrc && LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc);
                             targetanchor && this._targetDoc !== targetanchor && r?.focus(targetanchor);
                         }}
                             Document={this._targetDoc!}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 18be30a88..ec88b8d1d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -381,8 +381,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
     // creates links between terms in a document and documents which have a matching Id
     hyperlinkTerm = (tr: any, target: Doc, newAutoLinks: Set<Doc>) => {
-        if (this._editorView && (this._editorView as any).docView && !Doc.AreProtosEqual(target, this.rootDoc)) {
-            const flattened1 = this.findInNode(this._editorView, this._editorView.state.doc, StrCast(target.title).replace(/^@/, ""));
+        const editorView = this._editorView;
+        if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.rootDoc)) {
+            const flattened1 = this.findInNode(editorView, editorView.state.doc, StrCast(target.title).replace(/^@/, ""));
             var alink: Doc | undefined;
             flattened1.forEach((flat, i) => {
                 const flattened = this.findInNode(this._editorView!, this._editorView!.state.doc, StrCast(target.title).replace(/^@/, ""));
@@ -391,9 +392,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) &&
                     Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || DocUtils.MakeLink({ doc: this.props.Document }, { doc: target }, "automatic")!);
                 newAutoLinks.add(alink);
-                const allAnchors = [{ href: Doc.localServerPath(this.props.Document), title: "a link", anchorId: this.props.Document[Id] }];
-                const link = this._editorView!.state.schema.marks.autoLinkAnchor.create({ allAnchors, linkDoc: alink[Id], title: "auto link", location });
-                tr = tr.addMark(flattened[i].from, flattened[i].to, link);
+                const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() });
+                const sel = flattened[i];
+                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.splitter.name)) {
+                        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 ?? []));
+                        const link = editorView.state.schema.marks.autoLinkAnchor.create({ allAnchors, title: "auto term", location: "add:right" });
+                        tr = tr.addMark(pos, pos + node.nodeSize, link);
+                    }
+                });
+                tr = tr.removeMark(sel.from, sel.to, splitter);
             });
         }
         return tr;
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index bafae84dc..00c03875b 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -294,6 +294,25 @@ export class RichTextRules {
                     return state.tr.deleteRange(start, end).insert(start, fieldView);
                 }),
 
+
+            // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document 
+            // wiki:title
+            new InputRule(
+                new RegExp(/wiki:([a-zA-Z_@:\.\?\-0-9]+ )$/),
+                (state, match, start, end) => {
+                    const title = match[1];
+                    this.TextBox.EditorView?.dispatch(state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))));
+
+                    this.TextBox.makeLinkAnchor(undefined, "add:right", `https://en.wikipedia.org/wiki/${title.trim()}`, "wikipedia reference");
+
+                    const fstate = this.TextBox.EditorView?.state;
+                    if (fstate) {
+                        const tr = fstate?.tr.deleteRange(start, start + 5);
+                        return tr.setSelection(new TextSelection(tr.doc.resolve(end - 5))).insertText(" ");
+                    }
+                    return state.tr;
+                }),
+
             // create an inline view of a document {{ <layoutKey> : <Doc> }}  
             // {{:Doc}} => show default view of document   
             // {{<layout>}} => show layout for this doc   
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 52ef06b7f..1f6ce014f 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -19,13 +19,17 @@ export const marks: { [index: string]: MarkSpec } = {
     },
 
 
-    // :: MarkSpec A linkAnchor. The anchor can have multiple links, where each link has an href URL and a title for use in menus and hover (Dash links have linkIDs & targetIDs). `title`
-    // defaults to the empty string. Rendered and parsed as an `<a>`
+    // :: MarkSpec an autoLinkAnchor. These are automatically generated anchors to "published" documents based on the anchor text matching the
+    // published document's title. 
+    // NOTE: unlike linkAnchors, the autoLinkAnchor's href's indicate the target anchor of the hyperlink and NOT the source.  This is because
+    // automatic links do not create a text selection Marker document for the source anchor, but use the text document itself.  Since 
+    // multiple automatic links can be created each having the same source anchor (the whole document), the target href of the link is needed to
+    // disambiguate links from one another.
+    // Rendered and parsed as an `<a>`
     // element.
     autoLinkAnchor: {
         attrs: {
             allAnchors: { default: [] as { href: string, title: string, anchorId: string }[] },
-            linkDoc: { default: "" },
             location: { default: null },
             title: { default: null },
         },
@@ -44,7 +48,8 @@ export const marks: { [index: string]: MarkSpec } = {
             return ["a", { class: anchorids, "data-targethrefs": targethrefs, "data-linkdoc": node.attrs.linkDoc, title: node.attrs.title, location: node.attrs.location, style: `background: lightBlue` }, 0];
         }
     },
-    // :: MarkSpec A linkAnchor. The anchor can have multiple links, where each link has an href URL and a title for use in menus and hover (Dash links have linkIDs & targetIDs). `title`
+    // :: MarkSpec A linkAnchor. The anchor can have multiple links, where each linkAnchor specifies an href to the URL of the source selection Marker text,
+    // and a title for use in menus and hover. `title`
     // defaults to the empty string. Rendered and parsed as an `<a>`
     // element.
     linkAnchor: {
-- 
cgit v1.2.3-70-g09d2

