aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts9
-rw-r--r--src/client/util/CurrentUserUtils.ts35
-rw-r--r--src/client/util/DropConverter.ts48
-rw-r--r--src/client/views/collections/TreeView.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx4
5 files changed, 60 insertions, 38 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index b7d8222b9..e6969d1f3 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1024,6 +1024,15 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.PRES), new List<Doc>(), options);
}
+ /**
+ * Creates a Doc to edit a script and write the compiled script into the specified field.
+ * Typically, this would be used to create a template that can then be applied to some other Doc
+ * in order to customize a behavior, such as onClick.
+ * @param script
+ * @param options
+ * @param fieldKey the field that the compiled script is written into.
+ * @returns the Scripting Doc
+ */
export function ScriptingDocument(script: Opt<ScriptField> | null, options: DocumentOptions = {}, fieldKey?: string) {
return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script ? script : undefined, { ...options, layout: fieldKey ? ScriptingBox.LayoutString(fieldKey) : undefined });
}
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index cfba003fc..564a46514 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -105,9 +105,12 @@ export class CurrentUserUtils {
{ opts: { title: "onCheckedClick"}, script: "console.log(heading, checked, containingTreeView)"},
];
const reqdClickList = reqdTempOpts.map(opts => {
+ const title = opts.opts.title?.toString();
const allOpts = {...reqdClickOpts, ...opts.opts};
- const clickDoc = tempClicks ? DocListCast(tempClicks.data).find(doc => doc.title === opts.opts.title): undefined;
- return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title?.toString());
+ const clickDoc = tempClicks ? DocListCast(tempClicks.data).find(doc => doc.title === title): undefined;
+ const script = ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name});
+ const scriptDoc = Docs.Create.ScriptingDocument(script, allOpts, title)
+ return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(scriptDoc);
});
const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, isSystem: true};
@@ -118,13 +121,13 @@ export class CurrentUserUtils {
static setupNoteTemplates(doc: Doc, field="template_notes") {
const tempNotes = DocCast(doc[field]);
const reqdTempOpts:DocumentOptions[] = [
- { noteType: "Postit", backgroundColor: "yellow", icon: "sticky-note"},
- { noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" },
- { noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
+ { title: "Postit", backgroundColor: "yellow", icon: "sticky-note"},
+ { title: "Idea", backgroundColor: "pink", icon: "lightbulb" },
+ { title: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
const reqdNoteList = reqdTempOpts.map(opts => {
- const reqdOpts = {...opts, isSystem:true, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
- const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined;
- return DocUtils.AssignOpts(noteType, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts), true, opts.noteType??"Note");
+ const reqdOpts = {...opts, isSystem:true, width:200, layout_autoHeight: true, layout_fitWidth: true};
+ const noteTemp = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.title === opts.title): undefined;
+ return DocUtils.AssignOpts(noteTemp, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts));
});
const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true };
@@ -149,16 +152,16 @@ export class CurrentUserUtils {
const templateIconsDoc = DocUtils.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts));
const makeIconTemplate = (type: DocumentType | undefined, templateField: string, opts:DocumentOptions) => {
- const iconFieldName = "icon" + (type ? "_" + type : "");
- const curIcon = DocCast(templateIconsDoc[iconFieldName]);
+ const title = "icon" + (type ? "_" + type : "");
+ const curIcon = DocCast(templateIconsDoc[title]);
let creator = labelBox;
switch (opts.iconTemplate) {
case DocumentType.IMG : creator = imageBox; break;
case DocumentType.FONTICON: creator = fontBox; break;
}
- const allopts = {isSystem: true, onClickScriptDisable: "never", ...opts};
+ const allopts = {isSystem: true, onClickScriptDisable: "never", ...opts, title};
return DocUtils.AssignScripts( (curIcon?.iconTemplate === opts.iconTemplate ?
- DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[iconFieldName] = MakeTemplate(creator(allopts, templateField), true, iconFieldName, templateField))),
+ DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[title] = MakeTemplate(creator(allopts, templateField)))),
{onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", });
};
const labelBox = (opts: DocumentOptions, fieldKey:string) => Docs.Create.LabelDocument({
@@ -211,7 +214,7 @@ export class CurrentUserUtils {
};
const headerBtnHgt = 10;
const headerTemplate = (opts:DocumentOptions) => {
- const header = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "text",
+ const header = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "Untitled Header",
layout:
"<HTMLdiv transformOrigin='top left' width='{100/scale}%' height='{100/scale}%' transform='scale({scale})'>" +
` <FormattedTextBox {...props} dontScale='true' fieldKey={'text'} height='calc(100% - ${headerBtnHgt}px - {this._headerHeight||0}px)'/>` +
@@ -224,7 +227,7 @@ export class CurrentUserUtils {
// " <FormattedTextBox {...props} fieldKey={'header'} dontSelectOnLoad={'true'} ignoreAutoHeight={'true'} pointerEvents='{this._headerPointerEvents||`none`}' fontSize='{this._headerFontSize}px' height='{this._headerHeight}px' background='{this._headerColor||this.target.mySharedDocs.userColor}' />" +
// " <FormattedTextBox {...props} fieldKey={'text'} position='absolute' top='{(this._headerHeight)*scale}px' height='calc({100/scale}% - {this._headerHeight}px)'/>" +
// "</div>";
- MakeTemplate(Doc.GetProto(header), true, "Untitled Header");
+ MakeTemplate(Doc.GetProto(header));
return header;
}
const slideView = (opts:DocumentOptions) => {
@@ -232,9 +235,9 @@ export class CurrentUserUtils {
[
Docs.Create.MulticolumnDocument([], { title: "hero", _height: 200, isSystem: true }),
Docs.Create.TextDocument("", { title: "text", _layout_fitWidth:true, _height: 100, isSystem: true, _text_fontFamily: StrCast(Doc.UserDoc().fontFamily), _text_fontSize: StrCast(Doc.UserDoc().fontSize) })
- ], opts);
+ ], {...opts, title: "Untitled Slide View"});
- MakeTemplate(Doc.GetProto(slide), true, "Untitled Slide View");
+ MakeTemplate(Doc.GetProto(slide));
return slide;
}
const plotlyApi = () => {
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index ba981145d..3df3e36c6 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -12,43 +12,55 @@ import { ButtonType, FontIconBox } from '../views/nodes/FontIconBox/FontIconBox'
import { DragManager } from './DragManager';
import { ScriptingGlobals } from './ScriptingGlobals';
-export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt<string> = undefined, templateField: string = '') {
- if (templateField) doc[DocData].title = templateField; /// the title determines which field is being templated
- doc.isTemplateDoc = makeTemplate(doc, first, rename);
+/**
+ * Converts a Doc to a render template that can be applied to other Docs to customize how they render while
+ * still using the other Doc as the backing data store (ie, dataDoc). During rendering, if a layout Doc is provided
+ * with 'isTemplateDoc' set, then the layout Doc is treated as a template for the rendered Doc. The template Doc is
+ * "expanded" to create an template instance for the rendered Doc.
+ *
+ *
+ * @param doc the doc to convert to a template
+ * @returns 'doc'
+ */
+export function MakeTemplate(doc: Doc) {
+ doc.isTemplateDoc = makeTemplate(doc, true);
return doc;
}
-//
-// converts 'doc' into a template that can be used to render other documents.
-// the title of doc is used to determine which field is being templated, so
-// passing a value for 'rename' allows the doc to be given a meangingful name
-// after it has been converted to
-function makeTemplate(doc: Doc, first: boolean = true, rename: Opt<string> = undefined): boolean {
+
+/**
+ * Recursively converts 'doc' into a template that can be used to render other documents.
+ *
+ * For recurive Docs in the template, their target fieldKey is defined by their title,
+ * not by whatever fieldKey they used in their layout.
+ * @param doc
+ * @param first whether this is the topmost root of the recursive template
+ * @returns whether a template was successfully created
+ */
+function makeTemplate(doc: Doc, first: boolean = true): boolean {
const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
if (layoutDoc.layout instanceof Doc) {
- // its already a template
- return true;
+ return true; // its already a template
}
const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)![0];
const fieldKey = layout.replace("fieldKey={'", '').replace(/'}$/, '');
const docs = DocListCast(layoutDoc[fieldKey]);
- let any = false;
+ let isTemplate = false;
docs.forEach(d => {
if (!StrCast(d.title).startsWith('-')) {
- any = Doc.MakeMetadataFieldTemplate(d, layoutDoc[DocData]) || any;
+ isTemplate = Doc.MakeMetadataFieldTemplate(d, layoutDoc[DocData]) || isTemplate;
} else if (d.type === DocumentType.COL || d.data instanceof RichTextField) {
- any = makeTemplate(d, false) || any;
+ isTemplate = makeTemplate(d, false) || isTemplate;
}
});
if (first && !docs.length) {
// bcz: feels hacky : if the root level document has items, it's not a field template
- any = Doc.MakeMetadataFieldTemplate(doc, layoutDoc[DocData], true) || any;
+ isTemplate = Doc.MakeMetadataFieldTemplate(doc, layoutDoc[DocData], true) || isTemplate;
} else if (layoutDoc[fieldKey] instanceof RichTextField || layoutDoc[fieldKey] instanceof ImageField) {
if (!StrCast(layoutDoc.title).startsWith('-')) {
- any = Doc.MakeMetadataFieldTemplate(layoutDoc, layoutDoc[DocData], true);
+ isTemplate = Doc.MakeMetadataFieldTemplate(layoutDoc, layoutDoc[DocData], true);
}
}
- rename && (doc.title = rename);
- return any;
+ return isTemplate;
}
export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
data?.draggedDocuments.map((doc, i) => {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 285a789e6..0c0e49411 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -631,7 +631,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
}
return (
<div>
- {!docs?.length || this._props.AddToMap /* hack to identify pres box trees */ ? null : (
+ {!docs?.length || this.treeView.outlineMode || this._props.AddToMap /* hack to identify pres box trees */ ? null : (
<div className="treeView-sorting">
<IconButton
color={sortings[sorting]?.color}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 4a1a51558..54e3e7b44 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -940,9 +940,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
description: 'Make Default Layout',
event: () => {
if (!this.layoutDoc.isTemplateDoc) {
- const title = StrCast(this.Document.title);
- this.Document.title = 'text';
- MakeTemplate(this.Document, true, title);
+ MakeTemplate(this.Document);
}
Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.Document);
Doc.AddDocToList(Cast(Doc.UserDoc().template_notes, Doc, null), 'data', this.Document);