From c23d9ba83c87511a626bfe8d1da5dd981e311262 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 23 Jan 2020 18:24:38 -0500
Subject: got rid of extension docs.  changed layout-specific keys to start
 with "_" which flags them to be written to the current layout document

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

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

diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 80752303c..57b091ce4 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -136,7 +136,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     addDocument = (value: string, shiftDown?: boolean) => {
         this._createAliasSelected = false;
         const key = StrCast(this.props.parent.props.Document.sectionFilter);
-        const newDoc = Docs.Create.TextDocument({ height: 18, width: 200, title: value });
+        const newDoc = Docs.Create.TextDocument({ _height: 18, _width: 200, title: value });
         newDoc[key] = this.getValue(this.props.heading);
         return this.props.parent.props.addDocument(newDoc);
     }
@@ -258,7 +258,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     @computed get contentLayout() {
         const rows = Math.max(1, Math.min(this.props.docList.length, Math.floor((this.props.parent.props.PanelWidth() - 2 * this.props.parent.xMargin) / (this.props.parent.columnWidth + this.props.parent.gridGap))));
         const style = this.props.parent; const collapsed = this._collapsed;
-        const chromeStatus = this.props.parent.props.Document.chromeStatus;
+        const chromeStatus = this.props.parent.props.Document._chromeStatus;
         const newEditableViewProps = {
             GetValue: () => "",
             SetValue: this.addDocument,
-- 
cgit v1.2.3-70-g09d2


From e78f2663901b4cbd9fddc3418e40b8798ecfd994 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 25 Jan 2020 12:01:15 -0500
Subject: added text templates for FormattedText, added field views in
 formatted text box,  got rid of documentText @@@ initing of FormattedText

---
 src/client/documents/Documents.ts                  |  8 ++--
 src/client/util/DictationManager.ts                |  2 +-
 src/client/util/RichTextRules.ts                   | 17 ++++++-
 src/client/util/RichTextSchema.tsx                 | 53 +++++++++++++++++++++-
 src/client/views/PreviewCursor.tsx                 |  2 +-
 .../collections/CollectionMasonryViewFieldRow.tsx  |  2 +-
 .../views/collections/CollectionSchemaView.tsx     |  2 +-
 .../CollectionStackingViewFieldColumn.tsx          |  2 +-
 src/client/views/collections/CollectionSubView.tsx |  6 +--
 .../views/collections/CollectionTreeView.tsx       | 11 +++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |  8 ++--
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        | 36 ++++++---------
 src/client/views/nodes/KeyValueBox.tsx             |  2 +-
 src/client/views/nodes/WebBox.tsx                  |  3 +-
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 .../authentication/models/current_user_utils.ts    | 10 ++--
 18 files changed, 112 insertions(+), 58 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 58aec6173..04ab514f0 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -52,6 +52,7 @@ import { DocumentBox } from "../views/nodes/DocumentBox";
 import { InkingStroke } from "../views/InkingStroke";
 import { InkField } from "../../new_fields/InkField";
 import { InkingControl } from "../views/InkingControl";
+import { RichTextField } from "../../new_fields/RichTextField";
 const requestImageSize = require('../util/request-image-size');
 const path = require('path');
 
@@ -72,6 +73,7 @@ export interface DocumentOptions {
     _gridGap?: number; // gap between items in masonry view
     _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
+    _textTemplate?: RichTextField; // template used by a formattedTextBox to create a text box to render
     x?: number;
     y?: number;
     z?: number;
@@ -441,8 +443,8 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.COLOR), "", options);
         }
 
-        export function TextDocument(options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.TEXT), "", options);
+        export function TextDocument(text: string, options: DocumentOptions = {}) {
+            return InstanceFromProto(Prototypes.get(DocumentType.TEXT), text, options);
         }
 
         export function InkDocument(color: string, tool: number, strokeWidth: number, points: { X: number, Y: number }[], options: DocumentOptions = {}) {
@@ -703,7 +705,7 @@ export namespace Docs {
                 created = Docs.Create.StackingDocument(DocListCast(field), resolved);
                 layout = CollectionView.LayoutString;
             } else {
-                created = Docs.Create.TextDocument({ ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved });
+                created = Docs.Create.TextDocument("", { ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved });
                 layout = FormattedTextBox.LayoutString;
             }
             created.layout = layout?.(fieldKey);
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index fa7f63965..3394cb93d 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -332,7 +332,7 @@ export namespace DictationManager {
 
             ["new outline", {
                 action: (target: DocumentView) => {
-                    const newBox = Docs.Create.TextDocument({ _width: 400, _height: 200, title: "My Outline", _autoHeight: true });
+                    const newBox = Docs.Create.TextDocument("", { _width: 400, _height: 200, title: "My Outline", _autoHeight: true });
                     const proto = newBox.proto!;
                     const prompt = "Press alt + r to start dictating here...";
                     const head = 3;
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index 02b7502d8..bc8a0abb1 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -2,7 +2,7 @@ import { textblockTypeInputRule, smartQuotes, emDash, ellipsis, InputRule } from
 import { schema } from "./RichTextSchema";
 import { wrappingInputRule } from "./prosemirrorPatches";
 import { NodeSelection, TextSelection } from "prosemirror-state";
-import { NumCast, Cast } from "../../new_fields/Types";
+import { StrCast, Cast } from "../../new_fields/Types";
 import { Doc } from "../../new_fields/Doc";
 import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
 import { Docs, DocUtils } from "../documents/Documents";
@@ -71,6 +71,19 @@ export const inpRules = {
             }),
 
         // make current selection a hyperlink portal (assumes % was used to initiate an EnteringStyle mode)
+        new InputRule(
+            new RegExp(/!$/),
+            (state, match, start, end) => {
+                if (state.selection.to === state.selection.from || !(schema as any).EnteringStyle) return null;
+                const value = state.doc.textBetween(start, end);
+
+                const node = (state.doc.resolve(start) as any).nodeAfter;
+                const sm = state.storedMarks || undefined;
+                const fieldView = state.schema.nodes.dashField.create({ fieldKey: StrCast(value) });
+                const replaced = node ? state.tr.replaceRangeWith(start, end, fieldView).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr;
+                return replaced.doc.nodeSize > end - 2 ? replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2))) : replaced;
+            }),
+        // make current selection a hyperlink portal (assumes % was used to initiate an EnteringStyle mode)
         new InputRule(
             new RegExp(/@$/),
             (state, match, start, end) => {
@@ -196,7 +209,7 @@ export const inpRules = {
         new InputRule(
             new RegExp(/%#$/),
             (state, match, start, end) => {
-                const target = Docs.Create.TextDocument({ _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: FormattedTextBox.FocusedBox!.dataDoc, _autoHeight: true, fontSize: 9, title: "inline comment" });
+                const target = Docs.Create.TextDocument("", { _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: FormattedTextBox.FocusedBox!.dataDoc, _autoHeight: true, fontSize: 9, title: "inline comment" });
                 const node = (state.doc.resolve(start) as any).nodeAfter;
                 const newNode = schema.nodes.dashComment.create({ docid: target[Id] });
                 const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: target[Id], float: "right" });
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index d64098e5f..21916e3d6 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -8,7 +8,7 @@ import { EditorState, NodeSelection, TextSelection, Plugin } from "prosemirror-s
 import { StepMap } from "prosemirror-transform";
 import { EditorView } from "prosemirror-view";
 import * as ReactDOM from 'react-dom';
-import { Doc, WidthSym, HeightSym } from "../../new_fields/Doc";
+import { Doc, WidthSym, HeightSym, DataSym, Field } from "../../new_fields/Doc";
 import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from "../../Utils";
 import { DocServer } from "../DocServer";
 import { DocumentView } from "../views/nodes/DocumentView";
@@ -16,7 +16,7 @@ import { DocumentManager } from "./DocumentManager";
 import ParagraphNodeSpec from "./ParagraphNodeSpec";
 import { Transform } from "./Transform";
 import React = require("react");
-import { BoolCast, NumCast, Cast } from "../../new_fields/Types";
+import { BoolCast, NumCast, StrCast } from "../../new_fields/Types";
 import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
 
 const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
@@ -175,6 +175,19 @@ export const nodes: { [index: string]: NodeSpec } = {
         }
     },
 
+    dashField: {
+        inline: true,
+        attrs: {
+            fieldKey: { default: "" },
+        },
+        group: "inline",
+        draggable: false,
+        toDOM(node) {
+            const attrs = { style: `width: ${node.attrs.width}, height: ${node.attrs.height}` };
+            return ["div", { ...node.attrs, ...attrs }];
+        }
+    },
+
     video: {
         inline: true,
         attrs: {
@@ -799,6 +812,42 @@ export class DashDocView {
     }
 }
 
+export class DashFieldView {
+    _fieldWrapper: HTMLDivElement;
+    _labelSpan: HTMLSpanElement;
+    _fieldSpan: HTMLSpanElement;
+    _reactionDisposer: IReactionDisposer | undefined;
+    _textBoxDoc: Doc;
+
+    constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
+        this._textBoxDoc = tbox.props.Document;
+        this._fieldWrapper = document.createElement("div");
+        this._fieldWrapper.style.width = node.attrs.width;
+        this._fieldWrapper.style.height = node.attrs.height;
+        this._fieldWrapper.style.position = "relative";
+        this._fieldWrapper.style.display = "inline";
+
+        this._fieldSpan = document.createElement("span");
+        this._fieldSpan.style.position = "relative";
+        this._fieldSpan.style.display = "inline";
+
+        this._labelSpan = document.createElement("span");
+        this._labelSpan.style.position = "relative";
+        this._labelSpan.style.display = "inline";
+        this._labelSpan.style.fontWeight = "bold";
+        this._labelSpan.style.fontSize = "larger";
+        this._labelSpan.innerHTML = `${node.attrs.fieldKey}: `;
+        this._reactionDisposer && this._reactionDisposer();
+        this._reactionDisposer = reaction(() => this._textBoxDoc[DataSym][node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field), { fireImmediately: true });
+        this._fieldWrapper.appendChild(this._labelSpan);
+        this._fieldWrapper.appendChild(this._fieldSpan);
+        (this as any).dom = this._fieldWrapper;
+    }
+    destroy() {
+        this._reactionDisposer && this._reactionDisposer();
+    }
+}
+
 export class OrderedListView {
     update(node: any) {
         return false; // if attr's of an ordered_list (e.g., bulletStyle) change, return false forces the dom node to be recreated which is necessary for the bullet labels to update
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index b1c84667d..c011adb20 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -49,7 +49,7 @@ export class PreviewCursor extends React.Component<{}> {
                 }
 
                 // creates text document
-                return PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument({
+                return PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", {
                     _width: 500,
                     limitHeight: 400,
                     _autoHeight: true,
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 57b091ce4..e25a2f5eb 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -136,7 +136,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     addDocument = (value: string, shiftDown?: boolean) => {
         this._createAliasSelected = false;
         const key = StrCast(this.props.parent.props.Document.sectionFilter);
-        const newDoc = Docs.Create.TextDocument({ _height: 18, _width: 200, title: value });
+        const newDoc = Docs.Create.TextDocument("", { _height: 18, _width: 200, title: value });
         newDoc[key] = this.getValue(this.props.heading);
         return this.props.parent.props.addDocument(newDoc);
     }
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 9ecb8dc43..a35c945b9 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -477,7 +477,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @undoBatch
     createRow = () => {
-        const newDoc = Docs.Create.TextDocument({ title: "", _width: 100, _height: 30 });
+        const newDoc = Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 });
         this.props.addDocument(newDoc);
     }
 
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 0960b0e96..dabc14445 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -152,7 +152,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         }
         this._createAliasSelected = false;
         const key = StrCast(this.props.parent.props.Document.sectionFilter);
-        const newDoc = Docs.Create.TextDocument({ _height: 18, _width: 200, documentText: "@@@" + value, title: value, _autoHeight: true });
+        const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, title: value, _autoHeight: true });
         newDoc[key] = this.getValue(this.props.heading);
         const maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
         const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d1a5bed1e..db3fde797 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -224,7 +224,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                         this.props.addDocument && this.props.addDocument(Docs.Create.WebDocument(href, { ...options, title: href }));
                     }
                 } else if (text) {
-                    this.props.addDocument && this.props.addDocument(Docs.Create.TextDocument({ ...options, _width: 100, _height: 25, documentText: "@@@" + text }));
+                    this.props.addDocument && this.props.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 100, _height: 25 }));
                 }
                 return;
             }
@@ -262,7 +262,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
             }
             let matches: RegExpExecArray | null;
             if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
-                const newBox = Docs.Create.TextDocument({ ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
+                const newBox = Docs.Create.TextDocument("", { ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
                 const proto = newBox.proto!;
                 const documentId = matches[2];
                 proto[GoogleRef] = documentId;
@@ -333,7 +333,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                 Promise.all(promises).finally(() => { completed && completed(); batch.end(); });
             } else {
                 if (text && !text.includes("https://")) {
-                    this.props.addDocument(Docs.Create.TextDocument({ ...options, documentText: "@@@" + text, _width: 400, _height: 315 }));
+                    this.props.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 }));
                 }
                 batch.end();
             }
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 485abf8b9..2208de264 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -33,6 +33,7 @@ import { CollectionSubView } from "./CollectionSubView";
 import "./CollectionTreeView.scss";
 import React = require("react");
 import { CollectionViewType } from './CollectionView';
+import { RichTextField } from '../../../new_fields/RichTextField';
 
 
 export interface TreeViewProps {
@@ -634,18 +635,18 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                 const { TextDocument, ImageDocument, MulticolumnDocument, TreeDocument } = Docs.Create;
                 const { Document } = this.props;
                 const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif";
+                const detailedTemplate = `{ "doc": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "short_description" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "year" } } ] },  { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] }  ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`;
 
                 const detailedLayout = Docs.Create.StackingDocument([
                     ImageDocument(fallbackImg, { title: "activeHero" }),
                     MulticolumnDocument([], {
                         title: "data", _height: 100, onChildClick: ScriptField.MakeFunction(
                             `containingCollection.resolvedDataDoc.activeHero = copyField(this.data);
-                        containingCollection.resolvedDataDoc.activeHero["activeHero-nativeWidth"] = copyField(this.data["data-nativeWidth"]);
-                        containingCollection.resolvedDataDoc.activeHero["activeHero-nativeHeight"] = copyField(this.data["data-nativeHeight"]);
+                            containingCollection.resolvedDataDoc.activeHero["activeHero-nativeWidth"] = copyField(this.data["data-nativeWidth"]);
+                            containingCollection.resolvedDataDoc.activeHero["activeHero-nativeHeight"] = copyField(this.data["data-nativeHeight"]);
                         `, { containingCollection: Doc.name })
                     }),
-                    TextDocument({ title: "short_description", _autoHeight: true }),
-                    ...["year", "company", "degrees_of_freedom"].map(key => TextDocument({ title: key, _height: 30 }))
+                    TextDocument("", { title: "details", _autoHeight: true, _textTemplate: new RichTextField(detailedTemplate, "short_description year company") })
                 ], { _chromeStatus: "disabled", title: "detailed layout stack" });
                 detailedLayout.isTemplateDoc = makeTemplate(detailedLayout);
 
@@ -733,7 +734,7 @@ Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey
     };
     const capturedVariables = { layoutDoc, facetHeader };
     return new List<Doc>(Array.from(facetValues).sort().map(facetValue => {
-        const value = Docs.Create.TextDocument({ title: facetValue.toString() });
+        const value = Docs.Create.TextDocument("", { title: facetValue.toString() });
         value.treeViewChecked = ComputedField.MakeFunction(text, params, { ...capturedVariables, facetValue });
         return value;
     }));
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 7aa9d4922..70f8a0e73 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -921,7 +921,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             description: "Add Note ...",
             subitems: DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data).map((note, i) => ({
                 description: (i + 1) + ": " + StrCast(note.title),
-                event: (args: { x: number, y: number }) => this.addLiveTextBox(Docs.Create.TextDocument({ _width: 200, _height: 100, x: this.getTransform().transformPoint(args.x, args.y)[0], y: this.getTransform().transformPoint(args.x, args.y)[1], _autoHeight: true, layout: note, title: StrCast(note.title) })),
+                event: (args: { x: number, y: number }) => this.addLiveTextBox(Docs.Create.TextDocument("", { _width: 200, _height: 100, x: this.getTransform().transformPoint(args.x, args.y)[0], y: this.getTransform().transformPoint(args.x, args.y)[1], _autoHeight: true, layout: note, title: StrCast(note.title) })),
                 icon: "eye"
             })) as ContextMenuProps[],
             icon: "eye"
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 741712b6e..6a1590b8e 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -84,7 +84,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                 }
                 ns.map(line => {
                     const indent = line.search(/\S|$/);
-                    const newBox = Docs.Create.TextDocument({ _width: 200, _height: 35, x: x + indent / 3 * 10, y: y, documentText: "@@@" + line, title: line });
+                    const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: y, title: line });
                     this.props.addDocument(newBox);
                     y += 40 * this.props.getTransform().Scale;
                 });
@@ -101,10 +101,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             });
         } else if (!e.ctrlKey) {
             this.props.addLiveTextDocument(
-                Docs.Create.TextDocument({ _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" }));
+                Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" }));
         } else if (e.keyCode > 48 && e.keyCode <= 57) {
             const notes = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data);
-            const text = Docs.Create.TextDocument({ _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" });
+            const text = Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" });
             text.layout = notes[(e.keyCode - 49) % notes.length];
             this.props.addLiveTextDocument(text);
         }
@@ -374,7 +374,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             return d;
         });
         newCollection._chromeStatus = "disabled";
-        const summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, _width: 300, _height: 100, _autoHeight: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" });
+        const summary = Docs.Create.TextDocument("", { x: bounds.left, y: bounds.top, _width: 300, _height: 100, _autoHeight: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" });
         Doc.GetProto(summary).summarizedDocs = new List<Doc>([newCollection]);
         newCollection.x = bounds.left + bounds.width;
         Doc.GetProto(newCollection).summaryDoc = summary;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c8b1f9794..609eb689e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -531,7 +531,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             let fieldTemplate: Doc;
             switch (doc.type) {
                 case DocumentType.TEXT:
-                    fieldTemplate = Docs.Create.TextDocument(options);
+                    fieldTemplate = Docs.Create.TextDocument("", options);
                     break;
                 case DocumentType.PDF:
                     fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options);
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index b794ad0c5..fab267358 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -12,7 +12,7 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from "
 import { ReplaceStep } from 'prosemirror-transform';
 import { EditorView } from "prosemirror-view";
 import { DateField } from '../../../new_fields/DateField';
-import { Doc, DocListCastAsync, Opt, WidthSym, HeightSym, DataSym } from "../../../new_fields/Doc";
+import { Doc, DocListCastAsync, Opt, WidthSym, HeightSym, DataSym, Field } from "../../../new_fields/Doc";
 import { Copy, Id } from '../../../new_fields/FieldSymbols';
 import { RichTextField } from "../../../new_fields/RichTextField";
 import { RichTextUtils } from '../../../new_fields/RichTextUtils';
@@ -27,7 +27,7 @@ import { DictationManager } from '../../util/DictationManager';
 import { DragManager } from "../../util/DragManager";
 import buildKeymap from "../../util/ProsemirrorExampleTransfer";
 import { inpRules } from "../../util/RichTextRules";
-import { DashDocCommentView, FootnoteView, ImageResizeView, DashDocView, OrderedListView, schema, SummaryView } from "../../util/RichTextSchema";
+import { DashDocCommentView, FootnoteView, ImageResizeView, DashDocView, OrderedListView, schema, SummaryView, DashFieldView } from "../../util/RichTextSchema";
 import { SelectionManager } from "../../util/SelectionManager";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { DocAnnotatableComponent, DocAnnotatableProps } from "../DocComponent";
@@ -534,7 +534,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
             () => this.tryUpdateHeight()
         );
 
-        this.setupEditor(this.config, this.dataDoc, this.props.fieldKey);
+        this.setupEditor(this.config, this.props.fieldKey);
 
         this._searchReactionDisposer = reaction(() => this.layoutDoc.searchMatch,
             search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
@@ -736,28 +736,18 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
         }
     }
 
-    private setupEditor(config: any, doc: Doc, fieldKey: string) {
-        const field = doc ? Cast(doc[fieldKey], RichTextField) : undefined;
-        let startup = StrCast(doc.documentText);
-        startup = startup.startsWith("@@@") ? startup.replace("@@@", "") : "";
-        if (!field && doc) {
-            const text = StrCast(doc[fieldKey]);
-            if (text) {
-                startup = text;
-            } else if (Cast(doc[fieldKey], "number")) {
-                startup = NumCast(doc[fieldKey], 99).toString();
-            }
-        }
+    private setupEditor(config: any, fieldKey: string) {
+        const rtfField = Cast(this.props.Document._textTemplate || this.dataDoc[fieldKey], RichTextField);
         if (this.ProseRef) {
             const self = this;
-            this._editorView && this._editorView.destroy();
+            this._editorView?.destroy();
             this._editorView = new EditorView(this.ProseRef, {
-                state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config),
+                state: rtfField?.Data ? EditorState.fromJSON(config, JSON.parse(rtfField.Data)) : EditorState.create(config),
                 handleScrollToSelection: (editorView) => {
                     const ref = editorView.domAtPos(editorView.state.selection.from);
                     let refNode = ref.node as any;
                     while (refNode && !("getBoundingClientRect" in refNode)) refNode = refNode.parentElement;
-                    const r1 = refNode && refNode.getBoundingClientRect();
+                    const r1 = refNode?.getBoundingClientRect();
                     const r3 = self._ref.current!.getBoundingClientRect();
                     if (r1.top < r3.top || r1.top > r3.bottom) {
                         r1 && (self._scrollRef.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale);
@@ -767,6 +757,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                 dispatchTransaction: this.dispatchTransaction,
                 nodeViews: {
                     dashComment(node, view, getPos) { return new DashDocCommentView(node, view, getPos); },
+                    dashField(node, view, getPos) { return new DashFieldView(node, view, getPos, self); },
                     dashDoc(node, view, getPos) { return new DashDocView(node, view, getPos, self); },
                     image(node, view, getPos) { return new ImageResizeView(node, view, getPos, self.props.addDocTab); },
                     summary(node, view, getPos) { return new SummaryView(node, view, getPos); },
@@ -777,9 +768,9 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                 handlePaste: this.handlePaste,
             });
             this._editorView.state.schema.Document = this.props.Document;
-            if (startup && this._editorView) {
-                Doc.GetProto(doc).documentText = undefined;
-                this._editorView.dispatch(this._editorView.state.tr.insertText(startup));
+            const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field);
+            if (startupText) {
+                this._editorView.dispatch(this._editorView.state.tr.insertText(startupText));
             }
         }
 
@@ -788,8 +779,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
             FormattedTextBox.SelectOnLoad = "";
             this.props.select(false);
         }
-        const rtf = doc ? Cast(doc[fieldKey], RichTextField) : undefined;
-        (selectOnLoad || (rtf && !rtf.Text)) && this._editorView!.focus();
+        (selectOnLoad /* || !rtfField?.Text*/) && this._editorView!.focus();
         // add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet.
         this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.round(Date.now() / 1000 / 5) })];
     }
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 499cd2877..7aad6f90e 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -210,7 +210,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
     inferType = async (data: FieldResult, metaKey: string) => {
         const options = { _width: 300, _height: 300, title: metaKey };
         if (data instanceof RichTextField || typeof data === "string" || typeof data === "number") {
-            return Docs.Create.TextDocument(options);
+            return Docs.Create.TextDocument("", options);
         } else if (data instanceof List) {
             if (data.length === 0) {
                 return Docs.Create.StackingDocument([], options);
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 1445b5b08..a48dc286e 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -83,13 +83,12 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
         const field = Cast(this.props.Document[this.props.fieldKey], WebField);
         if (field) url = field.url.href;
 
-        const newBox = Docs.Create.TextDocument({
+        const newBox = Docs.Create.TextDocument(url, {
             x: NumCast(this.props.Document.x),
             y: NumCast(this.props.Document.y),
             title: url,
             _width: 200,
             _height: 70,
-            documentText: "@@@" + url
         });
 
         SelectionManager.SelectedDocuments().map(dv => {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index fe601175d..a9053fd55 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -558,7 +558,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
     startDrag = (e: PointerEvent, ele: HTMLElement): void => {
         e.preventDefault();
         e.stopPropagation();
-        const targetDoc = Docs.Create.TextDocument({ _width: 200, _height: 200, title: "Note linked to " + this.props.Document.title });
+        const targetDoc = Docs.Create.TextDocument("", { _width: 200, _height: 200, title: "Note linked to " + this.props.Document.title });
         const annotationDoc = this.highlight("rgba(146, 245, 95, 0.467)"); // yellowish highlight color when dragging out a text selection
         if (annotationDoc) {
             DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 818a30e9f..6f99af8f6 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -33,11 +33,11 @@ export class CurrentUserUtils {
     // a default set of note types .. not being used yet...
     static setupNoteTypes(doc: Doc) {
         return [
-            Docs.Create.TextDocument({ title: "Note", backgroundColor: "yellow", isTemplateDoc: true }),
-            Docs.Create.TextDocument({ title: "Idea", backgroundColor: "pink", isTemplateDoc: true }),
-            Docs.Create.TextDocument({ title: "Topic", backgroundColor: "lightBlue", isTemplateDoc: true }),
-            Docs.Create.TextDocument({ title: "Person", backgroundColor: "lightGreen", isTemplateDoc: true }),
-            Docs.Create.TextDocument({ title: "Todo", backgroundColor: "orange", isTemplateDoc: true })
+            Docs.Create.TextDocument("", { title: "Note", backgroundColor: "yellow", isTemplateDoc: true }),
+            Docs.Create.TextDocument("", { title: "Idea", backgroundColor: "pink", isTemplateDoc: true }),
+            Docs.Create.TextDocument("", { title: "Topic", backgroundColor: "lightBlue", isTemplateDoc: true }),
+            Docs.Create.TextDocument("", { title: "Person", backgroundColor: "lightGreen", isTemplateDoc: true }),
+            Docs.Create.TextDocument("", { title: "Todo", backgroundColor: "orange", isTemplateDoc: true })
         ];
     }
 
-- 
cgit v1.2.3-70-g09d2

