aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSam Wilkins <35748010+samwilkins333@users.noreply.github.com>2020-01-21 19:03:22 -0500
committerGitHub <noreply@github.com>2020-01-21 19:03:22 -0500
commit6042b43ea190006ebe7f51bef7b9ae6d0770b233 (patch)
tree3a52edc8083a472e3c74fb4b6ad63d8d13ce76ba /src
parent7fffe13954ed0113bf1b2f9318518d015dc63844 (diff)
parent8a4a8212b024e2804596a08ea820be646c9a7c0f (diff)
Merge pull request #332 from browngraphicslab/facet_refactor
Facet refactor
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts1
-rw-r--r--src/client/views/collections/CollectionPivotView.tsx44
-rw-r--r--src/client/views/collections/CollectionSubView.tsx10
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx9
-rw-r--r--src/new_fields/Doc.ts45
-rw-r--r--src/new_fields/ScriptField.ts13
6 files changed, 85 insertions, 37 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 91085cd0f..d7292837c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -788,7 +788,6 @@ export namespace DocUtils {
});
}
- @undoBatch
export function MakeLink(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, title: string = "", description: string = "", id?: string) {
const sv = DocumentManager.Instance.getDocumentView(source.doc);
if (sv && sv.props.ContainingCollectionDoc === target.doc) return;
diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx
index 816939a41..f31f1aba6 100644
--- a/src/client/views/collections/CollectionPivotView.tsx
+++ b/src/client/views/collections/CollectionPivotView.tsx
@@ -9,8 +9,8 @@ import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormV
import { CollectionTreeView } from "./CollectionTreeView";
import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
import { Docs } from "../../documents/Documents";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { CompileScript } from "../../util/Scripting";
+import { ScriptField, ComputedField } from "../../../new_fields/ScriptField";
+import { CompileScript, Scripting } from "../../util/Scripting";
import { anchorPoints, Flyout } from "../TemplateMenu";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { List } from "../../../new_fields/List";
@@ -25,7 +25,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) {
}
componentDidMount() {
this.props.Document.freeformLayoutEngine = "pivot";
- if (true || !this.props.Document.facetCollection) {
+ if (!this.props.Document.facetCollection) {
const facetCollection = Docs.Create.FreeformDocument([], { title: "facetFilters", yMargin: 0, treeViewHideTitle: true });
facetCollection.target = this.props.Document;
@@ -38,14 +38,12 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) {
if (script.compiled) {
facetCollection.onCheckedClick = new ScriptField(script);
}
-
this._narrativeDisposer = reaction(() => this.props.Document.childDetailed,
(childDetailed) =>
DocCastAsync(childDetailed).then(childDetailed => {
if (childDetailed instanceof Doc) {
- const targetKey = "childDetailed";
const captured: { [name: string]: Field } = {};
- captured[targetKey] = new PrefetchProxy(childDetailed);
+ captured.childDetailed = new PrefetchProxy(childDetailed);
const openDocText = "const alias = getAlias(this); Doc.ApplyTemplateTo(childDetailed, alias, 'layout_detailed'); useRightSplit(alias); ";
const openDocScript = CompileScript(openDocText, {
params: { this: Doc.name, heading: "boolean", context: Doc.name },
@@ -76,23 +74,35 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) {
return facets.toArray();
}
- facetClick = (facet: string) => {
- const facetCollection = this.props.Document.facetCollection;
+ /**
+ * Responds to clicking the check box in the flyout menu
+ */
+ facetClick = (facetHeader: string) => {
+ const { Document, fieldKey } = this.props;
+ const facetCollection = Document.facetCollection;
if (facetCollection instanceof Doc) {
- const found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facet);
+ const found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facetHeader);
if (found !== -1) {
//Doc.RemoveDocFromList(facetCollection, "data", DocListCast(facetCollection.data)[found]);
(facetCollection.data as List<Doc>).splice(found, 1);
} else {
- const facetValues = new Set<string>();
- this.childDocs.forEach(child => {
- Object.keys(Doc.GetProto(child)).forEach(key => child[key] instanceof Doc && facetValues.add((child[key] as Doc)[facet]?.toString() || "(null)"));
- facetValues.add(child[facet]?.toString() || "(null)");
- });
-
- const newFacetVals = facetValues.toArray().sort().map(val => Docs.Create.TextDocument({ title: val.toString() }));
- const newFacet = Docs.Create.FreeformDocument(newFacetVals, { title: facet, treeViewOpen: true, isFacetFilter: true });
+ const newFacet = Docs.Create.FreeformDocument([], { title: facetHeader, treeViewOpen: true, isFacetFilter: true });
Doc.AddDocToList(facetCollection, "data", newFacet);
+ const { dataDoc } = this;
+ const capturedVariables = {
+ layoutDoc: Document,
+ dataDoc,
+ dataKey: fieldKey,
+ facetHeader
+ };
+ const params = {
+ layoutDoc: Doc.name,
+ dataDoc: Doc.name,
+ dataKey: "string",
+ facetHeader: "string"
+ };
+ newFacet.container = dataDoc;
+ newFacet.data = ComputedField.MakeFunction("readFacetData(layoutDoc, dataDoc, dataKey, facetHeader)", params, capturedVariables);
}
}
}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5f4ee3669..9357b0507 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -90,7 +90,15 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
// to its children which may be templates.
// If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey'
@computed get dataField() {
- return this.props.annotationsKey ? (this.extensionDoc ? this.extensionDoc[this.props.annotationsKey] : undefined) : this.dataDoc[this.props.fieldKey];
+ const { annotationsKey, fieldKey } = this.props;
+ const { extensionDoc, dataDoc } = this;
+ if (annotationsKey) {
+ if (extensionDoc) {
+ return extensionDoc[annotationsKey];
+ }
+ return undefined;
+ }
+ return dataDoc[fieldKey];
}
get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4a6dffc1c..ffaad2ddd 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -373,12 +373,12 @@ class TreeView extends React.Component<TreeViewProps> {
@action
bulletClick = (e: React.MouseEvent) => {
if (this.props.onCheckedClick && this.props.document.type !== DocumentType.COL) {
- this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check";
+ // this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check";
ScriptCast(this.props.onCheckedClick).script.run({
this: this.props.document.isTemplateField && this.props.dataDoc ? this.props.dataDoc : this.props.document,
heading: this.props.containingCollection.title,
- checked: this.props.document.treeViewChecked === "check" ? false : this.props.document.treeViewChecked === "x" ? "x" : "none",
- context: this.props.treeViewId
+ checked: this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check",
+ context: this.props.treeViewId,
}, console.log);
} else {
this.treeViewOpen = !this.treeViewOpen;
@@ -634,12 +634,11 @@ export class CollectionTreeView extends CollectionSubView(Document) {
}
ContextMenu.Instance.addItem({
description: "Buxton Layout", icon: "eye", event: () => {
- const { TextDocument, ImageDocument, MulticolumnDocument } = Docs.Create;
+ const { TextDocument, ImageDocument } = Docs.Create;
const { Document } = this.props;
const fallback = "http://www.cs.brown.edu/~bcz/face.gif";
const wrapper = Docs.Create.StackingDocument([
ImageDocument(fallback, { title: "hero" }),
- MulticolumnDocument([], { title: "data", height: 100 }),
...["short_description", "year", "company", "degrees_of_freedom"].map(key => TextDocument({ title: key }))
], { autoHeight: true, chromeStatus: "disabled" });
wrapper.disableLOD = true;
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 6b0ec3fd3..48ff431bc 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -1,4 +1,4 @@
-import { observable, ObservableMap, runInAction, action, untracked } from "mobx";
+import { observable, ObservableMap, runInAction } from "mobx";
import { alias, map, serializable } from "serializr";
import { DocServer } from "../client/DocServer";
import { DocumentType } from "../client/documents/DocumentTypes";
@@ -11,11 +11,12 @@ import { PrefetchProxy, ProxyField } from "./Proxy";
import { FieldId, RefField } from "./RefField";
import { listSpec } from "./Schema";
import { ComputedField, ScriptField } from "./ScriptField";
-import { BoolCast, Cast, FieldValue, NumCast, PromiseValue, StrCast, ToConstructor } from "./Types";
+import { BoolCast, Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types";
import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util";
import { intersectRect } from "../Utils";
import { UndoManager } from "../client/util/UndoManager";
import { computedFn } from "mobx-utils";
+import { Docs } from "../client/documents/Documents";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -809,16 +810,15 @@ Scripting.addGlobal(function matchFieldValue(doc: Doc, key: string, value: any)
}
return false;
});
-Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers: string) {
+Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: string) {
const docFilters = Cast(container.docFilter, listSpec("string"), []);
- let found = false;
- for (let i = 0; i < docFilters.length && !found; i += 3) {
+ for (let i = 0; i < docFilters.length; i += 3) {
if (docFilters[i] === key && docFilters[i + 1] === value) {
- found = true;
docFilters.splice(i, 3);
+ break;
}
}
- if (!found || modifiers !== "none") {
+ if (modifiers !== undefined) {
docFilters.push(key);
docFilters.push(value);
docFilters.push(modifiers);
@@ -826,4 +826,35 @@ Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: an
}
const docFilterText = Doc.MakeDocFilter(docFilters);
container.viewSpecScript = docFilterText ? ScriptField.MakeFunction(docFilterText, { doc: Doc.name }) : undefined;
+});
+
+Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey: string, facetHeader: string) {
+ const facetValues = new Set<string>();
+ DocListCast(dataDoc[dataKey]).forEach(child => {
+ Object.keys(Doc.GetProto(child)).forEach(key => child[key] instanceof Doc && facetValues.add((child[key] as Doc)[facetHeader]?.toString() || "(null)"));
+ facetValues.add(child[facetHeader]?.toString() || "(null)");
+ });
+ const text = "determineCheckedState(layoutDoc, facetHeader, facetValue)";
+ const params = {
+ layoutDoc: Doc.name,
+ facetHeader: "string",
+ facetValue: "string"
+ };
+ const capturedVariables = { layoutDoc, facetHeader };
+ return new List<Doc>(Array.from(facetValues).sort().map(facetValue => {
+ const value = Docs.Create.TextDocument({ title: facetValue.toString() });
+ value.treeViewChecked = ComputedField.MakeFunction(text, params, { ...capturedVariables, facetValue });
+ return value;
+ }));
+});
+
+Scripting.addGlobal(function determineCheckedState(layoutDoc: Doc, facetHeader: string, facetValue: string) {
+ const docFilters = Cast(layoutDoc.docFilter, listSpec("string"), []);
+ for (let i = 0; i < docFilters.length; i += 3) {
+ const [header, value, state] = docFilters.slice(i, i + 3);
+ if (header === facetHeader && value === facetValue) {
+ return state;
+ }
+ }
+ return undefined;
}); \ No newline at end of file
diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts
index 09a18c258..f8a8d1226 100644
--- a/src/new_fields/ScriptField.ts
+++ b/src/new_fields/ScriptField.ts
@@ -3,7 +3,7 @@ import { CompiledScript, CompileScript, scriptingGlobal, ScriptOptions } from ".
import { Copy, ToScriptString, ToString, Parent, SelfProxy } from "./FieldSymbols";
import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr";
import { Deserializable, autoObject } from "../client/util/SerializationHelper";
-import { Doc } from "../new_fields/Doc";
+import { Doc, Field } from "../new_fields/Doc";
import { Plugins } from "./util";
import { computedFn } from "mobx-utils";
import { ProxyField } from "./Proxy";
@@ -104,12 +104,13 @@ export class ScriptField extends ObjectField {
[ToString]() {
return "script field";
}
- public static CompileScript(script: string, params: object = {}, addReturn = false) {
+ public static CompileScript(script: string, params: object = {}, addReturn = false, capturedVariables?: { [name: string]: Field }) {
const compiled = CompileScript(script, {
params: { this: Doc.name, _last_: "any", ...params },
typecheck: false,
editable: true,
- addReturn: addReturn
+ addReturn: addReturn,
+ capturedVariables
});
return compiled;
}
@@ -130,12 +131,12 @@ export class ComputedField extends ScriptField {
_lastComputedResult: any;
//TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc
value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, _last_: this._lastComputedResult }, console.log).result);
- public static MakeScript(script: string, params: object = {}, ) {
+ public static MakeScript(script: string, params: object = {}) {
const compiled = ScriptField.CompileScript(script, params, false);
return compiled.compiled ? new ComputedField(compiled) : undefined;
}
- public static MakeFunction(script: string, params: object = {}) {
- const compiled = ScriptField.CompileScript(script, params, true);
+ public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) {
+ const compiled = ScriptField.CompileScript(script, params, true, capturedVariables);
return compiled.compiled ? new ComputedField(compiled) : undefined;
}
}