diff options
| author | bobzel <zzzman@gmail.com> | 2025-04-30 14:43:29 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2025-04-30 14:43:29 -0400 |
| commit | 0317a667a5d4a0f298522eeddb8afa96e7b7ecfc (patch) | |
| tree | 2d66c3caa5c102a3ca78837b87e61c16fd07fc01 /src/client/views/nodes/scrapbook/ScrapbookBox.tsx | |
| parent | 9ec7df6af508eccdfda3a195a69c8bb1f86c41ea (diff) | |
| parent | 2296c314be710f983d595de37c9d8039d73568a6 (diff) | |
Merge branch 'master' into task_nodes_aarav
Diffstat (limited to 'src/client/views/nodes/scrapbook/ScrapbookBox.tsx')
| -rw-r--r-- | src/client/views/nodes/scrapbook/ScrapbookBox.tsx | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx new file mode 100644 index 000000000..6cfe9a62c --- /dev/null +++ b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx @@ -0,0 +1,143 @@ +import { action, makeObservable, observable } from 'mobx'; +import * as React from 'react'; +import { Doc, DocListCast } from '../../../../fields/Doc'; +import { List } from '../../../../fields/List'; +import { emptyFunction } from '../../../../Utils'; +import { Docs } from '../../../documents/Documents'; +import { DocumentType } from '../../../documents/DocumentTypes'; +import { CollectionView } from '../../collections/CollectionView'; +import { ViewBoxAnnotatableComponent } from '../../DocComponent'; +import { DocumentView } from '../DocumentView'; +import { FieldView, FieldViewProps } from '../FieldView'; +import { DragManager } from '../../../util/DragManager'; +import { RTFCast, StrCast, toList } from '../../../../fields/Types'; +import { undoable } from '../../../util/UndoManager'; +// Scrapbook view: a container that lays out its child items in a grid/template +export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { + @observable createdDate: string; + + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + this.createdDate = this.getFormattedDate(); + + // ensure we always have a List<Doc> in dataDoc['items'] + if (!this.dataDoc[this.fieldKey]) { + this.dataDoc[this.fieldKey] = new List<Doc>(); + } + this.createdDate = this.getFormattedDate(); + this.setTitle(); + } + + public static LayoutString(fieldStr: string) { + return FieldView.LayoutString(ScrapbookBox, fieldStr); + } + + getFormattedDate(): string { + return new Date().toLocaleDateString(undefined, { + year: 'numeric', + month: 'short', + day: 'numeric', + }); + } + + @action + setTitle() { + const title = `Scrapbook - ${this.createdDate}`; + if (this.dataDoc.title !== title) { + this.dataDoc.title = title; + + const image = Docs.Create.TextDocument('image'); + image.accepts_docType = DocumentType.IMG; + const placeholder = new Doc(); + placeholder.proto = image; + placeholder.original = image; + placeholder._width = 250; + placeholder._height = 200; + placeholder.x = 0; + placeholder.y = -100; + //placeholder.overrideFields = new List<string>(['x', 'y']); // shouldn't need to do this for layout fields since the placeholder already overrides its protos + + const summary = Docs.Create.TextDocument('summary'); + summary.accepts_docType = DocumentType.RTF; + summary.accepts_textType = 'one line'; + const placeholder2 = new Doc(); + placeholder2.proto = summary; + placeholder2.original = summary; + placeholder2.x = 0; + placeholder2.y = 200; + placeholder2._width = 250; + //placeholder2.overrideFields = new List<string>(['x', 'y', '_width']); // shouldn't need to do this for layout fields since the placeholder already overrides its protos + this.dataDoc[this.fieldKey] = new List<Doc>([placeholder, placeholder2]); + } + } + + componentDidMount() { + this.setTitle(); + } + + childRejectDrop = (de: DragManager.DropEvent, subView?: DocumentView) => { + return true; // disable dropping documents onto any child of the scrapbook. + }; + rejectDrop = (de: DragManager.DropEvent, subView?: DocumentView) => { + // Test to see if the dropped doc is dropped on an acceptable location (anywerhe? on a specific box). + // const draggedDocs = de.complete.docDragData?.draggedDocuments; + return false; // allow all Docs to be dropped onto scrapbook -- let filterAddDocument make the final decision. + }; + + filterAddDocument = (docIn: Doc | Doc[]) => { + const docs = toList(docIn); + if (docs?.length === 1) { + const placeholder = DocListCast(this.dataDoc[this.fieldKey]).find(d => + (d.accepts_docType === docs[0].$type || // match fields based on type, or by analyzing content .. simple example of matching text in placeholder to dropped doc's type + RTFCast(d[Doc.LayoutDataKey(d)])?.Text.includes(StrCast(docs[0].$type))) + ); // prettier-ignore + + if (placeholder) { + // ugh. we have to tell the underlying view not to add the Doc so that we can add it where we want it. + // However, returning 'false' triggers an undo. so this settimeout is needed to make the assignment happen after the undo. + setTimeout( + undoable(() => { + //StrListCast(placeholder.overrideFields).map(field => (docs[0][field] = placeholder[field])); // // shouldn't need to do this for layout fields since the placeholder already overrides its protos + placeholder.proto = docs[0]; + }, 'Scrapbook add') + ); + return false; + } + } + return false; + }; + + render() { + return ( + <div style={{ background: 'beige', width: '100%', height: '100%' }}> + <CollectionView + {...this._props} // + setContentViewBox={emptyFunction} + rejectDrop={this.rejectDrop} + childRejectDrop={this.childRejectDrop} + filterAddDocument={this.filterAddDocument} + /> + {/* <div style={{ border: '1px black', borderStyle: 'dotted', position: 'absolute', top: '50%', width: '100%', textAlign: 'center' }}>Drop an image here</div> */} + </div> + ); + } +} + +// Register scrapbook +Docs.Prototypes.TemplateMap.set(DocumentType.SCRAPBOOK, { + layout: { view: ScrapbookBox, dataField: 'items' }, + options: { + acl: '', + _height: 200, + _xMargin: 10, + _yMargin: 10, + _layout_fitWidth: false, + _layout_autoHeight: true, + _layout_reflowVertical: true, + _layout_reflowHorizontal: true, + _freeform_fitContentsToBox: true, + defaultDoubleClick: 'ignore', + systemIcon: 'BsImages', + }, +}); |
