diff options
Diffstat (limited to 'src/client/views/collections/collectionSchema')
5 files changed, 54 insertions, 59 deletions
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 05670562e..6442385c0 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -200,7 +200,7 @@ export class CollectionSchemaView extends CollectionSubView() { this._props.setContentViewBox?.(this); document.addEventListener('keydown', this.onKeyDown); - Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1])); + Object.entries(this._documentOptions).forEach(pair => this.fieldInfos.set(pair[0], pair[1] as FInfo)); this._keysDisposer = observe( this.dataDoc[this.fieldKey ?? 'data'] as List<Doc>, change => { @@ -359,7 +359,7 @@ export class CollectionSchemaView extends CollectionSubView() { @action addNewKey = (key: string, defaultVal: FieldType | undefined) => { this.childDocs.forEach(doc => { - doc[DocData][key] = defaultVal; + if (doc[DocData][key] === undefined) doc[DocData][key] = defaultVal; }); }; @@ -1193,7 +1193,7 @@ export class CollectionSchemaView extends CollectionSubView() { let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.Document).length > 0; if (notFiltered) { notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.Document).length > 0; - const fieldKey = Doc.LayoutFieldKey(d); + const fieldKey = Doc.LayoutDataKey(d); const isAnnotatableDoc = d[fieldKey] instanceof List && !(d[fieldKey] as List<Doc>)?.some(ele => !(ele instanceof Doc)); const docChildDocs = d[isAnnotatableDoc ? fieldKey + '_annotations' : fieldKey]; const sidebarDocs = isAnnotatableDoc && d[fieldKey + '_sidebar']; @@ -1206,7 +1206,7 @@ export class CollectionSchemaView extends CollectionSubView() { newarray = []; // eslint-disable-next-line no-loop-func subDocs.forEach(t => { - const docFieldKey = Doc.LayoutFieldKey(t); + const docFieldKey = Doc.LayoutDataKey(t); const isSubDocAnnotatable = t[docFieldKey] instanceof List && !(t[docFieldKey] as List<Doc>)?.some(ele => !(ele instanceof Doc)); notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !childFiltersByRanges.length) || DocUtils.FilterDocs([t], childDocFilters, childFiltersByRanges, d).length)); DocListCast(t[isSubDocAnnotatable ? docFieldKey + '_annotations' : docFieldKey]).forEach(newdoc => newarray.push(newdoc)); @@ -1293,7 +1293,6 @@ export class CollectionSchemaView extends CollectionSubView() { isContentActive = () => this._props.isSelected() || this._props.isContentActive(); screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0); previewWidthFunc = () => this.previewWidth; - onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); displayedDocsFunc = () => this.docsWithDrag.docs; render() { return ( @@ -1307,15 +1306,7 @@ export class CollectionSchemaView extends CollectionSubView() { this.setColDrag(false); }}> <div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }} /> - <div - className="schema-table" - style={{ width: `calc(100% - ${this.previewWidth}px)` }} - onWheel={e => this._props.isContentActive() && e.stopPropagation()} - ref={ele => { - // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling - this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel); - (this._oldWheel = ele)?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); - }}> + <div className="schema-table" style={{ width: `calc(100% - ${this.previewWidth}px)` }} onWheel={e => this._props.isContentActive() && e.stopPropagation()} ref={ele => this.fixWheelEvents(ele, this._props.isContentActive)}> <div className="schema-header-row" style={{ height: this.rowHeightFunc() }}> <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}> <IconButton diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx index e89822b4c..9ad94cb31 100644 --- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx +++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx @@ -21,11 +21,11 @@ import DOMPurify from 'dompurify'; */ export interface SchemaCellFieldProps { + Doc: Doc; contents: FieldType | undefined; fieldContents?: FieldViewProps; editing?: boolean; oneLine?: boolean; - Document: Doc; fieldKey: string; // eslint-disable-next-line no-use-before-define refSelectModeInfo: { enabled: boolean; currEditing: SchemaCellField | undefined }; @@ -55,7 +55,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro }); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function } - get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore + get docIndex(){return DocumentView.getDocViewIndex(this._props.Doc);} // prettier-ignore get selfRefPattern() { return `d${this.docIndex}.${this._props.fieldKey}`; @@ -85,6 +85,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro () => this._editing, editing => { if (editing) { + this.setContent((this._unrenderedContent = this._props.GetValue() ?? '')); this.setupRefSelect(this.refSelectConditionMet); } else { this._overlayDisposer?.(); @@ -99,7 +100,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro () => this._props.GetValue(), fieldVal => { this._unrenderedContent = fieldVal ?? ''; - this.finalizeEdit(false, false, false); + this._editing && this.finalizeEdit(false, false, false); } ); } diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 81a2d8e64..134f2ed31 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -107,7 +107,7 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea focus: emptyFunction, addDocTab: SchemaTableCell.addFieldDoc, pinToPres: returnZero, - Document: DocCast(Document.rootDocument, Document), + Document: DocCast(Document.rootDocument, Document)!, fieldKey: fieldKey, PanelWidth: columnWidth, PanelHeight: props.rowHeight, @@ -115,12 +115,11 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea }; const readOnly = this.getFinfo(fieldKey)?.readOnly ?? false; const cursor = !readOnly ? 'text' : 'default'; - const pointerEvents: 'all' | 'none' = 'all'; - return { color, fieldProps, cursor, pointerEvents }; + return { color, fieldProps, cursor }; }; @computed get editableView() { - const { color, fieldProps, pointerEvents } = this.renderProps(this._props); + const { color, fieldProps } = this.renderProps(this._props); return ( <div @@ -132,7 +131,6 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea style={{ color, width: '100%', - pointerEvents, }}> <EditableView ref={r => { @@ -232,6 +230,7 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea className="schema-column-header" style={{ width: this._props.columnWidths[this._props.columnIndex], + pointerEvents: this.props.isContentActive() ? undefined : 'none', }} onPointerEnter={() => { this.handlePointerEnter(); diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index da203abfa..c9853fab0 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -171,7 +171,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() { isolatedSelection={this.isolatedSelection} key={key} rowSelected={this._props.isSelected} - Document={this.Document} + Doc={this.Document} col={index} fieldKey={key} allowCRs={false} // to enter text with new lines, must use \n diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 1b4f200a3..8b34b4139 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -32,6 +32,7 @@ import { FInfotoColType } from './CollectionSchemaView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaCellField } from './SchemaCellField'; +import { DocLayout } from '../../../../fields/DocSymbols'; /** * SchemaTableCells make up the majority of the visual representation of the SchemaView. @@ -40,7 +41,7 @@ import { SchemaCellField } from './SchemaCellField'; */ export interface SchemaTableCellProps { - Document: Doc; + Doc: Doc; col: number; deselectCell: () => void; selectCell: (doc: Doc, col: number, shift: boolean, ctrl: boolean) => void; @@ -71,7 +72,7 @@ export interface SchemaTableCellProps { } function selectedCell(props: SchemaTableCellProps) { - return props.isRowActive() && props.selectedCol() === props.col && props.selectedCells()?.filter(d => d === props.Document)?.length; + return props.isRowActive() && props.selectedCol() === props.col && props.selectedCells()?.filter(d => d === props.Doc)?.length; } @observer @@ -84,11 +85,11 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro makeObservable(this); } - get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore + get docIndex(){return DocumentView.getDocViewIndex(this._props.Doc);} // prettier-ignore get isDefault(){return SchemaColumnHeader.isDefaultField(this._props.fieldKey);} // prettier-ignore - get lockedInteraction(){return (this.isDefault || this._props.Document._lockedSchemaEditing);} // prettier-ignore + get lockedInteraction(){return (this.isDefault || this._props.Doc._lockedSchemaEditing);} // prettier-ignore get backgroundColor() { if (this.lockedInteraction) { @@ -102,15 +103,16 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro return true; }; public static renderProps(props: SchemaTableCellProps) { - const { Document, fieldKey, /* getFinfo,*/ columnWidth, isRowActive } = props; + const { Doc: Document, fieldKey, /* getFinfo,*/ columnWidth, isRowActive } = props; let protoCount = 0; + const layoutDoc = fieldKey.startsWith('_') ? Document[DocLayout] : Document; let doc: Doc | undefined = Document; while (doc) { if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) break; protoCount++; doc = DocCast(doc.proto); } - const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue'; // color of text in cells + const color = layoutDoc !== Document ? 'red' : protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue'; // color of text in cells const textDecoration = ''; const fieldProps: FieldViewProps = { childFilters: returnEmptyFilter, @@ -130,7 +132,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro focus: emptyFunction, addDocTab: SchemaTableCell.addFieldDoc, pinToPres: returnZero, - Document: DocCast(Document.rootDocument, Document), + Document: Document, fieldKey: fieldKey, PanelWidth: columnWidth, PanelHeight: props.rowHeight, @@ -166,16 +168,19 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro while ((matches = idPattern.exec(field)) !== null) { results.push([matches[0], matches[1].replace(/"/g, '')]); } - results.forEach(idFuncPair => { - modField = modField.replace(idFuncPair[0], 'd' + DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1])).toString()); - }); + results + .filter(idFuncPair => IdToDoc(idFuncPair[1])) + .forEach(idFuncPair => { + modField = modField.replace(idFuncPair[0], 'd' + DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1])!).toString()); + }); if (modField.endsWith(';')) modField = modField.substring(0, modField.length - 1); const inQuotes = (strField: string) => { return (strField.startsWith('`') && strField.endsWith('`')) || (strField.startsWith("'") && strField.endsWith("'")) || (strField.startsWith('"') && strField.endsWith('"')); }; - if (!inQuotes(this._submittedValue) && inQuotes(modField)) modField = modField.substring(1, modField.length - 1); + const submittedValue = this._submittedValue.startsWith(eqSymbol) ? this._submittedValue.slice(eqSymbol.length) : this._submittedValue; + if (!inQuotes(submittedValue) && inQuotes(modField)) modField = modField.substring(1, modField.length - 1); return eqSymbol + modField; }; @@ -196,7 +201,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro <SchemaCellField fieldKey={this._props.fieldKey} refSelectModeInfo={this._props.refSelectModeInfo} - Document={this._props.Document} + Doc={this._props.Doc} highlightCells={(text: string) => this._props.highlightCells(this.adjustSelfReference(text))} getCells={(text: string) => this._props.eqHighlightFunc(this.adjustSelfReference(text))} ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)} @@ -211,8 +216,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro this._props.finishEdit?.(); return true; } - const hasNoLayout = Doc.IsDataProto(fieldProps.Document) ? true : undefined; // the "delegate" is a a data document so never write to it's proto - const ret = Doc.SetField(fieldProps.Document, this._props.fieldKey.replace(/^_/, ''), value, hasNoLayout); + const ret = Doc.SetField(fieldProps.Document, this._props.fieldKey, value); this._submittedValue = value; this._props.finishEdit?.(); return ret; @@ -224,7 +228,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro get getCellType() { const columnTypeStr = this._props.getFinfo(this._props.fieldKey)?.fieldType; - const cellValue = this._props.Document[this._props.fieldKey]; + const cellValue = this._props.Doc[this._props.fieldKey]; if (cellValue instanceof ImageField) return ColumnType.Image; if (cellValue instanceof DateField) return ColumnType.Date; @@ -252,8 +256,8 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro const sides: Array<string | undefined> = []; sides[0] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // left sides[1] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // right - sides[2] = !this._props.isolatedSelection(this._props.Document)[0] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top - sides[3] = !this._props.isolatedSelection(this._props.Document)[1] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom + sides[2] = !this._props.isolatedSelection(this._props.Doc)[0] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top + sides[3] = !this._props.isolatedSelection(this._props.Doc)[1] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom return sides; } @@ -272,7 +276,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro if (this._props.refSelectModeInfo.enabled && !selectedCell(this._props)) { e.stopPropagation(); e.preventDefault(); - this._props.selectReference(this._props.Document, this._props.col); + this._props.selectReference(this._props.Doc, this._props.col); return; } @@ -280,9 +284,9 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro const ctrl: boolean = e.ctrlKey; if (this._props.isRowActive?.()) { if (selectedCell(this._props) && ctrl) { - this._props.selectCell(this._props.Document, this._props.col, shift, ctrl); + this._props.selectCell(this._props.Doc, this._props.col, shift, ctrl); e.stopPropagation(); - } else !selectedCell(this._props) && this._props.selectCell(this._props.Document, this._props.col, shift, ctrl); + } else !selectedCell(this._props) && this._props.selectCell(this._props.Doc, this._props.col, shift, ctrl); } })} style={{ @@ -321,12 +325,12 @@ export class SchemaImageCell extends ObservableReactComponent<SchemaTableCellPro } get url() { - const field = Cast(this._props.Document[this._props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc - const alts = DocListCast(this._props.Document[this._props.fieldKey + '_alternates']); // retrieve alternate documents that may be rendered as alternate images + const field = Cast(this._props.Doc[this._props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc + const alts = DocListCast(this._props.Doc[this._props.fieldKey + '_alternates']); // retrieve alternate documents that may be rendered as alternate images const altpaths = alts - .map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url) + .map(doc => Cast(doc[Doc.LayoutDataKey(doc)], ImageField, null)?.url) .filter(url => url) - .map(url => this.choosePath(url)); // access the primary layout data of the alternate documents + .map(url => this.choosePath(url!)); // access the primary layout data of the alternate documents const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; // If there is a path, follow it; otherwise, follow a link to a default image icon const url = paths.length ? paths : [ClientUtils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')]; @@ -359,7 +363,7 @@ export class SchemaImageCell extends ObservableReactComponent<SchemaTableCellPro }; render() { - const aspect = Doc.NativeAspect(this._props.Document); // aspect ratio + const aspect = Doc.NativeAspect(this._props.Doc); // aspect ratio // let width = Math.max(75, this._props.columnWidth); // get a with that is no smaller than 75px // const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px const height = this._props.rowHeight() ? this._props.rowHeight() - (this._props.padding || 6) * 2 : undefined; @@ -377,9 +381,9 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp } @observable _pickingDate: boolean = false; - @computed get date(): DateField { + @computed get date(): DateField | undefined { // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined. - return DateCast(this._props.Document[this._props.fieldKey]); + return DateCast(this._props.Doc[this._props.fieldKey]); } handleChange = undoable((date: Date | null) => { @@ -388,7 +392,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp // this.applyToDoc(this._document, this._props.row, this._props.col, script.run); // } else { // ^ DateCast is always undefined for some reason, but that is what the field should be set to - date && (this._props.Document[this._props.fieldKey] = new DateField(date)); + date && (this._props.Doc[this._props.fieldKey] = new DateField(date)); // } }, 'date change'); @@ -397,7 +401,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp return ( <> <div style={{ pointerEvents: 'none' }} tabIndex={1}> - <DatePicker dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={emptyFunction} /> + <DatePicker dateFormat="Pp" selected={this.date?.date ?? new Date()} onChange={emptyFunction} /> </div> {pointerEvents === 'none' || !selectedCell(this._props) ? null : ( <Popup @@ -408,7 +412,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp background={SnappingManager.userBackgroundColor} popup={ <div style={{ width: 'fit-content', height: '200px' }}> - <DatePicker open dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={this.handleChange} /> + <DatePicker open dateFormat="Pp" selected={this.date?.date ?? new Date()} onChange={this.handleChange} /> </div> } /> @@ -451,11 +455,11 @@ export class SchemaBoolCell extends ObservableReactComponent<SchemaTableCellProp onPointerDown={e => e.stopPropagation()} style={{ marginRight: 4 }} type="checkbox" - checked={BoolCast(this._props.Document[this._props.fieldKey])} + checked={BoolCast(this._props.Doc[this._props.fieldKey])} onChange={undoable((value: React.ChangeEvent<HTMLInputElement> | undefined) => { if ((value?.nativeEvent as MouseEvent | PointerEvent).shiftKey) { this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? '')); - } else Doc.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? '')); + } else Doc.SetField(this._props.Doc, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? '')); }, 'set bool cell')} /> @@ -463,14 +467,14 @@ export class SchemaBoolCell extends ObservableReactComponent<SchemaTableCellProp contents="" fieldContents={fieldProps} editing={selectedCell(this._props) ? undefined : false} - GetValue={() => Field.toKeyValueString(this._props.Document, this._props.fieldKey)} + GetValue={() => Field.toKeyValueString(this._props.Doc, this._props.fieldKey)} SetValue={undoable((value: string, shiftDown?: boolean, enterKey?: boolean) => { if (shiftDown && enterKey) { this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), value); this._props.finishEdit?.(); return true; } - const set = Doc.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), value, Doc.IsDataProto(this._props.Document) ? true : undefined); + const set = Doc.SetField(this._props.Doc, this._props.fieldKey.replace(/^_/, ''), value, Doc.IsDataProto(this._props.Doc) ? true : undefined); this._props.finishEdit?.(); return set; }, 'set bool cell')} @@ -538,10 +542,10 @@ export class SchemaEnumerationCell extends ObservableReactComponent<SchemaTableC }} menuPortalTarget={this._props.menuTarget} menuPosition="absolute" - placeholder={StrCast(this._props.Document[this._props.fieldKey], 'select...')} + placeholder={StrCast(this._props.Doc[this._props.fieldKey], 'select...')} options={options} isMulti={false} - onChange={val => Doc.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), `"${val?.value ?? ''}"`)} + onChange={val => Doc.SetField(this._props.Doc, this._props.fieldKey.replace(/^_/, ''), `"${val?.value ?? ''}"`)} /> </div> </div> |
