aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts76
-rw-r--r--src/client/util/CurrentUserUtils.ts2
-rw-r--r--src/client/util/DragManager.ts1
-rw-r--r--src/client/views/PropertiesButtons.tsx3
-rw-r--r--src/client/views/PropertiesView.tsx2
-rw-r--r--src/client/views/StyleProvider.tsx4
-rw-r--r--src/client/views/collections/CollectionMenu.tsx192
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.scss492
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx698
-rw-r--r--src/client/views/collections/CollectionNoteTakingViewColumn.tsx330
-rw-r--r--src/client/views/collections/CollectionNoteTakingViewDivider.tsx61
-rw-r--r--src/client/views/collections/CollectionStackingView.scss34
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx240
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx22
-rw-r--r--src/client/views/collections/CollectionView.tsx25
-rw-r--r--src/client/views/nodes/DocumentView.tsx26
-rw-r--r--src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx11
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx1
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx1
19 files changed, 2019 insertions, 202 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 64d26e425..31cb0678a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1035,6 +1035,10 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Stacking }, id, undefined, protoId);
}
+ export function NoteTakingDocument(documents: Array<Doc>, options: DocumentOptions, id?: string, protoId?: string) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.NoteTaking }, id, undefined, protoId);
+ }
+
export function MulticolumnDocument(documents: Array<Doc>, options: DocumentOptions) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Multicolumn });
}
@@ -1485,47 +1489,49 @@ export namespace DocUtils {
return ctor ? ctor(path, options) : undefined;
}
- export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false): void {
- !simpleMenu &&
- ContextMenu.Instance.addItem({
- description: 'Quick Notes',
- subitems: DocListCast((Doc.UserDoc()['template-notes'] as Doc).data).map((note, i) => ({
- description: ':' + StrCast(note.title),
- event: undoBatch((args: { x: number; y: number }) => {
- const textDoc = Docs.Create.TextDocument('', {
- _width: 200,
- x,
- y,
- _autoHeight: note._autoHeight !== false,
- title: StrCast(note.title) + '#' + (note.aliasCount = NumCast(note.aliasCount) + 1),
- });
- textDoc.layoutKey = 'layout_' + note.title;
- textDoc[textDoc.layoutKey] = note;
- docTextAdder(textDoc);
- }),
- icon: StrCast(note.icon) as IconProp,
- })) as ContextMenuProps[],
- icon: 'sticky-note',
- });
+ export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false, pivotField?: string, pivotValue?: string): void {
+ !simpleMenu && ContextMenu.Instance.addItem({
+ description: "Quick Notes",
+ subitems: DocListCast((Doc.UserDoc()["template-notes"] as Doc).data).map((note, i) => ({
+ description: ":" + StrCast(note.title),
+ event: undoBatch((args: { x: number, y: number }) => {
+ const textDoc = Docs.Create.TextDocument("", {
+ _width: 200, x, y, _autoHeight: note._autoHeight !== false,
+ title: StrCast(note.title) + "#" + (note.aliasCount = NumCast(note.aliasCount) + 1),
+ });
+ textDoc.layoutKey = "layout_" + note.title;
+ textDoc[textDoc.layoutKey] = note;
+ if (pivotField) {
+ textDoc[pivotField] = pivotValue;
+ }
+ docTextAdder(textDoc);
+ }),
+ icon: StrCast(note.icon) as IconProp
+ })) as ContextMenuProps[],
+ icon: "sticky-note"
+ });
const documentList: ContextMenuProps[] = DocListCast(DocListCast(Doc.MyTools?.data)[0]?.data)
.filter(btnDoc => !btnDoc.hidden)
.map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null))
.filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation)
.map((dragDoc, i) => ({
- description: ':' + StrCast(dragDoc.title).replace('Untitled ', ''),
- event: undoBatch((args: { x: number; y: number }) => {
- const newDoc = DocUtils.copyDragFactory(dragDoc);
- if (newDoc) {
- newDoc.author = Doc.CurrentUserEmail;
- newDoc.x = x;
- newDoc.y = y;
- EquationBox.SelectOnLoad = newDoc[Id];
- if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id];
- docAdder?.(newDoc);
+ description: ":" + StrCast(dragDoc.title).replace("Untitled ",""),
+ event: undoBatch((args: { x: number, y: number }) => {
+ const newDoc = DocUtils.copyDragFactory(dragDoc);
+ if (newDoc) {
+ newDoc.author = Doc.CurrentUserEmail;
+ newDoc.x = x;
+ newDoc.y = y;
+ EquationBox.SelectOnLoad = newDoc[Id];
+ if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id];
+ if (pivotField) {
+ newDoc[pivotField] = pivotValue;
}
- }),
- icon: Doc.toIcon(dragDoc),
- })) as ContextMenuProps[];
+ docAdder?.(newDoc);
+ }
+ }),
+ icon: Doc.toIcon(dragDoc),
+ })) as ContextMenuProps[];
ContextMenu.Instance.addItem({
description: 'Create document',
subitems: documentList,
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index f55ed6e72..28dc44c25 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -669,7 +669,7 @@ export class CurrentUserUtils {
CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Multicolumn,
CollectionViewType.Multirow, CollectionViewType.Time, CollectionViewType.Carousel,
CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map,
- CollectionViewType.Grid]),
+ CollectionViewType.Grid, CollectionViewType.NoteTaking]),
title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: 'setView(value, _readOnly_)'}},
{ title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()'}, width: 20, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
{ title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()'}, width: 20, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 4338072df..3a1bb1673 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -456,6 +456,7 @@ export namespace DragManager {
SnappingManager.SetIsDragging(false);
SnappingManager.clearSnapLines();
batch.end();
+ docsBeingDragged = [];
});
var startWindowDragTimer: any;
const moveHandler = (e: PointerEvent) => {
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 8c4c1d00b..39e7b89c1 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -348,7 +348,8 @@ export class PropertiesButtons extends React.Component<{}, {}> {
const isInk = layoutField instanceof InkField;
const isMap = this.selectedDoc?.type === DocumentType.MAP;
const isCollection = this.selectedDoc?.type === DocumentType.COL;
- const isStacking = this.selectedDoc?._viewType === CollectionViewType.Stacking;
+ //TODO: will likely need to create separate note-taking view type here
+ const isStacking = this.selectedDoc?._viewType === CollectionViewType.Stacking || this.selectedDoc?._viewType === CollectionViewType.NoteTaking;
const isFreeForm = this.selectedDoc?._viewType === CollectionViewType.Freeform;
const isTree = this.selectedDoc?._viewType === CollectionViewType.Tree;
const isTabView = this.selectedTabView;
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index aecbc4255..ef0e057dc 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1616,7 +1616,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
const type = PresBox.Instance.activeItem?.type;
const viewType = PresBox.Instance.activeItem?._viewType;
const pannable: boolean = (type === DocumentType.COL && viewType === CollectionViewType.Freeform) || type === DocumentType.IMG;
- const scrollable: boolean = type === DocumentType.PDF || type === DocumentType.WEB || type === DocumentType.RTF || viewType === CollectionViewType.Stacking;
+ const scrollable: boolean = type === DocumentType.PDF || type === DocumentType.WEB || type === DocumentType.RTF || viewType === CollectionViewType.Stacking || viewType === CollectionViewType.NoteTaking;
return (
<div className="propertiesView" style={{ width: this.props.width }}>
<div className="propertiesView-title" style={{ width: this.props.width }}>
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 334f381be..692f7b98e 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -110,6 +110,8 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
return undefined;
case StyleProp.WidgetColor:
return isAnnotated ? Colors.LIGHT_BLUE : darkScheme() ? 'lightgrey' : 'dimgrey';
+ // return doc = dragManager.dragDocument ? props.dragEffects.opacity??CastofOpacityonline94 : Cast())
+ // same idea for background Color
case StyleProp.Opacity:
return Cast(doc?._opacity, 'number', Cast(doc?.opacity, 'number', null));
case StyleProp.HideLinkButton:
@@ -154,7 +156,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
case StyleProp.JitterRotation:
return comicStyle() ? random(-1, 1, NumCast(doc?.x), NumCast(doc?.y)) * ((props?.PanelWidth() || 0) > (props?.PanelHeight() || 0) ? 5 : 10) : 0;
case StyleProp.HeaderMargin:
- return ([CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._viewType as any) || (doc?.type === DocumentType.RTF && !showTitle()?.includes('noMargin')) || doc?.type === DocumentType.LABEL) &&
+ return ([CollectionViewType.Stacking, CollectionViewType.NoteTaking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._viewType as any) || (doc?.type === DocumentType.RTF && !showTitle()?.includes('noMargin')) || doc?.type === DocumentType.LABEL) &&
showTitle() &&
!StrCast(doc?.showTitle).includes(':hover')
? 15
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 2c0e44bc3..aa1765c14 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -311,44 +311,25 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
},
};
- @computed get _freeform_commands() {
- return Doc.noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand];
- }
- @computed get _stacking_commands() {
- return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand];
- }
- @computed get _masonry_commands() {
- return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand];
- }
- @computed get _schema_commands() {
- return Doc.noviceMode ? undefined : [this._templateCommand, this._narrativeCommand];
- }
- @computed get _doc_commands() {
- return Doc.noviceMode ? undefined : [this._openLinkInCommand, this._onClickCommand];
- }
- @computed get _tree_commands() {
- return undefined;
- }
+ @computed get _freeform_commands() { return Doc.noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
+ @computed get _stacking_commands() { return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
+ @computed get _notetaking_commands() { return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
+ @computed get _masonry_commands() { return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
+ @computed get _schema_commands() { return Doc.noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; }
+ @computed get _doc_commands() { return Doc.noviceMode ? undefined : [this._openLinkInCommand, this._onClickCommand]; }
+ @computed get _tree_commands() { return undefined; }
private get _buttonizableCommands() {
switch (this.props.type) {
- default:
- return this._doc_commands;
- case CollectionViewType.Freeform:
- return this._freeform_commands;
- case CollectionViewType.Tree:
- return this._tree_commands;
- case CollectionViewType.Schema:
- return this._schema_commands;
- case CollectionViewType.Stacking:
- return this._stacking_commands;
- case CollectionViewType.Masonry:
- return this._stacking_commands;
- case CollectionViewType.Time:
- return this._freeform_commands;
- case CollectionViewType.Carousel:
- return this._freeform_commands;
- case CollectionViewType.Carousel3D:
- return this._freeform_commands;
+ default: return this._doc_commands;
+ case CollectionViewType.Freeform: return this._freeform_commands;
+ case CollectionViewType.Tree: return this._tree_commands;
+ case CollectionViewType.Schema: return this._schema_commands;
+ case CollectionViewType.Stacking: return this._stacking_commands;
+ case CollectionViewType.NoteTaking: return this._notetaking_commands;
+ case CollectionViewType.Masonry: return this._stacking_commands;
+ case CollectionViewType.Time: return this._freeform_commands;
+ case CollectionViewType.Carousel: return this._freeform_commands;
+ case CollectionViewType.Carousel3D: return this._freeform_commands;
}
}
private _commandRef = React.createRef<HTMLInputElement>();
@@ -382,16 +363,12 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
default:
return this.otherSubChrome;
case CollectionViewType.Invalid:
- case CollectionViewType.Freeform:
- return <CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} />;
- case CollectionViewType.Stacking:
- return <CollectionStackingViewChrome key="collchrome" {...this.props} />;
- case CollectionViewType.Schema:
- return <CollectionSchemaViewChrome key="collchrome" {...this.props} />;
- case CollectionViewType.Tree:
- return <CollectionTreeViewChrome key="collchrome" {...this.props} />;
- case CollectionViewType.Masonry:
- return <CollectionStackingViewChrome key="collchrome" {...this.props} />;
+ case CollectionViewType.Freeform: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} />);
+ case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
+ case CollectionViewType.NoteTaking: return (<CollectionNoteTakingViewChrome key="collchrome" {...this.props} />);
+ case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" {...this.props} />);
+ case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" {...this.props} />);
+ case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
case CollectionViewType.Carousel:
case CollectionViewType.Carousel3D:
return <Collection3DCarouselViewChrome key="collchrome" {...this.props} />;
@@ -588,7 +565,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
const size: number = PresBox.Instance?._selectedArray.size;
const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
const activeDoc = presSelected ? PresBox.Instance?.childDocs[PresBox.Instance?.childDocs.indexOf(presSelected) + 1] : PresBox.Instance?.childDocs[PresBox.Instance?.childDocs.length - 1];
- if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
+ if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking || targetDoc._viewType === CollectionViewType.NoteTaking) {
const scroll = targetDoc._scrollTop;
activeDoc.presPinView = true;
activeDoc.presPinViewScroll = scroll;
@@ -1146,6 +1123,127 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView
}
@observer
+export class CollectionNoteTakingViewChrome extends React.Component<CollectionViewMenuProps> {
+ @observable private _currentKey: string = "";
+ @observable private suggestions: string[] = [];
+
+ get document() { return this.props.docView.props.Document; }
+
+ @computed private get descending() { return StrCast(this.document._columnsSort) === "descending"; }
+ @computed get pivotField() { return StrCast(this.document._pivotField); }
+
+ getKeySuggestions = async (value: string): Promise<string[]> => {
+ const val = value.toLowerCase();
+ const docs = DocListCast(this.document[this.props.fieldKey]);
+
+ if (Doc.UserDoc().noviceMode) {
+ if (docs instanceof Doc) {
+ const keys = Object.keys(docs).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 ||
+ key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 ||
+ (key[0].toUpperCase() === key[0] && key[0] !== "_"));
+ return keys.filter(key => key.toLowerCase().indexOf(val) > -1);
+ } else {
+ const keys = new Set<string>();
+ docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
+ const noviceKeys = Array.from(keys).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 ||
+ key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 ||
+ (key[0]?.toUpperCase() === key[0] && key[0] !== "_"));
+ return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1);
+ }
+ }
+
+ if (docs instanceof Doc) {
+ return Object.keys(docs).filter(key => key.toLowerCase().indexOf(val) > -1);
+ } else {
+ const keys = new Set<string>();
+ docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
+ return Array.from(keys).filter(key => key.toLowerCase().indexOf(val) > -1);
+ }
+ }
+
+ @action
+ onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => {
+ this._currentKey = newValue;
+ }
+
+ getSuggestionValue = (suggestion: string) => suggestion;
+
+ renderSuggestion = (suggestion: string) => {
+ return <p>{suggestion}</p>;
+ }
+
+ onSuggestionFetch = async ({ value }: { value: string }) => {
+ const sugg = await this.getKeySuggestions(value);
+ runInAction(() => {
+ this.suggestions = sugg;
+ });
+ }
+
+ @action
+ onSuggestionClear = () => {
+ this.suggestions = [];
+ }
+
+ @action
+ setValue = (value: string) => {
+ this.document._pivotField = value;
+ return true;
+ }
+
+ @action toggleSort = () => {
+ this.document._columnsSort =
+ this.document._columnsSort === "descending" ? "ascending" :
+ this.document._columnsSort === "ascending" ? undefined : "descending";
+ }
+ @action resetValue = () => { this._currentKey = this.pivotField; };
+
+ render() {
+ const doctype = this.props.docView.Document.type;
+ const isPres: boolean = (doctype === DocumentType.PRES);
+ return (
+ isPres ? (null) : <div className="collectionStackingViewChrome-cont">
+ <div className="collectionStackingViewChrome-pivotField-cont">
+ <div className="collectionStackingViewChrome-pivotField-label">
+ GROUP BY:
+ </div>
+ <div className="collectionStackingViewChrome-sortIcon" onClick={this.toggleSort} style={{ transform: `rotate(${this.descending ? "180" : "0"}deg)` }}>
+ <FontAwesomeIcon icon="caret-up" size="2x" color="white" />
+ </div>
+ <div className="collectionStackingViewChrome-pivotField">
+ <EditableView
+ GetValue={() => this.pivotField}
+ autosuggestProps={
+ {
+ resetValue: this.resetValue,
+ value: this._currentKey,
+ onChange: this.onKeyChange,
+ autosuggestProps: {
+ inputProps:
+ {
+ value: this._currentKey,
+ onChange: this.onKeyChange
+ },
+ getSuggestionValue: this.getSuggestionValue,
+ suggestions: this.suggestions,
+ alwaysRenderSuggestions: true,
+ renderSuggestion: this.renderSuggestion,
+ onSuggestionsFetchRequested: this.onSuggestionFetch,
+ onSuggestionsClearRequested: this.onSuggestionClear
+ }
+ }}
+ oneLine
+ SetValue={this.setValue}
+ contents={this.pivotField ? this.pivotField : "N/A"}
+ />
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
+
+
+@observer
export class CollectionSchemaViewChrome extends React.Component<CollectionViewMenuProps> {
// private _textwrapAllRows: boolean = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []).length > 0;
get document() {
diff --git a/src/client/views/collections/CollectionNoteTakingView.scss b/src/client/views/collections/CollectionNoteTakingView.scss
new file mode 100644
index 000000000..a878033ed
--- /dev/null
+++ b/src/client/views/collections/CollectionNoteTakingView.scss
@@ -0,0 +1,492 @@
+@import "../global/globalCssVariables";
+
+.collectionNoteTakingView-DocumentButtons {
+ display: flex;
+ justify-content: space-between;
+ margin: auto;
+}
+
+.collectionNoteTakingView-addDocumentButton {
+ display: flex;
+ overflow: hidden;
+ margin: auto;
+ width: 100%;
+ overflow: ellipses;
+
+ .editableView-container-editing-oneLine,
+ .editableView-container-editing {
+ color: grey;
+ padding: 10px;
+ width: 100%;
+ }
+
+ .editableView-input:hover,
+ .editableView-container-editing:hover,
+ .editableView-container-editing-oneLine:hover {
+ cursor: text
+ }
+
+ .editableView-input {
+ outline-color: black;
+ letter-spacing: 2px;
+ color: grey;
+ border: 0px;
+ padding: 12px 10px 11px 10px;
+ }
+
+ font-size: 75%;
+ letter-spacing: 2px;
+ cursor: pointer;
+
+ .editableView-input {
+ outline-color: black;
+ letter-spacing: 2px;
+ color: grey;
+ border: 0px;
+ padding: 12px 10px 11px 10px;
+ }
+}
+
+.collectionNoteTakingView {
+ display: flex;
+}
+
+// TODO:glr Turn this into a seperate class
+.documentButtonMenu {
+ position: relative;
+ height: fit-content;
+ border-bottom: $standard-border;
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ align-content: center;
+ padding: 5px 0 5px 0;
+
+ .documentExplanation {
+ width: 90%;
+ margin: 5px;
+ font-size: 11px;
+ background-color: $light-blue;
+ color: $medium-blue;
+ padding: 10px;
+ border-radius: 10px;
+ border: solid 2px $medium-blue;
+ }
+}
+
+.collectionNoteTakingView {
+ height: 100%;
+ width: 100%;
+ position: absolute;
+ top: 0;
+ overflow-y: auto;
+ overflow-x: hidden;
+ flex-wrap: wrap;
+ transition: top .5s;
+
+ >div {
+ position: relative;
+ display: block;
+ }
+
+ .collectionNoteTakingViewFieldColumn {
+ height: max-content;
+ }
+
+ .collectionNoteTakingViewFieldColumnDragging {
+ height: 100%;
+ }
+
+ .collectionSchemaView-previewDoc {
+ height: 100%;
+ position: absolute;
+ }
+
+ .collectionNoteTakingView-docView-container {
+ width: 45%;
+ margin: 5% 2.5%;
+ padding-left: 2.5%;
+ height: auto;
+ }
+
+ .collectionNoteTakingView-Nodes {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ top: 0;
+ left: 0;
+ width: 100%;
+ position: absolute;
+ }
+
+ .collectionNoteTakingView-description {
+ font-size: 100%;
+ margin-bottom: 1vw;
+ padding: 10px;
+ height: 2vw;
+ width: 100%;
+ font-family: $sans-serif;
+ background: $dark-gray;
+ color: $white;
+ }
+
+ .collectionNoteTakingView-columnDragger {
+ width: 15;
+ height: 15;
+ position: absolute;
+ margin-left: -5;
+ }
+
+ // Documents in NoteTaking view
+ .collectionNoteTakingView-columnDoc {
+ display: flex;
+ // margin: auto; // Removed auto so that it is no longer center aligned - this could be something we change
+ position: relative;
+
+ &:hover {
+ .hoverButtons{
+ opacity: 1;
+ }
+ }
+
+ .hoverButtons {
+ display: flex;
+ opacity: 0;
+ position: absolute;
+ height: 100%;
+ left: -35px;
+ justify-content: center;
+ align-items: center;
+ padding: 0px 10px;
+
+ .buttonWrapper {
+ padding: 3px;
+ border-radius: 3px;
+
+ &:hover {
+ background: rgba(0, 0, 0, 0.26);
+ }
+ }
+ }
+ }
+
+ .collectionNoteTakingView-collapseBar {
+ margin-left: 2px;
+ margin-right: 2px;
+ margin-top: 2px;
+ background: $medium-gray;
+ height: 5px;
+
+ &.active {
+ margin-left: 0;
+ margin-right: 0;
+ background: red;
+ }
+ }
+
+ .collectionNoteTakingView-miniHeader {
+ width: 100%;
+
+ .editableView-container-editing-oneLine {
+ min-height: 20px;
+ display: flex;
+ align-items: center;
+ flex-direction: row;
+ }
+
+ span::before,
+ span::after {
+ content: "";
+ width: 50%;
+ border-top: dashed gray 1px;
+ position: relative;
+ display: inline-block;
+ }
+
+ span::before {
+ margin-right: 10px;
+ }
+
+ span::after {
+ margin-left: 10px;
+ }
+
+ span {
+ position: relative;
+ text-align: center;
+ white-space: nowrap;
+ overflow: visible;
+ width: 100%;
+ display: flex;
+ color: gray;
+ align-items: center;
+ }
+ }
+
+ .collectionNoteTakingView-sectionHeader {
+ text-align: center;
+ margin: auto;
+ margin-bottom: 10px;
+ background: $medium-gray;
+ // overflow: hidden; overflow is visible so the color menu isn't hidden -ftong
+
+ .editableView-input {
+ color: $dark-gray;
+ }
+
+ .editableView-input:hover,
+ .editableView-container-editing:hover,
+ .editableView-container-editing-oneLine:hover {
+ cursor: text
+ }
+
+ .collectionNoteTakingView-sectionHeader-subCont {
+ outline: none;
+ border: 0px;
+ width: 100%;
+ letter-spacing: 2px;
+ font-size: 75%;
+ transition: transform 0.2s;
+ position: relative;
+ height: 30px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: $dark-gray;
+
+ .editableView-container-editing-oneLine,
+ .editableView-container-editing {
+ color: grey;
+ padding: 10px;
+ }
+
+ .editableView-input:hover,
+ .editableView-container-editing:hover,
+ .editableView-container-editing-oneLine:hover {
+ cursor: text;
+ }
+
+ .editableView-input {
+ padding: 12px 10px 11px 10px;
+ border: 0px;
+ color: grey;
+ text-align: center;
+ letter-spacing: 2px;
+ outline-color: black;
+ }
+ }
+
+ .collectionNoteTakingView-sectionColor {
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 100%;
+ display: none;
+
+ [class*="css"] {
+ max-width: 102px;
+ }
+
+ .collectionNoteTakingView-sectionColorButton {
+ height: 30px;
+ display: inherit;
+ }
+
+ .collectionNoteTakingView-colorPicker {
+ width: 78px;
+ z-index: 10;
+ position: relative;
+ background: white;
+
+ .colorOptions {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .colorPicker {
+ cursor: pointer;
+ width: 20px;
+ height: 20px;
+ border-radius: 10px;
+ margin: 3px;
+
+ &.active {
+ border: 2px solid white;
+ box-shadow: 0 0 0 2px lightgray;
+ }
+ }
+ }
+ }
+
+ .collectionNoteTakingView-sectionOptions {
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 100%;
+ display: none;
+
+ [class*="css"] {
+ max-width: 102px;
+ }
+
+ .collectionNoteTakingView-sectionOptionButton {
+ height: 30px;
+ }
+
+ .collectionNoteTakingView-optionPicker {
+
+ .optionOptions {
+ display: inline;
+ }
+
+ .optionPicker {
+ cursor: pointer;
+ height: 20px;
+ border-radius: 10px;
+ margin: 3px;
+ width: max-content;
+
+ &.active {
+ color: red;
+ }
+ }
+ }
+ }
+
+ .collectionNoteTakingView-sectionDelete {
+ position: absolute;
+ right: 25px;
+ top: 0;
+ height: 100%;
+ display: none;
+ }
+ }
+
+ .collectionNoteTakingView-sectionHeader:hover {
+ .collectionNoteTakingView-sectionColor {
+ display: unset;
+ }
+
+ .collectionNoteTakingView-sectionOptions {
+ display: unset;
+ }
+
+ .collectionNoteTakingView-sectionDelete {
+ display: unset;
+ }
+ }
+
+ .collectionNoteTakingView-addDocumentButton,
+ .collectionNoteTakingView-addGroupButton {
+ display: flex;
+ overflow: hidden;
+ margin: auto;
+ width: 90%;
+ overflow: ellipses;
+
+ .editableView-container-editing-oneLine,
+ .editableView-container-editing {
+ color: grey;
+ padding: 10px;
+ width: 100%;
+ }
+
+ .editableView-input:hover,
+ .editableView-container-editing:hover,
+ .editableView-container-editing-oneLine:hover {
+ cursor: text
+ }
+
+ .editableView-input {
+ outline-color: black;
+ letter-spacing: 2px;
+ color: grey;
+ border: 0px;
+ padding: 12px 10px 11px 10px;
+ }
+ }
+
+ .collectionNoteTakingView-addDocumentButton {
+ font-size: 75%;
+ letter-spacing: 2px;
+ cursor: pointer;
+
+ .editableView-input {
+ outline-color: black;
+ letter-spacing: 2px;
+ color: grey;
+ border: 0px;
+ padding: 12px 10px 11px 10px;
+ }
+ }
+
+ .collectionNoteTakingView-addGroupButton {
+ background: rgb(238, 238, 238);
+ font-size: 75%;
+ text-align: center;
+ letter-spacing: 2px;
+ height: fit-content;
+ }
+
+ .rc-switch {
+ position: absolute;
+ display: inline-block;
+ bottom: 4px;
+ right: 4px;
+ width: 70px;
+ height: 30px;
+ border-radius: 40px 40px;
+ background-color: lightslategrey;
+ }
+
+ .rc-switch:after {
+ position: absolute;
+ width: 22px;
+ height: 22px;
+ left: 3px;
+ top: 4px;
+ border-radius: 50% 50%;
+ background-color: #fff;
+ content: " ";
+ cursor: pointer;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26);
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ transition: left 0.3s cubic-bezier(0.35, 0, 0.25, 1);
+ -webkit-animation-timing-function: cubic-bezier(0.35, 0, 0.25, 1);
+ animation-timing-function: cubic-bezier(0.35, 0, 0.25, 1);
+ -webkit-animation-duration: 0.3s;
+ animation-duration: 0.3s;
+ }
+
+ .rc-switch-checked:after {
+ left: 44px;
+ }
+
+ .rc-switch-inner {
+ color: #fff;
+ font-size: 12px;
+ position: absolute;
+ left: 28px;
+ top: 8px;
+ }
+
+ .rc-switch-checked .rc-switch-inner {
+ left: 8px;
+ }
+}
+
+@media only screen and (max-device-width: 480px) {
+
+ .collectionNoteTakingView .collectionNoteTakingView-columnDragger,
+ .collectionNoteTakingView-columnDragger {
+ width: 0.1;
+ height: 0.1;
+ opacity: 0;
+ font-size: 0;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
new file mode 100644
index 000000000..eb81f6e5e
--- /dev/null
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -0,0 +1,698 @@
+import React = require("react");
+import { CursorProperty } from "csstype";
+import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
+import { observer } from "mobx-react";
+import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
+import { Copy, Id, ToScriptString, ToString } from "../../../fields/FieldSymbols";
+import { List } from "../../../fields/List";
+import { listSpec } from "../../../fields/Schema";
+import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
+import { TraceMobx } from "../../../fields/util";
+import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, smoothScroll, Utils } from "../../../Utils";
+import { Docs, DocUtils } from "../../documents/Documents";
+import { DocumentType } from '../../documents/DocumentTypes';
+import { DragManager, dropActionType } from "../../util/DragManager";
+import { SnappingManager } from "../../util/SnappingManager";
+import { Transform } from "../../util/Transform";
+import { undoBatch } from "../../util/UndoManager";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
+import { LightboxView } from "../LightboxView";
+import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
+import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from "../nodes/DocumentView";
+import { StyleProp } from "../StyleProvider";
+import "./CollectionNoteTakingView.scss";
+import CollectionNoteTakingViewDivider from "./CollectionNoteTakingViewDivider";
+import { CollectionNoteTakingViewColumn } from "./CollectionNoteTakingViewColumn";
+import { CollectionSubView } from "./CollectionSubView";
+import { CollectionViewType } from "./CollectionView";
+import { ObjectField } from "../../../fields/ObjectField";
+import { faThumbsDown } from "@fortawesome/free-solid-svg-icons";
+const _global = (window /* browser */ || global /* node */) as any;
+
+export type collectionNoteTakingViewProps = {
+ chromeHidden?: boolean;
+ viewType?: CollectionViewType;
+ NativeWidth?: () => number;
+ NativeHeight?: () => number;
+};
+
+//TODO: somehow need to update the mapping and then have everything else rerender. Maybe with a refresh boolean like
+// in Hypermedia?
+
+@observer
+export class CollectionNoteTakingView extends CollectionSubView<Partial<collectionNoteTakingViewProps>>() {
+ _pivotFieldDisposer?: IReactionDisposer;
+ _autoHeightDisposer?: IReactionDisposer;
+ _masonryGridRef: HTMLDivElement | null = null;
+ _draggerRef = React.createRef<HTMLDivElement>();
+ // _docXfs: { height: () => number, width: () => number, noteTakingDocTransform: () => Transform }[] = [];
+ // @observable _docsByColumnHeader = new Map<string, Doc[]>();
+ //TODO: need to make sure that we save the mapping
+ @observable docsDraggedRowCol: number[] = [];
+ @observable _cursor: CursorProperty = "grab";
+ @observable _scroll = 0; // used to force the document decoration to update when scrolling
+ @computed get chromeHidden() { return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); }
+ @computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null); }
+ @computed get pivotField() { return "Col" }
+ @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => (pair.layout instanceof Doc) && !pair.layout.hidden).map(pair => pair.layout); }
+ @computed get headerMargin() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); }
+ @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); }
+ @computed get yMargin() { return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5); } // 2 * this.gridGap)); }
+ @computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); }
+ @computed get numGroupColumns() { return this.columnHeaders.length; }
+ @observable columnStartXCoords: number[] = []
+ @computed get PanelWidth() {return this.props.PanelWidth()}
+ @computed get maxColWdith() {return this.props.PanelWidth() - 2 * this.xMargin;}
+
+ // If the user has not yet created any docs (in another view), this will create a single column. Otherwise,
+ // it will adjust according to the
+ constructor(props: any) {
+ super(props);
+ if (this.columnHeaders === undefined) {
+ this.layoutDoc._columnHeaders = new List<SchemaHeaderField>([new SchemaHeaderField('New Column')]);
+ this.columnStartXCoords = [0]
+ // add all of the docs that have not been added to a column to this new column
+ } else {
+ const numHeaders = this.columnHeaders.length
+ this.resizeColumns(numHeaders)
+ }
+ }
+
+ // passed as a prop to the NoteTakingField, which uses this function
+ // to render the docs you see within an individual column.
+ children = (docs: Doc[]) => {
+ TraceMobx();
+ return docs.map((d, i) => {
+ const height = () => this.getDocHeight(d);
+ const width = () => this.getDocWidth(d);
+ const style = { width: width(), marginTop: this.gridGap, height: height() };
+ return <div className={`collectionNoteTakingView-columnDoc`} key={d[Id]} style={style} >
+ {this.getDisplayDoc(d, width)}
+ </div>;
+ });
+ }
+
+ // [CAVEATS] (1) keep track of the offsetting
+ // (2) documentView gets unmounted as you remove it from the list
+ get Sections() {
+ const columnHeaders = this.columnHeaders;
+ const sections = new Map<SchemaHeaderField, Doc[]>(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
+ let docs = this.childDocs
+ const rowCol = this.docsDraggedRowCol
+
+ // filter out the currently dragged docs from the child docs, since we will insert them later
+ if (rowCol.length && DragManager.docsBeingDragged.length) {
+ const docIdsToRemove = new Set()
+ DragManager.docsBeingDragged.forEach(d => {
+ docIdsToRemove.add(d[Id])
+ })
+ docs = docs.filter(d => !docIdsToRemove.has(d[Id]))
+ }
+
+ // this will sort the docs into the correct columns (minus the ones you're currently dragging)
+ docs.map(d => {
+ if (!d[this.pivotField]) {
+ d[this.pivotField] = columnHeaders.length > 0 ? columnHeaders[0].heading : `New Column`
+ };
+ const sectionValue = d[this.pivotField] as object;
+
+ // look for if header exists already
+ const existingHeader = columnHeaders.find(sh => sh.heading === sectionValue.toString());
+ if (existingHeader) {
+ sections.get(existingHeader)!.push(d);
+ }
+ });
+
+ // now we add back in the docs that we're dragging
+ if (rowCol.length && DragManager.docsBeingDragged.length) {
+ const colHeader = columnHeaders[rowCol[1]]
+ // TODO: get the actual offset that occurs if the docs were in that column
+ const offset = 0
+ sections.get(colHeader)?.splice(rowCol[0] - offset, 0, ...DragManager.docsBeingDragged)
+ }
+ return sections;
+ }
+
+ componentDidMount() {
+ super.componentDidMount?.();
+ // reset section headers when a new filter is inputted
+ this._pivotFieldDisposer = reaction(
+ () => this.pivotField,
+ () => this.layoutDoc._columnHeaders = new List()
+ );
+
+ this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight,
+ autoHeight => autoHeight && this.props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
+ this.headerMargin + Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))))));
+ }
+
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this._pivotFieldDisposer?.();
+ this._autoHeightDisposer?.();
+ }
+
+ @action
+ moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean): boolean => {
+ return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false;
+ }
+
+ createRef = (ele: HTMLDivElement | null) => {
+ this._masonryGridRef = ele;
+ this.createDashEventsTarget(ele!); //so the whole grid is the drop target?
+ }
+
+ @computed get onChildClickHandler() { return () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); }
+ @computed get onChildDoubleClickHandler() { return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); }
+
+ addDocTab = (doc: Doc, where: string) => {
+ if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+ this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
+ return true;
+ }
+ return this.props.addDocTab(doc, where);
+ }
+
+ scrollToBottom = () => {
+ smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight);
+ }
+
+ // let's dive in and get the actual document we want to drag/move around
+ focusDocument = (doc: Doc, options?: DocFocusOptions) => {
+ Doc.BrushDoc(doc);
+
+ let focusSpeed = 0;
+ const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName("documentView-node")).find((node: any) => node.id === doc[Id]);
+ if (found) {
+ const top = found.getBoundingClientRect().top;
+ const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
+ if (Math.floor(localTop[1]) !== 0) {
+ smoothScroll(focusSpeed = doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+ }
+ }
+ const endFocus = async (moved: boolean) => options?.afterFocus ? options?.afterFocus(moved) : ViewAdjustment.doNothing;
+ this.props.focus(this.rootDoc, {
+ willZoom: options?.willZoom, scale: options?.scale, afterFocus: (didFocus: boolean) =>
+ new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed))
+ });
+ }
+
+ styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => {
+ if (property === StyleProp.Opacity && doc) {
+ if (this.props.childOpacity) {
+ return this.props.childOpacity();
+ }
+ if (this.Document._currentFrame !== undefined) {
+ return CollectionFreeFormDocumentView.getValues(doc, NumCast(this.Document._currentFrame))?.opacity;
+ }
+ }
+ return this.props.styleProvider?.(doc, props, property);
+ }
+
+ isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+
+ // rules for displaying the documents
+ getDisplayDoc(doc: Doc, width: () => number) {
+ const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc;
+ const height = () => this.getDocHeight(doc);
+ let dref: Opt<DocumentView>;
+ const noteTakingDocTransform = () => this.getDocTransform(doc, dref);
+ return <DocumentView ref={r => dref = r || undefined}
+ Document={doc}
+ DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])}
+ renderDepth={this.props.renderDepth + 1}
+ PanelWidth={width}
+ PanelHeight={height}
+ styleProvider={this.styleProvider}
+ docViewPath={this.props.docViewPath}
+ fitWidth={this.props.childFitWidth}
+ isContentActive={emptyFunction}
+ originalBackgroundColor={StrCast(doc.backgroundColor)}
+ //TODO: change this from a prop to a parameter passed into a function
+ isNoteTakingView={true}
+ isDocumentActive={this.isContentActive}
+ LayoutTemplate={this.props.childLayoutTemplate}
+ LayoutTemplateString={this.props.childLayoutString}
+ NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeWidth(doc) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
+ NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeHeight(doc) ? height : undefined}
+ dontCenter={this.props.childIgnoreNativeSize ? "xy" : undefined}
+ dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)}
+ rootSelected={this.rootSelected}
+ showTitle={this.props.childShowTitle}
+ dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
+ onClick={this.onChildClickHandler}
+ onDoubleClick={this.onChildDoubleClickHandler}
+ ScreenToLocalTransform={noteTakingDocTransform}
+ focus={this.focusDocument}
+ docFilters={this.childDocFilters}
+ hideDecorationTitle={this.props.childHideDecorationTitle?.()}
+ hideResizeHandles={this.props.childHideResizeHandles?.()}
+ hideTitle={this.props.childHideTitle?.()}
+ docRangeFilters={this.childDocRangeFilters}
+ searchFilterDocs={this.searchFilterDocs}
+ ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+ ContainingCollectionView={this.props.CollectionView}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ removeDocument={this.props.removeDocument}
+ contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+ addDocTab={this.addDocTab}
+ bringToFront={returnFalse}
+ scriptContext={this.props.scriptContext}
+ pinToPres={this.props.pinToPres}
+ />;
+ }
+
+ // This is used to get the coordinates of a document when we go from a view like freeform to columns
+ getDocTransform(doc: Doc, dref?: DocumentView) {
+ const y = this._scroll; // required for document decorations to update when the text box container is scrolled
+ const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined);
+ // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off
+ return new Transform(- translateX + (dref?.centeringX || 0), - translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale);
+ }
+
+ // how to get the width of a document. Currently returns the width of the column (minus margins)
+ // if a note doc. Otherwise, returns the normal width (for graphs, images, etc...)
+ getDocWidth(d: Doc) {
+ const heading = d[this.pivotField] as object
+ const castedSectionValue = heading.toString()
+ const existingHeader = this.columnHeaders.find(sh => sh.heading === (castedSectionValue));
+ const colStartXCoords = this.columnStartXCoords
+ if (!existingHeader) {
+ return 1000
+ }
+ const index = this.columnHeaders.indexOf(existingHeader)
+ const endColValue = index == this.columnHeaders.length - 1 ? this.PanelWidth : this.columnStartXCoords[index+1]
+ const maxWidth = endColValue - colStartXCoords[index] - 3 * this.xMargin
+ if (d.type === DocumentType.RTF) {
+ return maxWidth
+ }
+ const width = d[WidthSym]()
+ return width < maxWidth ? width : maxWidth
+ }
+
+ // how to get the height of a document. Nothing special here.
+ getDocHeight(d?: Doc) {
+ if (!d || d.hidden) return 0;
+ const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+ const childDataDoc = (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc;
+ const maxHeight = (lim => lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim)(NumCast(this.layoutDoc.childLimitHeight, -1));
+ const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0);
+ const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0);
+ if (nw && nh) {
+ // const colWid = this.columnWidth / this.numGroupColumns;
+ // const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid);
+ const docWid = this.getDocWidth(d)
+ return Math.min(
+ maxHeight,
+ docWid * nh / nw);
+ }
+ const childHeight = NumCast(childLayoutDoc._height);
+ const panelHeight = (childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin;
+ return Math.min(childHeight, maxHeight, panelHeight);
+ }
+
+ // called when a column is either added or deleted. This function creates n evenly spaced columns
+ resizeColumns = (n: number) => {
+ const totalWidth = this.PanelWidth
+ const dividerWidth = 32
+ const totaldividerWidth = (n - 1) * dividerWidth
+ const colWidth = (totalWidth - totaldividerWidth) / n
+ const newColXCoords: number[] = []
+ let colStart = 0
+ for (let i = 0; i < n; i++) {
+ newColXCoords.push(colStart)
+ colStart += colWidth + dividerWidth
+ }
+ this.columnStartXCoords = newColXCoords
+ }
+
+ // This function is used to preview where a document will drop in a column once a drag is complete.
+ @action
+ onPointerOver = (e: React.PointerEvent) => {
+ if (DragManager.docsBeingDragged.length && this.childDocList) {
+ // get the current docs for the column based on the mouse's x coordinate
+ // will use again later, which is why we're saving as local
+ const xCoord = e.clientX - 2 * this.gridGap
+ const colDocs = this.getDocsFromXCoord(xCoord)
+ // get the index for where you need to insert the doc you are currently dragging
+ const clientY = e.clientY
+ let dropInd = -1;
+ // unsure whether we still want this dropAfter field
+ // let dropAfter = 0;
+ // manually set to 140, because not sure how to get exact value
+ let pos0 = 140
+ colDocs.forEach((doc, i) => {
+ const noteTakingDocTransform = () => this.getDocTransform(doc);
+ let pos1 = noteTakingDocTransform().inverse().transformPoint(0, this.getDocHeight(doc) + 2 * this.gridGap)[1];
+ pos1 += pos0
+ // updating drop position based on y coordinates
+ const yCoordInBetween = clientY > pos0 && (clientY < pos1 || i == colDocs.length - 1)
+ if (yCoordInBetween) {
+ dropInd = i;
+ // dropAfter = 0;
+ if (clientY > (pos0 + pos1) / 2) {
+ // dropAfter = 1;
+ }
+ }
+ pos0 = pos1
+ })
+ // we alter the pivot fields of the docs in case they are moved to a new column.
+ const colIndex = this.getColumnFromXCoord(xCoord)
+ const colHeader = StrCast(this.columnHeaders[colIndex].heading)
+ DragManager.docsBeingDragged.forEach(d => d[this.pivotField] = colHeader)
+ // used to notify sections to re-render
+ // console.log([dropInd, this.getColumnFromXCoord(xCoord)])
+ this.docsDraggedRowCol = [dropInd, this.getColumnFromXCoord(xCoord)]
+ }
+ }
+
+ // returns the column index for a given x-coordinate
+ getColumnFromXCoord = (xCoord: number): number => {
+ const numColumns = this.columnHeaders.length
+ const coords = this.columnStartXCoords.slice()
+ coords.push(this.PanelWidth)
+ let colIndex = 0
+ for (let i = 0; i < numColumns; i++) {
+ if (xCoord > coords[i] && xCoord < coords[i + 1]) {
+ colIndex = i
+ break
+ }
+ }
+ return colIndex
+ }
+
+ // returns the docs of a column based on the x-coordinate provided.
+ getDocsFromXCoord = (xCoord: number): Doc[] => {
+ const colIndex = this.getColumnFromXCoord(xCoord)
+ const colHeader = StrCast(this.columnHeaders[colIndex].heading)
+ // const docs = this.childDocList
+ const docs = this.childDocs
+ const docsMatchingHeader: Doc[] = []
+ if (docs) {
+ docs.map(d => {
+ if (d instanceof Promise) return;
+ const sectionValue = d[this.pivotField] as object;
+ if (sectionValue.toString() == colHeader) {
+ docsMatchingHeader.push(d)
+ }
+ })
+ }
+ return docsMatchingHeader;
+ }
+
+ @undoBatch
+ @action
+ onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
+ if (de.complete.docDragData) {
+ if (super.onInternalDrop(e, de)) {
+ DragManager.docsBeingDragged = []
+ // this.docsDraggedRowCol = []
+ // filter out the currently dragged docs from the child docs, since we will insert them later
+ const rowCol = this.docsDraggedRowCol
+ const droppedDocs = this.childDocs.slice().filter((d: Doc, ind: number) => ind >= this.childDocs.length); // if the drop operation adds something to the end of the list, then use that as the new document (may be different than what was dropped e.g., in the case of a button which is dropped but which creates say, a note).
+ const newDocs = droppedDocs.length ? droppedDocs : de.complete.docDragData.droppedDocuments;
+
+ // const docs = this.childDocs
+ const docs = this.childDocList
+ if (docs && newDocs.length) {
+ // remove the dragged documents from the childDocList
+ newDocs.filter(d => docs.indexOf(d) !== -1).forEach(d => docs.splice(docs.indexOf(d), 1))
+ // if the doc starts a columnm (or the drop index is undefined), we can just push it to the front. Otherwise we need to add it to the column properly
+ //TODO: you need to update childDocList instead. It seems that childDocs is a copy of the actual array we want to modify
+ if (rowCol[0] <= 0) {
+ docs.splice(0, 0, ...newDocs)
+ } else {
+ const colDocs = this.getDocsFromXCoord(de.x)
+ const previousDoc = colDocs[rowCol[0] - 1]
+ const previousDocIndex = docs.indexOf(previousDoc)
+ console.log(`docs: ${previousDocIndex}`)
+ docs.splice(previousDocIndex + 1, 0, ...newDocs)
+ }
+ }
+ }
+ } // it seems like we're creating a link here. Weird. I didn't know that you could establish links by dragging
+ else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
+ const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, _fitWidth: true, title: "dropped annotation" });
+ this.props.addDocument?.(source);
+ de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: de.complete.linkDragData.linkSourceGetAnchor() }, "doc annotation", ""); // TODODO this is where in text links get passed
+ e.stopPropagation();
+ }
+ else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+ return false;
+ }
+
+ @undoBatch
+ internalAnchorAnnoDrop(e: Event, annoDragData: DragManager.AnchorAnnoDragData) {
+ const dropCreator = annoDragData.dropDocCreator;
+ annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => {
+ const dropDoc = dropCreator(annotationOn);
+ return dropDoc || this.rootDoc;
+ };
+ return true;
+ }
+
+ // when dropping outside of the current noteTaking context (like a new tab, freeform view, etc...)
+ @undoBatch
+ @action
+ onExternalDrop = async (e: React.DragEvent): Promise<void> => {
+ const where = [e.clientX, e.clientY];
+ let targInd = -1;
+ const docs = this.getDocsFromXCoord(where[0])
+ docs.map((d, i) => {
+ const pos0 = this.getDocTransform(d).inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap);
+ const pos1 = this.getDocTransform(d).inverse().transformPoint(this.getDocWidth(d), this.getDocHeight(d));
+ // const pos0 = cd.noteTakingDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap);
+ // const pos1 = cd.noteTakingDocTransform().inverse().transformPoint(cd.width(), cd.height());
+ if (where[0] > pos0[0] && where[0] < pos1[0] && where[1] > pos0[1] && where[1] < pos1[1]) {
+ targInd = i;
+ }
+ })
+ // this._docXfs.map((cd, i) => {
+ // const pos = cd.noteTakingDocTransform().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap);
+ // const pos1 = cd.noteTakingDocTransform().inverse().transformPoint(cd.width(), cd.height());
+ // if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) {
+ // targInd = i;
+ // }
+ // });
+ super.onExternalDrop(e, {}, () => {
+ if (targInd !== -1) {
+ const newDoc = this.childDocs[this.childDocs.length - 1];
+ const docs = this.childDocList;
+ if (docs) {
+ docs.splice(docs.length - 1, 1);
+ docs.splice(targInd, 0, newDoc);
+ }
+ }
+ });
+ }
+
+ // setDocsForColHeader = (key: string, docs: Doc[]) => {
+ // this._docsByColumnHeader = new Map(this._docsByColumnHeader.set(key, docs))
+ // }
+
+ headings = () => Array.from(this.Sections);
+
+ refList: any[] = [];
+
+ sectionNoteTaking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
+ const type = "number";
+ return <CollectionNoteTakingViewColumn
+ unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
+ observeHeight={ref => {
+ if (ref) {
+ this.refList.push(ref);
+ this.observer = new _global.ResizeObserver(action((entries: any) => {
+ if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
+ const height = this.headerMargin +
+ Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
+ Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))));
+ if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) {
+ this.props.setHeight?.(height);
+ }
+ }
+ }));
+ this.observer.observe(ref);
+ }
+ }}
+ addDocument={this.addDocument}
+ // docsByColumnHeader={this._docsByColumnHeader}
+ // setDocsForColHeader={this.setDocsForColHeader}
+ chromeHidden={this.chromeHidden}
+ columnHeaders={this.columnHeaders}
+ Document={this.props.Document}
+ DataDoc={this.props.DataDoc}
+ resizeColumns={this.resizeColumns.bind(this)}
+ renderChildren={this.children}
+ numGroupColumns={this.numGroupColumns}
+ gridGap={this.gridGap}
+ pivotField={this.pivotField}
+ columnStartXCoords={this.columnStartXCoords}
+ maxColWidth={this.maxColWdith}
+ PanelWidth={this.PanelWidth}
+ key={heading?.heading ?? ""}
+ headings={this.headings}
+ heading={heading?.heading ?? ""}
+ headingObject={heading}
+ docList={docList}
+ yMargin={this.yMargin}
+ type={type}
+ createDropTarget={this.createDashEventsTarget}
+ screenToLocalTransform={this.props.ScreenToLocalTransform}
+ editableViewProps={{
+ GetValue: () => "",
+ SetValue: this.addGroup,
+ contents: "+ New Column"
+ }}
+ />;
+ }
+
+ // called when adding a new columnHeader
+ @action
+ addGroup = (value: string) => {
+ if (value && this.columnHeaders) {
+ this.resizeColumns(this.columnHeaders.length + 1)
+ const schemaHdrField = new SchemaHeaderField(value);
+ this.columnHeaders.push(schemaHdrField);
+ return true;
+ }
+ return false;
+ }
+
+ sortFunc = (a: [SchemaHeaderField, Doc[]], b: [SchemaHeaderField, Doc[]]): 1 | -1 => {
+ const descending = StrCast(this.layoutDoc._columnsSort) === "descending";
+ const firstEntry = descending ? b : a;
+ const secondEntry = descending ? a : b;
+ return firstEntry[0].heading > secondEntry[0].heading ? 1 : -1;
+ }
+
+ onContextMenu = (e: React.MouseEvent): void => {
+ // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
+ if (!e.isPropagationStopped()) {
+ const subItems: ContextMenuProps[] = [];
+ subItems.push({ description: `${this.layoutDoc._columnsFill ? "Variable Size" : "Autosize"} Column`, event: () => this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill, icon: "plus" });
+ subItems.push({ description: `${this.layoutDoc._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
+ subItems.push({ description: "Clear All", event: () => this.dataDoc.data = new List([]), icon: "times" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" });
+ }
+ }
+
+ // used to reset column sizes when using the drag handlers
+ @action
+ setColumnStartXCoords = (movementX: number, colIndex: number) => {
+ const coords = [...this.columnStartXCoords]
+ coords[colIndex] += movementX
+ this.columnStartXCoords = coords
+ }
+
+ @computed get renderedSections() {
+ TraceMobx();
+ // let sections = [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]];
+ // if (this.pivotField) {
+ // const entries = Array.from(this.Sections.entries());
+ // sections = this.layoutDoc._columnsSort ? entries.sort(this.sortFunc) : entries;
+ // }
+ const entries = Array.from(this.Sections.entries());
+ const sections = entries.sort(this.sortFunc)
+ const eles: JSX.Element[] = []
+ for (let i = 0; i < sections.length; i++) {
+ const col = this.sectionNoteTaking(sections[i][0], sections[i][1])
+ eles.push(col)
+ if (i < sections.length - 1) {
+ eles.push(
+ <CollectionNoteTakingViewDivider
+ index={i + 1}
+ setColumnStartXCoords={this.setColumnStartXCoords.bind(this)}
+ xMargin={this.xMargin}
+ />
+ )
+ }
+ }
+ return eles
+ }
+
+ @computed get buttonMenu() {
+ const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
+ // TODO:glr Allow support for multiple buttons
+ if (menuDoc) {
+ const width: number = NumCast(menuDoc._width, 30);
+ const height: number = NumCast(menuDoc._height, 30);
+ return (<div className="buttonMenu-docBtn"
+ style={{ width: width, height: height }}>
+ <DocumentView
+ Document={menuDoc}
+ DataDoc={menuDoc}
+ isContentActive={this.props.isContentActive}
+ isDocumentActive={returnTrue}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ addDocTab={this.props.addDocTab}
+ pinToPres={emptyFunction}
+ rootSelected={this.props.isSelected}
+ removeDocument={this.props.removeDocument}
+ ScreenToLocalTransform={Transform.Identity}
+ PanelWidth={() => 35}
+ PanelHeight={() => 35}
+ renderDepth={this.props.renderDepth}
+ focus={emptyFunction}
+ styleProvider={this.props.styleProvider}
+ docViewPath={returnEmptyDoclist}
+ whenChildContentsActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
+ docFilters={this.props.docFilters}
+ docRangeFilters={this.props.docRangeFilters}
+ searchFilterDocs={this.props.searchFilterDocs}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ />
+ </div>
+ );
+ }
+ }
+
+
+ @computed get nativeWidth() { return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc); }
+ @computed get nativeHeight() { return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc); }
+
+ @computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; }
+
+ @computed get backgroundEvents() { return SnappingManager.GetIsDragging(); }
+ observer: any;
+ render() {
+ TraceMobx();
+ const buttonMenu = this.rootDoc.buttonMenu;
+ const noviceExplainer = this.rootDoc.explainer;
+ return (
+ <>
+ {buttonMenu || noviceExplainer ? <div className="documentButtonMenu">
+ {buttonMenu ? this.buttonMenu : null}
+ {Doc.UserDoc().noviceMode && noviceExplainer ?
+ <div className="documentExplanation">
+ {noviceExplainer}
+ </div>
+ : null
+ }
+ </div> : null}
+ <div className="collectionNoteTakingView"
+ ref={this.createRef}
+ style={{
+ overflowY: this.props.isContentActive() ? "auto" : "hidden",
+ background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
+ pointerEvents: this.backgroundEvents ? "all" : undefined
+ }}
+ onScroll={action(e => this._scroll = e.currentTarget.scrollTop)}
+ onPointerOver={this.onPointerOver}
+ onDrop={this.onExternalDrop.bind(this)}
+ onContextMenu={this.onContextMenu}
+ onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}
+ >
+ {this.renderedSections}
+ </div>
+ </>
+
+ );
+ }
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
new file mode 100644
index 000000000..bdcb9c399
--- /dev/null
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -0,0 +1,330 @@
+import React = require("react");
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable } from "mobx";
+import { observer } from "mobx-react";
+import { Doc, DocListCast, Opt } from "../../../fields/Doc";
+import { Id } from "../../../fields/FieldSymbols";
+import { RichTextField } from "../../../fields/RichTextField";
+import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { ScriptField } from "../../../fields/ScriptField";
+import { ImageField } from "../../../fields/URLField";
+import { TraceMobx } from "../../../fields/util";
+import { emptyFunction, returnEmptyString, setupMoveUpEvents } from "../../../Utils";
+import { Docs, DocUtils } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
+import { DragManager } from "../../util/DragManager";
+import { SnappingManager } from "../../util/SnappingManager";
+import { Transform } from "../../util/Transform";
+import { undoBatch } from "../../util/UndoManager";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
+import { EditableView } from "../EditableView";
+import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
+import "./CollectionNoteTakingView.scss";
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+
+// So this is how we are storing a column
+interface CSVFieldColumnProps {
+ Document: Doc;
+ DataDoc: Opt<Doc>;
+ docList: Doc[];
+ heading: string;
+ pivotField: string;
+ chromeHidden?: boolean;
+ columnHeaders: SchemaHeaderField[] | undefined;
+ headingObject: SchemaHeaderField | undefined;
+ yMargin: number;
+ // columnWidth: number;
+ numGroupColumns: number;
+ gridGap: number;
+ type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined;
+ headings: () => object[];
+ renderChildren: (docs: Doc[]) => JSX.Element[];
+ addDocument: (doc: Doc | Doc[]) => boolean;
+ createDropTarget: (ele: HTMLDivElement) => void;
+ screenToLocalTransform: () => Transform;
+ observeHeight: (myref: any) => void;
+ unobserveHeight: (myref: any) => void;
+ editableViewProps: any;
+ resizeColumns: (n: number) => void
+ columnStartXCoords: number[]
+ PanelWidth: number
+ maxColWidth: number
+ // docsByColumnHeader: Map<string, Doc[]>
+ // setDocsForColHeader: (key: string, docs: Doc[]) => void
+}
+
+@observer
+export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColumnProps> {
+ @observable private _background = "inherit";
+
+ @computed get columnWidth() {
+ // base cases
+ if (!this.props.columnHeaders || !this.props.headingObject || this.props.columnHeaders.length == 1) {
+ return this.props.maxColWidth
+ }
+ const i = this.props.columnHeaders.indexOf(this.props.headingObject)
+ if (i < 0) {
+ return this.props.maxColWidth
+ }
+ const endColValue = i == this.props.numGroupColumns - 1 ? this.props.PanelWidth : this.props.columnStartXCoords[i+1]
+ // TODO make the math work here. 35 is half of 70, which is the current width of the divider
+ return endColValue - this.props.columnStartXCoords[i] - 30
+ }
+
+ private dropDisposer?: DragManager.DragDropDisposer;
+ private _headerRef: React.RefObject<HTMLDivElement> = React.createRef();
+
+ @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
+ @observable _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
+ _ele: HTMLElement | null = null;
+
+ // This is likely similar to what we will be doing. Why do we need to make these refs?
+ // is that the only way to have drop targets?
+ createColumnDropRef = (ele: HTMLDivElement | null) => {
+ this.dropDisposer?.();
+ if (ele) {
+ this._ele = ele;
+ this.props.observeHeight(ele);
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this));
+ }
+ }
+
+ componentWillUnmount() {
+ this.props.unobserveHeight(this._ele);
+ }
+
+ @undoBatch
+ columnDrop = action((e: Event, de: DragManager.DropEvent) => {
+ const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
+ drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false));
+ });
+
+ getValue = (value: string): any => {
+ const parsed = parseInt(value);
+ if (!isNaN(parsed)) return parsed;
+ if (value.toLowerCase().indexOf("true") > -1) return true;
+ if (value.toLowerCase().indexOf("false") > -1) return false;
+ return value;
+ }
+
+ @action
+ headingChanged = (value: string, shiftDown?: boolean) => {
+ const castedValue = this.getValue(value);
+ if (castedValue) {
+ if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) {
+ return false;
+ }
+ this.props.docList.forEach(d => d[this.props.pivotField] = castedValue);
+ if (this.props.headingObject) {
+ this.props.headingObject.setHeading(castedValue.toString());
+ this._heading = this.props.headingObject.heading;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @action pointerEntered = () => SnappingManager.GetIsDragging() && (this._background = "#b4b4b4");
+ @action pointerLeave = () => this._background = "inherit";
+ textCallback = (char: string) => this.addNewTextDoc("-typed text-", false, true);
+
+ @action
+ addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
+ if (!value && !forceEmptyNote) return false;
+ const key = this.props.pivotField;
+ const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _fitWidth: true, title: value, _autoHeight: true });
+ const colValue = this.getValue(this.props.heading);
+ newDoc[key] = colValue;
+ FormattedTextBox.SelectOnLoad = newDoc[Id];
+ FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? "" : " ";
+ return this.props.addDocument?.(newDoc) || false;
+ }
+
+ @action
+ deleteColumn = () => {
+ if (!this.props.columnHeaders) {
+ return
+ }
+ if (this.props.headingObject) {
+ const index = this.props.columnHeaders.indexOf(this.props.headingObject);
+ const newIndex = index == 0 ? 1 : index - 1
+ const newHeader = this.props.columnHeaders[newIndex];
+ this.props.docList.forEach(d => d[this.props.pivotField] = newHeader.heading.toString())
+ this.props.columnHeaders.splice(index, 1);
+ this.props.resizeColumns(this.props.columnHeaders.length)
+ }
+ }
+
+ headerDown = (e: React.PointerEvent<HTMLDivElement>) => setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
+
+ //TODO: I think this is where I'm supposed to edit stuff
+ startDrag = (e: PointerEvent, down: number[], delta: number[]) => {
+ console.log('in startDrag')
+ // is MakeAlias a way to make a copy of a doc without rendering it?
+ const alias = Doc.MakeAlias(this.props.Document);
+ // alias._width = this.props.columnWidth / (this.props.columnHeaders?.length || 1);
+ alias._width = this.columnWidth;
+ alias._pivotField = undefined;
+ let value = this.getValue(this._heading);
+ value = typeof value === "string" ? `"${value}"` : value;
+ alias.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.pivotField} === ${value}`, { doc: Doc.name });
+ if (alias.viewSpecScript) {
+ const options = {hideSource: false}
+ DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY, options);
+ console.log('in startDrag')
+ return true;
+ }
+ return false;
+ }
+
+ menuCallback = (x: number, y: number) => {
+ ContextMenu.Instance.clearItems();
+ const layoutItems: ContextMenuProps[] = [];
+ const docItems: ContextMenuProps[] = [];
+ const dataDoc = this.props.DataDoc || this.props.Document;
+ const pivotValue = this.getValue(this.props.heading);
+
+ DocUtils.addDocumentCreatorMenuItems((doc) => {
+ const key = this.props.pivotField;
+ doc[key] = this.getValue(this.props.heading);
+ FormattedTextBox.SelectOnLoad = doc[Id];
+ return this.props.addDocument?.(doc);
+ }, this.props.addDocument, x, y, true, this.props.pivotField, pivotValue);
+
+ Array.from(Object.keys(Doc.GetProto(dataDoc))).filter(fieldKey => dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof (dataDoc[fieldKey]) === "string").map(fieldKey =>
+ docItems.push({
+ description: ":" + fieldKey, event: () => {
+ const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.Document));
+ if (created) {
+ if (this.props.Document.isTemplateDoc) {
+ Doc.MakeMetadataFieldTemplate(created, this.props.Document);
+ }
+ return this.props.addDocument?.(created);
+ }
+ }, icon: "compress-arrows-alt"
+ }));
+ Array.from(Object.keys(Doc.GetProto(dataDoc))).filter(fieldKey => DocListCast(dataDoc[fieldKey]).length).map(fieldKey =>
+ docItems.push({
+ description: ":" + fieldKey, event: () => {
+ const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey });
+ if (created) {
+ const container = this.props.Document.resolvedDataDoc ? Doc.GetProto(this.props.Document) : this.props.Document;
+ if (container.isTemplateDoc) {
+ Doc.MakeMetadataFieldTemplate(created, container);
+ return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created);
+ }
+ return this.props.addDocument?.(created) || false;
+ }
+ }, icon: "compress-arrows-alt"
+ }));
+ !Doc.UserDoc().noviceMode && ContextMenu.Instance.addItem({ description: "Doc Fields ...", subitems: docItems, icon: "eye" });
+ !Doc.UserDoc().noviceMode && ContextMenu.Instance.addItem({ description: "Containers ...", subitems: layoutItems, icon: "eye" });
+ ContextMenu.Instance.setDefaultItem("::", (name: string): void => {
+ Doc.GetProto(this.props.Document)[name] = "";
+ const created = Docs.Create.TextDocument("", { title: name, _width: 250, _autoHeight: true });
+ if (created) {
+ if (this.props.Document.isTemplateDoc) {
+ Doc.MakeMetadataFieldTemplate(created, this.props.Document);
+ }
+ this.props.addDocument?.(created);
+ }
+ });
+ ContextMenu.Instance.displayMenu(x, y, undefined, true);
+ }
+
+ @computed get innards() {
+ TraceMobx();
+ const key = this.props.pivotField;
+ const heading = this._heading;
+ const columnYMargin = this.props.headingObject ? 0 : this.props.yMargin;
+ const evContents = heading ? heading : "25";
+ const headingView = this.props.headingObject ?
+ <div key={heading} className="collectionNoteTakingView-sectionHeader" ref={this._headerRef}
+ style={{
+ marginTop: 2 * this.props.yMargin,
+ // width: (this.props.columnWidth) /
+ // ((uniqueHeadings.length) || 1)
+ width: this.columnWidth - 20
+ }}>
+ <div className="collectionNoteTakingView-sectionHeader-subCont" onPointerDown={this.headerDown}
+ title={evContents === `No Value` ?
+ `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""}
+ style={{ background: evContents !== `No Value` ? this._color : "inherit" }}>
+ <EditableView
+ GetValue={() => evContents}
+ SetValue={this.headingChanged}
+ contents={evContents}
+ oneLine={true}
+ />
+ </div>
+ </div> : (null);
+ // const templatecols = `${this.props.columnWidth / this.props.numGroupColumns}px `;
+ const templatecols = `${this.columnWidth}px `;
+ const type = this.props.Document.type;
+ return <>
+ {headingView}
+ {<div>
+ <div key={`${heading}-stack`} className={`collectionNoteTakingView-Nodes`}
+ style={{
+ padding: `${columnYMargin}px ${0}px ${this.props.yMargin}px ${0}px`,
+ margin: "auto",
+ width: "max-content", //singleColumn ? undefined : `${cols * (style.columnWidth + style.gridGap) + 2 * style.xMargin - style.gridGap}px`,
+ height: 'max-content',
+ position: "relative",
+ gridGap: this.props.gridGap,
+ gridTemplateColumns: templatecols,
+ gridAutoRows: "0px"
+ }}>
+ {this.props.renderChildren(this.props.docList)}
+ </div>
+
+ {!this.props.chromeHidden && type !== DocumentType.PRES ?
+ <div className="collectionNoteTakingView-DocumentButtons"
+ // style={{ width: this.props.columnWidth / this.props.numGroupColumns, marginBottom: 10 }}>
+ style={{ width: this.columnWidth - 20, marginBottom: 10 }}>
+ <div key={`${heading}-add-document`} className="collectionNoteTakingView-addDocumentButton">
+ <EditableView
+ GetValue={returnEmptyString}
+ SetValue={this.addNewTextDoc}
+ textCallback={this.textCallback}
+ placeholder={"Type ':' for commands"}
+ contents={"+ New Node"}
+ menuCallback={this.menuCallback}
+ />
+ </div>
+ <div key={`${this.props.Document[Id]}-addGroup`} className="collectionNoteTakingView-addDocumentButton">
+ <EditableView {...this.props.editableViewProps} />
+ </div>
+ {(this.props.columnHeaders?.length && this.props.columnHeaders.length > 1) &&
+ <button className="collectionNoteTakingView-sectionDelete" onClick={this.deleteColumn}>
+ <FontAwesomeIcon icon="trash" size="lg" />
+ </button>
+ }
+ </div>
+ : null}
+ </div>
+ }
+ </>;
+ }
+
+
+ render() {
+ TraceMobx();
+ const heading = this._heading;
+ return (
+ <div className={"collectionNoteTakingViewFieldColumn" + (SnappingManager.GetIsDragging() ? "Dragging" : "")} key={heading}
+ style={{
+ //TODO: change this so that it's based on the column width
+ width: this.columnWidth,
+ height: "100%",
+ background: this._background
+ }}
+ ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}>
+ {this.innards}
+ </div >
+ );
+ }
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx
new file mode 100644
index 000000000..ed5dc3715
--- /dev/null
+++ b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx
@@ -0,0 +1,61 @@
+import { action, observable } from "mobx";
+import * as React from "react";
+
+interface DividerProps {
+ index: number
+ xMargin: number
+ setColumnStartXCoords: (movementX: number, colIndex: number) => void
+}
+
+export default class Divider extends React.Component<DividerProps>{
+ @observable private isHoverActive = false;
+ @observable private isResizingActive = false;
+
+ @action
+ private registerResizing = (e: React.PointerEvent<HTMLDivElement>) => {
+ e.stopPropagation();
+ e.preventDefault();
+ window.removeEventListener("pointermove", this.onPointerMove);
+ window.removeEventListener("pointerup", this.onPointerUp);
+ window.addEventListener("pointermove", this.onPointerMove);
+ window.addEventListener("pointerup", this.onPointerUp);
+ this.isResizingActive = true;
+ }
+
+ @action
+ private onPointerUp = () => {
+ this.isResizingActive = false;
+ this.isHoverActive = false;
+ window.removeEventListener("pointermove", this.onPointerMove);
+ window.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ @action
+ onPointerMove = ({ movementX }: PointerEvent) => {
+ this.props.setColumnStartXCoords(movementX, this.props.index)
+ }
+
+ render() {
+ return (
+ <div className="columnResizer"
+ style={{
+ display: "flex",
+ alignItems: "center",
+ cursor: "col-resize"
+ }}
+ onPointerEnter={action(() => this.isHoverActive = true)}
+ onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}
+ >
+ <div className="columnResizer-handler" onPointerDown={e => this.registerResizing(e)}
+ style={{
+ height: "95%",
+ width: 12,
+ borderRight: "4px solid #282828",
+ borderLeft: "4px solid #282828",
+ margin: "0px 10px"
+ }}
+ />
+ </div>
+ )
+ }
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 73572299a..9a498858a 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -130,9 +130,37 @@
margin-left: -5;
}
+ // Documents in stacking view
.collectionStackingView-columnDoc {
- display: inline-block;
- margin: auto;
+ display: flex;
+ // margin: auto; // Removed auto so that it is no longer center aligned - this could be something we change
+ position: relative;
+
+ &:hover {
+ .hoverButtons{
+ opacity: 1;
+ }
+ }
+
+ .hoverButtons {
+ display: flex;
+ opacity: 0;
+ position: absolute;
+ height: 100%;
+ left: -35px;
+ justify-content: center;
+ align-items: center;
+ padding: 0px 10px;
+
+ .buttonWrapper {
+ padding: 3px;
+ border-radius: 3px;
+
+ &:hover {
+ background: rgba(0, 0, 0, 0.26);
+ }
+ }
+ }
}
.collectionStackingView-masonryDoc {
@@ -203,6 +231,7 @@
.collectionStackingView-sectionHeader {
text-align: center;
margin: auto;
+ margin-bottom: 10px;
background: $medium-gray;
// overflow: hidden; overflow is visible so the color menu isn't hidden -ftong
@@ -385,6 +414,7 @@
.collectionStackingView-addDocumentButton {
font-size: 75%;
letter-spacing: 2px;
+ cursor: pointer;
.editableView-input {
outline-color: black;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7e66aa844..ff7594e5a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -34,6 +34,7 @@ const _global = (window /* browser */ || global) /* node */ as any;
export type collectionStackingViewProps = {
chromeHidden?: boolean;
+ // view type is stacking
viewType?: CollectionViewType;
NativeWidth?: () => number;
NativeHeight?: () => number;
@@ -42,75 +43,76 @@ export type collectionStackingViewProps = {
@observer
export class CollectionStackingView extends CollectionSubView<Partial<collectionStackingViewProps>>() {
_masonryGridRef: HTMLDivElement | null = null;
+ // used in a column dragger, likely due for the masonry grid view. We want to use this
_draggerRef = React.createRef<HTMLDivElement>();
+ // Not sure what a pivot field is. Seems like we cause reaction in MobX get rid of it once we exit this view
_pivotFieldDisposer?: IReactionDisposer;
+ // Seems like we cause reaction in MobX get rid of our height once we exit this view
_autoHeightDisposer?: IReactionDisposer;
- _docXfs: { height: () => number; width: () => number; stackedDocTransform: () => Transform }[] = [];
+ // keeping track of documents. Updated on internal and external drops. What's the difference?
+ _docXfs: { height: () => number, width: () => number, stackedDocTransform: () => Transform }[] = [];
+ // Doesn't look like this field is being used anywhere. Obsolete?
_columnStart: number = 0;
+ // map of node headers to their heights. Used in Masonry
@observable _heightMap = new Map<string, number>();
- @observable _cursor: CursorProperty = 'grab';
+ // Assuming that this is the current css cursor style
+ @observable _cursor: CursorProperty = "grab";
+ // gets reset whenever we scroll. Not sure what it is
@observable _scroll = 0; // used to force the document decoration to update when scrolling
- @computed get chromeHidden() {
- return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden);
- }
- @computed get columnHeaders() {
- return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null);
- }
- @computed get pivotField() {
- return StrCast(this.layoutDoc._pivotField);
- }
- @computed get filteredChildren() {
- return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.hidden).map(pair => pair.layout);
- }
- @computed get headerMargin() {
- return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin);
- }
- @computed get xMargin() {
- return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, 0.05 * this.props.PanelWidth()));
- }
- @computed get yMargin() {
- return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5);
- } // 2 * this.gridGap)); }
- @computed get gridGap() {
- return NumCast(this.layoutDoc._gridGap, 10);
- }
- @computed get isStackingView() {
- return (this.props.viewType ?? this.layoutDoc._viewType) === CollectionViewType.Stacking;
- }
- @computed get numGroupColumns() {
- return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1;
- }
- @computed get showAddAGroup() {
- return this.pivotField && !this.chromeHidden;
- }
+ // does this mean whether the browser is hidden? Or is chrome something else entirely?
+ @computed get chromeHidden() { return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); }
+ // it looks like this gets the column headers that Mehek was showing just now
+ @computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null); }
+ // Still not sure what a pivot is, but it appears that we can actually filter docs somehow?
+ @computed get pivotField() { return StrCast(this.layoutDoc._pivotField); }
+ // filteredChildren is what you want to work with. It's the list of things that you're currently displaying
+ @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => (pair.layout instanceof Doc) && !pair.layout.hidden).map(pair => pair.layout); }
+ // how much margin we give the header
+ @computed get headerMargin() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); }
+ @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); }
+ @computed get yMargin() { return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5); } // 2 * this.gridGap)); }
+ @computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); }
+ // are we stacking or masonry?
+ @computed get isStackingView() { return (this.props.viewType ?? this.layoutDoc._viewType) === (CollectionViewType.Stacking || CollectionViewType.NoteTaking); }
+ // this is the number of StackingViewFieldColumns that we have
+ @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
+ // reveals a button to add a group in masonry view
+ @computed get showAddAGroup() { return this.pivotField && !this.chromeHidden; }
+ // columnWidth handles the margin on the left and right side of the documents
@computed get columnWidth() {
- return Math.min(this.props.PanelWidth() - 2 * this.xMargin, this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
- }
- @computed get NodeWidth() {
- return this.props.PanelWidth() - this.gridGap;
+ return Math.min(this.props.PanelWidth() - 2 * this.xMargin,
+ this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
}
+
+ @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
constructor(props: any) {
super(props);
if (this.columnHeaders === undefined) {
+ // TODO: what is a layout doc? Is it literally how this document is supposed to be layed out?
+ // here we're making an empty list of column headers (again, what Mehek showed us)
this.layoutDoc._columnHeaders = new List<SchemaHeaderField>();
}
}
+ // TODO: plj - these are the children
children = (docs: Doc[]) => {
+ //TODO: can somebody explain me to what exactly TraceMobX is?
TraceMobx();
+ // appears that we are going to reset the _docXfs. TODO: what is Xfs?
this._docXfs.length = 0;
return docs.map((d, i) => {
const height = () => this.getDocHeight(d);
const width = () => this.getDocWidth(d);
+ // assuming we need to get rowSpan because we might be dealing with many columns. Grid gap makes sense if multiple columns
const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
+ // just getting the style
const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
- return (
- <div className={`collectionStackingView-${this.isStackingView ? 'columnDoc' : 'masonryDoc'}`} key={d[Id]} style={style}>
- {this.getDisplayDoc(d, width)}
- </div>
- );
+ // So we're choosing whether we're going to render a column or a masonry doc
+ return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} style={style} >
+ {this.getDisplayDoc(d, width)}
+ </div>;
});
};
@action
@@ -118,7 +120,10 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
this._heightMap.set(key, sectionHeight);
};
+ // is sections that all collections inherit? I think this is how we show the masonry/columns
+ //TODO: this seems important
get Sections() {
+ // appears that pivot field IS actually for sorting
if (!this.pivotField || this.columnHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>();
if (this.columnHeaders === undefined) {
@@ -146,6 +151,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
});
// remove all empty columns if hideHeadings is set
+ // we will want to have something like this, so that we can hide columns and add them back in
if (this.layoutDoc._columnsHideIfEmpty) {
Array.from(fields.keys())
.filter(key => !fields.get(key)!.length)
@@ -218,6 +224,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight);
};
+ // let's dive in and get the actual document we want to drag/move around
focusDocument = (doc: Doc, options?: DocFocusOptions) => {
Doc.BrushDoc(doc);
@@ -269,7 +276,10 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
};
isContentActive = () => this.props.isSelected() || this.props.isContentActive();
- isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined);
+
+ isChildContentActive = () => this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive));
+ // this is what renders the document that you see on the screen
+ // called in Children: this actually adds a document to our children list
getDisplayDoc(doc: Doc, width: () => number) {
const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
const height = () => this.getDocHeight(doc);
@@ -277,52 +287,50 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
let dref: Opt<DocumentView>;
const stackedDocTransform = () => this.getDocTransform(doc, dref);
this._docXfs.push({ stackedDocTransform, width, height });
- return (
- <DocumentView
- ref={r => (dref = r || undefined)}
- Document={doc}
- DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])}
- renderDepth={this.props.renderDepth + 1}
- PanelWidth={width}
- PanelHeight={height}
- styleProvider={this.styleProvider}
- docViewPath={this.props.docViewPath}
- fitWidth={this.props.childFitWidth}
- isContentActive={this.isChildContentActive}
- onKey={this.onKeyDown}
- isDocumentActive={this.isContentActive}
- LayoutTemplate={this.props.childLayoutTemplate}
- LayoutTemplateString={this.props.childLayoutString}
- NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
- NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeHeight(doc)) ? height : undefined}
- dontCenter={this.props.childIgnoreNativeSize ? 'xy' : undefined}
- dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't autoHeight resize if dontRegisterView is set, but they need to.
+ //DocumentView is how the node will be rendered
+ return <DocumentView ref={r => dref = r || undefined}
+ Document={doc}
+ DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])}
+ renderDepth={this.props.renderDepth + 1}
+ PanelWidth={width}
+ PanelHeight={height}
+ styleProvider={this.styleProvider}
+ docViewPath={this.props.docViewPath}
+ fitWidth={this.props.childFitWidth}
+ isContentActive={this.isChildContentActive}
+ onKey={this.onKeyDown}
+ isDocumentActive={this.isContentActive}
+ LayoutTemplate={this.props.childLayoutTemplate}
+ LayoutTemplateString={this.props.childLayoutString}
+ NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeWidth(doc) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
+ NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeHeight(doc) ? height : undefined}
+ dontCenter={this.props.childIgnoreNativeSize ? "xy" : undefined}
+ dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't autoHeight resize if dontRegisterView is set, but they need to.
rootSelected={this.rootSelected}
- showTitle={this.props.childShowTitle}
- dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onDoubleClick={this.onChildDoubleClickHandler}
- ScreenToLocalTransform={stackedDocTransform}
- focus={this.focusDocument}
- docFilters={this.childDocFilters}
- hideDecorationTitle={this.props.childHideDecorationTitle?.()}
- hideResizeHandles={this.props.childHideResizeHandles?.()}
- hideTitle={this.props.childHideTitle?.()}
- docRangeFilters={this.childDocRangeFilters}
- searchFilterDocs={this.searchFilterDocs}
- ContainingCollectionDoc={this.props.CollectionView?.props.Document}
- ContainingCollectionView={this.props.CollectionView}
- addDocument={this.props.addDocument}
- moveDocument={this.props.moveDocument}
- removeDocument={this.props.removeDocument}
- contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)}
- whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
- addDocTab={this.addDocTab}
- bringToFront={returnFalse}
- scriptContext={this.props.scriptContext}
- pinToPres={this.props.pinToPres}
- />
- );
+ showTitle={this.props.childShowTitle}
+ dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
+ onClick={this.onChildClickHandler}
+ onDoubleClick={this.onChildDoubleClickHandler}
+ ScreenToLocalTransform={stackedDocTransform}
+ focus={this.focusDocument}
+ docFilters={this.childDocFilters}
+ hideDecorationTitle={this.props.childHideDecorationTitle?.()}
+ hideResizeHandles={this.props.childHideResizeHandles?.()}
+ hideTitle={this.props.childHideTitle?.()}
+ docRangeFilters={this.childDocRangeFilters}
+ searchFilterDocs={this.searchFilterDocs}
+ ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+ ContainingCollectionView={this.props.CollectionView}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ removeDocument={this.props.removeDocument}
+ contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)}
+ whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+ addDocTab={this.addDocTab}
+ bringToFront={returnFalse}
+ scriptContext={this.props.scriptContext}
+ pinToPres={this.props.pinToPres}
+ />;
}
getDocTransform(doc: Doc, dref?: DocumentView) {
@@ -334,7 +342,13 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
getDocWidth(d?: Doc) {
if (!d) return 0;
const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
- const maxWidth = this.columnWidth / this.numGroupColumns;
+ // TODO: pj - replace with a better way to calculate the margin
+ let margin = 25;
+ d.margin = 25;
+ if (this.columnWidth < 150){
+ margin = 0;
+ }
+ const maxWidth = (this.columnWidth / this.numGroupColumns) - (margin * 2);
if (!this.layoutDoc._columnsFill && !(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d))) {
return Math.min(d[WidthSym](), maxWidth);
}
@@ -357,6 +371,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return Math.min(childHeight, maxHeight, panelHeight);
}
+ // This following three functions must be from the view Mehek showed
columnDividerDown = (e: React.PointerEvent) => {
runInAction(() => (this._cursor = 'grabbing'));
setupMoveUpEvents(
@@ -381,13 +396,46 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
);
}
+ // TODO: plj
+ @action
+ onPointerOver = (e: React.PointerEvent) => {
+ // console.log("hovering over something")
+ if (DragManager.docsBeingDragged.length) {
+ // essentially copying code from onInternalDrop for this:
+ const doc = DragManager.docsBeingDragged[0]
+ // console.log(doc[LayoutSym]())
+
+ console.log(doc[DataSym])
+ console.log(Doc.IndexOf(doc, this.childDocs))
+
+ }
+
+
+ }
+
+ //used in onPointerOver to swap two nodes in the rendered filtered children list
+ swapNodes = (i: number, j: number) => {
+
+ }
+
+ //plj added this
+ @action
+ onPointerDown = (e: React.PointerEvent) => {
+
+ }
+
+ // TODO: plj - look at this. Start with making changes to db, and then transition to client side
@undoBatch
@action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
+ // Fairly confident that this is where the swapping of nodes in the various arrays happens
+ console.log('drop')
const where = [de.x, de.y];
+ // start at -1 until we're sure we want to add it to the column
let dropInd = -1;
let dropAfter = 0;
if (de.complete.docDragData) {
+ // going to re-add the docs to the _docXFs based on position of where we just dropped
this._docXfs.map((cd, i) => {
const pos = cd
.stackedDocTransform()
@@ -402,11 +450,14 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
});
const oldDocs = this.childDocs.length;
if (super.onInternalDrop(e, de)) {
+ // check to see if we actually need anything to the new column of nodes (if droppedDocs != empty)
const droppedDocs = this.childDocs.slice().filter((d: Doc, ind: number) => ind >= oldDocs); // if the drop operation adds something to the end of the list, then use that as the new document (may be different than what was dropped e.g., in the case of a button which is dropped but which creates say, a note).
const newDocs = droppedDocs.length ? droppedDocs : de.complete.docDragData.droppedDocuments; // if nothing was added to the end of the list, then presumably the dropped documents were already in the list, but possibly got reordered so we use them.
const docs = this.childDocList;
+ // reset drag manager docs, because we just dropped
DragManager.docsBeingDragged = [];
+ // still figuring out where to add the document
if (docs && newDocs.length) {
const insertInd = dropInd === -1 ? docs.length : dropInd + dropAfter;
const offset = newDocs.reduce((off, ndoc) => (this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off), 0);
@@ -435,7 +486,10 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
@undoBatch
@action
+ //What is the difference between internal and external drop?? Does internal mean we're dropping inside of a collection?
+ // I take it back: external drop means we took it out of column/collection that we were just in
onExternalDrop = async (e: React.DragEvent): Promise<void> => {
+ console.log('external drop')
const where = [e.clientX, e.clientY];
let targInd = -1;
this._docXfs.map((cd, i) => {
@@ -461,6 +515,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
};
headings = () => Array.from(this.Sections);
refList: any[] = [];
+ // what a section looks like if we're in stacking view
sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
const key = this.pivotField;
let type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined = undefined;
@@ -512,6 +567,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
);
};
+ // what a section looks like if we're in masonry. Shouldn't actually need to use this.
sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[], first: boolean) => {
const key = this.pivotField;
let type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined = undefined;
@@ -557,6 +613,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
};
@action
+ // What are we adding a group to?
addGroup = (value: string) => {
if (value && this.columnHeaders) {
const schemaHdrField = new SchemaHeaderField(value);
@@ -584,6 +641,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
};
+ //
@computed get renderedSections() {
TraceMobx();
let sections = [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]];
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index f3a798143..d29c0b183 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -26,6 +26,7 @@ const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
+// So this is how we are storing a column
interface CSVFieldColumnProps {
Document: Doc;
DataDoc: Opt<Doc>;
@@ -41,6 +42,7 @@ interface CSVFieldColumnProps {
gridGap: number;
type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined;
headings: () => object[];
+ // I think that stacking view actually has a single column and then supposedly you can add more columns? Unsure
renderChildren: (docs: Doc[]) => JSX.Element[];
addDocument: (doc: Doc | Doc[]) => boolean;
createDropTarget: (ele: HTMLDivElement) => void;
@@ -62,6 +64,8 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
_ele: HTMLElement | null = null;
+ // This is likely similar to what we will be doing. Why do we need to make these refs?
+ // is that the only way to have drop targets?
createColumnDropRef = (ele: HTMLDivElement | null) => {
this.dropDisposer?.();
if (ele) {
@@ -75,6 +79,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
this.props.unobserveHeight(this._ele);
}
+ //TODO: what is scripting? I found it in SetInPlace def but don't know what that is
@undoBatch
columnDrop = action((e: Event, de: DragManager.DropEvent) => {
const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
@@ -146,7 +151,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
headerDown = (e: React.PointerEvent<HTMLDivElement>) => setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
+ //TODO: I think this is where I'm supposed to edit stuff
startDrag = (e: PointerEvent, down: number[], delta: number[]) => {
+ // is MakeAlias a way to make a copy of a doc without rendering it?
const alias = Doc.MakeAlias(this.props.Document);
alias._width = this.props.columnWidth / (this.props.columnHeaders?.length || 1);
alias._pivotField = undefined;
@@ -312,21 +319,26 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
}}>
{this.props.renderChildren(this.props.docList)}
</div>
- {!this.props.chromeHidden ?
+ {!this.props.chromeHidden && type !== DocumentType.PRES ?
+ // TODO: this is the "new" button: see what you can work with here
+ // change cursor to pointer for this, and update dragging cursor
+ //TODO: there is a bug that occurs when adding a freeform document and trying to move it around
+ //TODO: would be great if there was additional space beyond the frame, so that you can actually see your
+ // bottom note
+ //TODO: ok, so we are using a single column, and this is it!
<div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton"
- style={{ width: this.props.columnWidth / this.props.numGroupColumns, marginBottom: 10 }}>
+ style={{ width: this.props.columnWidth / this.props.numGroupColumns, marginBottom: 10, marginLeft: 25 }}>
<EditableView
GetValue={returnEmptyString}
SetValue={this.addNewTextDoc}
textCallback={this.textCallback}
- contents={"+ NEW"}
+ placeholder={"Type ':' for commands"}
+ contents={<FontAwesomeIcon icon={"plus"}/>}
toggle={this.toggleVisibility}
menuCallback={this.menuCallback} />
</div>
: null
}
-
-
</div>
}
</>;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index f0cb23eab..4ea675d35 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -26,6 +26,7 @@ import { CollectionGridView } from './collectionGrid/CollectionGridView';
import { CollectionLinearView } from './collectionLinear';
import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
+import { CollectionNoteTakingView } from './CollectionNoteTakingView';
import { CollectionPileView } from './CollectionPileView';
import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView';
import { CollectionStackingView } from './CollectionStackingView';
@@ -125,6 +126,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
case CollectionViewType.Carousel: return <CollectionCarouselView key="collview" {...props} />;
case CollectionViewType.Carousel3D: return <CollectionCarousel3DView key="collview" {...props} />;
case CollectionViewType.Stacking: return <CollectionStackingView key="collview" {...props} />;
+ case CollectionViewType.NoteTaking: return <CollectionNoteTakingView key="collview" {...props} />;
case CollectionViewType.Masonry: return <CollectionStackingView key="collview" {...props} />;
case CollectionViewType.Time: return <CollectionTimeView key="collview" {...props} />;
case CollectionViewType.Grid: return <CollectionGridView key="collview" {...props} />;
@@ -138,17 +140,18 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
if (addExtras && CollectionView._safeMode) {
ContextMenu.Instance.addItem({ description: 'Test Freeform', event: () => func(CollectionViewType.Invalid), icon: 'project-diagram' });
}
- subItems.push({ description: 'Schema', event: () => func(CollectionViewType.Schema), icon: 'th-list' });
- subItems.push({ description: 'Tree', event: () => func(CollectionViewType.Tree), icon: 'tree' });
- subItems.push({ description: 'Stacking', event: () => (func(CollectionViewType.Stacking)._autoHeight = true), icon: 'ellipsis-v' });
- subItems.push({ description: 'Multicolumn', event: () => func(CollectionViewType.Multicolumn), icon: 'columns' });
- subItems.push({ description: 'Multirow', event: () => func(CollectionViewType.Multirow), icon: 'columns' });
- subItems.push({ description: 'Masonry', event: () => func(CollectionViewType.Masonry), icon: 'columns' });
- subItems.push({ description: 'Carousel', event: () => func(CollectionViewType.Carousel), icon: 'columns' });
- subItems.push({ description: '3D Carousel', event: () => func(CollectionViewType.Carousel3D), icon: 'columns' });
- !Doc.noviceMode && subItems.push({ description: 'Pivot/Time', event: () => func(CollectionViewType.Time), icon: 'columns' });
- !Doc.noviceMode && subItems.push({ description: 'Map', event: () => func(CollectionViewType.Map), icon: 'globe-americas' });
- subItems.push({ description: 'Grid', event: () => func(CollectionViewType.Grid), icon: 'th-list' });
+ subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" });
+ subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" });
+ subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" });
+ subItems.push({ description: "Notetaking", event: () => func(CollectionViewType.NoteTaking)._autoHeight = true, icon: "ellipsis-v" });
+ subItems.push({ description: "Multicolumn", event: () => func(CollectionViewType.Multicolumn), icon: "columns" });
+ subItems.push({ description: "Multirow", event: () => func(CollectionViewType.Multirow), icon: "columns" });
+ subItems.push({ description: "Masonry", event: () => func(CollectionViewType.Masonry), icon: "columns" });
+ subItems.push({ description: "Carousel", event: () => func(CollectionViewType.Carousel), icon: "columns" });
+ subItems.push({ description: "3D Carousel", event: () => func(CollectionViewType.Carousel3D), icon: "columns" });
+ !Doc.noviceMode && subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" });
+ !Doc.noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" });
+ subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" });
if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) {
const existingVm = ContextMenu.Instance.findByDescription(category);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index edaa40bad..afb618b34 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -156,6 +156,9 @@ export interface DocumentViewSharedProps {
scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document
createNewFilterDoc?: () => void;
updateFilterDoc?: (doc: Doc) => void;
+ // Parker added both of these
+ originalBackgroundColor?: string;
+ isNoteTakingView?: boolean;
}
// these props are specific to DocuentViews
@@ -491,6 +494,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) {
if (this._mainCont.current) {
const dragData = new DragManager.DocumentDragData([this.props.Document]);
+ if (this.props.isNoteTakingView) {
+ dragData.draggedDocuments.forEach((doc) => {
+ doc.backgroundColor = "#C9DAEF";
+ doc.opacity = 0.5;
+ });
+ }
const [left, top] = this.props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0);
dragData.offset = this.props
.ScreenToLocalTransform()
@@ -502,9 +511,22 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
dragData.treeViewDoc = this.props.treeViewDoc;
dragData.removeDocument = this.props.removeDocument;
dragData.moveDocument = this.props.moveDocument;
+ //dragData.dimSource :
+ // dragEffects field, set dim
+ // add kv pairs to a doc, swap properties with the node while dragging, and then swap when dropping
+ // add a dragEffects prop to DocumentView as a function that sets up. Each view has its own prop, when you start dragging:
+ // in Draganager, figure out which doc(s) you're dragging and change what opacity function returns
const ffview = this.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
- ffview && runInAction(() => (ffview.ChildDrag = this.props.DocumentView()));
- DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart) }, () => setTimeout(action(() => ffview && (ffview.ChildDrag = undefined)))); // this needs to happen after the drop event is processed.
+ ffview && runInAction(() => (ffview.ChildDrag = this.props.DocumentView()));
+ DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStar && !this.props.isNoteTakingView)},
+ () => setTimeout(action(() => {
+ ffview && (ffview.ChildDrag = undefined)
+ //TODO: is there a better way than adding another field to the props? Not quite sure how "this" works tbh
+ if (this.props.isNoteTakingView) {
+ this.props.Document.backgroundColor = "";
+ this.props.Document.opacity = 1;
+ }
+ }))); // this needs to happen after the drop event is processed.
ffview?.setupDragLines(false);
}
}
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 630ae18f5..697f8f47f 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -1,5 +1,5 @@
import { InfoWindow } from '@react-google-maps/api';
-import { action, computed } from 'mobx';
+import { action } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
@@ -7,6 +7,7 @@ import { Id } from '../../../../fields/FieldSymbols';
import { emptyFunction, OmitKeys, returnAll, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents } from '../../../../Utils';
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
+import { CollectionNoteTakingView } from '../../collections/CollectionNoteTakingView';
import { CollectionStackingView } from '../../collections/CollectionStackingView';
import { ViewBoxAnnotatableProps } from '../../DocComponent';
import { FieldViewProps } from '../FieldView';
@@ -40,10 +41,10 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
});
};
- _stack: CollectionStackingView | null | undefined;
- childFitWidth = (doc: Doc) => doc.type === DocumentType.RTF;
- addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.AddDocToList(this.props.place, 'data', d), true as boolean);
- removeDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.RemoveDocFromList(this.props.place, 'data', d), true as boolean);
+ _stack: CollectionStackingView | CollectionNoteTakingView | null | undefined;
+ childFitWidth = (doc:Doc) => doc.type === DocumentType.RTF;
+ addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.AddDocToList(this.props.place, "data", d), true as boolean);
+ removeDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.RemoveDocFromList(this.props.place, "data", d), true as boolean);
render() {
return (
<InfoWindow anchor={this.props.markerMap[this.props.place[Id]]} onCloseClick={this.handleInfoWindowClose}>
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 6e5eb3300..dc01d8305 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -144,6 +144,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return Cast(this.activeItem?.presentationTargetDoc, Doc, null);
}
@computed get scrollable(): boolean {
+ //TODO: likely do NOT have to update this for note-taking view, but still worth putting here
if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
else return false;
}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 0cf15d297..5ac506f21 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -202,6 +202,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
/**
* Function to drag and drop the pres element to a diferent location
*/
+ //TODO: this is what you need to look into
startDrag = (e: PointerEvent) => {
const miniView: boolean = this.toolbarWidth <= 100;
const activeItem = this.rootDoc;