aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/MainView.tsx1
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.scss4
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx312
-rw-r--r--src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx2
-rw-r--r--src/client/views/collections/collectionSchema/SchemaRowBox.tsx83
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx40
-rw-r--r--src/client/views/nodes/DocumentView.tsx22
-rw-r--r--src/client/views/nodes/ImageBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx7
-rw-r--r--src/mobile/MobileInterface.tsx2
10 files changed, 299 insertions, 176 deletions
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 2c7d3d32a..637824c31 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -315,6 +315,7 @@ export class MainView extends ObservableReactComponent<{}> {
fa.faSnowflake,
fa.faStar,
fa.faMicrophone,
+ fa.faCircleHalfStroke,
fa.faKeyboard,
fa.faQuestion,
fa.faTasks,
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 9768877ff..6fb8e40db 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -176,12 +176,12 @@
}
}
- .schema-column-resizer.left {
+ /*.schema-column-resizer.left {
min-width: 5px;
transform: translate(-3px, 0px);
align-self: flex-start;
background-color: $medium-gray;
- }
+ }*/ // creates awkward thick gray borders between colheaders
}
.schema-header-menu {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 77247e675..023b72778 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -12,7 +12,7 @@ import { Id } from '../../../../fields/FieldSymbols';
import { List } from '../../../../fields/List';
import { listSpec } from '../../../../fields/Schema';
import { ColumnType } from '../../../../fields/SchemaHeaderField';
-import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, Cast, NumCast, StrCast } from '../../../../fields/Types';
import { DocUtils } from '../../../documents/DocUtils';
import { Docs, DocumentOptions, FInfo } from '../../../documents/Documents';
import { DragManager } from '../../../util/DragManager';
@@ -50,7 +50,6 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'author_date', '
@observer
export class CollectionSchemaView extends CollectionSubView() {
private _keysDisposer: any;
- private _closestDropIndex: number = 0;
private _previewRef: HTMLDivElement | null = null;
private _makeNewColumn: boolean = false;
private _documentOptions: DocumentOptions = new DocumentOptions();
@@ -82,7 +81,13 @@ export class CollectionSchemaView extends CollectionSubView() {
@observable _menuValue: string = '';
@observable _filterColumnIndex: number | undefined = undefined;
@observable _filterSearchValue: string = '';
- @observable _selectedCell: [Doc, number] | undefined = undefined;
+ @observable _selectedCol: number = 0;
+ @observable _selectedCells: Array<Doc> = [];
+ @observable _mouseCoordinates = { x: 0, y: 0 };
+ @observable _lowestSelectedIndex = -1; //lowest index among selected rows; used to properly sync dragged docs with cursor position
+ @observable _relCursorIndex = -1; //cursor index relative to the current selected cells
+ @observable _draggedColIndex = 0;
+ @observable _colBeingDragged = false;
// target HTMLelement portal for showing a popup menu to edit cell values.
public get MenuTarget() {
@@ -90,7 +95,8 @@ export class CollectionSchemaView extends CollectionSubView() {
}
@computed get _selectedDocs() {
- const selected = DocumentView.SelectedDocs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.Document));
+ // get all selected documents then filter out any whose parent is not this schema document
+ const selected = DocumentView.SelectedDocs().filter(doc => this.childDocs.includes(doc));
if (!selected.length) {
// if no schema doc is directly selected, test if a child of a schema doc is selected (such as in the preview window)
const childOfSchemaDoc = DocumentView.SelectedDocs().find(sel => DocumentView.getContextPath(sel, true).includes(this.Document));
@@ -118,6 +124,10 @@ export class CollectionSchemaView extends CollectionSubView() {
return Cast(this.layoutDoc.schema_columnKeys, listSpec('string'), defaultColumnKeys);
}
+ @computed get rowKeys() {
+ return Cast(this.layoutDoc.schema_rowKeys, listSpec('string'), []);
+ }
+
@computed get storedColumnWidths() {
const widths = NumListCast(
this.layoutDoc.schema_columnWidths,
@@ -125,12 +135,18 @@ export class CollectionSchemaView extends CollectionSubView() {
);
const totalWidth = widths.reduce((sum, width) => sum + width, 0);
+ //If the total width of all columns is not the width of the schema table minus the width of the row menu, resize them appropriately
if (totalWidth !== this.tableWidth - CollectionSchemaView._rowMenuWidth) {
return widths.map(w => (w / totalWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth));
}
return widths;
}
+ @computed get rowHeights() {
+ const heights = this.childDocs.map(() => this.rowHeightFunc());
+ return heights;
+ }
+
@computed get displayColumnWidths() {
return this._displayColumnWidths ?? this.storedColumnWidths;
}
@@ -150,8 +166,8 @@ export class CollectionSchemaView extends CollectionSubView() {
Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1]));
this._keysDisposer = observe(
this.dataDoc[this.fieldKey ?? 'data'] as List<Doc>,
- change => {
- switch (change.type as any) {
+ (change: any) => {
+ switch (change.type) {
case 'splice':
// prettier-ignore
(change as any).added.forEach((doc: Doc) => // for each document added
@@ -188,13 +204,14 @@ export class CollectionSchemaView extends CollectionSubView() {
const lastIndex = this.rowIndex(lastDoc);
const curDoc = this.sortedDocs.docs[lastIndex];
if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
- !e.shiftKey && this.clearSelection();
const newDoc = this.sortedDocs.docs[lastIndex + 1];
if (this._selectedDocs.includes(newDoc)) {
DocumentView.DeselectView(DocumentView.getFirstDocumentView(curDoc));
+ this.deselectCell(curDoc);
} else {
- this.addDocToSelection(newDoc, e.shiftKey);
- this._selectedCell && (this._selectedCell[0] = newDoc);
+ const shift: boolean = e.shiftKey;
+ const ctrl: boolean = e.ctrlKey;
+ this.selectCell(newDoc, this._selectedCol, shift, ctrl);
this.scrollToDoc(newDoc, {});
}
}
@@ -208,12 +225,14 @@ export class CollectionSchemaView extends CollectionSubView() {
const firstIndex = this.rowIndex(firstDoc);
const curDoc = this.sortedDocs.docs[firstIndex];
if (firstIndex > 0 && firstIndex < this.childDocs.length) {
- !e.shiftKey && this.clearSelection();
const newDoc = this.sortedDocs.docs[firstIndex - 1];
- if (this._selectedDocs.includes(newDoc)) DocumentView.DeselectView(DocumentView.getFirstDocumentView(curDoc));
- else {
- this.addDocToSelection(newDoc, e.shiftKey);
- this._selectedCell && (this._selectedCell[0] = newDoc);
+ if (this._selectedDocs.includes(newDoc)) {
+ DocumentView.DeselectView(DocumentView.getFirstDocumentView(curDoc));
+ this.deselectCell(curDoc);
+ } else {
+ const shift: boolean = e.shiftKey;
+ const ctrl: boolean = e.ctrlKey;
+ this.selectCell(newDoc, this._selectedCol, shift, ctrl);
this.scrollToDoc(newDoc, {});
}
}
@@ -222,17 +241,17 @@ export class CollectionSchemaView extends CollectionSubView() {
}
break;
case 'ArrowRight':
- if (this._selectedCell) {
- this._selectedCell[1] = Math.min(this._selectedCell[1] + 1, this.columnKeys.length - 1);
+ if (this._selectedCells) {
+ this._selectedCol = Math.min(this._colEles.length - 1, this._selectedCol + 1);
} else if (this._selectedDocs.length > 0) {
- this.selectCell(this._selectedDocs[0], 0);
+ this.selectCell(this._selectedDocs[0], 0, false, false);
}
break;
case 'ArrowLeft':
- if (this._selectedCell) {
- this._selectedCell[1] = Math.max(this._selectedCell[1] - 1, 0);
+ if (this._selectedCells) {
+ this._selectedCol = Math.max(0, this._selectedCol - 1);
} else if (this._selectedDocs.length > 0) {
- this.selectCell(this._selectedDocs[0], 0);
+ this.selectCell(this._selectedDocs[0], 0, false, false);
}
break;
case 'Backspace': {
@@ -240,7 +259,7 @@ export class CollectionSchemaView extends CollectionSubView() {
break;
}
case 'Escape': {
- this.deselectCell();
+ this.deselectAllCells();
break;
}
default:
@@ -248,6 +267,9 @@ export class CollectionSchemaView extends CollectionSubView() {
}
};
+ @action
+ changeSelectedCellColumn = () => {};
+
@undoBatch
setColumnSort = (field: string | undefined, desc: boolean = false) => {
this.layoutDoc.sortField = field;
@@ -345,6 +367,9 @@ export class CollectionSchemaView extends CollectionSubView() {
@undoBatch
moveColumn = (fromIndex: number, toIndex: number) => {
+ if (this._selectedCol === fromIndex) this._selectedCol = toIndex;
+ else if (toIndex === this._selectedCol) this._selectedCol = fromIndex; //keeps selected cell consistent
+
const currKeys = this.columnKeys.slice();
currKeys.splice(toIndex, 0, currKeys.splice(fromIndex, 1)[0]);
this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
@@ -352,27 +377,22 @@ export class CollectionSchemaView extends CollectionSubView() {
const currWidths = this.storedColumnWidths.slice();
currWidths.splice(toIndex, 0, currWidths.splice(fromIndex, 1)[0]);
this.layoutDoc.schema_columnWidths = new List<number>(currWidths);
+
+ this._draggedColIndex = toIndex;
};
@action
dragColumn = (e: PointerEvent, index: number) => {
+ this._draggedColIndex = index;
+ this._colBeingDragged = true;
const dragData = new DragManager.ColumnDragData(index);
const dragEles = [this._colEles[index]];
this.childDocs.forEach(doc => dragEles.push(this._rowEles.get(doc).children[1].children[index]));
DragManager.StartColumnDrag(dragEles, dragData, e.x, e.y);
-
- document.removeEventListener('pointermove', this.highlightDropColumn);
- document.addEventListener('pointermove', this.highlightDropColumn);
- const stopHighlight = () => {
- document.removeEventListener('pointermove', this.highlightDropColumn);
- document.removeEventListener('pointerup', stopHighlight);
- };
- document.addEventListener('pointerup', stopHighlight);
-
return true;
};
- findDropIndex = (mouseX: number) => {
+ findColDropIndex = (mouseX: number) => {
let index: number | undefined;
this.displayColumnWidths.reduce((total, curr, i) => {
if (total <= mouseX && total + curr >= mouseX) {
@@ -380,26 +400,79 @@ export class CollectionSchemaView extends CollectionSubView() {
else index = i + 1;
}
return total + curr;
- }, CollectionSchemaView._rowMenuWidth);
+ }, 2 * CollectionSchemaView._rowMenuWidth); //probably prone to issues; find better implementation (!!!)
return index;
};
+ /**
+ * Calculates the relative index of the cursor in the group of selected rows, ie.
+ * if five rows are selected and the cursor is in the middle row, its relative index would be 2.
+ * Used to align actively dragged documents properly with the cursor.
+ * @param mouseY the initial Y position of the cursor on drag
+ */
@action
- highlightDropColumn = (e: PointerEvent) => {
- e.stopPropagation();
- const mouseX = this.ScreenToLocalBoxXf().transformPoint(e.clientX, e.clientY)[0];
- const index = this.findDropIndex(mouseX);
+ setRelCursorIndex = (mouseY: number) => {
+ this._mouseCoordinates.y = mouseY; //updates this.rowDropIndex computed value to overwrite the old cached value
+
+ let rowHeight = CollectionSchemaView._rowHeight;
+ let adjInitMouseY = mouseY - rowHeight - 100; //rowHeight: height of the column menu cells | 100: height of the top menu
+ let yOffset = this._lowestSelectedIndex * rowHeight;
+
+ const heights = this._selectedDocs.map(() => this.rowHeightFunc());
+ let index: number = 0;
+ heights.reduce((total, curr, i) => {
+ if (total <= adjInitMouseY && total + curr >= adjInitMouseY) {
+ if (adjInitMouseY <= total + curr) index = i;
+ else index = i + 1;
+ }
+ return total + curr;
+ }, yOffset);
+ this._relCursorIndex = index;
+ };
+
+ //Uses current mouse position to calculate the indexes of actively dragged docs
+ findRowDropIndex = (mouseY: number) => {
+ let rowHeight = CollectionSchemaView._rowHeight;
+ let index: number = 0;
+ this.rowHeights.reduce((total, curr, i) => {
+ if (total <= mouseY && total + curr >= mouseY) {
+ if (mouseY <= total + curr) index = i;
+ else index = i + 1;
+ }
+ return total + curr;
+ }, rowHeight);
+
+ //fix index if selected rows are dragged out of bounds
+ let adjIndex = index - this._relCursorIndex;
+ let maxY = this.rowHeights.reduce((total, curr) => total + curr, 0) + rowHeight;
+ if (mouseY > maxY) adjIndex = this.childDocs.length - 1;
+ else if (adjIndex <= 0) adjIndex = 0;
+
+ return adjIndex;
+ };
+
+ @action
+ highlightDraggedColumn = (index: number) => {
this._colEles.forEach((colRef, i) => {
- let leftStyle = '';
- let rightStyle = '';
- if (i + 1 === index) rightStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
- if (i === index && i === 0) leftStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
- colRef.style.borderLeft = leftStyle;
- colRef.style.borderRight = rightStyle;
- this.childDocs.forEach(doc => {
- this._rowEles.get(doc).children[1].children[i].style.borderLeft = leftStyle;
- this._rowEles.get(doc).children[1].children[i].style.borderRight = rightStyle;
- });
+ let edgeStyle = '';
+ if (i === index) edgeStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
+
+ //border styles of menu cell
+ colRef.style.borderLeft = edgeStyle;
+ colRef.style.borderRight = edgeStyle;
+ colRef.style.borderTop = edgeStyle;
+
+ for (let doc = 0; doc < this.childDocs.length; ++doc) {
+ if (i === this._selectedCol && this._selectedDocs.includes(this.childDocs[doc])) {
+ continue;
+ } else {
+ this._rowEles.get(this.childDocs[doc]).children[1].children[i].style.borderLeft = edgeStyle;
+ this._rowEles.get(this.childDocs[doc]).children[1].children[i].style.borderRight = edgeStyle;
+ if (doc === this.childDocs.length - 1) {
+ this._rowEles.get(this.childDocs[doc]).children[1].children[i].style.borderBottom = edgeStyle;
+ }
+ }
+ }
});
};
@@ -422,7 +495,10 @@ export class CollectionSchemaView extends CollectionSubView() {
};
@action
- clearSelection = () => DocumentView.DeselectAll();
+ clearSelection = () => {
+ DocumentView.DeselectAll();
+ this.deselectAllCells();
+ };
selectRows = (doc: Doc, lastSelected: Doc) => {
const index = this.rowIndex(doc);
@@ -431,63 +507,95 @@ export class CollectionSchemaView extends CollectionSubView() {
const endRow = Math.max(lastSelectedRow, index);
for (let i = startRow; i <= endRow; i++) {
const currDoc = this.sortedDocs.docs[i];
- if (!this._selectedDocs.includes(currDoc)) this.addDocToSelection(currDoc, true);
+ if (!this._selectedDocs.includes(currDoc)) {
+ this.selectCell(currDoc, this._selectedCol, false, true);
+ }
}
};
@action
- selectCell = (doc: Doc, index: number) => {
- this._selectedCell = [doc, index];
+ selectCell = (doc: Doc, col: number, shiftKey: boolean, ctrlKey: boolean) => {
+ if (!shiftKey && !ctrlKey) this.clearSelection();
+ !this._selectedCells && (this._selectedCells = []);
+ !shiftKey && this._selectedCells && this._selectedCells.push(doc);
+ let index = this.rowIndex(doc);
+
+ if (!this) return;
+ const lastSelected = Array.from(this._selectedDocs).lastElement();
+ if (shiftKey && lastSelected && !this._selectedDocs.includes(doc)) this.selectRows(doc, lastSelected);
+ else if (ctrlKey) {
+ if (lastSelected && this._selectedDocs.includes(doc)) {
+ DocumentView.DeselectView(DocumentView.getFirstDocumentView(doc));
+ this.deselectCell(doc);
+ } else this.addDocToSelection(doc, true);
+ } else this.addDocToSelection(doc, false);
+ this._selectedCol = col;
+
+ if (this._lowestSelectedIndex === -1 || index < this._lowestSelectedIndex) this._lowestSelectedIndex = index;
+
+ //let selectedIndexes: Array<Number> = this._selectedCells.map(doc => this.rowIndex(doc));
+ };
+
+ @action
+ deselectCell = (doc: Doc) => {
+ this._selectedCells && (this._selectedCells = this._selectedCells.filter(d => d !== doc));
+ if (this.rowIndex(doc) == this._lowestSelectedIndex) this._lowestSelectedIndex = Math.min(...this._selectedDocs.map(doc => this.rowIndex(doc)));
};
@action
- deselectCell = () => {
- this._selectedCell = undefined;
+ deselectAllCells = () => {
+ this._selectedCells = [];
+ this._lowestSelectedIndex = -1;
};
sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc));
- setDropIndex = (index: number) => {
- this._closestDropIndex = index;
- };
+ @computed
+ get rowDropIndex() {
+ const mouseY = this.ScreenToLocalBoxXf().transformPoint(this._mouseCoordinates.x, this._mouseCoordinates.y)[1];
+ const index = this.findRowDropIndex(mouseY);
+ return index;
+ }
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
if (de.complete.columnDragData) {
- const mouseX = this.ScreenToLocalBoxXf().transformPoint(de.x, de.y)[0];
- const index = this.findDropIndex(mouseX);
- this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex);
+ this._colBeingDragged = false;
+ e.stopPropagation();
this._colEles.forEach((colRef, i) => {
+ //style for menu cell
colRef.style.borderLeft = '';
colRef.style.borderRight = '';
+ colRef.style.borderTop = '';
+
this.childDocs.forEach(doc => {
- this._rowEles.get(doc).children[1].children[i].style.borderLeft = '';
- this._rowEles.get(doc).children[1].children[i].style.borderRight = '';
+ if (!(this._selectedDocs.includes(doc) && i === this._selectedCol)) {
+ this._rowEles.get(doc).children[1].children[i].style.borderLeft = '';
+ this._rowEles.get(doc).children[1].children[i].style.borderRight = '';
+ this._rowEles.get(doc).children[1].children[i].style.borderBottom = '';
+ }
});
});
-
- e.stopPropagation();
return true;
}
+
const draggedDocs = de.complete.docDragData?.draggedDocuments;
if (draggedDocs && super.onInternalDrop(e, de) && !this.sortField) {
- const pushedDocs = this.childDocs.filter((doc, index) => index >= this._closestDropIndex && !draggedDocs.includes(doc));
- const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs];
- const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc));
- this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...removed, ...draggedDocs, ...pushedDocs]);
+ let map = draggedDocs?.map(doc => this.rowIndex(doc));
+ console.log(map);
+ this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...this.sortedDocs.docs]);
this.clearSelection();
draggedDocs.forEach(doc => {
- const draggedView = DocumentView.getFirstDocumentView(doc);
- if (draggedView) DocumentView.removeView(draggedView);
DocumentView.addViewRenderedCb(doc, dv => dv.select(true));
});
+ this._lowestSelectedIndex = Math.min(...draggedDocs?.map(doc => this.rowIndex(doc)));
return true;
}
return false;
};
onExternalDrop = async (e: React.DragEvent): Promise<void> => {
- super.onExternalDrop(e, {}, undoBatch(action(docus => docus.map((doc: Doc) => this.addDocument(doc)))));
+ super.onExternalDrop(e, {}, undoBatch(action(docs => docs.map((doc: Doc) => this.addDocument(doc)))));
};
onDividerDown = (e: React.PointerEvent) => setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, emptyFunction);
@@ -541,7 +649,7 @@ export class CollectionSchemaView extends CollectionSubView() {
id=""
value={this._newFieldDefault ?? 0}
onPointerDown={e => e.stopPropagation()}
- onChange={action(e => {
+ onChange={action((e: any) => {
this._newFieldDefault = e.target.value;
})}
/>
@@ -555,7 +663,7 @@ export class CollectionSchemaView extends CollectionSubView() {
id=""
value={this._newFieldDefault}
onPointerDown={e => e.stopPropagation()}
- onChange={action(e => {
+ onChange={action((e: any) => {
this._newFieldDefault = e.target.checked;
})}
/>
@@ -570,7 +678,7 @@ export class CollectionSchemaView extends CollectionSubView() {
id=""
value={this._newFieldDefault ?? ''}
onPointerDown={e => e.stopPropagation()}
- onChange={action(e => {
+ onChange={action((e: any) => {
this._newFieldDefault = e.target.value;
})}
/>
@@ -607,7 +715,28 @@ export class CollectionSchemaView extends CollectionSubView() {
};
setColumnValues = (key: string, value: string) => {
- this.childDocs.forEach(doc => Doc.SetField(doc, key, value));
+ const selectedDocs: Doc[] = new Array();
+ this.childDocs.forEach(doc => {
+ let docIsSelected = this._selectedCells && !(this._selectedCells?.filter(d => d === doc).length === 0);
+ if (docIsSelected) {
+ selectedDocs.push(doc);
+ }
+ });
+ if (selectedDocs.length === 1) {
+ this.childDocs.forEach(doc => Doc.SetField(doc, key, value));
+ } else {
+ selectedDocs.forEach(doc => Doc.SetField(doc, key, value));
+ }
+ return true;
+ };
+
+ setSelectedColumnValues = (key: string, value: string) => {
+ this.childDocs.forEach(doc => {
+ let docIsSelected = this._selectedCells && !(this._selectedCells?.filter(d => d === doc).length === 0);
+ if (docIsSelected) {
+ Doc.SetField(doc, key, value);
+ }
+ });
return true;
};
@@ -758,7 +887,7 @@ export class CollectionSchemaView extends CollectionSubView() {
<div className="schema-key-search">
<div
className="schema-column-menu-button"
- onPointerDown={action(e => {
+ onPointerDown={action((e: any) => {
e.stopPropagation();
this._makeNewField = true;
})}>
@@ -838,7 +967,7 @@ export class CollectionSchemaView extends CollectionSubView() {
type="checkbox"
onPointerDown={e => e.stopPropagation()}
onClick={e => e.stopPropagation()}
- onChange={action(e => {
+ onChange={action((e: any) => {
if (e.target.checked) {
Doc.setDocFilter(this.Document, columnKey, key, 'check');
} else {
@@ -861,7 +990,7 @@ export class CollectionSchemaView extends CollectionSubView() {
{this.renderFilterOptions}
<div
className="schema-column-menu-button"
- onPointerDown={action(e => {
+ onPointerDown={action((e: any) => {
e.stopPropagation();
this.closeFilterMenu();
})}>
@@ -871,12 +1000,27 @@ export class CollectionSchemaView extends CollectionSubView() {
);
}
+ @action
+ onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {
+ if (DragManager.docsBeingDragged.length) {
+ this._mouseCoordinates = { x: e.clientX, y: e.clientY };
+ }
+ if (this._colBeingDragged) {
+ let newIndex = this.findColDropIndex(e.clientX);
+ if (newIndex != this._draggedColIndex) this.moveColumn(this._draggedColIndex, newIndex ?? this._draggedColIndex);
+ this._draggedColIndex = newIndex ? newIndex : this._draggedColIndex;
+ this.highlightDraggedColumn(newIndex ?? this._draggedColIndex);
+ }
+ };
+
@computed get sortedDocs() {
const field = StrCast(this.layoutDoc.sortField);
- const desc = BoolCast(this.layoutDoc.sortDesc);
+ const desc = BoolCast(this.layoutDoc.sortDesc); // is this an ascending or descending sort
+ const staticDocs = this.childDocs.filter(d => !DragManager.docsBeingDragged.includes(d));
const docs = !field
- ? this.childDocs
- : [...this.childDocs].sort((docA, docB) => {
+ ? staticDocs
+ : [...staticDocs].sort((docA, docB) => {
+ // this sorts the documents based on the selected field. returning -1 for a before b, 0 for a = b, 1 for a > b
const aStr = Field.toString(docA[field] as FieldType);
const bStr = Field.toString(docB[field] as FieldType);
let out = 0;
@@ -885,8 +1029,11 @@ export class CollectionSchemaView extends CollectionSubView() {
if (desc) out *= -1;
return out;
});
+
+ docs.splice(this.rowDropIndex, 0, ...DragManager.docsBeingDragged);
return { docs };
}
+
rowHeightFunc = () => (BoolCast(this.layoutDoc._schema_singleLine) ? CollectionSchemaView._rowSingleLineHeight : CollectionSchemaView._rowHeight);
sortedDocsFunc = () => this.sortedDocs;
isContentActive = () => this._props.isSelected() || this._props.isContentActive();
@@ -896,8 +1043,8 @@ export class CollectionSchemaView extends CollectionSubView() {
_oldWheel: any;
render() {
return (
- <div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)}>
- <div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }} />
+ <div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)} onPointerMove={e => this.onPointerMove(e)}>
+ <div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }}></div>
<div
className="schema-table"
style={{ width: `calc(100% - ${this.previewWidth}px)` }}
@@ -1053,6 +1200,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
if (property === StyleProp.Opacity) return 1;
return DefaultStyleProvider(doc, props, property);
};
+ isRowContentActive = () => this._props.schema.isContentActive() || this._props.schema._props.isSelected() || this._props.schema._props.isAnyChildContentActive();
render() {
return (
<DocumentView
@@ -1079,7 +1227,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
ScreenToLocalTransform={this.screenToLocalXf}
dragWhenActive
isDocumentActive={this._props.schema._props.childDocumentsActive?.() ? this._props.schema._props.isDocumentActive : this._props.schema.isContentActive}
- isContentActive={emptyFunction}
+ isContentActive={this.isRowContentActive}
whenChildContentsActiveChanged={this._props.schema._props.whenChildContentsActiveChanged}
hideDecorations
hideTitle
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 389fc66b3..6b5a34ec0 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -45,7 +45,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
@action
onPointerDown = (e: React.PointerEvent) => {
- this.props.isContentActive(true) && setupMoveUpEvents(this, e, moveEv => this.props.dragColumn(moveEv, this.props.columnIndex), emptyFunction, emptyFunction, false);
+ this.props.isContentActive(true) && setupMoveUpEvents(this, e, moveEv => this.props.dragColumn(moveEv, this.props.columnIndex), emptyFunction, emptyFunction);
};
render() {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 32b48e4d1..059aa912e 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -9,8 +9,6 @@ import { returnFalse, setupMoveUpEvents } from '../../../../ClientUtils';
import { emptyFunction } from '../../../../Utils';
import { Doc } from '../../../../fields/Doc';
import { BoolCast } from '../../../../fields/Types';
-import { DragManager } from '../../../util/DragManager';
-import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import { undoable } from '../../../util/UndoManager';
import { ViewBoxBaseComponent } from '../../DocComponent';
@@ -54,63 +52,21 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
this._props.setContentViewBox?.(this);
}
- select = (ctrlKey: boolean, shiftKey: boolean) => {
- if (!this.schemaView) return;
- const lastSelected = Array.from(this.schemaView._selectedDocs).lastElement();
- if (shiftKey && lastSelected) this.schemaView.selectRows(this.Document, lastSelected);
- else {
- this._props.select?.(ctrlKey);
- }
- };
-
- onPointerEnter = () => {
- if (SnappingManager.IsDragging && this._props.isContentActive()) {
- document.removeEventListener('pointermove', this.onPointerMove);
- document.addEventListener('pointermove', this.onPointerMove);
- }
- };
-
- onPointerMove = (e: any) => {
- const dragIsRow = DragManager.docsBeingDragged.some(doc => doc.embedContainer === this.schemaDoc); // this.schemaView?._selectedDocs.has(doc) ?? false;
-
- if (this._ref && dragIsRow) {
- const rect = this._ref.getBoundingClientRect();
- const y = e.clientY - rect.top; // y position within the element.
- const height = this._ref.clientHeight;
- const halfLine = height / 2;
- if (y <= halfLine) {
- this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
- this._ref.style.borderBottom = '0px';
- this.schemaView?.setDropIndex(this.rowIndex);
- } else if (y > halfLine) {
- this._ref.style.borderTop = '0px';
- this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
- this.schemaView?.setDropIndex(this.rowIndex + 1);
- }
- }
- };
-
- onPointerLeave = () => {
- if (this._ref) {
- this._ref.style.borderTop = '0px';
- this._ref.style.borderBottom = '0px';
- }
- document.removeEventListener('pointermove', this.onPointerMove);
- };
-
+ setCursorIndex = (mouseY: number) => this.schemaView?.setRelCursorIndex(mouseY);
+ selectedCol = () => this.schemaView._selectedCol;
getFinfo = computedFn((fieldKey: string) => this.schemaView?.fieldInfos.get(fieldKey));
- selectCell = (doc: Doc, col: number) => this.schemaView?.selectCell(doc, col);
- deselectCell = () => this.schemaView?.deselectCell();
- selectedCell = () => this.schemaView?._selectedCell;
+ selectCell = (doc: Doc, col: number, shift: boolean, ctrl: boolean) => this.schemaView?.selectCell(doc, col, shift, ctrl);
+ deselectCell = () => this.schemaView?.deselectAllCells();
+ selectedCells = () => this.schemaView?._selectedDocs;
setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false;
+ setSelectedColumnValues = (field: any, value: any) => this.schemaView?.setSelectedColumnValues(field, value) ?? false;
columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
render() {
return (
<div
className="schema-row"
+ onPointerDown={e => this.setCursorIndex(e.clientY)}
style={{ height: this._props.PanelHeight(), backgroundColor: this._props.isSelected() ? Colors.LIGHT_BLUE : undefined }}
- onPointerEnter={this.onPointerEnter}
- onPointerLeave={this.onPointerLeave}
ref={(row: HTMLDivElement | null) => {
row && this.schemaView?.addRowRef?.(this.Document, row);
this._ref = row;
@@ -122,8 +78,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
pointerEvents: !this._props.isContentActive() ? 'none' : undefined,
}}>
<IconButton
- tooltip="whether document interactions are enabled"
- icon={this.Document._lockedPosition ? <CgLockUnlock size="12px" /> : <CgLock size="12px" />}
+ tooltip="close"
+ icon={<CgClose size="16px" />}
size={Size.XSMALL}
onPointerDown={e =>
setupMoveUpEvents(
@@ -133,14 +89,14 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
emptyFunction,
undoable(clickEv => {
clickEv.stopPropagation();
- Doc.toggleLockedPosition(this.Document);
+ this._props.removeDocument?.(this.Document);
}, 'Delete Row')
)
}
/>
<IconButton
- tooltip="close"
- icon={<CgClose size="16px" />}
+ tooltip="whether document interactions are enabled"
+ icon={this.Document._lockedPosition ? <CgLockUnlock size="12px" /> : <CgLock size="12px" />}
size={Size.XSMALL}
onPointerDown={e =>
setupMoveUpEvents(
@@ -148,13 +104,12 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
e,
returnFalse,
emptyFunction,
- undoable(clickEv => {
- clickEv.stopPropagation();
- this._props.removeDocument?.(this.Document);
- }, 'Delete Row')
+ undoable(e => {
+ e.stopPropagation();
+ Doc.toggleLockedPosition(this.Document);
+ }, 'Delete Row') //(??) should this be something else?
)
- }
- />
+ }></IconButton>
<IconButton
tooltip="open preview"
icon={<FaExternalLinkAlt />}
@@ -187,8 +142,10 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
getFinfo={this.getFinfo}
selectCell={this.selectCell}
deselectCell={this.deselectCell}
- selectedCell={this.selectedCell}
+ selectedCells={this.selectedCells}
+ selectedCol={this.selectedCol}
setColumnValues={this.setColumnValues}
+ setSelectedColumnValues={this.setSelectedColumnValues}
oneLine={BoolCast(this.schemaDoc?._singleLine)}
menuTarget={this.schemaView.MenuTarget}
transform={() => {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 3df7ecdbe..48c86ac27 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -10,7 +10,7 @@ import * as React from 'react';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import Select from 'react-select';
-import { ClientUtils, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../ClientUtils';
+import { ClientUtils, StopEvent, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../ClientUtils';
import { emptyFunction } from '../../../../Utils';
import { DateField } from '../../../../fields/DateField';
import { Doc, DocListCast, Field } from '../../../../fields/Doc';
@@ -37,8 +37,9 @@ export interface SchemaTableCellProps {
Document: Doc;
col: number;
deselectCell: () => void;
- selectCell: (doc: Doc, col: number) => void;
- selectedCell: () => [Doc, number] | undefined;
+ selectCell: (doc: Doc, col: number, shift: boolean, ctrl: boolean) => void;
+ selectedCells: () => Doc[] | undefined;
+ selectedCol: () => number;
fieldKey: string;
maxWidth?: () => number;
columnWidth: () => number;
@@ -47,6 +48,7 @@ export interface SchemaTableCellProps {
isRowActive: () => boolean | undefined;
getFinfo: (fieldKey: string) => FInfo | undefined;
setColumnValues: (field: string, value: string) => boolean;
+ setSelectedColumnValues: (field: string, value: string) => boolean;
oneLine?: boolean; // whether all input should fit on one line vs allowing textare multiline inputs
allowCRs?: boolean; // allow carriage returns in text input (othewrise CR ends the edit)
finishEdit?: () => void; // notify container that edit is over (eg. to hide view in DashFieldView)
@@ -80,7 +82,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
doc = DocCast(doc.proto);
}
const parenCount = Math.max(0, protoCount - 1);
- const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue';
+ const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue'; //color of text in cells
const textDecoration = color !== 'black' && parenCount ? 'underline' : '';
const fieldProps: FieldViewProps = {
childFilters: returnEmptyFilter,
@@ -113,8 +115,9 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
}
@computed get selected() {
- const selected: [Doc, number] | undefined = this._props.selectedCell();
- return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col;
+ const selectedDocs: Doc[] | undefined = this._props.selectedCells();
+ let isSelected = this._props.isRowActive() && selectedDocs?.filter(doc => doc === this._props.Document).length !== 0 && this._props.selectedCol() === this._props.col;
+ return isSelected;
}
@computed get defaultCellContent() {
@@ -186,7 +189,17 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
return (
<div
className="schema-table-cell"
- onPointerDown={action(() => !this.selected && this._props.selectCell(this._props.Document, this._props.col))}
+ onContextMenu={e => StopEvent(e)}
+ onPointerDown={action(e => {
+ const shift: boolean = e.shiftKey;
+ const ctrl: boolean = e.ctrlKey;
+ if (this._props.isRowActive?.() !== false) {
+ if (this.selected && ctrl) {
+ this._props.selectCell(this._props.Document, this._props.col, shift, ctrl);
+ e.stopPropagation();
+ } else !this.selected && this._props.selectCell(this._props.Document, this._props.col, shift, ctrl);
+ }
+ })}
style={{ padding: this._props.padding, maxWidth: this._props.maxWidth?.(), width: this._props.columnWidth() || undefined, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
{this.content}
</div>
@@ -318,8 +331,9 @@ export class SchemaRTFCell extends ObservableReactComponent<SchemaTableCellProps
}
@computed get selected() {
- const selected: [Doc, number] | undefined = this._props.selectedCell();
- return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col;
+ const selected = this._props.selectedCells();
+ return this._props.isRowActive() && selected && selected?.filter(doc => doc === this._props.Document).length !== 0 && this._props.selectedCol() === this._props.col;
+ //return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col;
}
// if the text box blurs and none of its contents are focused(), then the edit finishes
@@ -342,8 +356,8 @@ export class SchemaBoolCell extends ObservableReactComponent<SchemaTableCellProp
}
@computed get selected() {
- const selected: [Doc, number] | undefined = this._props.selectedCell();
- return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col;
+ const selected = this._props.selectedCells();
+ return this._props.isRowActive() && selected && selected?.filter(doc => doc === this._props.Document).length !== 0 && this._props.selectedCol() === this._props.col;
}
render() {
const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this._props);
@@ -387,8 +401,8 @@ export class SchemaEnumerationCell extends ObservableReactComponent<SchemaTableC
}
@computed get selected() {
- const selected: [Doc, number] | undefined = this._props.selectedCell();
- return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col;
+ const selected = this._props.selectedCells();
+ return this._props.isRowActive() && selected && selected?.filter(doc => doc === this._props.Document).length !== 0 && this._props.selectedCol() === this._props.col;
}
render() {
const { color, textDecoration, cursor, pointerEvents } = SchemaTableCell.renderProps(this._props);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 4a5c32b4c..3191e04db 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -350,7 +350,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
const sendToBack = e.altKey;
this._singleClickFunc =
// prettier-ignore
- clickFunc ?? (() => (sendToBack ? documentView._props.bringToFront?.(this.Document, true) :
+ clickFunc ?? (() => (sendToBack ? documentView._props.bringToFront?.(this.Document, true) :
this._props.select(e.ctrlKey||e.shiftKey, e.metaKey)));
const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') {
@@ -1319,17 +1319,17 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale;
isSelected = () => this.IsSelected;
select = (extendSelection: boolean, focusSelection?: boolean) => {
- if (this.IsSelected && DocumentView.Selected().length > 1) DocumentView.DeselectView(this);
- else {
- DocumentView.SelectView(this, extendSelection);
- if (focusSelection) {
- DocumentView.showDocument(this.Document, {
- willZoomCentered: true,
- zoomScale: 0.9,
- zoomTime: 500,
- });
- }
+ // if (this.IsSelected && DocumentView.Selected().length > 1) DocumentView.DeselectView(this);
+ // else {
+ DocumentView.SelectView(this, extendSelection);
+ if (focusSelection) {
+ DocumentView.showDocument(this.Document, {
+ willZoomCentered: true,
+ zoomScale: 0.9,
+ zoomTime: 500,
+ });
}
+ //}
};
backgroundColor = () => this._docViewInternal?.backgroundBoxColor;
DataTransition = () => this._props.DataTransition?.() || StrCast(this.Document.dataTransition);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 3945da104..d4f8b5550 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -334,7 +334,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
background: usePath === undefined ? 'white' : usePath === 'alternate' ? 'black' : 'gray',
color: usePath === undefined ? 'black' : 'white',
}}>
- <FontAwesomeIcon icon="turn-up" size="lg" />
+ <FontAwesomeIcon icon="circle-half-stroke" size="lg" />
</div>
</Tooltip>
);
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 5d53a2a5f..9903d0e8a 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -141,7 +141,6 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
this._reactionDisposer?.();
}
isRowActive = () => (this._props.nodeSelected() || this._expanded) && this._props.editable;
-
finishEdit = action(() => {
if (this._expanded) {
this._expanded = false;
@@ -150,7 +149,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
setTimeout(() => !this._props.tbox.ProseRef?.contains(document.activeElement) && this._props.tbox._props.onBlur?.());
}
});
- selectedCell = (): [Doc, number] | undefined => (this._dashDoc ? [this._dashDoc, 0] : undefined);
+ selectedCells = () => (this._dashDoc ? [this._dashDoc] : undefined);
columnWidth = () => Math.min(this._props.tbox._props.PanelWidth(), Math.max(50, this._props.tbox._props.PanelWidth() - 100)); // try to leave room for the fieldKey
// set the display of the field's value (checkbox for booleans, span of text for strings)
@@ -168,13 +167,15 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
selectCell={emptyFunction}
maxWidth={this._props.hideKey || this._hideKey ? undefined : this._props.tbox._props.PanelWidth}
columnWidth={this._expanded || this._props.nodeSelected() ? this.columnWidth : returnZero}
- selectedCell={this.selectedCell}
+ selectedCells={this.selectedCells}
+ selectedCol={returnZero}
fieldKey={this._fieldKey}
rowHeight={returnZero}
isRowActive={this.isRowActive}
padding={0}
getFinfo={emptyFunction}
setColumnValues={returnFalse}
+ setSelectedColumnValues={returnFalse}
allowCRs
oneLine={!this._expanded && !this._props.nodeSelected()}
finishEdit={this.finishEdit}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 7e67690d3..d8ba89fdb 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -60,6 +60,7 @@ import {
faLongArrowAltLeft,
faLongArrowAltRight,
faMicrophone,
+ faCircleHalfStroke,
faMinus,
faMobile,
faMousePointer,
@@ -197,6 +198,7 @@ library.add(
faHighlighter,
faLongArrowAltRight,
faMicrophone,
+ faCircleHalfStroke,
faMousePointer,
faMusic,
faObjectGroup,