aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-03-16 21:15:00 -0400
committerbobzel <zzzman@gmail.com>2025-03-16 21:15:00 -0400
commit1ffa8a8fb3e16bd5a3338d18782ddda0c2ffca03 (patch)
tree14fd95eb1d3ca5f5415e3703c4cbca2d7fe368aa /src
parentdf708c90d8356934d2e3d9123129c761d328c1fe (diff)
a lot of code cleanup for doc creators templates
Diffstat (limited to 'src')
-rw-r--r--src/client/views/Main.tsx6
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx89
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx3
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx189
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx167
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx90
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts (renamed from src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx)23
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts (renamed from src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx)157
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DecorationField.ts11
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts164
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts72
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts159
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateFieldUtils.ts (renamed from src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx)37
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.ts (renamed from src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx)23
14 files changed, 572 insertions, 618 deletions
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index fc2d7f572..b335432c9 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -65,8 +65,8 @@ import { PresBox, PresElementBox } from './nodes/trails';
import { FaceRecognitionHandler } from './search/FaceRecognitionHandler';
import { SearchBox } from './search/SearchBox';
import { StickerPalette } from './smartdraw/StickerPalette';
-import { Field } from './nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field';
-import { FieldUtils } from './nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils';
+import { TemplateField } from './nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField';
+import { TemplateFieldUtils } from './nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateFieldUtils';
dotenv.config();
@@ -102,7 +102,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' };
new PingManager();
new KeyManager();
new FaceRecognitionHandler();
- Field.initField = FieldUtils.initField; // set the init function for fields
+ TemplateField.initField = TemplateFieldUtils.initField; // set the init function for fields
// initialize plugins and classes that require plugins
CollectionDockingView.Init(TabDocView);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index a702218b0..97faf01c2 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -27,7 +27,7 @@ import { DocumentView, DocumentViewInternal } from '../../DocumentView';
import { OpenWhere } from '../../OpenWhere';
import { DataVizBox } from '../DataVizBox';
import './DocCreatorMenu.scss';
-import { Field, ViewType } from './FieldTypes/Field';
+import { TemplateField, ViewType } from './TemplateFieldTypes/TemplateField';
import { Template } from './Template';
import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
import { TemplateManager } from './TemplateManager';
@@ -371,7 +371,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
}
@action updateRenderedPreviewCollection = async (template: Template) => {
- this._fullyRenderedDocs = (await this.createDocsFromTemplate(template)) ?? [];
+ this._fullyRenderedDocs = ((await this.createDocsFromTemplate(template)) ?? []).filter(doc => doc).map(doc => doc!);
console.log(this._fullyRenderedDocs);
this.updateRenderedDocCollection();
};
@@ -630,7 +630,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
await Promise.all(renderedTemplatePromises);
}
- templates.forEach(template => template.mainField.initializeDocument({ subfields: [], title: template.title, opts: {}, viewType: ViewType.FREEFORM, tl: [0, 0], br: [900, 900] }));
+ templates.forEach(template => template.mainField.initializeDocument({ title: template.title, opts: {}, viewType: ViewType.FREEFORM, tl: [0, 0], br: [900, 900] }, []));
setTimeout(() => {
this.setSuggestedTemplates(templates);
@@ -638,10 +638,10 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
});
};
- renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number): Promise<boolean> => {
+ renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number | undefined): Promise<boolean> => {
const generateAndLoadImage = async (fieldNum: string, column: Col, prompt: string) => {
const url = await this.generateGPTImage(prompt);
- const field: Field = template.getFieldByID(Number(fieldNum));
+ const field: TemplateField = template.getFieldByID(Number(fieldNum));
field.setContent(url ?? '', ViewType.IMG);
field.setTitle(col.title);
@@ -665,7 +665,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
return true;
};
- renderGPTTextCall = async (template: Template, col: Col, fieldNum: number): Promise<boolean> => {
+ renderGPTTextCall = async (template: Template, col: Col, fieldNum: number | undefined): Promise<boolean> => {
const wordLimit = (size: TemplateFieldSize) => {
switch (size) {
case TemplateFieldSize.TINY:
@@ -697,7 +697,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
if (res) {
const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
Object.entries(assignments).forEach(([, /* title */ info]) => {
- const field: Field = template.getFieldByID(Number(info.number));
+ const field: TemplateField = template.getFieldByID(Number(info.number));
// const column = this.getColByTitle(title);
field.setContent(info.content ?? '', ViewType.TEXT);
@@ -771,7 +771,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
return templateCopy.mainField.renderedDoc;
};
- let docs: Promise<Doc>[];
+ let docs: Promise<Doc | undefined>[];
if (this.DEBUG_MODE) {
docs = [1, 2, 3, 4].map(() => processContent({}));
} else {
@@ -868,30 +868,31 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
get templatesPreviewContents() {
const GPTOptions = <div></div>;
- const previewDoc = (doc: Doc, template: Template) => (
- <DocumentView
- Document={doc}
- isContentActive={emptyFunction} // !!! should be return false
- addDocument={returnFalse}
- moveDocument={returnFalse}
- removeDocument={returnFalse}
- PanelWidth={() => (this._selectedTemplate === template ? 104 : 111)}
- PanelHeight={() => (this._selectedTemplate === template ? 104 : 111)}
- ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)}
- renderDepth={1}
- whenChildContentsActiveChanged={emptyFunction}
- focus={emptyFunction}
- styleProvider={DefaultStyleProvider}
- addDocTab={this._props.addDocTab}
- pinToPres={() => undefined}
- childFilters={returnEmptyFilter}
- childFiltersByRanges={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- fitContentsToBox={returnFalse}
- fitWidth={returnFalse}
- hideDecorations={true}
- />
- );
+ const previewDoc = (doc: Doc | undefined, template: Template) =>
+ !doc ? null : (
+ <DocumentView
+ Document={doc}
+ isContentActive={emptyFunction} // !!! should be return false
+ addDocument={returnFalse}
+ moveDocument={returnFalse}
+ removeDocument={returnFalse}
+ PanelWidth={() => (this._selectedTemplate === template ? 104 : 111)}
+ PanelHeight={() => (this._selectedTemplate === template ? 104 : 111)}
+ ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)}
+ renderDepth={1}
+ whenChildContentsActiveChanged={emptyFunction}
+ focus={emptyFunction}
+ styleProvider={DefaultStyleProvider}
+ addDocTab={this._props.addDocTab}
+ pinToPres={() => undefined}
+ childFilters={returnEmptyFilter}
+ childFiltersByRanges={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ fitContentsToBox={returnFalse}
+ fitWidth={returnFalse}
+ hideDecorations={true}
+ />
+ );
//<img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} />
@@ -1096,19 +1097,13 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
const collectionFactory = (): ((docs: Doc[], options: DocumentOptions) => Doc) => {
switch (this._layout.type) {
- case LayoutType.CAROUSEL3D:
- return Docs.Create.Carousel3DDocument;
- case LayoutType.FREEFORM:
- return Docs.Create.FreeformDocument;
- case LayoutType.CARD:
- return Docs.Create.CardDeckDocument;
- case LayoutType.MASONRY:
- return Docs.Create.MasonryDocument;
- case LayoutType.CAROUSEL:
- return Docs.Create.CarouselDocument;
- default:
- return Docs.Create.FreeformDocument;
- }
+ case LayoutType.CAROUSEL3D: return Docs.Create.Carousel3DDocument;
+ case LayoutType.FREEFORM: return Docs.Create.FreeformDocument;
+ case LayoutType.CARD: return Docs.Create.CardDeckDocument;
+ case LayoutType.MASONRY: return Docs.Create.MasonryDocument;
+ case LayoutType.CAROUSEL: return Docs.Create.CarouselDocument;
+ default: return Docs.Create.FreeformDocument;
+ } // prettier-ignore
};
const collection = collectionFactory()(this._fullyRenderedDocs, {
@@ -1241,9 +1236,9 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
emptyFunction,
undoable(clickEv => {
clickEv.stopPropagation();
- if (!this._selectedTemplate) return;
+ if (!this._selectedTemplate || !this._selectedTemplate.getRenderedDoc()) return;
const layout: DataVizTemplateLayout = {
- template: this._selectedTemplate.getRenderedDoc(),
+ template: this._selectedTemplate.getRenderedDoc()!,
layout: { type: this._layout.type, xMargin: this._layout.xMargin, yMargin: this._layout.yMargin, repeat: 0 },
columns: this.columnsCount,
rows: this.rowsCount,
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
deleted file mode 100644
index 98a9dc7a6..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DecorationField.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-import { DynamicField } from './DynamicField';
-
-export class DecorationField extends DynamicField {}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
deleted file mode 100644
index f100830d3..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ /dev/null
@@ -1,189 +0,0 @@
-import { Doc, DocListCast } from '../../../../../../fields/Doc';
-import { Docs } from '../../../../../documents/Documents';
-import { Field, FieldSettings, ViewType } from './Field';
-import { List } from '../../../../../../fields/List';
-import { DocData } from '../../../../../../fields/DocSymbols';
-import { DocumentType } from '../../../../../documents/DocumentTypes';
-import { reaction } from 'mobx';
-import { IDisposer } from 'mobx-utils';
-
-export class DynamicField extends Field {
- protected subfields!: Field[];
-
- protected disposers: { [name: string]: IDisposer } = {};
- init(settings: FieldSettings, id: number, parent?: DynamicField) {
- super.baseinit(undefined as unknown as Doc, settings, parent, id);
- const { doc, subFields } = this.initializeDocument(settings);
- this.Document = doc;
- this.subfields = subFields;
-
- this.disposers.fieldList = reaction(
- () => DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]),
- docs => {
- console.log('updated');
- this.handleFieldUpdate(docs);
- }
- );
- return this;
- }
-
- static setupSubfields(subFieldSettings: FieldSettings[] | undefined, parent?: DynamicField): Field[] {
- return subFieldSettings?.map((fieldSettings, index) => Field.initField!(fieldSettings, index, parent)) || [];
- }
-
- get getSubfields(): Field[] {
- return this.subfields ?? [];
- }
- get getAllSubfields() {
- let fields: Field[] = [];
- this.subfields?.forEach(field => {
- fields.push(field);
- fields = fields.concat(field instanceof DynamicField ? field.getAllSubfields : ([] as Field[]));
- });
- return fields;
- }
-
- setSubFields = (fields: Field[]) => {
- this.subfields = fields;
- };
- handleFieldUpdate = (newDocsList: Doc[]) => {
- const currRenderedDocs: Set<Doc> = new Set();
- this.subfields.forEach(field => currRenderedDocs.add(field.Document));
- newDocsList.forEach(doc => {
- if (!currRenderedDocs.has(doc)) {
- this.addFieldFromDoc(doc);
- }
- });
- currRenderedDocs.forEach(doc => {
- if (!newDocsList.includes(doc)) {
- const fields = this.subfields.filter(field => field.Document === doc);
- fields.forEach(field => this.removeField(field));
- }
- });
- };
-
- addFieldFromDoc = (doc: Doc) => {
- const par = this.Document;
- const settings: FieldSettings = {
- tl: [Number(doc._x) / Number(par._width), Number(doc._y) / Number(par._height)],
- br: [(Number(doc._x) + Number(doc._width)) / Number(par._width), (Number(doc._y) + Number(doc._height)) / Number(par._height)],
- viewType: doc.type === DocumentType.COL ? ViewType.FREEFORM : ViewType.STATIC,
- opts: {},
- };
-
- const newField: Field = Field.initField!(settings, this.subfields.length, this);
- this.subfields.push(newField);
- };
-
- addField = (field: Field) => {
- if (!this.subfields.includes(field)) {
- this.subfields.push(field);
- console.log('field added');
- // Doc.SetContainer(field.Document, this.Document);
- }
- };
-
- dispose = () => {
- Object.values(this.disposers).forEach(disposer => disposer?.());
- };
-
- removeField = (field: Field) => {
- // var childDocs: Doc[] = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]);
- // this.Document[Doc.LayoutFieldKey(this.Document)] = new List<Doc>([...childDocs.splice(childDocs.indexOf(field.Document), 1)]);
- this.subfields.splice(this.subfields.indexOf(field), 1);
- field instanceof DynamicField && field.dispose();
- };
-
- exchangeFields = (newField: Field, oldField: Field) => {
- this.subfields.splice(this.subfields.indexOf(oldField), 1, newField);
- // this.renderedDoc.
- };
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- setContent = (content: string, type: ViewType) => {
- return;
- };
- getContent = () => {
- return '';
- };
- get isContentField(): boolean {
- return false;
- }
-
- addChildToDocument = (doc: Doc) => {
- Doc.SetContainer(doc, this.Document);
- };
-
- matches = (): Array<number> => {
- return [];
- };
-
- async makeClone(parent?: DynamicField): Promise<Field> {
- const field = (await super.makeClone(parent)) as unknown as DynamicField;
- field.subfields = await Promise.all(this.subfields.map(async cloneField => await cloneField.makeClone(field)));
- field.Document[DocData].data = new List<Doc>(field.subfields.map(subfield => subfield.renderedDoc));
- return field;
- }
- initializeDocument = (settings: FieldSettings) => {
- const subFields = DynamicField.setupSubfields(settings.subfields, this);
- const renderedSubfields = subFields.map(field => field.renderedDoc);
- settings.opts.title = settings.title;
- switch (settings.viewType) {
- case ViewType.CAROUSEL3D:
- return { doc: Docs.Create.Carousel3DDocument(renderedSubfields, settings.opts), subFields };
- case ViewType.FREEFORM:
- return { doc: Docs.Create.FreeformDocument(renderedSubfields, settings.opts), subFields };
- default:
- return { doc: Docs.Create.FreeformDocument(renderedSubfields, settings.opts), subFields };
- }
- };
-}
-
-// export class DynamicField extends Field {
-// protected subfields: Field[];
-
-// protected Document!: Doc;
-
-// constructor(settings: FieldSettings, id: number, parent?: Field) {
-// super(settings, id, parent);
-// this.subfields = this.setupSubfields(this);
-// this.initializeDocument();
-// }
-
-// setContent = (content: string, type: ViewType) => { return };
-// getContent = () => { return '' };
-// get isContentField(): boolean { return false };
-
-// addChildToDocument = (doc: Doc) => {
-// Doc.SetContainer(doc, this.Document);
-// }
-
-// matches = (cols: Col[]): Array<number> => {
-// return [];
-// }
-
-// initializeDocument = (): Doc => {
-// let doc: Doc;
-// const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
-// switch (this.settings.viewType) {
-// case ViewType.CAROUSEL3D:
-// doc = Docs.Create.Carousel3DDocument(renderedSubfields, {
-// title: this.title,
-// });
-// break;
-// case ViewType.FREEFORM:
-// doc = Docs.Create.FreeformDocument(renderedSubfields, {
-// title: this.title,
-// });
-// break;
-// default:
-// doc = Docs.Create.FreeformDocument(renderedSubfields, {
-// title: this.title,
-// });
-// break;
-// }
-
-// this.Document = doc;
-// return doc;
-// }
-
-// }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
deleted file mode 100644
index 111ad8328..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ /dev/null
@@ -1,167 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-/* eslint-disable no-use-before-define */
-import { computed } from 'mobx';
-import { Doc } from '../../../../../../fields/Doc';
-import { DocData } from '../../../../../../fields/DocSymbols';
-import { Copy } from '../../../../../../fields/FieldSymbols';
-import { ObjectField } from '../../../../../../fields/ObjectField';
-import { ComputedField } from '../../../../../../fields/ScriptField';
-import { DocumentOptions } from '../../../../../documents/Documents';
-import { Col } from '../DocCreatorMenu';
-import { TemplateFieldSize, TemplateFieldType } from '../TemplateBackend';
-
-export abstract class Field {
- Document!: Doc;
-
- static initField?: (settings: FieldSettings, index: number, parent: any /* DynamicField */ | undefined, sameId?: boolean) => Field = undefined;
-
- protected parent?: any;
- protected id!: number;
- settings!: FieldSettings;
- protected title: string = '';
- dimensions!: FieldDimensions;
-
- constructor() {}
-
- baseinit(doc: Doc, settings: FieldSettings, parent?: any, id: number = 1) {
- this.id = id;
- this.Document = doc;
- this.parent = parent;
- this.settings = settings;
- this.title = settings.title ?? '';
- this.dimensions = this.getLocalDimensions({ tl: this.settings.tl, br: this.settings.br }, this.parent?.getDimensions);
- this.applyBasicOpts(this.dimensions, settings);
- return this;
- }
-
- get renderedDoc() {
- return this.Document;
- }
- get getDimensions() {
- return this.dimensions;
- }
- get getID() {
- return this.id;
- }
- get getDescription(): string {
- return this.settings.description ?? '';
- }
- get viewType(): ViewType {
- return this.settings.viewType;
- }
-
- setTitle = (title: string) => {
- this.title = title;
- this.Document.title = title;
- };
- getTitle = () => {
- return this.title;
- };
-
- abstract get isContentField(): boolean;
- abstract setContent(content: string, type: ViewType): void;
- abstract getContent(): string;
-
- async makeClone(parent?: any /* DynamicField*/): Promise<Field> {
- const field = Field.initField!(this.settings, this.id, parent, true); // create a value for this.Document/subfields that we want to ignore
- field.Document = (await Doc.MakeClone(this.Document)).clone;
- field.title = this.title;
- field.dimensions = this.dimensions;
- return field;
- }
-
- @computed get documentOptions(): DocumentOptions {
- const opts: DocumentOptions = {};
- Object.assign(opts, this.Document[DocData]);
- Object.entries(opts).forEach(([key, field]) => {
- if (field instanceof ObjectField) {
- Object.assign(opts, { [key]: ObjectField.MakeCopy(field) });
- } else if (field instanceof ComputedField) {
- Object.assign(opts, { [key]: field[Copy]() });
- }
- });
- return opts;
- }
-
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- changeFieldType = (newType: ViewType): Field => {
- const newField = Field.initField!(this.settings, this.id, this.parent, true);
- this.parent?.exchangeFields(newField, this);
- return newField;
- };
-
- matches = (cols: Col[]): number[] => {
- const colMatchesField = (col: Col) => {
- const isMatch: boolean = (this.settings.sizes?.some(size => col.sizes?.includes(size)) && this.settings.types?.includes(col.type)) ?? false;
- return isMatch;
- };
-
- const matches: Array<number> = [];
-
- cols.forEach((col, v) => {
- if (colMatchesField(col)) {
- matches.push(v);
- }
- });
-
- return matches;
- };
-
- private getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions?: FieldDimensions): FieldDimensions => {
- if (!parentDimensions) {
- return { width: coords.br[0] - coords.tl[0], height: coords.br[1] - coords.tl[1], coord: { x: coords.tl[0], y: coords.tl[1] } };
- }
- const l = (coords.tl[0] * parentDimensions.width) / 2;
- const t = coords.tl[1] * parentDimensions.height / 2; //prettier-ignore
- const r = (coords.br[0] * parentDimensions.width) / 2;
- const b = coords.br[1] * parentDimensions.height / 2; //prettier-ignore
- const width = r - l;
- const height = b - t;
- const coord = { x: l, y: t };
- return { width, height, coord };
- };
-
- private applyBasicOpts = (dimensions: FieldDimensions, settings: FieldSettings) => {
- const opts: DocumentOptions = settings.opts;
- opts.isDefaultTemplateDoc ??= true;
- opts._layout_hideScroll ??= true;
- opts.x ??= dimensions.coord.x;
- opts.y ??= dimensions.coord.y;
- opts._height ??= dimensions.height;
- opts._width ??= dimensions.width;
- opts._nativeWidth ??= dimensions.width;
- opts._nativeHeight ??= dimensions.height;
- opts._layout_nativeDimEditable ??= true;
- };
-}
-
-export type FieldSettings = {
- tl: [number, number];
- br: [number, number];
- opts: DocumentOptions;
- viewType: ViewType;
- title?: string;
- subfields?: FieldSettings[];
- types?: TemplateFieldType[];
- sizes?: TemplateFieldSize[];
- description?: string;
-};
-
-export enum ViewType {
- CAROUSEL3D = 'carousel3d',
- FREEFORM = 'freeform',
- STATIC = 'static',
- DEC = 'decoration',
- IMG = 'image',
- TEXT = 'text',
-}
-
-export type FieldDimensions = {
- width: number;
- height: number;
- coord: { x: number; y: number };
-};
-
-export type FieldTree = {
- node: { field: Field; subfields: FieldTree[] };
-};
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
deleted file mode 100644
index 75aea5440..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticContentField.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import { DocData } from '../../../../../../fields/DocSymbols';
-import { RichTextField } from '../../../../../../fields/RichTextField';
-import { ImageField } from '../../../../../../fields/URLField';
-import { Docs } from '../../../../../documents/Documents';
-import { Field, FieldSettings, ViewType } from './Field';
-import { FieldUtils } from './FieldUtils';
-import { DynamicField } from './DynamicField';
-
-export abstract class StaticContentField extends Field {
- protected content: string = '';
-
- abstract setContent(content: string, type?: ViewType): void;
- getContent = () => {
- return this.content ?? 'unset';
- };
- get isContentField(): boolean {
- return true;
- }
-}
-
-export class ImageTemplateField extends StaticContentField {
- init(settings: FieldSettings, id: number, parent: DynamicField | undefined) {
- super.baseinit(this.initializeDocument(settings), settings, parent, id);
- return this;
- }
-
- setContent = (url: string, type?: ViewType) => {
- this.settings.viewType = type ?? this.settings.viewType;
-
- if (type === ViewType.IMG || type === undefined) {
- const imgField = new ImageField(url);
- this.Document[DocData].data = imgField;
- this.content = url;
- } else {
- const updatedField = this.changeFieldType(type);
- updatedField.setContent(url, type);
- }
- };
-
- initializeDocument = (settings: FieldSettings) => {
- settings.opts.title = settings.title;
- settings.opts._layout_fitWidth = false;
-
- return Docs.Create.ImageDocument('', settings.opts);
- };
-}
-
-export class TextTemplateField extends StaticContentField {
- init(settings: FieldSettings, id: number, parent?: DynamicField) {
- super.baseinit(this.initializeDocument(settings), settings, parent, id);
- this.Document.text_fontSize = `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, '', true)}`;
- return this;
- }
- setContent = (text: string, type?: ViewType) => {
- this.settings.viewType = type ?? this.settings.viewType;
-
- if (type === ViewType.TEXT || type === undefined) {
- const rtf = {
- doc: {
- type: 'doc',
- content: [
- {
- type: 'paragraph',
- content: [
- {
- type: 'text',
- text,
- },
- ],
- },
- ],
- },
- selection: { type: 'text', anchor: 1, head: 1 },
- storedMarks: [],
- };
- this.content = text;
- const field = new RichTextField(JSON.stringify(rtf), text);
- this.Document[DocData]['text'] = field;
- } else {
- const updatedField = this.changeFieldType(type);
- updatedField.setContent(text, type);
- }
- };
-
- initializeDocument = (settings: FieldSettings) => {
- const opts = settings.opts;
- opts.title = settings.title;
- return Docs.Create.TextDocument('', opts);
- };
-}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
index 3c610b36a..ef6867e32 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
@@ -1,7 +1,7 @@
import { makeAutoObservable } from 'mobx';
import { Col } from './DocCreatorMenu';
-import { DynamicField } from './FieldTypes/DynamicField';
-import { Field, FieldSettings } from './FieldTypes/Field';
+import { DynamicField } from './TemplateFieldTypes/DynamicField';
+import { TemplateField, FieldSettings } from './TemplateFieldTypes/TemplateField';
import { TemplateLayouts } from './TemplateBackend';
export class Template {
@@ -14,13 +14,13 @@ export class Template {
this.mainField = this.setupMainField(templateInfo);
}
- get childFields(): Field[] {
+ get childFields(): TemplateField[] {
return this.mainField.getSubfields;
}
- get allFields(): Field[] {
+ get allFields(): TemplateField[] {
return this.mainField.getAllSubfields;
}
- get contentFields(): Field[] {
+ get contentFields(): TemplateField[] {
return this.allFields.filter(field => field.isContentField);
}
get doc() {
@@ -37,15 +37,15 @@ export class Template {
cloneBase = async (): Promise<Template> => {
const clone: Template = new Template(TemplateLayouts.BasicSettings);
clone.mainField = (await this.mainField.makeClone(undefined)) as unknown as DynamicField;
- clone.mainField.renderedDoc._width = this.mainField.renderedDoc._width;
- clone.mainField.renderedDoc._height = this.mainField.renderedDoc._height;
+ // clone.mainField.renderedDoc._width = this.mainField.renderedDoc._width;
+ // clone.mainField.renderedDoc._height = this.mainField.renderedDoc._height;
return clone;
};
printFieldInfo = () => {
this.allFields.forEach(field => {
const doc = field.renderedDoc;
- console.log('title: ', field.getTitle(), ' width: ', doc.width);
+ console.log('title: ', field.getTitle(), ' width: ', doc?.width);
});
};
@@ -53,7 +53,7 @@ export class Template {
return this.doc;
};
- getFieldByID = (id: number): Field => {
+ getFieldByID = (id: number): TemplateField => {
return this.allFields.filter(field => field.getID === id)[0];
};
@@ -62,7 +62,7 @@ export class Template {
};
setupMainField = (templateInfo: FieldSettings) => {
- return new DynamicField().init(templateInfo, 1);
+ return DynamicField.Create(templateInfo, 1);
};
get descriptionSummary(): string {
@@ -82,8 +82,7 @@ export class Template {
}
isValidTemplate = (cols: Col[]) => {
- const matches: number[][] = this.getMatches(cols);
- const maxMatches: number = this.maxMatches(matches);
+ const maxMatches = this.maxMatches(this.getMatches(cols));
return maxMatches === this.contentFields.length;
};
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts
index 2b32d49aa..9b0fac3a6 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts
@@ -1,4 +1,4 @@
-import { FieldSettings, ViewType } from "./FieldTypes/Field";
+import { FieldSettings, ViewType } from './TemplateFieldTypes/TemplateField';
export enum TemplateFieldType {
TEXT = 'text',
@@ -24,8 +24,8 @@ export class TemplateLayouts {
tl: [0, 0],
br: [400, 700],
viewType: ViewType.FREEFORM,
- opts: {}
- }
+ opts: {},
+ };
public static FourField001: FieldSettings = {
title: 'fourfield001',
@@ -100,7 +100,7 @@ export class TemplateLayouts {
public static FourField002: FieldSettings = {
title: 'fourfield002',
viewType: ViewType.FREEFORM,
- tl: [0,0],
+ tl: [0, 0],
br: [425, 778],
opts: {
backgroundColor: '#242425',
@@ -273,8 +273,8 @@ export class TemplateLayouts {
public static FourField004: FieldSettings = {
title: 'fourfield04',
viewType: ViewType.FREEFORM,
- tl: [0,0],
- br: [414,583],
+ tl: [0, 0],
+ br: [414, 583],
opts: {
backgroundColor: '#6CCAF0',
//borderColor: '#1088C3',
@@ -350,44 +350,44 @@ export class TemplateLayouts {
public static FourField005: FieldSettings = {
title: 'fourfield05',
viewType: ViewType.FREEFORM,
- tl: [0,0],
- br: [400,550],
+ tl: [0, 0],
+ br: [400, 550],
opts: {
backgroundColor: '#95A575',
},
subfields: [
{
viewType: ViewType.STATIC,
- tl: [-0.9, -.925],
- br: [-.075, -.775],
+ tl: [-0.9, -0.925],
+ br: [-0.075, -0.775],
types: [TemplateFieldType.TEXT],
sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
description: 'A small text field for a title or word(s) that categorize the rest of the content.',
opts: {
borderColor: '#3B4A2C',
borderWidth: 8,
- hCentering: "h-center",
+ hCentering: 'h-center',
backgroundColor: '#B8DC90',
},
},
{
viewType: ViewType.STATIC,
- tl: [.075, -.925],
- br: [.9, -.775],
+ tl: [0.075, -0.925],
+ br: [0.9, -0.775],
types: [TemplateFieldType.TEXT],
sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
description: 'A small text field for a title that categorizes the rest of the content.',
opts: {
borderColor: '#3B4A2C',
borderWidth: 8,
- hCentering: "h-center",
+ hCentering: 'h-center',
backgroundColor: '#B8DC90',
},
},
{
viewType: ViewType.DEC,
- tl: [-.82, -.4],
- br: [-.5, -.2],
+ tl: [-0.82, -0.4],
+ br: [-0.5, -0.2],
opts: {
backgroundColor: '#94B058',
borderColor: '#3B4A2C',
@@ -396,8 +396,8 @@ export class TemplateLayouts {
},
{
viewType: ViewType.STATIC,
- tl: [-0.66, -.65],
- br: [0.66, .25],
+ tl: [-0.66, -0.65],
+ br: [0.66, 0.25],
types: [TemplateFieldType.VISUAL],
sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
description: 'A medium to large field in the center of the template, for the main visual content.',
@@ -409,22 +409,22 @@ export class TemplateLayouts {
},
{
viewType: ViewType.STATIC,
- tl: [-.875, .425],
- br: [0.875, .925],
+ tl: [-0.875, 0.425],
+ br: [0.875, 0.925],
types: [TemplateFieldType.TEXT],
sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
description: 'A medium to large field at the bottom of the template, for the main text content.',
opts: {
borderColor: '#3B4A2C',
borderWidth: 8,
- hCentering: "h-center",
+ hCentering: 'h-center',
backgroundColor: '#B8DC90',
},
},
{
viewType: ViewType.DEC,
- tl: [-1.1, -.62],
- br: [-.9, -.5],
+ tl: [-1.1, -0.62],
+ br: [-0.9, -0.5],
opts: {
backgroundColor: '#7A9D31',
borderColor: '#3B4A2C',
@@ -434,7 +434,7 @@ export class TemplateLayouts {
{
viewType: ViewType.DEC,
tl: [-1.1, 0],
- br: [-.9, .15],
+ br: [-0.9, 0.15],
opts: {
backgroundColor: '#94B058',
borderColor: '#3B4A2C',
@@ -443,8 +443,8 @@ export class TemplateLayouts {
},
{
viewType: ViewType.DEC,
- tl: [-.93, -.265],
- br: [-.715, -.125],
+ tl: [-0.93, -0.265],
+ br: [-0.715, -0.125],
opts: {
backgroundColor: '#728745',
borderColor: '#3B4A2C',
@@ -453,8 +453,8 @@ export class TemplateLayouts {
},
{
viewType: ViewType.DEC,
- tl: [.7, -.45],
- br: [.85, -.3],
+ tl: [0.7, -0.45],
+ br: [0.85, -0.3],
opts: {
backgroundColor: '#7A9D31',
borderColor: '#3B4A2C',
@@ -463,8 +463,8 @@ export class TemplateLayouts {
},
{
viewType: ViewType.DEC,
- tl: [.8, .03],
- br: [1.2, .33],
+ tl: [0.8, 0.03],
+ br: [1.2, 0.33],
opts: {
backgroundColor: '#728745',
borderColor: '#3B4A2C',
@@ -473,43 +473,43 @@ export class TemplateLayouts {
},
{
viewType: ViewType.DEC,
- tl: [.875, -.13],
- br: [1.2, .12],
+ tl: [0.875, -0.13],
+ br: [1.2, 0.12],
opts: {
backgroundColor: '#94B058',
borderColor: '#3B4A2C',
borderWidth: 8,
},
},
- ]
- }
+ ],
+ };
public static FourFieldCarousel: FieldSettings = {
title: 'title_fourfieldcarousel',
viewType: ViewType.FREEFORM,
- tl:[0,0],
- br:[500, 600],
+ tl: [0, 0],
+ br: [500, 600],
opts: {
backgroundColor: '#D7CBAB',
},
subfields: [
{
viewType: ViewType.STATIC,
- tl: [-0.8, -.9],
- br: [0.8, -.5],
+ tl: [-0.8, -0.9],
+ br: [0.8, -0.5],
types: [TemplateFieldType.TEXT],
sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
description: 'A small text field for a title that categorizes the rest of the content.',
opts: {
- hCentering: "h-center",
+ hCentering: 'h-center',
backgroundColor: 'transparent',
text_transform: 'uppercase',
},
},
{
viewType: ViewType.CAROUSEL3D,
- tl: [-0.9, -.5],
- br: [0.9, .25],
+ tl: [-0.9, -0.5],
+ br: [0.9, 0.25],
opts: {
borderColor: '#847F69',
borderWidth: 8,
@@ -518,8 +518,8 @@ export class TemplateLayouts {
subfields: [
{
viewType: ViewType.STATIC,
- tl: [-.4, -.6],
- br: [.4, .6],
+ tl: [-0.4, -0.6],
+ br: [0.4, 0.6],
types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
description: 'A medium to large field for content that will share central focus with other content in the carousel.',
@@ -530,8 +530,8 @@ export class TemplateLayouts {
},
{
viewType: ViewType.STATIC,
- tl: [-.4, -.6],
- br: [.4, .6],
+ tl: [-0.4, -0.6],
+ br: [0.4, 0.6],
types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
description: 'A medium to large field for content that will share central focus with other content in the carousel.',
@@ -542,8 +542,8 @@ export class TemplateLayouts {
},
{
viewType: ViewType.STATIC,
- tl: [-.4, -.6],
- br: [.4, .6],
+ tl: [-0.4, -0.6],
+ br: [0.4, 0.6],
types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
description: 'A medium to large field for content that will share central focus with other content in the carousel.',
@@ -552,28 +552,27 @@ export class TemplateLayouts {
//borderWidth: '8',
},
},
- ]
+ ],
},
{
viewType: ViewType.STATIC,
- tl: [-0.9, .35],
- br: [0.9, .9],
+ tl: [-0.9, 0.35],
+ br: [0.9, 0.9],
types: [TemplateFieldType.TEXT],
sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
description: 'A medium text field for a description of the content in the carousel.',
opts: {
- hCentering: "h-center",
+ hCentering: 'h-center',
backgroundColor: 'transparent',
},
},
- ]
- }
-
+ ],
+ };
public static ThreeField001: FieldSettings = {
title: 'threefield001',
viewType: ViewType.FREEFORM,
- tl: [0,0],
+ tl: [0, 0],
br: [575, 770],
opts: {
backgroundColor: '#DDD3A9',
@@ -592,17 +591,17 @@ export class TemplateLayouts {
},
subfields: [
{
- viewType: ViewType.STATIC,
- tl: [-1.25, -1.25],
- br: [1.25, 1.25],
- types: [TemplateFieldType.VISUAL],
- sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
- description: 'A medium to large field for visual content that is the central focus.',
- opts: {
- _rotation: -45,
+ viewType: ViewType.STATIC,
+ tl: [-1.25, -1.25],
+ br: [1.25, 1.25],
+ types: [TemplateFieldType.VISUAL],
+ sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+ description: 'A medium to large field for visual content that is the central focus.',
+ opts: {
+ _rotation: -45,
+ },
},
- },
- ]
+ ],
},
{
viewType: ViewType.STATIC,
@@ -639,13 +638,13 @@ export class TemplateLayouts {
subfields: [
{
viewType: ViewType.DEC,
- tl: [-1, -.7],
- br: [1, -.625],
+ tl: [-1, -0.7],
+ br: [1, -0.625],
opts: {
backgroundColor: 'yellow',
},
},
- ]
+ ],
},
{
viewType: ViewType.FREEFORM,
@@ -658,13 +657,13 @@ export class TemplateLayouts {
subfields: [
{
viewType: ViewType.DEC,
- tl: [-1, -.7],
- br: [1, -.625],
+ tl: [-1, -0.7],
+ br: [1, -0.625],
opts: {
backgroundColor: 'yellow',
},
},
- ]
+ ],
},
{
viewType: ViewType.FREEFORM,
@@ -677,13 +676,13 @@ export class TemplateLayouts {
subfields: [
{
viewType: ViewType.DEC,
- tl: [-1, -.7],
- br: [1, -.625],
+ tl: [-1, -0.7],
+ br: [1, -0.625],
opts: {
backgroundColor: 'yellow',
},
},
- ]
+ ],
},
{
viewType: ViewType.FREEFORM,
@@ -696,13 +695,13 @@ export class TemplateLayouts {
subfields: [
{
viewType: ViewType.DEC,
- tl: [-1, -.7],
- br: [1, -.625],
+ tl: [-1, -0.7],
+ br: [1, -0.625],
opts: {
backgroundColor: 'yellow',
},
},
- ]
+ ],
},
],
};
@@ -710,7 +709,7 @@ export class TemplateLayouts {
public static ThreeField002: FieldSettings = {
title: 'threefield002',
viewType: ViewType.FREEFORM,
- tl: [0,0],
+ tl: [0, 0],
br: [477, 662],
opts: {
backgroundColor: '#9E9C95',
@@ -767,5 +766,3 @@ export class TemplateLayouts {
],
};
}
-
-
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DecorationField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DecorationField.ts
new file mode 100644
index 000000000..4f5ad89b6
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DecorationField.ts
@@ -0,0 +1,11 @@
+import { DynamicField } from './DynamicField';
+import { FieldSettings, TemplateField } from './TemplateField';
+
+export class DecorationField extends DynamicField {
+ private constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+ super(settings, parent, id);
+ }
+ static Create(settings: FieldSettings, id: number | undefined, parent?: TemplateField) {
+ return DynamicField.Create(settings, id, parent);
+ }
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
new file mode 100644
index 000000000..0917093b1
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
@@ -0,0 +1,164 @@
+import { reaction } from 'mobx';
+import { IDisposer } from 'mobx-utils';
+import { Doc, DocListCast } from '../../../../../../fields/Doc';
+import { DocData } from '../../../../../../fields/DocSymbols';
+import { List } from '../../../../../../fields/List';
+import { NumCast } from '../../../../../../fields/Types';
+import { Docs } from '../../../../../documents/Documents';
+import { DocumentType } from '../../../../../documents/DocumentTypes';
+import { FieldSettings, TemplateField, ViewType } from './TemplateField';
+
+export class DynamicField extends TemplateField {
+ protected _disposers: { [name: string]: IDisposer } = {};
+ protected _subfields: TemplateField[] | undefined;
+
+ protected constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+ super(settings, parent, id);
+ }
+ static Create(settings: FieldSettings, id: number | undefined, parent?: TemplateField) {
+ const field = new DynamicField(settings, parent, id);
+ field._subfields = settings.subfields?.map((fieldSettings, index) => TemplateField.initField(fieldSettings, index, field)) || [];
+ field._renderDoc = field.initializeDocument(settings, field._subfields);
+ field._disposers.fieldList = reaction(() => DocListCast(field._renderDoc?.[Doc.LayoutFieldKey(field._renderDoc)]), field.handleFieldUpdate);
+ return field;
+ }
+
+ get getSubfields(): TemplateField[] {
+ return this._subfields ?? [];
+ }
+ get getAllSubfields() {
+ return (
+ this._subfields?.reduce((fields, field) => {
+ fields.push(field, ...((field as DynamicField).getAllSubfields ?? []));
+ return fields;
+ }, [] as TemplateField[]) ?? []
+ );
+ }
+
+ setSubFields = (fields: TemplateField[]) => (this._subfields = fields);
+
+ handleFieldUpdate = (newDocsList: Doc[]) => {
+ const currRenderedDocs = new Set(this._subfields?.filter(field => field.renderedDoc).map(field => field.renderedDoc!));
+ newDocsList.forEach(doc => !currRenderedDocs.has(doc) && this.addFieldFromDoc(doc));
+ currRenderedDocs.forEach(doc => {
+ if (!newDocsList.includes(doc)) {
+ this._subfields?.forEach(field => field.renderedDoc === doc && this.removeField(field));
+ }
+ });
+ };
+
+ addFieldFromDoc = (doc: Doc) => {
+ const par = this._renderDoc;
+ const settings: FieldSettings = {
+ tl: [Number(doc._x) / NumCast(par?._width, 1), Number(doc?._y) / NumCast(par?._height, 1)],
+ br: [(Number(doc._x) + Number(doc._width)) / NumCast(par?._width, 1), (Number(doc._y) + Number(doc._height)) / NumCast(par?._height, 1)],
+ viewType: doc.type === DocumentType.COL ? ViewType.FREEFORM : ViewType.STATIC,
+ opts: {},
+ };
+
+ this._subfields?.push(TemplateField.initField(settings, this._subfields?.length ?? 0, this));
+ };
+
+ addField = (field: TemplateField) => {
+ if (!this._subfields?.includes(field)) {
+ this._subfields?.push(field);
+ // Doc.SetContainer(field.Document, this.Document);
+ }
+ };
+
+ dispose = () => Object.values(this._disposers).forEach(disposer => disposer?.());
+
+ removeField = (field: TemplateField) => {
+ // var childDocs: Doc[] = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]);
+ // this.Document[Doc.LayoutFieldKey(this.Document)] = new List<Doc>([...childDocs.splice(childDocs.indexOf(field.Document), 1)]);
+ this._subfields?.splice(this._subfields?.indexOf(field), 1);
+ (field as DynamicField).dispose?.();
+ };
+
+ // implement Field's abstract method for replacing a subfield with a new one
+ exchangeFields(newField: TemplateField, oldField: TemplateField) {
+ this._subfields?.splice(this._subfields?.indexOf(oldField), 1, newField);
+ }
+
+ get isContentField(): boolean {
+ return false;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ setContent(content: string, type: ViewType) {}
+
+ getContent = () => '';
+
+ addChildToDocument = (doc: Doc) => this._renderDoc && Doc.SetContainer(doc, this._renderDoc);
+
+ matches = (): Array<number> => [];
+
+ async makeClone(parent?: DynamicField): Promise<TemplateField> {
+ const clone = (await super.makeClone(parent)) as unknown as DynamicField;
+ if (this._subfields) {
+ clone._subfields = await Promise.all(this._subfields.map(async cloneField => await cloneField.makeClone(clone)));
+ }
+ clone._renderDoc && (clone._renderDoc[DocData].data = new List<Doc>(clone._subfields?.filter(sub => sub.renderedDoc).map(sub => sub.renderedDoc!) ?? []));
+ return clone;
+ }
+
+ initializeDocument = (settings: FieldSettings, subFields: TemplateField[]) => {
+ const renderedSubfields = subFields?.filter(field => field.renderedDoc).map(field => field.renderedDoc!) ?? [];
+ settings.opts.title = settings.title;
+ switch (settings.viewType) {
+ case ViewType.CAROUSEL3D: return Docs.Create.Carousel3DDocument(renderedSubfields, settings.opts);
+ case ViewType.FREEFORM:
+ default: return Docs.Create.FreeformDocument(renderedSubfields, settings.opts);
+ } // prettier-ignore
+ };
+}
+
+// export class DynamicField extends Field {
+// protected subfields: Field[];
+
+// protected Document!: Doc;
+
+// constructor(settings: FieldSettings, id: number, parent?: Field) {
+// super(settings, id, parent);
+// this.subfields = this.setupSubfields(this);
+// this.initializeDocument();
+// }
+
+// setContent = (content: string, type: ViewType) => { return };
+// getContent = () => { return '' };
+// get isContentField(): boolean { return false };
+
+// addChildToDocument = (doc: Doc) => {
+// Doc.SetContainer(doc, this.Document);
+// }
+
+// matches = (cols: Col[]): Array<number> => {
+// return [];
+// }
+
+// initializeDocument = (): Doc => {
+// let doc: Doc;
+// const renderedSubfields: Doc[] = this.subfields.map(field => field.renderedDoc);
+// switch (this.settings.viewType) {
+// case ViewType.CAROUSEL3D:
+// doc = Docs.Create.Carousel3DDocument(renderedSubfields, {
+// title: this.title,
+// });
+// break;
+// case ViewType.FREEFORM:
+// doc = Docs.Create.FreeformDocument(renderedSubfields, {
+// title: this.title,
+// });
+// break;
+// default:
+// doc = Docs.Create.FreeformDocument(renderedSubfields, {
+// title: this.title,
+// });
+// break;
+// }
+
+// this.Document = doc;
+// return doc;
+// }
+
+// }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
new file mode 100644
index 000000000..b8839efab
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
@@ -0,0 +1,72 @@
+import { DocData } from '../../../../../../fields/DocSymbols';
+import { RichTextField } from '../../../../../../fields/RichTextField';
+import { ImageField } from '../../../../../../fields/URLField';
+import { Docs } from '../../../../../documents/Documents';
+import { FieldSettings, TemplateField, ViewType } from './TemplateField';
+import { TemplateFieldUtils } from './TemplateFieldUtils';
+
+export abstract class StaticContentField extends TemplateField {
+ protected _content: string = '';
+
+ getContent = () => this._content ?? 'unset';
+ get isContentField(): boolean {
+ return true;
+ }
+}
+
+export class ImageTemplateField extends StaticContentField {
+ private constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+ super(settings, parent, id);
+ }
+ static Create(settings: FieldSettings, id: number | undefined, parent: TemplateField | undefined) {
+ const field = new ImageTemplateField(settings, parent, id);
+ field._renderDoc = field.initializeDocument(settings);
+ return field;
+ }
+
+ setContent(url: string, type?: ViewType) {
+ super.setContent(url, type);
+
+ if (type === ViewType.IMG || type === undefined) {
+ this._renderDoc && (this._renderDoc[DocData].data = new ImageField(url));
+ this._content = url;
+ } else {
+ this.changeFieldType(type).setContent(url, type);
+ }
+ }
+
+ initializeDocument = (settings: FieldSettings) => {
+ settings.opts.title = settings.title;
+ settings.opts._layout_fitWidth = false;
+
+ return Docs.Create.ImageDocument('', settings.opts);
+ };
+}
+
+export class TextTemplateField extends StaticContentField {
+ private constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+ super(settings, parent, id);
+ }
+ static Create(settings: FieldSettings, id: number, parent?: TemplateField) {
+ const field = new TextTemplateField(settings, parent, id);
+ field._renderDoc = field.initializeDocument(settings);
+ field._renderDoc.text_fontSize = `${TemplateFieldUtils.calculateFontSize(field._dimensions?.width ?? 10, field._dimensions?.height ?? 10, '', true)}`;
+ return field;
+ }
+ setContent(text: string, type?: ViewType) {
+ super.setContent(text, type);
+
+ if (type === ViewType.TEXT || type === undefined) {
+ this._content = text;
+ this._renderDoc && (this._renderDoc[DocData].text = RichTextField.textToRtf(text));
+ } else {
+ this.changeFieldType(type).setContent(text, type);
+ }
+ }
+
+ initializeDocument = (settings: FieldSettings | undefined) => {
+ const opts = settings?.opts;
+ opts && (opts.title = settings?.title ?? '');
+ return Docs.Create.TextDocument('', opts);
+ };
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
new file mode 100644
index 000000000..318bffde5
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
@@ -0,0 +1,159 @@
+/* eslint-disable no-use-before-define */
+import { computed } from 'mobx';
+import { Doc } from '../../../../../../fields/Doc';
+import { DocData } from '../../../../../../fields/DocSymbols';
+import { Copy } from '../../../../../../fields/FieldSymbols';
+import { ObjectField } from '../../../../../../fields/ObjectField';
+import { DocumentOptions } from '../../../../../documents/Documents';
+import { Col } from '../DocCreatorMenu';
+import { TemplateFieldSize, TemplateFieldType } from '../TemplateBackend';
+
+export abstract class TemplateField {
+ /**
+ * Creates and initializes a new TemplateField based on the settings and parameters
+ *
+ * implemented in FieldUtils and assigned in main (to avoid import cycles)
+ *
+ * @param settings - specification of the field type and other parameters
+ * @param index -
+ * @param parent - TemplateField that contains the new field
+ * @param sameId -
+ * @returns TemplateField
+ */
+ static initField: (settings: FieldSettings | undefined, index: number | undefined, parent: TemplateField | undefined, sameId?: boolean) => TemplateField;
+
+ protected _parent?: TemplateField;
+ protected _id: number;
+ protected _title: string = '';
+ protected _settings: FieldSettings;
+ protected _renderDoc: Doc | undefined;
+ protected _dimensions: FieldDimensions | undefined;
+
+ constructor(settings: FieldSettings, parent?: TemplateField, id: number = 1) {
+ this._id = id;
+ this._parent = parent;
+ this._settings = settings;
+ this._title = settings.title ?? '';
+ this._dimensions = this.getLocalDimensions(this._settings, this._parent?.getDimensions);
+ this.applyBasicOpts(this._dimensions, settings);
+ return this;
+ }
+
+ get renderedDoc() {
+ return this._renderDoc;
+ }
+ get getDimensions() {
+ return this._dimensions;
+ }
+ get getID() {
+ return this._id;
+ }
+ get getDescription(): string {
+ return this._settings?.description ?? '';
+ }
+ get viewType(): ViewType | undefined {
+ return this._settings?.viewType;
+ }
+
+ setTitle = (title: string) => {
+ this._title = title;
+ this._renderDoc && (this._renderDoc.title = title);
+ };
+ getTitle = () => this._title;
+
+ abstract get isContentField(): boolean;
+ setContent(content: string, type?: ViewType) {
+ this._settings && (this._settings.viewType = type ?? this._settings.viewType);
+ }
+
+ abstract getContent(): string;
+
+ async makeClone(parent?: TemplateField): Promise<TemplateField> {
+ const clone = TemplateField.initField(this._settings, this._id, parent, true); // create a value for this.Document/subfields that we want to ignore
+ clone._renderDoc = this._renderDoc ? (await Doc.MakeClone(this._renderDoc)).clone : undefined;
+ clone._title = this._title;
+ clone._dimensions = this._dimensions;
+ return clone;
+ }
+
+ @computed get documentOptions(): DocumentOptions {
+ const opts: DocumentOptions = {};
+ Object.assign(opts, this._renderDoc?.[DocData]);
+ Object.entries(opts).forEach(([key, field]) => {
+ Object.assign(opts, { [key]: field instanceof Object ? ObjectField.MakeCopy(field) : field[Copy]() });
+ });
+ return opts;
+ }
+ exchangeFields(newField: TemplateField, oldField: TemplateField) {
+ throw new Error('Only DynamicField can exchange fields.' + newField._title + ' ' + oldField._title);
+ }
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ changeFieldType = (newType: ViewType): TemplateField => {
+ const newField = TemplateField.initField(this._settings, this._id, this._parent, true);
+ this._parent?.exchangeFields(newField, this);
+ return newField;
+ };
+
+ matches = (cols: Col[]): number[] => {
+ const colMatchesField = (col: Col) => (this._settings?.sizes?.some(size => col.sizes?.includes(size)) && this._settings.types?.includes(col.type)) ?? false;
+
+ const matches: Array<number> = [];
+ cols.forEach((col, v) => colMatchesField(col) && matches.push(v));
+ return matches;
+ };
+
+ private getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions?: FieldDimensions): FieldDimensions => {
+ if (!parentDimensions) {
+ return { width: coords.br[0] - coords.tl[0], height: coords.br[1] - coords.tl[1], coord: { x: coords.tl[0], y: coords.tl[1] } };
+ }
+ const l = (coords.tl[0] * parentDimensions.width) / 2;
+ const t = coords.tl[1] * parentDimensions.height / 2; //prettier-ignore
+ const r = (coords.br[0] * parentDimensions.width) / 2;
+ const b = coords.br[1] * parentDimensions.height / 2; //prettier-ignore
+ return { width: r-l, height: b-t, coord: { x: l, y: t } }; //prettier-ignore
+ };
+
+ private applyBasicOpts = (dimensions: FieldDimensions, settings: FieldSettings | undefined) => {
+ const opts: DocumentOptions = settings?.opts ?? {};
+ opts.isDefaultTemplateDoc ??= true;
+ opts._layout_hideScroll ??= true;
+ opts.x ??= dimensions.coord.x;
+ opts.y ??= dimensions.coord.y;
+ opts._height ??= dimensions.height;
+ opts._width ??= dimensions.width;
+ opts._nativeWidth ??= dimensions.width;
+ opts._nativeHeight ??= dimensions.height;
+ opts._layout_nativeDimEditable ??= true;
+ };
+}
+
+export type FieldSettings = {
+ tl: [number, number];
+ br: [number, number];
+ opts: DocumentOptions;
+ viewType: ViewType;
+ title?: string;
+ subfields?: FieldSettings[];
+ types?: TemplateFieldType[];
+ sizes?: TemplateFieldSize[];
+ description?: string;
+};
+
+export enum ViewType {
+ CAROUSEL3D = 'carousel3d',
+ FREEFORM = 'freeform',
+ STATIC = 'static',
+ DEC = 'decoration',
+ IMG = 'image',
+ TEXT = 'text',
+}
+
+export type FieldDimensions = {
+ width: number;
+ height: number;
+ coord: { x: number; y: number };
+};
+
+export type FieldTree = {
+ node: { field: TemplateField; subfields: FieldTree[] };
+};
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateFieldUtils.ts
index 0582c9ed3..c38d769cd 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateFieldUtils.ts
@@ -1,23 +1,30 @@
-import { Field, FieldSettings, ViewType } from './Field';
-import { TextTemplateField, ImageTemplateField } from './StaticContentField';
import { DecorationField } from './DecorationField';
import { DynamicField } from './DynamicField';
+import { ImageTemplateField, TextTemplateField } from './StaticContentField';
+import { FieldSettings, TemplateField, ViewType } from './TemplateField';
-export class FieldUtils {
- public static initField = (settings: FieldSettings, index: number, parent: DynamicField | undefined, sameId: boolean = false): Field => {
+export class TemplateFieldUtils {
+ /**
+ * Creates and initializes a new TemplateField based on the settings and parameters
+ *
+ * implements Field.initField ... see main.tsx
+ *
+ * @param settings - specification of the field type and other parameters
+ * @param index -
+ * @param parent - TemplateField that contains the new field
+ * @param sameId -
+ * @returns TemplateField
+ */
+ public static initField = (settings: FieldSettings, index: number, parent: TemplateField | undefined, sameId: boolean = false): TemplateField => {
const id = sameId ? index : parent ? Number(`${parent.getID}${index}`) : 1;
- switch (settings.viewType) {
+ switch (settings?.viewType) {
case ViewType.FREEFORM:
- case ViewType.CAROUSEL3D:
- return new DynamicField().init(settings, id, parent);
- case ViewType.IMG:
- return new ImageTemplateField().init(settings, id, parent);
- case ViewType.TEXT:
- return new TextTemplateField().init(settings, id, parent);
- case ViewType.DEC:
- return new DecorationField().init(settings, id, parent);
- }
- return new TextTemplateField().init(settings, id, parent);
+ case ViewType.CAROUSEL3D: return DynamicField.Create(settings, id, parent);
+ case ViewType.IMG: return ImageTemplateField.Create(settings, id, parent);
+ case ViewType.TEXT: return TextTemplateField.Create(settings, id, parent);
+ case ViewType.DEC: return DecorationField.Create(settings, id, parent);
+ default: return TextTemplateField.Create(settings, id, parent);
+ } // prettier-ignore
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.ts
index 09b4ce029..1959cf9d6 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.ts
@@ -1,10 +1,9 @@
-import { makeAutoObservable } from "mobx";
-import { Col } from "./DocCreatorMenu";
-import { FieldSettings } from "./FieldTypes/Field";
-import { Template } from "./Template";
+import { makeAutoObservable } from 'mobx';
+import { Col } from './DocCreatorMenu';
+import { FieldSettings } from './TemplateFieldTypes/TemplateField';
+import { Template } from './Template';
export class TemplateManager {
-
templates: Template[] = [];
constructor(templateSettings: FieldSettings[]) {
@@ -16,19 +15,19 @@ export class TemplateManager {
const initializedTemplates: Template[] = [];
templateSettings.forEach(settings => initializedTemplates.push(new Template(settings)));
return initializedTemplates;
- }
+ };
getValidTemplates = (cols: Col[]): Template[] => {
- console.log('called in manager with templates: ', this.templates)
+ console.log('called in manager with templates: ', this.templates);
return this.templates.filter(template => template.isValidTemplate(cols));
- }
+ };
- addTemplate = (newTemplate: Template) =>{
+ addTemplate = (newTemplate: Template) => {
this.templates.push(newTemplate);
- }
+ };
removeTemplate = (template: Template) => {
this.templates.splice(this.templates.indexOf(template), 1);
template.cleanup();
- }
-} \ No newline at end of file
+ };
+}