From d334eb163e0e960c9d662eb696fcf98aa02fdadf Mon Sep 17 00:00:00 2001 From: srichman333 Date: Thu, 28 Sep 2023 03:09:23 -0400 Subject: doesn't lag / glitch system but scrolling can be kinda funky --- .../views/nodes/DataVizBox/components/TableBox.tsx | 139 +++++++++++++++------ 1 file changed, 100 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 5045fde3a..243c1a0c7 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,5 +1,5 @@ import { Button, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, Field, NumListCast } from '../../../../../fields/Doc'; @@ -31,6 +31,9 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { + @observable startID: number = 0; + @observable endID: number = 20; + _inputChangedDisposer?: IReactionDisposer; componentDidMount() { // if the tableData changes (ie., when records are selected by the parent (input) visulization), @@ -67,8 +70,61 @@ export class TableBox extends React.Component { this.props.layoutDoc.dataViz_highlitedRows = new List(highlighted.filter(rowId => this._tableDataIds.includes(rowId))); // filters through highlighted to remove guids that were removed in the incoming data }; + @action handleScroll = () => { + console.log("scroll") + // console.log("before", this.startID, this.endID) + var container = document.getElementsByClassName("table-container"); + var eachCell = document.getElementsByClassName("table-row"); + if (eachCell.length==0 || container.length==0) return; + + var useContainer; + if (container.length==1) useContainer = container[0]; + else { + for (var i=0; i= -1){ + this.startID -= 1; + this.endID -= 1; + } + + // bottom + else if (useContainer.scrollHeight - 50 <= useContainer.scrollTop + useContainer.getBoundingClientRect().height && this.endID<=this._tableDataIds.length){ + this.startID += 1; + this.endID += 1; + } + + // regular scroll + else { + let newStart = (useContainer.scrollTop / useCell.getBoundingClientRect().height ) - 1; + newStart = Math.floor(Number(newStart)) + if (newStart=-1){ this.startID -= 1; } + if (newStart>this.startID) { this.startID += 1; } + + let newEnd = this.startID + useContainer.getBoundingClientRect().height / useCell.getBoundingClientRect().height + 1; + newEnd = Math.floor(Number(newEnd)) + if (newEndthis.endID && this.endID<=this._tableDataIds.length) { this.endID += 1; } + } + } + else { + this.endID = this._tableDataIds.length - 1; + } + } + render() { if (this._tableData.length > 0) { + return (
{
r?.addEventListener( 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this) (e: WheelEvent) => { if (!r.scrollTop && e.deltaY <= 0) e.preventDefault(); + this.handleScroll(); e.stopPropagation(); }, { passive: false } @@ -98,7 +155,7 @@ export class TableBox extends React.Component { }> - + {this.columns.map(col => ( {this._tableDataIds ?.map(rowId => ({ record: this.props.records[rowId], rowId })) - .map(({ record, rowId }) => ( - { - const highlited = Cast(this.props.layoutDoc.dataViz_highlitedRows, listSpec('number'), null); - const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); - if (e.metaKey) { - // highlighting a row - if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1); - else highlited?.push(rowId); - if (!selected?.includes(rowId)) selected?.push(rowId); - } else { - // selecting a row - if (selected?.includes(rowId)) { - if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1); - selected.splice(selected.indexOf(rowId), 1); - } else selected?.push(rowId); - } - e.stopPropagation(); - })} - style={{ - background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', - width: '110%', - }}> - {this.columns.map(col => { - // each cell - const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false; - return ( - - ); - })} - - ))} + .map(({ record, rowId }) => { + if (this.startID<=rowId && rowId<=this.endID){ + return ( + { + const highlited = Cast(this.props.layoutDoc.dataViz_highlitedRows, listSpec('number'), null); + const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); + if (e.metaKey) { + // highlighting a row + if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1); + else highlited?.push(rowId); + if (!selected?.includes(rowId)) selected?.push(rowId); + } else { + // selecting a row + if (selected?.includes(rowId)) { + if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1); + selected.splice(selected.indexOf(rowId), 1); + } else selected?.push(rowId); + } + e.stopPropagation(); + })} + style={{ + background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', + width: '110%', + }}> + {this.columns.map(col => { + // each cell + const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false; + return ( + + ); + })} + + ) + } + })}
{
- {record[col]} -
+ {record[col]} +
-- cgit v1.2.3-70-g09d2 From 0d7cb9352552c16f6a7621eb18933ff73e7357af Mon Sep 17 00:00:00 2001 From: srichman333 Date: Thu, 28 Sep 2023 09:50:39 -0400 Subject: smoother scrolling --- .../views/nodes/DataVizBox/components/TableBox.tsx | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 243c1a0c7..07d151702 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -92,29 +92,34 @@ export class TableBox extends React.Component { } } if (useCell && useContainer){ + + // check for 20 (inital value) as end point + if (this.endID == 20){ + let newEnd = this.startID + useContainer.getBoundingClientRect().height / useCell.getBoundingClientRect().height + 1; + newEnd = Math.floor(Number(newEnd)) + if (newEndthis.endID && this.endID<=this._tableDataIds.length) { this.endID += .1; } + } + // top if (useContainer.scrollTop <= 10 && this.startID >= -1){ - this.startID -= 1; - this.endID -= 1; + this.startID -= .01; + this.endID -= .01; } // bottom else if (useContainer.scrollHeight - 50 <= useContainer.scrollTop + useContainer.getBoundingClientRect().height && this.endID<=this._tableDataIds.length){ - this.startID += 1; - this.endID += 1; + this.startID += .1; + this.endID += .1; } // regular scroll else { let newStart = (useContainer.scrollTop / useCell.getBoundingClientRect().height ) - 1; newStart = Math.floor(Number(newStart)) - if (newStart=-1){ this.startID -= 1; } - if (newStart>this.startID) { this.startID += 1; } + if (newStart=-1){ this.startID -= .1; this.endID -= -.1; } + if (newStart>this.startID) { this.startID += .1; this.endID += .1; } - let newEnd = this.startID + useContainer.getBoundingClientRect().height / useCell.getBoundingClientRect().height + 1; - newEnd = Math.floor(Number(newEnd)) - if (newEndthis.endID && this.endID<=this._tableDataIds.length) { this.endID += 1; } } } else { -- cgit v1.2.3-70-g09d2 From 1256010bee4d427d35f5ccb13d7ba08b424df3e5 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Thu, 28 Sep 2023 15:43:51 -0400 Subject: header fix + more consistent bar height --- .../views/nodes/DataVizBox/components/TableBox.tsx | 144 ++++++++++----------- 1 file changed, 72 insertions(+), 72 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 07d151702..556a8b281 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -71,8 +71,6 @@ export class TableBox extends React.Component { }; @action handleScroll = () => { - console.log("scroll") - // console.log("before", this.startID, this.endID) var container = document.getElementsByClassName("table-container"); var eachCell = document.getElementsByClassName("table-row"); if (eachCell.length==0 || container.length==0) return; @@ -109,17 +107,16 @@ export class TableBox extends React.Component { // bottom else if (useContainer.scrollHeight - 50 <= useContainer.scrollTop + useContainer.getBoundingClientRect().height && this.endID<=this._tableDataIds.length){ - this.startID += .1; - this.endID += .1; + this.startID += .01; + this.endID += .01; } // regular scroll else { - let newStart = (useContainer.scrollTop / useCell.getBoundingClientRect().height ) - 1; - newStart = Math.floor(Number(newStart)) - if (newStart=-1){ this.startID -= .1; this.endID -= -.1; } - if (newStart>this.startID) { this.startID += .1; this.endID += .1; } - + let newStart = (useContainer.scrollTop / useCell.getBoundingClientRect().height ) - 1; + newStart = Math.floor(Number(newStart)) + if (newStart=-1){ this.startID -= .01; this.endID -= -.01; } + else if (newStart>this.startID) { this.startID += .01; this.endID += .01; } } } else { @@ -161,69 +158,72 @@ export class TableBox extends React.Component { - {this.columns.map(col => ( - - ))} + {this.columns.map(col => { + if (this.startID>0) return; + return ( + + )} + )} -- cgit v1.2.3-70-g09d2 From 3884211ab83db30965a4dc1c4b3133684904ebb9 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Mon, 2 Oct 2023 17:54:58 -0400 Subject: better scrolling in data tables --- .../views/nodes/DataVizBox/components/TableBox.tsx | 42 ++++++++++------------ 1 file changed, 19 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 556a8b281..dd13c5749 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -32,7 +32,7 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { @observable startID: number = 0; - @observable endID: number = 20; + @observable endID: number = 15; _inputChangedDisposer?: IReactionDisposer; componentDidMount() { @@ -90,33 +90,29 @@ export class TableBox extends React.Component { } } if (useCell && useContainer){ - - // check for 20 (inital value) as end point - if (this.endID == 20){ - let newEnd = this.startID + useContainer.getBoundingClientRect().height / useCell.getBoundingClientRect().height + 1; - newEnd = Math.floor(Number(newEnd)) - if (newEndthis.endID && this.endID<=this._tableDataIds.length) { this.endID += .1; } - } - + let atEnd = false; // top - if (useContainer.scrollTop <= 10 && this.startID >= -1){ - this.startID -= .01; - this.endID -= .01; + if (useContainer.scrollTop <= 10){ + atEnd = true; + if (this.startID >= -1){ + this.startID -= .001; + this.endID -= .001; + } } - // bottom - else if (useContainer.scrollHeight - 50 <= useContainer.scrollTop + useContainer.getBoundingClientRect().height && this.endID<=this._tableDataIds.length){ - this.startID += .01; - this.endID += .01; + else if (useContainer.scrollHeight / (useContainer.scrollTop + useContainer.getBoundingClientRect().height) < 1.1 && this.endID<=this._tableDataIds.length){ + this.startID += .015; + this.endID += .015; } - // regular scroll - else { - let newStart = (useContainer.scrollTop / useCell.getBoundingClientRect().height ) - 1; - newStart = Math.floor(Number(newStart)) - if (newStart=-1){ this.startID -= .01; this.endID -= -.01; } - else if (newStart>this.startID) { this.startID += .01; this.endID += .01; } + else if (this.endID<=this._tableDataIds.length && !atEnd) { + let newStart = (useContainer.scrollTop / useCell.getBoundingClientRect().height ) ; + if (newStart=-1){ + this.startID -= .001; + this.endID -= .001; } + else if (newStart>this.startID) { + this.startID += .001; + this.endID += .001; } } } else { -- cgit v1.2.3-70-g09d2 From a376f30189e847ac763c08288428de415f1ce081 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 10 Oct 2023 12:12:33 -0400 Subject: fixes for scrolling large datasets in TableBox --- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 80 ++---- .../views/nodes/DataVizBox/components/TableBox.tsx | 267 +++++++++------------ 2 files changed, 142 insertions(+), 205 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index b9db5fe15..299494c83 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -36,7 +36,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // all CSV records in the dataset (that aren't an empty row) @computed.struct get records() { var records = DataVizBox.dataset.get(CsvCast(this.rootDoc[this.fieldKey]).url.href); - return records?.filter(record => Object.keys(record).some(key => record[key])); + return records?.filter(record => Object.keys(record).some(key => record[key])) ?? []; } // currently chosen visualization type: line, pie, histogram, table @@ -110,70 +110,38 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // toggles for user to decide which chart type to view the data in renderVizView = () => { - const width = this.props.PanelWidth() * 0.9; - const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9; - const margin = { top: 10, right: 25, bottom: 75, left: 45 }; - if (this.records) { - switch (this.dataVizView) { - case DataVizView.TABLE: - return ; - case DataVizView.LINECHART: - return ( - (this._vizRenderer = r ?? undefined)} - height={height} - width={width} - fieldKey={this.fieldKey} - margin={margin} - rootDoc={this.rootDoc} - axes={this.axes} - records={this.records} - dataDoc={this.dataDoc} - /> - ); - case DataVizView.HISTOGRAM: - return ( - (this._vizRenderer = r ?? undefined)} - height={height} - width={width} - fieldKey={this.fieldKey} - margin={margin} - rootDoc={this.rootDoc} - axes={this.axes} - records={this.records} - dataDoc={this.dataDoc} - /> - ); - case DataVizView.PIECHART: - return ( - (this._vizRenderer = r ?? undefined)} - height={height} - width={width} - fieldKey={this.fieldKey} - margin={margin} - rootDoc={this.rootDoc} - axes={this.axes} - records={this.records} - dataDoc={this.dataDoc} - /> - ); - } + const sharedProps = { + rootDoc: this.rootDoc, + layoutDoc: this.layoutDoc, + records: this.records, + axes: this.axes, + height: (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9, + width: this.props.PanelWidth() * 0.9, + margin: { top: 10, right: 25, bottom: 75, left: 45 }, + }; + if (!this.records.length) return 'no data/visualization'; + switch (this.dataVizView) { + case DataVizView.TABLE: + return ; + case DataVizView.LINECHART: + return (this._vizRenderer = r ?? undefined)} />; + case DataVizView.HISTOGRAM: + return (this._vizRenderer = r ?? undefined)} />; + case DataVizView.PIECHART: + return (this._vizRenderer = r ?? undefined)} />; } - return 'no data/visualization'; }; render() { - return !this.records?.length ? ( + return !this.records.length ? ( // displays how to get data into the DataVizBox if its empty
To create a DataViz box, either import / drag a CSV file into your canvas or copy a data table and use the command 'ctrl + p' to bring the data table to your canvas.
) : (
e.stopPropagation()} ref={r => r?.addEventListener( diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index dd13c5749..edf0ea4c7 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,6 +1,7 @@ import { Button, Type } from 'browndash-components'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import { actionFieldDecorator } from 'mobx/lib/internal'; import * as React from 'react'; import { Doc, Field, NumListCast } from '../../../../../fields/Doc'; import { List } from '../../../../../fields/List'; @@ -32,13 +33,17 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { @observable startID: number = 0; - @observable endID: number = 15; + @observable endID: number = 0; + _tableContainerRef: HTMLDivElement | null = null; + _tableRef = React.createRef(); _inputChangedDisposer?: IReactionDisposer; componentDidMount() { // if the tableData changes (ie., when records are selected by the parent (input) visulization), // then we need to remove any selected rows that are no longer part of the visualized dataset. this._inputChangedDisposer = reaction(() => this._tableData.slice(), this.filterSelectedRowsDown, { fireImmediately: true }); + + this._tableContainerRef && this.handleScroll(); } componentWillUnmount() { this._inputChangedDisposer?.(); @@ -70,59 +75,88 @@ export class TableBox extends React.Component { this.props.layoutDoc.dataViz_highlitedRows = new List(highlighted.filter(rowId => this._tableDataIds.includes(rowId))); // filters through highlighted to remove guids that were removed in the incoming data }; - @action handleScroll = () => { - var container = document.getElementsByClassName("table-container"); - var eachCell = document.getElementsByClassName("table-row"); - if (eachCell.length==0 || container.length==0) return; + @computed get viewScale() { + return this.props.docView?.()?.props.ScreenToLocalTransform().Scale || 1; + } + @computed get rowHeight() { + const tableHeight = this._tableRef.current?.getBoundingClientRect().height; + return !tableHeight ? 1 : (this.viewScale * tableHeight) / this._tableDataIds.length; + } - var useContainer; - if (container.length==1) useContainer = container[0]; - else { - for (var i=0; i { + if (this._tableContainerRef) { + this.startID = Math.floor(this._tableContainerRef.scrollTop / this.rowHeight); + this.endID = this.startID + (this._tableContainerRef.getBoundingClientRect().height * this.viewScale) / this.rowHeight; } - var useCell; - if (eachCell.length==1) useCell = eachCell[0]; - else { - for (var i=0; i { + const highlited = Cast(this.props.layoutDoc.dataViz_highlitedRows, listSpec('number'), null); + const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); + if (e.metaKey) { + // highlighting a row + if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1); + else highlited?.push(rowId); + if (!selected?.includes(rowId)) selected?.push(rowId); + } else { + // selecting a row + if (selected?.includes(rowId)) { + if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1); + selected.splice(selected.indexOf(rowId), 1); + } else selected?.push(rowId); } - if (useCell && useContainer){ - let atEnd = false; - // top - if (useContainer.scrollTop <= 10){ - atEnd = true; - if (this.startID >= -1){ - this.startID -= .001; - this.endID -= .001; + e.stopPropagation(); + }; + + columnPointerDown = (e: React.PointerEvent, col: string) => { + const downX = e.clientX; + const downY = e.clientY; + setupMoveUpEvents( + {}, + e, + e => { + // dragging off a column to create a brushed DataVizBox + const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; + const targetCreator = (annotationOn: Doc | undefined) => { + const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); + embedding._dataViz = DataVizView.TABLE; + embedding._dataViz_axes = new List([col, col]); + embedding._dataViz_parentViz = this.props.rootDoc; + embedding.annotationOn = annotationOn; + embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors); + embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor; + embedding.pieSliceColors = Field.Copy(this.props.layoutDoc.pieSliceColors); + return embedding; + }; + if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { + DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, { + dragComplete: e => { + if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { + e.linkDocument.link_displayLine = true; + e.linkDocument.link_matchEmbeddings = true; + e.linkDocument.link_displayArrow = true; + // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; + // e.annoDragData.linkSourceDoc.followLinkZoom = false; + } + }, + }); + return true; } - } - // bottom - else if (useContainer.scrollHeight / (useContainer.scrollTop + useContainer.getBoundingClientRect().height) < 1.1 && this.endID<=this._tableDataIds.length){ - this.startID += .015; - this.endID += .015; - } - // regular scroll - else if (this.endID<=this._tableDataIds.length && !atEnd) { - let newStart = (useContainer.scrollTop / useCell.getBoundingClientRect().height ) ; - if (newStart=-1){ - this.startID -= .001; - this.endID -= .001; } - else if (newStart>this.startID) { - this.startID += .001; - this.endID += .001; } - } - } - else { - this.endID = this._tableDataIds.length - 1; - } - } + return false; + }, + emptyFunction, + action(e => { + const newAxes = this.props.axes; + if (newAxes.includes(col)) newAxes.splice(newAxes.indexOf(col), 1); + else if (newAxes.length > 1) newAxes[1] = col; + else newAxes.push(col); + this.props.selectAxes(newAxes); + }) + ); + }; render() { if (this._tableData.length > 0) { - return (
{
+ style={{ height: '100%', overflow: 'auto' }} + onScroll={this.handleScroll} + ref={r => { + this._tableContainerRef = r; r?.addEventListener( 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this) (e: WheelEvent) => { if (!r.scrollTop && e.deltaY <= 0) e.preventDefault(); - this.handleScroll(); e.stopPropagation(); }, { passive: false } - ) - }> -
{ - const downX = e.clientX; - const downY = e.clientY; - setupMoveUpEvents( - {}, - e, - e => { - // dragging off a column to create a brushed DataVizBox - const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; - const targetCreator = (annotationOn: Doc | undefined) => { - const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); - embedding._dataViz = DataVizView.TABLE; - embedding._dataViz_axes = new List([col, col]); - embedding._dataViz_parentViz = this.props.rootDoc; - embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; - embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors); - embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor; - embedding.pieSliceColors = Field.Copy(this.props.layoutDoc.pieSliceColors); - return embedding; - }; - if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { - DragManager.StartAnchorAnnoDrag( - e.target instanceof HTMLElement ? [e.target] : [], - new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), - downX, - downY, - { - dragComplete: e => { - if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.linkDocument.link_displayLine = true; - e.linkDocument.link_matchEmbeddings = true; - // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; - // e.annoDragData.linkSourceDoc.followLinkZoom = false; - } - }, - } - ); - return true; - } - return false; - }, - emptyFunction, - action(e => { - const newAxes = this.props.axes; - if (newAxes.includes(col)) newAxes.splice(newAxes.indexOf(col), 1); - else if (newAxes.length > 1) newAxes[1] = col; - else newAxes.push(col); - this.props.selectAxes(newAxes); - }) - ); - }}> - {col} - { + const downX = e.clientX; + const downY = e.clientY; + setupMoveUpEvents( + {}, + e, + e => { + // dragging off a column to create a brushed DataVizBox + const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; + const targetCreator = (annotationOn: Doc | undefined) => { + const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); + embedding._dataViz = DataVizView.TABLE; + embedding._dataViz_axes = new List([col, col]); + embedding._dataViz_parentViz = this.props.rootDoc; + embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; + embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors); + embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor; + embedding.pieSliceColors = Field.Copy(this.props.layoutDoc.pieSliceColors); + return embedding; + }; + if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { + DragManager.StartAnchorAnnoDrag( + e.target instanceof HTMLElement ? [e.target] : [], + new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), + downX, + downY, + { + dragComplete: e => { + if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { + e.linkDocument.link_displayLine = true; + e.linkDocument.link_matchEmbeddings = true; + // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; + // e.annoDragData.linkSourceDoc.followLinkZoom = false; + } + }, + } + ); + return true; + } + return false; + }, + emptyFunction, + action(e => { + const newAxes = this.props.axes; + if (newAxes.includes(col)) newAxes.splice(newAxes.indexOf(col), 1); + else if (newAxes.length > 1) newAxes[1] = col; + else newAxes.push(col); + this.props.selectAxes(newAxes); + }) + ); + }}> + {col} +
+ ); + }}> +
- - {this.columns.map(col => { - if (this.startID>0) return; - return ( + + {this.columns.map(col => + this.startID > 0 ? null : ( - )} + ) )} {this._tableDataIds ?.map(rowId => ({ record: this.props.records[rowId], rowId })) - .map(({ record, rowId }) => { - if (this.startID<=rowId && rowId<=this.endID){ - return ( - { - const highlited = Cast(this.props.layoutDoc.dataViz_highlitedRows, listSpec('number'), null); - const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); - if (e.metaKey) { - // highlighting a row - if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1); - else highlited?.push(rowId); - if (!selected?.includes(rowId)) selected?.push(rowId); - } else { - // selecting a row - if (selected?.includes(rowId)) { - if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1); - selected.splice(selected.indexOf(rowId), 1); - } else selected?.push(rowId); - } - e.stopPropagation(); - })} - style={{ - background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', - width: '110%', - }}> - {this.columns.map(col => { - // each cell - const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false; - return ( - - ); - })} - - ) - } - })} + .map(({ record, rowId }) => + this.startID > rowId || rowId > this.endID ? ( + + + ) : ( + this.tableRowClick(e, rowId)} + style={{ + background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', + width: '110%', + }}> + {this.columns.map(col => { + const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false; + return ( + + ); + })} + + ) + )}
{ fontWeight: 'bolder', border: '3px solid black', }} - onPointerDown={e => { - const downX = e.clientX; - const downY = e.clientY; - setupMoveUpEvents( - {}, - e, - e => { - // dragging off a column to create a brushed DataVizBox - const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; - const targetCreator = (annotationOn: Doc | undefined) => { - const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); - embedding._dataViz = DataVizView.TABLE; - embedding._dataViz_axes = new List([col, col]); - embedding._dataViz_parentViz = this.props.rootDoc; - embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; - embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors); - embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor; - embedding.pieSliceColors = Field.Copy(this.props.layoutDoc.pieSliceColors); - return embedding; - }; - if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { - DragManager.StartAnchorAnnoDrag( - e.target instanceof HTMLElement ? [e.target] : [], - new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), - downX, - downY, - { - dragComplete: e => { - if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.linkDocument.link_displayLine = true; - e.linkDocument.link_matchEmbeddings = true; - // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; - // e.annoDragData.linkSourceDoc.followLinkZoom = false; - } - }, - } - ); - return true; - } - return false; - }, - emptyFunction, - action(e => { - const newAxes = this.props.axes; - if (newAxes.includes(col)) newAxes.splice(newAxes.indexOf(col), 1); - else if (newAxes.length > 1) newAxes[1] = col; - else newAxes.push(col); - this.props.selectAxes(newAxes); - }) - ); - }}> + onPointerDown={e => this.columnPointerDown(e, col)}> {col}
- {record[col]} -
{/* empty row data for out-of-view items needed to give row the default row height so that scrolling works */} +
+
{record[col]}
+
-- cgit v1.2.3-70-g09d2 From 2da948c2f19c2afa6c0f92964a2622d0e9a2f144 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 10 Oct 2023 14:36:07 -0400 Subject: more fixes for virtual scrolling and added keeps scroll pos on drag --- .../views/nodes/DataVizBox/components/TableBox.tsx | 138 +++++++++++---------- 1 file changed, 72 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index edf0ea4c7..b8f65cb7d 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,7 +1,6 @@ import { Button, Type } from 'browndash-components'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; -import { actionFieldDecorator } from 'mobx/lib/internal'; import * as React from 'react'; import { Doc, Field, NumListCast } from '../../../../../fields/Doc'; import { List } from '../../../../../fields/List'; @@ -32,18 +31,18 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { - @observable startID: number = 0; - @observable endID: number = 0; - _tableContainerRef: HTMLDivElement | null = null; - _tableRef = React.createRef(); - _inputChangedDisposer?: IReactionDisposer; + _containerRef: HTMLDivElement | null = null; + + @observable _scrollTop = -1; + @observable _tableHeight = 0; + @observable _tableContainerHeight = 0; + componentDidMount() { // if the tableData changes (ie., when records are selected by the parent (input) visulization), // then we need to remove any selected rows that are no longer part of the visualized dataset. this._inputChangedDisposer = reaction(() => this._tableData.slice(), this.filterSelectedRowsDown, { fireImmediately: true }); - - this._tableContainerRef && this.handleScroll(); + this.handleScroll(); } componentWillUnmount() { this._inputChangedDisposer?.(); @@ -79,14 +78,17 @@ export class TableBox extends React.Component { return this.props.docView?.()?.props.ScreenToLocalTransform().Scale || 1; } @computed get rowHeight() { - const tableHeight = this._tableRef.current?.getBoundingClientRect().height; - return !tableHeight ? 1 : (this.viewScale * tableHeight) / this._tableDataIds.length; + return (this.viewScale * this._tableHeight) / this._tableDataIds.length; + } + @computed get startID() { + return this.rowHeight ? Math.floor(this._scrollTop / this.rowHeight) : 0; + } + @computed get endID() { + return Math.ceil(this.startID + (this._tableContainerHeight * this.viewScale) / (this.rowHeight || 1)); } - @action handleScroll = () => { - if (this._tableContainerRef) { - this.startID = Math.floor(this._tableContainerRef.scrollTop / this.rowHeight); - this.endID = this.startID + (this._tableContainerRef.getBoundingClientRect().height * this.viewScale) / this.rowHeight; + if (!this.props.docView?.()?.ContentDiv?.hidden) { + this._scrollTop = this._containerRef?.scrollTop ?? 0; } }; @action @@ -175,66 +177,70 @@ export class TableBox extends React.Component { className={`table-container ${this.columns[0]}`} style={{ height: '100%', overflow: 'auto' }} onScroll={this.handleScroll} - ref={r => { - this._tableContainerRef = r; - r?.addEventListener( - 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this) - (e: WheelEvent) => { - if (!r.scrollTop && e.deltaY <= 0) e.preventDefault(); - e.stopPropagation(); - }, - { passive: false } - ); - }}> - + ref={action((r: HTMLDivElement | null) => { + this._containerRef = r; + if (!this.props.docView?.()?.ContentDiv?.hidden && r) { + this._tableContainerHeight = r.getBoundingClientRect().height ?? 0; + r.addEventListener( + 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this) + (e: WheelEvent) => { + if (!r.scrollTop && e.deltaY <= 0) e.preventDefault(); + e.stopPropagation(); + }, + { passive: false } + ); + } + })}> +
{ + if (!this.props.docView?.()?.ContentDiv?.hidden && r) { + this._tableHeight = r?.getBoundingClientRect().height ?? 0; + } + })}> +
- {this.columns.map(col => - this.startID > 0 ? null : ( - - ) - )} + {this.columns.map(col => ( + + ))} {this._tableDataIds + .filter(rowId => this.startID <= rowId && rowId <= this.endID) ?.map(rowId => ({ record: this.props.records[rowId], rowId })) - .map(({ record, rowId }) => - this.startID > rowId || rowId > this.endID ? ( - - - ) : ( - this.tableRowClick(e, rowId)} - style={{ - background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', - width: '110%', - }}> - {this.columns.map(col => { - const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false; - return ( - - ); - })} - - ) - )} + .map(({ record, rowId }) => ( + this.tableRowClick(e, rowId)} + style={{ + background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', + width: '110%', + }}> + {this.columns.map(col => { + const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false; + return ( + + ); + })} + + ))} +
this.columnPointerDown(e, col)}> - {col} - this.columnPointerDown(e, col)}> + {col} +
{/* empty row data for out-of-view items needed to give row the default row height so that scrolling works */} -
-
{record[col]}
-
+
{record[col]}
+
-- cgit v1.2.3-70-g09d2 From 5eca36aa3e775646d96671b922bf7205074ab135 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 10 Oct 2023 14:52:54 -0400 Subject: made tablebox row height a css variable. fixed panmode so that left drag selects w/ marquee and two finger vertical pan isn't clamped. --- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 9 ++++----- src/client/views/global/globalCssVariables.scss | 3 +++ src/client/views/global/globalCssVariables.scss.d.ts | 1 + src/client/views/nodes/DataVizBox/components/Chart.scss | 3 ++- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 3 ++- 6 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 676e96714..3a8e8f2ef 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1082,7 +1082,7 @@ export class CollectionFreeFormView extends CollectionSubView Transform; @@ -223,7 +222,7 @@ export class MarqueeView extends React.Component height directly, but you can set the height of all of it's s. So this is the height of a tableBox row. + height: $DATA_VIZ_TABLE_ROW_HEIGHT !important; // bcz: hack. you can't set a height directly, but you can set the height of all of it's s. So this is the height of a tableBox row. padding: 0 !important; vertical-align: middle !important; } diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index b8f65cb7d..8f16df1dc 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -10,6 +10,7 @@ import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../../Utils'; import { DragManager } from '../../../../util/DragManager'; import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; +import { DATA_VIZ_TABLE_ROW_HEIGHT } from '../../../global/globalCssVariables.scss'; import './Chart.scss'; interface TableBoxProps { @@ -198,7 +199,7 @@ export class TableBox extends React.Component { this._tableHeight = r?.getBoundingClientRect().height ?? 0; } })}> -
+
{this.columns.map(col => ( -- cgit v1.2.3-70-g09d2 From 54e80f26df04f1a031d1d7e4b840fe9426d4d2cf Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 11 Oct 2023 15:06:40 -0400 Subject: fixed panMode to not do marquee selection on nested but inactive collections. --- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index a6a3280eb..5c053fefc 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -222,7 +222,7 @@ export class MarqueeView extends React.Component Date: Thu, 12 Oct 2023 11:24:19 -0400 Subject: performance fixes to reduce re-rendering : moved link brushing out of Doc's highlighting and into Annotation.tsx, stopped freeformview from rerendering whenever its invalidated by not always setting layoutElements to a new list. --- src/client/documents/Documents.ts | 4 +- src/client/views/FilterPanel.tsx | 4 +- src/client/views/StyleProvider.tsx | 4 +- src/client/views/collections/CollectionSubView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 18 ++++++--- src/client/views/nodes/DocumentView.tsx | 43 +++------------------- src/client/views/nodes/ImageBox.tsx | 1 - src/client/views/nodes/MapBox/MapBox.tsx | 10 ++--- src/client/views/nodes/PDFBox.tsx | 2 - src/client/views/nodes/WebBox.tsx | 20 ++-------- .../views/nodes/formattedText/FormattedTextBox.tsx | 1 - src/client/views/pdf/Annotation.tsx | 10 ++++- src/client/views/pdf/PDFViewer.tsx | 3 +- src/fields/Doc.ts | 34 ++++++----------- 14 files changed, 57 insertions(+), 101 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b1632dadf..11b5f9f08 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { action, reaction, runInAction } from 'mobx'; import { basename } from 'path'; import { DateField } from '../../fields/DateField'; -import { Doc, DocListCast, Field, Opt, updateCachedAcls } from '../../fields/Doc'; +import { Doc, DocListCast, Field, LinkedTo, Opt, updateCachedAcls } from '../../fields/Doc'; import { Initializing } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { HtmlField } from '../../fields/HtmlField'; @@ -1302,7 +1302,7 @@ export namespace DocUtils { if (!unsets.length && !exists.length && !xs.length && !checks.length && !matches.length) return true; const failsNotEqualFacets = !xs.length ? false : xs.some(value => Doc.matchFieldValue(d, facetKey, value)); const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value)); - const satisfiesExistsFacets = !exists.length ? true : exists.some(value => (facetKey !== '-linkedTo' ? d[facetKey] !== undefined : LinkManager.Instance.getAllRelatedLinks(d).length)); + const satisfiesExistsFacets = !exists.length ? true : exists.some(value => (facetKey !== LinkedTo ? d[facetKey] !== undefined : LinkManager.Instance.getAllRelatedLinks(d).length)); const satisfiesUnsetsFacets = !unsets.length ? true : unsets.some(value => d[facetKey] === undefined); const satisfiesMatchFacets = !matches.length ? true diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx index 69ceb0f65..0df88f970 100644 --- a/src/client/views/FilterPanel.tsx +++ b/src/client/views/FilterPanel.tsx @@ -5,7 +5,7 @@ import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider'; import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai'; import { CiCircleRemove } from 'react-icons/ci'; import Select from 'react-select'; -import { Doc, DocListCast, Field, StrListCast } from '../../fields/Doc'; +import { Doc, DocListCast, Field, LinkedTo, StrListCast } from '../../fields/Doc'; import { RichTextField } from '../../fields/RichTextField'; import { DocumentOptions, FInfo } from '../documents/Documents'; import { DocumentManager } from '../util/DocumentManager'; @@ -57,7 +57,7 @@ export class FilterPanel extends React.Component { @computed get _allFacets() { // trace(); - const noviceReqFields = ['author', 'tags', 'text', 'type', '-linkedTo']; + const noviceReqFields = ['author', 'tags', 'text', 'type', LinkedTo]; const noviceLayoutFields: string[] = []; //["_layout_curPage"]; const noviceFields = [...noviceReqFields, ...noviceLayoutFields]; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index f2e1ee0a2..6ee96de5b 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { Dropdown, DropdownType, IconButton, IListItemProps, ListBox, ListItem, Popup, Shadows, Size, Type } from 'browndash-components'; -import { action, runInAction } from 'mobx'; +import { action, runInAction, untracked } from 'mobx'; import { extname } from 'path'; import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs'; import { Doc, Opt, StrListCast } from '../../fields/Doc'; @@ -277,7 +277,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt { - const dashView = DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard); + const dashView = untracked(() => DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard)); const showFilterIcon = StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length ? 'green' // #18c718bd' //'hasFilter' diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 158f9d8ee..011bc1de5 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -67,7 +67,7 @@ export function CollectionSubView(moreProps?: X) { return this.layoutDoc[this.props.fieldKey]; } - get childLayoutPairs(): { layout: Doc; data: Doc }[] { + @computed get childLayoutPairs(): { layout: Doc; data: Doc }[] { const { Document, DataDoc } = this.props; const validPairs = this.childDocs .map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc)) @@ -77,7 +77,7 @@ export function CollectionSubView(moreProps?: X) { }); return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types } - get childDocList() { + @computed get childDocList() { return Cast(this.dataField, listSpec(Doc)); } collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._childFilters); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3a8e8f2ef..407f18d62 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { DateField } from '../../../../fields/DateField'; @@ -59,7 +59,7 @@ export type collectionFreeformViewProps = { originTopLeft?: boolean; annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; - childPointerEvents?: string; + childPointerEvents?: () => string | undefined; viewField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; @@ -1082,7 +1082,7 @@ export class CollectionFreeFormView extends CollectionSubView this._pointerEvents; @@ -1511,6 +1511,7 @@ export class CollectionFreeFormView extends CollectionSubView { for (const entry of array) { const lastPos = this._cachedPool.get(entry[0]); // last computed pos @@ -1528,12 +1529,15 @@ export class CollectionFreeFormView extends CollectionSubView this._cachedPool.set(k[0], k[1])); const elements = computedElementData.slice(); @@ -1609,7 +1613,9 @@ export class CollectionFreeFormView extends CollectionSubView this.doLayoutComputation, - elements => (this._layoutElements = elements || []), + elements => { + if (elements !== undefined) this._layoutElements = elements || []; + }, { fireImmediately: true, name: 'doLayout' } ); @@ -1917,7 +1923,7 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? undefined : this.nudge} addDocTab={this.addDocTab} slowLoadDocuments={this.slowLoadDocuments} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e4fc6c4a2..e8c33a10e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -156,7 +156,6 @@ export interface DocumentViewSharedProps { contentBounds?: () => undefined | { x: number; y: number; r: number; b: number }; fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document suppressSetHeight?: boolean; - thumbShown?: () => boolean; setContentView?: (view: DocComponentView) => any; CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; PanelWidth: () => number; @@ -299,10 +298,11 @@ export class DocumentViewInternal extends DocComponent this._isContentActive; - @observable _retryThumb = 1; - @computed get _thumbShown() { - const childHighlighted = () => false; - // Array.from(Doc.highlightedDocs.keys()) - // .concat(Array.from(Doc.brushManager.BrushedDoc.keys())) - // .some(doc => Doc.AreProtosEqual(DocCast(doc.annotationOn), this.rootDoc)); - const childOverlayed = () => Array.from(DocumentManager._overlayViews).some(view => Doc.AreProtosEqual(view.rootDoc, this.rootDoc)); - return !this.props.LayoutTemplateString && - !this.isContentActive() && - LightboxView.LightboxDoc !== this.rootDoc && - this.thumb && - !Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) && - ((!childHighlighted() && !childOverlayed() && !Doc.isBrushedHighlightedDegree(this.rootDoc)) || this.rootDoc._type_collection === CollectionViewType.Docking) - ? true - : false; - } - thumbShown = () => this._thumbShown; childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)]; /// disable pointer events on content when there's an enabled onClick script (but not the browse script) and the contents aren't forced active, or if contents are marked inactive @@ -918,25 +901,11 @@ export class DocumentViewInternal extends DocComponent - {!this._retryThumb || !this.thumbShown() ? null : ( - { const createFunc = undoable( action(() => { - const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(true), ['latitude', 'longitude', '-linkedTo']); + const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(true), ['latitude', 'longitude', LinkedTo]); if (note && this.selectedPin) { note.latitude = this.selectedPin.latitude; note.longitude = this.selectedPin.longitude; @@ -383,7 +383,7 @@ export class MapBox extends ViewBoxAnnotatableComponent 600 ? (NumCast(this.Document._height) * this.props.PanelWidth()) / NumCast(this.Document._width) : undefined, }}>
this.sidebarBtnDown(e, false)} /> @@ -609,7 +608,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent>(); render() { TraceMobx(); - if (this.props.thumbShown?.()) return null; const pdfView = this.renderPdfView; const href = this.pdfUrl?.url.href; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index af20ff061..58a765d61 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -94,19 +94,6 @@ export class WebBox extends ViewBoxAnnotatableComponent { const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); - const scale = (this.props.NativeDimScaling?.() || 1) * mainContBounds.scale; const word = getWordAtPoint(e.target, e.clientX, e.clientY); this._setPreviewCursor?.(e.clientX, e.clientY, false, true, this.rootDoc); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); @@ -940,7 +926,7 @@ export class WebBox extends ViewBoxAnnotatableComponent - {this._hackHide || (this.webThumb && !this._webPageHasBeenRendered && LightboxView.LightboxDoc !== this.rootDoc) ? null : this.urlContent} + {this._hackHide ? null : this.urlContent}
); } @@ -968,6 +954,7 @@ export class WebBox extends ViewBoxAnnotatableComponent (this.props.isContentActive() ? 'all' : undefined); @computed get webpage() { const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any); @@ -999,7 +986,7 @@ export class WebBox extends ViewBoxAnnotatableComponent ); @@ -1090,7 +1077,6 @@ export class WebBox extends ViewBoxAnnotatableComponent
{ } }; + @computed get linkHighlighted() { + for (const link of LinkManager.Instance.getAllDirectLinks(this.props.document)) { + const a1 = LinkManager.getOppositeAnchor(link, this.props.document); + if (a1 && Doc.IsBrushedDegreeUnmemoized(DocCast(a1.annotationOn, this.props.document))) return true; + } + } + render() { const brushed = this.annoTextRegion && Doc.isBrushedHighlightedDegree(this.annoTextRegion); return ( @@ -108,7 +116,7 @@ class RegionAnnotation extends React.Component { height: NumCast(this.props.document._height), opacity: brushed === Doc.DocBrushStatus.highlighted ? 0.5 : undefined, pointerEvents: this.props.pointerEvents?.() as any, - outline: brushed === Doc.DocBrushStatus.linkHighlighted ? 'solid 1px lightBlue' : undefined, + outline: brushed === Doc.DocBrushStatus.unbrushed && this.linkHighlighted ? 'solid 1px lightBlue' : undefined, backgroundColor: brushed === Doc.DocBrushStatus.highlighted ? 'orange' : StrCast(this.props.document.backgroundColor), }} /> diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 23dc084ad..58a54764d 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -525,6 +525,7 @@ export class PDFViewer extends React.Component { return this.props.styleProvider?.(doc, props, property); }; + childPointerEvents = () => (this.props.isContentActive() !== false ? 'all' : 'none'); renderAnnotations = (childFilters: () => string[], mixBlendMode?: any, display?: string) => (
{ NativeHeight={returnZero} setContentView={emptyFunction} // override setContentView to do nothing pointerEvents={this.props.isContentActive() && (SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None) ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it. - childPointerEvents={this.props.isContentActive() !== false ? 'all' : 'none'} // but freeform children need to get events to allow text editing, etc + childPointerEvents={this.childPointerEvents} // but freeform children need to get events to allow text editing, etc renderDepth={this.props.renderDepth + 1} isAnnotationOverlay={true} fieldKey={this.props.fieldKey + '_annotations'} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 7170be6cc..9e3eb28f9 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -50,8 +50,9 @@ import { listSpec } from './Schema'; import { ComputedField, ScriptField } from './ScriptField'; import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types'; import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField'; -import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions } from './util'; +import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, TraceMobx } from './util'; import JSZip = require('jszip'); +export const LinkedTo = '-linkedTo'; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { const onDelegate = Object.keys(doc).includes(key.replace(/^_/, '')); @@ -853,22 +854,22 @@ export namespace Doc { export async function Zip(doc: Doc, zipFilename = 'dashExport.zip') { const { clone, map, linkMap } = await Doc.MakeClone(doc); const proms = new Set(); - function replacer(key: any, value: any) { + function replacer(key: any, value: any) { if (key && ['branchOf', 'cloneOf', 'cursors'].includes(key)) return undefined; - if (value?.__type === 'image') { + if (value?.__type === 'image') { const extension = value.url.replace(/.*\./, ''); proms.add(value.url.replace('.' + extension, '_o.' + extension)); return SerializationHelper.Serialize(new ImageField(value.url)); } - if (value?.__type === 'pdf') { + if (value?.__type === 'pdf') { proms.add(value.url); return SerializationHelper.Serialize(new PdfField(value.url)); } - if (value?.__type === 'audio') { + if (value?.__type === 'audio') { proms.add(value.url); return SerializationHelper.Serialize(new AudioField(value.url)); } - if (value?.__type === 'video') { + if (value?.__type === 'video') { proms.add(value.url); return SerializationHelper.Serialize(new VideoField(value.url)); } @@ -897,7 +898,9 @@ export namespace Doc { const zip = new JSZip(); var count = 0; - const promArr = Array.from(proms).filter(url => url?.startsWith("/files")).map(url => url.replace("/",""))// window.location.origin)); + const promArr = Array.from(proms) + .filter(url => url?.startsWith('/files')) + .map(url => url.replace('/', '')); // window.location.origin)); console.log(promArr.length); if (!promArr.length) { zip.file('docs.json', jsonDocs); @@ -905,7 +908,7 @@ export namespace Doc { } else promArr.forEach((url, i) => { // loading a file and add it in a zip file - JSZipUtils.getBinaryContent(window.location.origin+"/"+url, (err: any, data: any) => { + JSZipUtils.getBinaryContent(window.location.origin + '/' + url, (err: any, data: any) => { if (err) throw err; // or handle the error // // Generate a directory within the Zip file structure // const assets = zip.folder("assets"); @@ -1343,24 +1346,11 @@ export namespace Doc { protoBrushed = 1, selfBrushed = 2, highlighted = 3, - linkHighlighted = 4, } // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message) export function IsBrushedDegreeUnmemoized(doc: Doc) { if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed; const status = brushManager.BrushedDoc.has(doc) ? DocBrushStatus.selfBrushed : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed; - if (status === DocBrushStatus.unbrushed) { - const lastBrushed = Array.from(brushManager.BrushedDoc.keys()).lastElement(); - if (lastBrushed) { - for (const link of LinkManager.Instance.getAllDirectLinks(lastBrushed)) { - const a1 = Cast(link.link_anchor_1, Doc, null); - const a2 = Cast(link.link_anchor_2, Doc, null); - if (Doc.AreProtosEqual(a1, doc) || Doc.AreProtosEqual(a2, doc) || Doc.AreProtosEqual(Cast(a1.annotationOn, Doc, null), doc) || Doc.AreProtosEqual(Cast(a2.annotationOn, Doc, null), doc)) { - return DocBrushStatus.linkHighlighted; - } - } - } - } return status; } export function IsBrushedDegree(doc: Doc) { @@ -1472,7 +1462,7 @@ export namespace Doc { const isTransparent = (color: string) => color !== '' && DashColor(color).alpha() !== 1; return isTransparent(StrCast(doc[key])); } - if (key === '-linkedTo') { + if (key === LinkedTo) { // links are not a field value, so handled here. value is an expression of form ([field=]idToDoc("...")) const allLinks = LinkManager.Instance.getAllRelatedLinks(doc); const matchLink = (value: string, anchor: Doc) => { -- cgit v1.2.3-70-g09d2 From 0717e03ea10c3041ade2c0dbde0a157f76df41d1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 12 Oct 2023 12:46:26 -0400 Subject: fix for tableBox scrolling --- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 8f16df1dc..1ece3f238 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -241,7 +241,7 @@ export class TableBox extends React.Component { ))} -
+
-- cgit v1.2.3-70-g09d2 From 37cc69bcc8be3a6b160c45e5c16f969bd593fa88 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 16 Oct 2023 10:58:24 -0400 Subject: added auto reset view option for collections. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 36 +++++++++++++++------- src/client/views/nodes/DocumentView.tsx | 2 +- 2 files changed, 26 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 407f18d62..3f23ee15a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -109,6 +109,9 @@ export class CollectionFreeFormView extends CollectionSubView this.isContentActive(), + active => this.rootDoc[this.autoResetFieldKey] && !active && this.resetView() + ); + this._disposers.fitContent = reaction( () => this.rootDoc.fitContentOnce, fitContentOnce => { @@ -1774,9 +1782,21 @@ export class CollectionFreeFormView extends CollectionSubView { - if (!this.props.Document._isGroup) { - this.props.Document[this.panXFieldKey] = this.props.Document[this.panYFieldKey] = 0; - this.props.Document[this.scaleFieldKey] = 1; + this.rootDoc[this.panXFieldKey] = NumCast(this.rootDoc[this.panXFieldKey + '_reset']); + this.props.Document[this.panYFieldKey] = NumCast(this.rootDoc[this.panYFieldKey + '_reset']); + this.rootDoc[this.scaleFieldKey] = NumCast(this.rootDoc[this.scaleFieldKey + '_reset'], 1); + }; + /// + /// resetView restores a freeform collection to unit scale and centered at (0,0) UNLESS + /// the view is a group, in which case this does nothing (since Groups calculate their own scale and center) + /// + @undoBatch + toggleResetView = () => { + this.rootDoc[this.autoResetFieldKey] = !this.rootDoc[this.autoResetFieldKey]; + if (this.rootDoc[this.autoResetFieldKey]) { + this.rootDoc[this.panXFieldKey + '_reset'] = this.rootDoc[this.panXFieldKey]; + this.rootDoc[this.panYFieldKey + '_reset'] = this.rootDoc[this.panYFieldKey]; + this.rootDoc[this.scaleFieldKey + '_reset'] = this.rootDoc[this.scaleFieldKey]; } }; @@ -1786,6 +1806,7 @@ export class CollectionFreeFormView extends CollectionSubView (this._showAnimTimeline = !this._showAnimTimeline)), icon: 'eye' }); this.props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor)), icon: 'palette' }); - this.props.renderDepth && - optionItems.push({ - description: 'Fit Content Once', - event: () => { - this.fitContentOnce(); - }, - icon: 'object-group', - }); + this.props.renderDepth && optionItems.push({ description: 'Fit Content Once', event: this.fitContentOnce, icon: 'object-group' }); if (!Doc.noviceMode) { optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? 'Freeze' : 'Unfreeze') + ' Aspect', event: this.toggleNativeDimensions, icon: 'snowflake' }); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e8c33a10e..96d3adff5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -114,7 +114,7 @@ export interface DocComponentView { getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) restoreView?: (viewSpec: Doc) => boolean; scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt; // returns the duration of the focus - brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void; + brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void; // highlight a region of a view (used by freeforms) getView?: (doc: Doc) => Promise>; // returns a nested DocumentView for the specified doc or undefined addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) -- cgit v1.2.3-70-g09d2 From f6337ba3244f2d7270dccb6b319c047e608c6a72 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 16 Oct 2023 13:57:01 -0400 Subject: cleaned up css and cursor pointer for tableboxes. prevent links being drawn to keyvaluebox. --- .../CollectionFreeFormLayoutEngines.tsx | 1 - .../views/nodes/DataVizBox/components/Chart.scss | 40 ++++++++++++++-------- .../views/nodes/DataVizBox/components/TableBox.tsx | 12 +++---- src/client/views/nodes/DocumentView.tsx | 3 +- src/client/views/nodes/LinkAnchorBox.tsx | 4 +++ 5 files changed, 37 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 15b6e1d37..c1c01eacb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -6,7 +6,6 @@ import { RefField } from '../../../../fields/RefField'; import { listSpec } from '../../../../fields/Schema'; import { Cast, NumCast, StrCast } from '../../../../fields/Types'; import { aggregateBounds } from '../../../../Utils'; -import { ColorScheme } from '../../../util/SettingsManager'; import React = require('react'); export interface ViewDefBounds { diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss index a6ce0b88c..c788a64c2 100644 --- a/src/client/views/nodes/DataVizBox/components/Chart.scss +++ b/src/client/views/nodes/DataVizBox/components/Chart.scss @@ -92,21 +92,33 @@ .tableBox { display: flex; flex-direction: column; + cursor: default; height: calc(100% - 40px); // bcz: hack 40px is the size of the button rows - .table { - height: 100%; - } -} -.table-container { - overflow: scroll; - margin: 5px; - margin-left: 25px; - margin-right: 10px; - margin-bottom: 0; - tr td { - height: $DATA_VIZ_TABLE_ROW_HEIGHT !important; // bcz: hack. you can't set a height directly, but you can set the height of all of it's s. So this is the height of a tableBox row. - padding: 0 !important; - vertical-align: middle !important; + .tableBox-container { + overflow: scroll; + margin: 5px; + margin-left: 25px; + margin-right: 10px; + margin-bottom: 0; + .tableBox-table { + height: 100%; + width: 100%; + .tableBox-row { + cursor: pointer; + .tableBox-cell { + text-overflow: ellipsis; + width: 100%; + white-space: pre; + max-width: 150; + overflow: hidden; + } + } + } + tr td { + height: $DATA_VIZ_TABLE_ROW_HEIGHT !important; // bcz: hack. you can't set a height directly, but you can set the height of all of it's s. So this is the height of a tableBox row. + padding: 0 !important; + vertical-align: middle !important; + } } } .selectAll-buttons { diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 1ece3f238..b88389de6 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -175,7 +175,7 @@ export class TableBox extends React.Component {
{ @@ -193,7 +193,7 @@ export class TableBox extends React.Component { } })}> { if (!this.props.docView?.()?.ContentDiv?.hidden && r) { this._tableHeight = r?.getBoundingClientRect().height ?? 0; @@ -220,21 +220,19 @@ export class TableBox extends React.Component { {this._tableDataIds .filter(rowId => this.startID <= rowId && rowId <= this.endID) - ?.map(rowId => ({ record: this.props.records[rowId], rowId })) - .map(({ record, rowId }) => ( + ?.map(rowId => ( this.tableRowClick(e, rowId)} style={{ background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', - width: '110%', }}> {this.columns.map(col => { const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false; return ( ); })} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 96d3adff5..da665a502 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -52,6 +52,7 @@ import { LinkAnchorBox } from './LinkAnchorBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; import React = require('react'); +import { KeyValueBox } from './KeyValueBox'; const { Howl } = require('howler'); interface Window { @@ -963,7 +964,7 @@ export class DocumentViewInternal extends DocComponent d.link_displayLine || Doc.UserDoc().showLinkLines); return filtered.map(link => (
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 9bcd04cf5..fd7d13655 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -28,6 +28,10 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { @observable _x = 0; @observable _y = 0; + componentDidMount() { + this.props.setContentView?.(this); + } + @computed get linkSource() { return this.props.docViewPath()[this.props.docViewPath().length - 2].rootDoc; // this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.LinkSource); } -- cgit v1.2.3-70-g09d2 From abf40af6dd617de6486a97e8b5f276db232119ed Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 16 Oct 2023 16:38:06 -0400 Subject: fixed deleting docs --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3f23ee15a..bfc61f601 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1511,10 +1511,12 @@ export class CollectionFreeFormView extends CollectionSubView { for (const entry of array) { const lastPos = this._cachedPool.get(entry[0]); // last computed pos -- cgit v1.2.3-70-g09d2
-
{record[col]}
+
{this.props.records[rowId][col]}