aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts')
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
new file mode 100644
index 000000000..fd87ae973
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
@@ -0,0 +1,220 @@
+import { makeAutoObservable } from 'mobx';
+import { Col } from './DocCreatorMenu';
+import { TemplateFieldType, TemplateLayouts } from './TemplateBackend';
+import { DynamicField } from './TemplateFieldTypes/DynamicField';
+import { FieldSettings, TemplateField, ViewType } from './TemplateFieldTypes/TemplateField';
+import { Conditional } from './Backend/TemplateManager';
+import { ImageField } from '../../../../../fields/URLField';
+import { Doc } from '../../../../../fields/Doc';
+import { TemplateDataField } from './TemplateFieldTypes/DataField';
+
+export class Template {
+ _mainField: DynamicField;
+
+ private dataFields: TemplateDataField[] = [];
+
+ /**
+ * A Template can be created from a description of its fields (FieldSettings) or from a DynamicField
+ * @param definition definition of template as settings or DynamicField
+ */
+ constructor(definition: FieldSettings | DynamicField) {
+ makeAutoObservable(this);
+ this._mainField = definition instanceof DynamicField ? definition : this.setupMainField(definition);
+ }
+
+ get childFields(): TemplateField[] {
+ return this._mainField?.getSubfields ?? [];
+ }
+ get allFields(): TemplateField[] {
+ return this._mainField?.getAllSubfields ?? [];
+ }
+ get contentFields(): TemplateField[] {
+ return this.allFields.filter(field => field.isContentField);
+ }
+ get doc() {
+ return this._mainField?.renderedDoc;
+ }
+ get title() {
+ return this._mainField?.getTitle();
+ }
+
+ get descriptionSummary(): string {
+ let summary: string = '';
+ this.contentFields.forEach(field => {
+ summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getDescription ?? ''} ---`;
+ });
+ return summary;
+ }
+
+ get compiledContent(): string {
+ let summary: string = '';
+ this.contentFields.forEach(field => {
+ summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getContent() ?? ''} ---`;
+ });
+ return summary;
+ }
+
+ cleanup = () => {
+ //dispose each subfields disposers, etc.
+ };
+
+ clone = (withContent: boolean = false) => {
+ const clone = new Template(this._mainField?.makeClone(undefined, withContent) ?? TemplateLayouts.BasicSettings);
+ this.dataFields.forEach(field => clone.addDataField(field.title));
+ return clone;
+ };
+
+ getRenderedDoc = () => this.doc;
+
+ getFieldByID = (id: number): TemplateField => this.allFields.filter(field => field.getID === id)[0];
+
+ getFieldByTitle = (title: string) => [...this.allFields, ...this.dataFields].filter(field => field.getTitle() === title)[0];
+
+ setupMainField = (templateInfo: FieldSettings) => TemplateField.CreateField(templateInfo, 1, undefined) as DynamicField;
+
+ printFieldInfo = () => {
+ this.allFields.forEach(field => {
+ const doc = field.renderedDoc;
+ });
+ };
+
+ assignColToField = (fieldID: number, col: Col) => {
+ const field = this.getFieldByID(fieldID);
+ field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
+ field.setTitle(col.title);
+ }
+
+ addDataField = (title: string, content?: string) => {
+ this.dataFields.push(new TemplateDataField(title, content));
+ }
+
+ removeDataField = (title: string) => {
+ this.dataFields = this.dataFields.filter(field => !(field.title === title));
+ }
+
+ isValidTemplate = (cols: Col[]) => {
+ const maxMatches = this.maxMatches(this.getMatches(cols));
+ return maxMatches === this.contentFields.length && this.title !== 'template_framework';
+ };
+
+ applyConditionalLogicToField = (field: TemplateField | TemplateDataField, logic: Record<string, Conditional[]>) => {
+ if (field instanceof DynamicField) return;
+ const fieldStatements: Conditional[] = logic[field.getTitle()];
+ const content = field.getContent()
+ fieldStatements && fieldStatements.forEach(statement => {
+ console.log(statement);
+ if (content === statement.condition) {
+ if (statement.target === 'Template') {
+ this._mainField.renderedDoc![statement.attribute] = statement.value;
+ Object.assign(this._mainField.settings.opts, {[statement.attribute]: statement.value});
+ } else {
+ const targetField: TemplateField = this.getFieldByTitle(statement.target) as TemplateField;
+ if (targetField) {
+ targetField.renderedDoc![statement.attribute] = statement.value;
+ Object.assign(targetField.settings.opts, {[statement.attribute]: statement.value});
+ }
+ }
+ }
+ })
+ }
+
+ applyConditionalLogic = (logic: Record<string, Conditional[]>) => {
+ const fields: (TemplateField | TemplateDataField)[] = [...this.allFields, ...this.dataFields];
+ fields.forEach(field => this.applyConditionalLogicToField(field, logic));
+ }
+
+ setImageAsBackground(url: string, makeTransparent: boolean = false) {
+ const fieldSettings: FieldSettings = {
+ tl: [-1, -1],
+ br: [1, 1],
+ opts: {},
+ viewType: ViewType.IMG,
+ }
+
+ const field: TemplateField = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
+ field.setContent(url);
+
+ if (makeTransparent) {
+ this.allFields.forEach(field => {
+ field.updateDocSetting('backgroundColor', 'transparent');
+ field.updateDocSetting('borderWidth', '0');
+ });
+ }
+
+ this._mainField.makeBackgroundField(field);
+ }
+
+ /**
+ * This function is just a hack for now to get around weird document icon stuff (specifically it misses the background)
+ */
+ setMatteBackground(makeTransparent: boolean = false) {
+ if (this._mainField.hasBackground) {
+ return;
+ }
+
+ const fieldSettings: FieldSettings = {
+ tl: [-1, -1],
+ br: [1, 1],
+ opts: {backgroundColor: String(this._mainField.renderedDoc!.backgroundColor)},
+ viewType: ViewType.TEXT,
+ }
+
+ const field: TemplateField = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
+
+ if (makeTransparent) {
+ this.allFields.forEach(field => {
+ field.updateDocSetting('backgroundColor', 'transparent');
+ field.updateDocSetting('borderWidth', '0');
+ });
+ }
+
+ this._mainField.makeBackgroundField(field);
+ }
+
+ getMatches = (cols: Col[]): number[][] => {
+ const numFields = this.contentFields.length;
+
+ if (cols.length !== numFields) return [];
+
+ const matches: number[][] = Array(numFields)
+ .fill([])
+ .map(() => []);
+
+ this.contentFields.forEach((field, i) => (matches[i] = field.matches(cols)));
+
+ return matches;
+ };
+
+ maxMatches = (matches: number[][]) => {
+ if (matches.length === 0) return 0;
+
+ const fieldsCt = this.contentFields.length;
+ const used: boolean[] = Array(fieldsCt).fill(false);
+ const mt: number[] = Array(fieldsCt).fill(-1);
+
+ const augmentingPath = (v: number): boolean => {
+ if (!used[v]) {
+ used[v] = true;
+
+ for (const to of matches[v]) {
+ if (mt[to] === -1 || augmentingPath(mt[to])) {
+ mt[to] = v;
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ for (let v = 0; v < fieldsCt; ++v) {
+ used.fill(false);
+ augmentingPath(v);
+ }
+
+ let count: number = 0;
+ for (let i = 0; i < fieldsCt; ++i) {
+ if (mt[i] !== -1) ++count;
+ }
+ return count;
+ };
+}