aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx52
-rw-r--r--src/client/views/collections/CollectionNoteTakingViewColumn.tsx39
-rw-r--r--src/fields/List.ts72
-rw-r--r--src/fields/util.ts12
4 files changed, 80 insertions, 95 deletions
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index f24b98621..1bf5b7d86 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -42,12 +42,10 @@ export type collectionNoteTakingViewProps = {
@observer
export class CollectionNoteTakingView extends CollectionSubView<Partial<collectionNoteTakingViewProps>>() {
- _autoHeightDisposer?: IReactionDisposer;
+ _disposers: { [key: string]: 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 columnStartXCoords: number[] = [];
@observable docsDraggedRowCol: number[] = [];
@observable _cursor: CursorProperty = 'grab';
@observable _scroll = 0; // used to force the document decoration to update when scrolling
@@ -86,7 +84,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
@computed get numGroupColumns() {
return this.columnHeaders.length;
}
- @observable columnStartXCoords: number[] = [];
@computed get PanelWidth() {
return this.props.PanelWidth();
}
@@ -100,11 +97,9 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
super(props);
if (this.columnHeaders === undefined) {
this.dataDoc.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);
+ this.resizeColumns(this.columnHeaders.length);
}
}
@@ -126,7 +121,8 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
// [CAVEATS] (1) keep track of the offsetting
// (2) documentView gets unmounted as you remove it from the list
- get Sections() {
+ @computed get Sections() {
+ TraceMobx();
const columnHeaders = this.columnHeaders;
let docs = this.childDocs;
const sections = new Map<SchemaHeaderField, Doc[]>(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
@@ -169,16 +165,21 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
componentDidMount() {
super.componentDidMount?.();
document.addEventListener('pointerup', this.removeDocDragHighlight, true);
- this._autoHeightDisposer = reaction(
+ this._disposers.autoHeight = 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', ''))))))
);
+ this._disposers.headers = reaction(
+ () => this.columnHeaders.slice(),
+ headers => this.resizeColumns(headers.length),
+ { fireImmediately: true }
+ );
}
componentWillUnmount() {
document.removeEventListener('pointerup', this.removeDocDragHighlight, true);
super.componentWillUnmount();
- this._autoHeightDisposer?.();
+ Object.keys(this._disposers).forEach(key => this._disposers[key]());
}
@action
@@ -315,9 +316,8 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
// 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.notetakingCategoryField] as object) ?? 'unset';
- const castedSectionValue = heading.toString();
- const existingHeader = this.columnHeaders.find(sh => sh.heading === castedSectionValue);
+ const heading = StrCast(d[this.notetakingCategoryField], 'unset');
+ const existingHeader = this.columnHeaders.find(sh => sh.heading === heading);
const colStartXCoords = this.columnStartXCoords;
if (!existingHeader) {
return 1000;
@@ -352,6 +352,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
}
// called when a column is either added or deleted. This function creates n evenly spaced columns
+ @action
resizeColumns = (n: number) => {
const totalWidth = this.PanelWidth;
const dividerWidth = 32;
@@ -368,8 +369,8 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
// This function is used to preview where a document will drop in a column once a drag is complete.
@action
- onPointerOver = (ex: number, ey: number) => {
- if (this.childDocList) {
+ onPointerOver = (buttons: boolean, ex: number, ey: number) => {
+ if (this.childDocList && buttons) {
// 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 = this.props.ScreenToLocalTransform().transformPoint(ex, ey)[0] - 2 * this.gridGap;
@@ -500,7 +501,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
onExternalDrop = async (e: React.DragEvent): Promise<void> => {
const targInd = this.docsDraggedRowCol?.[0] || 0;
super.onExternalDrop(e, {}, docus => {
- this.onPointerOver(e.clientX, e.clientY);
+ this.onPointerOver(true, e.clientX, e.clientY);
docus?.map(doc => this.addDocument(doc));
const newDoc = this.childDocs.lastElement();
const docs = this.childDocList;
@@ -515,6 +516,11 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
headings = () => Array.from(this.Sections);
refList: any[] = [];
+ editableViewProps = () => ({
+ GetValue: () => '',
+ SetValue: this.addGroup,
+ contents: '+ New Column',
+ });
sectionNoteTaking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
const type = 'number';
@@ -544,7 +550,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
columnHeaders={this.columnHeaders}
Document={this.props.Document}
DataDoc={this.props.DataDoc}
- resizeColumns={this.resizeColumns.bind(this)}
+ resizeColumns={this.resizeColumns}
renderChildren={this.children}
numGroupColumns={this.numGroupColumns}
gridGap={this.gridGap}
@@ -561,11 +567,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
type={type}
createDropTarget={this.createDashEventsTarget}
screenToLocalTransform={this.props.ScreenToLocalTransform}
- editableViewProps={{
- GetValue: () => '',
- SetValue: this.addGroup,
- contents: '+ New Column',
- }}
+ editableViewProps={this.editableViewProps}
/>
);
};
@@ -622,7 +624,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
const col = this.sectionNoteTaking(sections[i][0], sections[i][1]);
eles.push(col);
if (i < sections.length - 1) {
- eles.push(<CollectionNoteTakingViewDivider key={`divider${i}`} index={i + 1} setColumnStartXCoords={this.setColumnStartXCoords.bind(this)} xMargin={this.xMargin} />);
+ eles.push(<CollectionNoteTakingViewDivider key={`divider${i}`} index={i + 1} setColumnStartXCoords={this.setColumnStartXCoords} xMargin={this.xMargin} />);
}
}
return eles;
@@ -705,7 +707,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
}}
onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))}
- onPointerOver={e => this.onPointerOver(e.clientX, e.clientY)}
+ onPointerOver={e => this.onPointerOver(e.buttons ? true : false, e.clientX, e.clientY)}
onDrop={this.onExternalDrop.bind(this)}
onContextMenu={this.onContextMenu}
onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}>
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 8452d895f..9b7518c60 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -47,7 +47,7 @@ interface CSVFieldColumnProps {
screenToLocalTransform: () => Transform;
observeHeight: (myref: any) => void;
unobserveHeight: (myref: any) => void;
- editableViewProps: any;
+ editableViewProps: () => any;
resizeColumns: (n: number) => void;
columnStartXCoords: number[];
PanelWidth: number;
@@ -112,7 +112,6 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
@action
headingChanged = (value: string, shiftDown?: boolean) => {
- console.log('HEADING CH');
const castedValue = this.getValue(value);
if (castedValue) {
if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) {
@@ -144,43 +143,17 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
return this.props.addDocument?.(newDoc) || false;
};
+ @undoBatch
@action
deleteColumn = () => {
- if (!this.props.columnHeaders) {
- return;
- }
- if (this.props.headingObject) {
+ if (this.props.columnHeaders && 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.docList.forEach(d => (d[this.props.pivotField] = 'unset'));
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[] = [];
@@ -256,7 +229,6 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
@computed get innards() {
TraceMobx();
- console.log('INNARD START');
const key = this.props.pivotField;
const heading = this._heading;
const columnYMargin = this.props.headingObject ? 0 : this.props.yMargin;
@@ -274,7 +246,6 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
}}>
<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} />
@@ -314,7 +285,7 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
<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} />
+ <EditableView {...this.props.editableViewProps()} />
</div>
{this.props.columnHeaders?.length && this.props.columnHeaders.length > 1 && (
<button className="collectionNoteTakingView-sectionDelete" onClick={this.deleteColumn}>
diff --git a/src/fields/List.ts b/src/fields/List.ts
index b15548327..5cc4ca543 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -1,25 +1,25 @@
-import { action, observable } from "mobx";
-import { alias, list, serializable } from "serializr";
-import { DocServer } from "../client/DocServer";
-import { ScriptingGlobals } from "../client/util/ScriptingGlobals";
-import { afterDocDeserialize, autoObject, Deserializable } from "../client/util/SerializationHelper";
-import { Field } from "./Doc";
-import { Copy, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from "./FieldSymbols";
-import { ObjectField } from "./ObjectField";
-import { ProxyField } from "./Proxy";
-import { RefField } from "./RefField";
-import { listSpec } from "./Schema";
-import { Cast } from "./Types";
-import { deleteProperty, getter, setter, updateFunction } from "./util";
+import { action, observable } from 'mobx';
+import { alias, list, serializable } from 'serializr';
+import { DocServer } from '../client/DocServer';
+import { ScriptingGlobals } from '../client/util/ScriptingGlobals';
+import { afterDocDeserialize, autoObject, Deserializable } from '../client/util/SerializationHelper';
+import { Field } from './Doc';
+import { Copy, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from './FieldSymbols';
+import { ObjectField } from './ObjectField';
+import { ProxyField } from './Proxy';
+import { RefField } from './RefField';
+import { listSpec } from './Schema';
+import { Cast } from './Types';
+import { deleteProperty, getter, setter, updateFunction } from './util';
const listHandlers: any = {
/// Mutator methods
copyWithin() {
- throw new Error("copyWithin not supported yet");
+ throw new Error('copyWithin not supported yet');
},
fill(value: any, start?: number, end?: number) {
if (value instanceof RefField) {
- throw new Error("fill with RefFields not supported yet");
+ throw new Error('fill with RefFields not supported yet');
}
const res = this[Self].__fields.fill(value, start, end);
this[Update]();
@@ -44,7 +44,7 @@ const listHandlers: any = {
}
}
const res = list.__fields.push(...items);
- this[Update]({ op: "$addToSet", items, length: length + items.length });
+ this[Update]({ op: '$addToSet', items, length: length + items.length });
return res;
}),
reverse() {
@@ -78,8 +78,13 @@ const listHandlers: any = {
}
}
const res = list.__fields.splice(start, deleteCount, ...items);
- this[Update](items.length === 0 && deleteCount ? { op: "$remFromSet", items: removed, length: list.__fields.length } :
- items.length && !deleteCount && start === list.__fields.length ? { op: "$addToSet", items, length: list.__fields.length } : undefined);
+ this[Update](
+ items.length === 0 && deleteCount
+ ? { op: '$remFromSet', items: removed, length: list.__fields.length }
+ : items.length && !deleteCount && start === list.__fields.length
+ ? { op: '$addToSet', items, length: list.__fields.length }
+ : undefined
+ );
return res.map(toRealField);
}),
unshift(...items: any[]) {
@@ -98,7 +103,6 @@ const listHandlers: any = {
const res = this[Self].__fields.unshift(...items);
this[Update]();
return res;
-
},
/// Accessor methods
concat: action(function (this: any, ...items: any[]) {
@@ -198,7 +202,7 @@ const listHandlers: any = {
},
[Symbol.iterator]() {
return this[Self].__realFields().values();
- }
+ },
};
function toObjectField(field: Field) {
@@ -217,14 +221,14 @@ function listGetter(target: any, prop: string | number | symbol, receiver: any):
}
interface ListSpliceUpdate<T> {
- type: "splice";
+ type: 'splice';
index: number;
added: T[];
removedCount: number;
}
interface ListIndexUpdate<T> {
- type: "update";
+ type: 'update';
index: number;
newValue: T;
}
@@ -233,7 +237,7 @@ type ListUpdate<T> = ListSpliceUpdate<T> | ListIndexUpdate<T>;
type StoredType<T extends Field> = T extends RefField ? ProxyField<T> : T;
-@Deserializable("list")
+@Deserializable('list')
class ListImpl<T extends Field> extends ObjectField {
constructor(fields?: T[]) {
super();
@@ -244,14 +248,16 @@ class ListImpl<T extends Field> extends ObjectField {
getOwnPropertyDescriptor: (target, prop) => {
if (prop in target.__fields) {
return {
- configurable: true,//TODO Should configurable be true?
+ configurable: true, //TODO Should configurable be true?
enumerable: true,
};
}
return Reflect.getOwnPropertyDescriptor(target, prop);
},
deleteProperty: deleteProperty,
- defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); },
+ defineProperty: () => {
+ throw new Error("Currently properties can't be defined on documents using Object.defineProperty");
+ },
});
this[SelfProxy] = list;
if (fields) {
@@ -265,7 +271,7 @@ class ListImpl<T extends Field> extends ObjectField {
// this requests all ProxyFields at the same time to avoid the overhead
// of separate network requests and separate updates to the React dom.
private __realFields() {
- const promised = this.__fields.filter(f => f instanceof ProxyField && f.promisedValue()).map(f => ({ field: f as any, promisedFieldId: (f instanceof ProxyField) ? f.promisedValue() : "" }));
+ const promised = this.__fields.filter(f => f instanceof ProxyField && f.promisedValue()).map(f => ({ field: f as any, promisedFieldId: f instanceof ProxyField ? f.promisedValue() : '' }));
// if we find any ProxyFields that don't have a current value, then
// start the server request for all of them
if (promised.length) {
@@ -282,7 +288,7 @@ class ListImpl<T extends Field> extends ObjectField {
return this.__fields.map(toRealField);
}
- @serializable(alias("fields", list(autoObject(), { afterDeserialize: afterDocDeserialize })))
+ @serializable(alias('fields', list(autoObject(), { afterDeserialize: afterDocDeserialize })))
private get __fields() {
return this.___fields;
}
@@ -299,7 +305,7 @@ class ListImpl<T extends Field> extends ObjectField {
}
[Copy]() {
- const copiedData = this[Self].__fields.map(f => f instanceof ObjectField ? f[Copy]() : f);
+ const copiedData = this[Self].__fields.map(f => (f instanceof ObjectField ? f[Copy]() : f));
const deepCopy = new ListImpl<T>(copiedData as any);
return deepCopy;
}
@@ -313,7 +319,7 @@ class ListImpl<T extends Field> extends ObjectField {
const update = this[OnUpdate];
// update && update(diff);
update?.(diff);
- }
+ };
private [Self] = this;
private [SelfProxy]: any;
@@ -328,9 +334,9 @@ class ListImpl<T extends Field> extends ObjectField {
export type List<T extends Field> = ListImpl<T> & (T | (T extends RefField ? Promise<T> : never))[];
export const List: { new <T extends Field>(fields?: T[]): List<T> } = ListImpl as any;
-ScriptingGlobals.add("List", List);
+ScriptingGlobals.add('List', List);
ScriptingGlobals.add(function compareLists(l1: any, l2: any) {
- const L1 = Cast(l1, listSpec("string"), []);
- const L2 = Cast(l2, listSpec("string"), []);
+ const L1 = Cast(l1, listSpec('string'), []);
+ const L2 = Cast(l2, listSpec('string'), []);
return !L1 && !L2 ? true : L1 && L2 && L1.length === L2.length && L2.reduce((p, v) => p && L1.includes(v), true);
-}, "compare two lists"); \ No newline at end of file
+}, 'compare two lists');
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 41e723119..d87bb6656 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -33,6 +33,7 @@ import { ObjectField } from './ObjectField';
import { PrefetchProxy, ProxyField } from './Proxy';
import { RefField } from './RefField';
import { RichTextField } from './RichTextField';
+import { SchemaHeaderField } from './SchemaHeaderField';
import { ComputedField } from './ScriptField';
import { ScriptCast, StrCast } from './Types';
@@ -455,7 +456,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
? {
redo: action(() => {
diff.items.forEach((item: any) => {
- const ind = receiver[prop].indexOf(item.value ? item.value() : item);
+ const ind = item instanceof SchemaHeaderField ? receiver[prop].findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) : receiver[prop].indexOf(item.value ? item.value() : item);
ind !== -1 && receiver[prop].splice(ind, 1);
});
lastValue = ObjectField.MakeCopy(receiver[prop]);
@@ -463,8 +464,13 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
undo: () => {
// console.log("undo $rem: " + prop, diff.items) // bcz: uncomment to log undo
diff.items.forEach((item: any) => {
- const ind = (prevValue as List<any>).indexOf(item.value ? item.value() : item);
- ind !== -1 && receiver[prop].indexOf(item.value ? item.value() : item) === -1 && receiver[prop].splice(ind, 0, item);
+ if (item instanceof SchemaHeaderField) {
+ const ind = (prevValue as List<any>).findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading);
+ ind !== -1 && receiver[prop].findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) === -1 && receiver[prop].splice(ind, 0, item);
+ } else {
+ const ind = (prevValue as List<any>).indexOf(item.value ? item.value() : item);
+ ind !== -1 && receiver[prop].indexOf(item.value ? item.value() : item) === -1 && receiver[prop].splice(ind, 0, item);
+ }
});
lastValue = ObjectField.MakeCopy(receiver[prop]);
},