1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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',
},
});
|