aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbob <bcz@cs.brown.edu>2020-02-27 15:10:14 -0500
committerbob <bcz@cs.brown.edu>2020-02-27 15:10:14 -0500
commit3c48667061fb417e3a7657a1951659d25b453a9f (patch)
tree2b837158110ee415e3242ddb990df26d2618a106 /src
parenta2974e187f6a279def7bd44c475a40aee0ac8286 (diff)
streamlined setting enumerations for fields in text boxes.
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts8
-rw-r--r--src/client/util/RichTextSchema.tsx47
-rw-r--r--src/client/views/collections/CollectionTimeView.scss4
-rw-r--r--src/new_fields/Doc.ts32
-rw-r--r--src/server/authentication/models/current_user_utils.ts15
5 files changed, 73 insertions, 33 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 6d5fd5677..a0b8a6382 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -622,12 +622,12 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List(schemaColumns), ...options, _viewType: CollectionViewType.Schema });
}
- export function TreeDocument(documents: Array<Doc>, options: DocumentOptions) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Tree });
+ export function TreeDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Tree }, id);
}
- export function StackingDocument(documents: Array<Doc>, options: DocumentOptions) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Stacking });
+ export function StackingDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Stacking }, id);
}
export function MulticolumnDocument(documents: Array<Doc>, options: DocumentOptions) {
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index cc6b035d7..a56aac9b1 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -22,6 +22,10 @@ import ParagraphNodeSpec from "./ParagraphNodeSpec";
import { Transform } from "./Transform";
import React = require("react");
import { CollectionSchemaBooleanCell } from "../views/collections/CollectionSchemaCells";
+import { ContextMenu } from "../views/ContextMenu";
+import { ContextMenuProps } from "../views/ContextMenuItem";
+import { Docs } from "../documents/Documents";
+import { CollectionView } from "../views/collections/CollectionView";
const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -863,23 +867,13 @@ export class DashFieldView {
constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
this._fieldKey = node.attrs.fieldKey;
this._textBoxDoc = tbox.props.Document;
- this._options = DocListCast(tbox.props.Document[node.attrs.fieldKey + "_options"]);
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-block";
- const onchanged = (e: any) => {
- this._reactionDisposer?.();
- let newText = this._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : this._fieldSpan.innerText;
- this._options?.forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title)));
- this._dashDoc![this._fieldKey] = newText;
- if (newText.startsWith(":=") && this._dashDoc && e.data === null && !e.inputType.includes("delete")) {
- Doc.Layout(tbox.props.Document)[this._fieldKey] = ComputedField.MakeFunction(this._fieldSpan.innerText.substring(2));
- }
- }
-
+ const self = this;
this._fieldSpan = document.createElement("div");
this._fieldSpan.id = Utils.GenerateGuid();
this._fieldSpan.contentEditable = "true";
@@ -887,12 +881,18 @@ export class DashFieldView {
this._fieldSpan.style.display = "inline-block";
this._fieldSpan.style.minWidth = "50px";
this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)";
- this._fieldSpan.addEventListener("input", onchanged);
this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); };
this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); };
this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); };
+ this._fieldSpan.oncontextmenu = function (e: any) {
+ ContextMenu.Instance.addItem({
+ description: "Show Enumeration Templates", event: () => {
+ e.stopPropagation();
+ DocServer.GetRefField(node.attrs.fieldKey).then(collview => collview instanceof Doc && tbox.props.addDocTab(collview, "onRight"));
+ }, icon: "expand-arrows-alt"
+ });
+ };
- const self = this;
const setDashDoc = (doc: Doc) => {
self._dashDoc = doc;
if (this._dashDoc && self._options?.length && !this._dashDoc[node.attrs.fieldKey]) {
@@ -910,6 +910,25 @@ export class DashFieldView {
}
e.preventDefault();
}
+ if (e.key === "Enter" && e.ctrlKey) {
+ Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]);
+ e.preventDefault();
+ } else if (e.key === "Enter") {
+ e.preventDefault();
+ let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText;
+ // look for a document whose id === the fieldKey being displayed. If there's a match, then that document
+ // holds the different enumerated values for the field in the titles of its collected documents.
+ // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down.
+
+ // alternatively, if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key
+ DocServer.GetRefField(node.attrs.fieldKey).then(options => {
+ (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title)));
+ self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText;
+ if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) {
+ Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2));
+ }
+ });
+ }
};
this._labelSpan = document.createElement("span");
@@ -924,7 +943,7 @@ export class DashFieldView {
setDashDoc(tbox.props.DataDoc || tbox.dataDoc);
}
this._reactionDisposer?.();
- this._reactionDisposer = reaction(() => {
+ this._reactionDisposer = reaction(() => { // this reaction will update the displayed text whenever the document's fieldKey's value changes
const dashVal = this._dashDoc?.[node.attrs.fieldKey];
return StrCast(dashVal).startsWith(":=") || !dashVal ? Doc.Layout(tbox.props.Document)[this._fieldKey] : dashVal;
}, fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)", { fireImmediately: true });
diff --git a/src/client/views/collections/CollectionTimeView.scss b/src/client/views/collections/CollectionTimeView.scss
index 6ea5e6908..865fc3cd2 100644
--- a/src/client/views/collections/CollectionTimeView.scss
+++ b/src/client/views/collections/CollectionTimeView.scss
@@ -10,7 +10,6 @@
.collectionTimeView-backBtn {
background: green;
display: inline;
- margin-right: 20px;
}
.collectionFreeform-customText {
@@ -68,6 +67,9 @@
padding: 5px;
border: 1px solid black;
display:none;
+ span {
+ margin-left : 10px;
+ }
}
.collectionTimeView-treeView {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 8e28a1e00..8ea347ec3 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -17,6 +17,7 @@ import { listSpec } from "./Schema";
import { ComputedField } from "./ScriptField";
import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types";
import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util";
+import { Docs } from "../client/documents/Documents";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -571,7 +572,7 @@ export namespace Doc {
export function ApplyTemplate(templateDoc: Doc) {
if (templateDoc) {
const applied = ApplyTemplateTo(templateDoc, Doc.MakeDelegate(new Doc()), "layout", templateDoc.title + "(..." + _applyCount++ + ")");
- applied && (Doc.GetProto(applied).layout = applied.layout);
+ applied && (Doc.GetProto(applied).type = templateDoc.type);
return applied;
}
return undefined;
@@ -843,14 +844,31 @@ export namespace Doc {
return id;
}
- export function enumeratedTextTemplate(doc: Doc, layoutString: string, captionKey: string, optionKey: string, modes: Doc[]) {
- doc.caption = RichTextField.DashField(optionKey);
+ // setup a document to use enumerated values for a specified field name:
+ // doc: text document
+ // layoutString: species which text field receives the document's main text (e.g., FormattedTextBox.LayoutString("Todo") )
+ // enumeratedFieldKey : specifies which enumerated field of the document is displayed in the caption (e.g., taskStatus)
+ // captionKey: specifies which field holds the caption template (e.g., caption) -- ideally this wouldn't be needed but would be derived from the layoutString's target field key
+ //
+ export function enumeratedTextTemplate(doc: Doc, layoutString: string, enumeratedFieldKey: string, enumeratedDocs: Doc[], captionKey: string = "caption") {
+ doc.caption = RichTextField.DashField(enumeratedFieldKey);
doc._showCaption = captionKey;
doc.layout = layoutString;
- const optionsField = `${optionKey}_options`;
- doc[optionsField] = new List<Doc>(modes);
- doc.backgroundColor = ComputedField.MakeFunction(`this['${optionsField}'].find(doc => doc.title === this.expandedTemplate.${optionKey})?._backgroundColor || "white"`);
- doc.color = ComputedField.MakeFunction(`this['${optionsField}'].find(doc => doc.title === this.expandedTemplate.${optionKey}).color || "black"`);
+
+ Doc.addEnumerationToTextField(doc, enumeratedFieldKey, enumeratedDocs);
+ }
+
+ export function addEnumerationToTextField(doc: Doc, enumeratedFieldKey: string, enumeratedDocs: Doc[]) {
+ DocServer.GetRefField(enumeratedFieldKey).then(optionsCollection => {
+ if (!(optionsCollection instanceof Doc)) {
+ optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey);
+ Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc);
+ }
+ const options = optionsCollection as Doc;
+ doc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options });
+ doc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options });
+ enumeratedDocs.map(enumeratedDoc => !DocListCast(options.data).find(d => d.title === enumeratedDoc.title) && Doc.AddDocToList(options, "data", enumeratedDoc));
+ });
}
}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 36259f513..ea19d9da8 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -36,6 +36,11 @@ export class CurrentUserUtils {
@observable public static GuestMobile: Doc | undefined;
static setupDefaultDocTemplates(doc: Doc, buttons?: string[]) {
+ const taskStatusValues = [
+ Docs.Create.TextDocument("todo", { title: "todo", _backgroundColor: "blue", color: "white" }),
+ Docs.Create.TextDocument("in progress", { title: "in progress", _backgroundColor: "yellow", color: "black" }),
+ Docs.Create.TextDocument("completed", { title: "completed", _backgroundColor: "green", color: "white" })
+ ];
const noteTemplates = [
Docs.Create.TextDocument("", { title: "Note", backgroundColor: "yellow" }),
Docs.Create.TextDocument("", { title: "Idea", backgroundColor: "pink" }),
@@ -43,12 +48,8 @@ export class CurrentUserUtils {
Docs.Create.TextDocument("", { title: "Person", backgroundColor: "lightGreen" }),
Docs.Create.TextDocument("", { title: "Todo", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption" })
];
- const modes = [
- Docs.Create.TextDocument("", { title: "todo", _backgroundColor: "blue", color: "white" }),
- Docs.Create.TextDocument("", { title: "in progress", _backgroundColor: "yellow", color: "black" }),
- Docs.Create.TextDocument("", { title: "completed", _backgroundColor: "green", color: "white" })
- ]
- Doc.enumeratedTextTemplate(Doc.GetProto(noteTemplates[4]), FormattedTextBox.LayoutString("Todo"), "caption", "taskStatus", modes);
+ doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
+ Doc.enumeratedTextTemplate(Doc.GetProto(noteTemplates[4]), FormattedTextBox.LayoutString("Todo"), "taskStatus", taskStatusValues);
doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt) ? nt : nt), { title: "Note Types", _height: 75 }));
}
@@ -196,7 +197,7 @@ export class CurrentUserUtils {
return Docs.Create.ButtonDocument({
_width: 50, _height: 25, title: "Library", fontSize: 10,
letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc.recentlyClosed as Doc], {
+ sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], {
title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, dropAction: "alias", lockedPosition: true, boxShadow: "0 0",
}),
targetContainer: sidebarContainer,