New: Improved Series list performance
This commit is contained in:
parent
466d4fba9e
commit
5a79b8502e
|
@ -21,17 +21,15 @@ class ImportSeries extends Component {
|
||||||
allSelected: false,
|
allSelected: false,
|
||||||
allUnselected: false,
|
allUnselected: false,
|
||||||
lastToggled: null,
|
lastToggled: null,
|
||||||
selectedState: {},
|
selectedState: {}
|
||||||
contentBody: null,
|
|
||||||
scrollTop: 0
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Control
|
// Control
|
||||||
|
|
||||||
setContentBodyRef = (ref) => {
|
setScrollerRef = (ref) => {
|
||||||
this.setState({ contentBody: ref });
|
this.setState({ scroller: ref });
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -94,13 +92,13 @@ class ImportSeries extends Component {
|
||||||
allSelected,
|
allSelected,
|
||||||
allUnselected,
|
allUnselected,
|
||||||
selectedState,
|
selectedState,
|
||||||
contentBody
|
scroller
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent title="Import Series">
|
<PageContent title="Import Series">
|
||||||
<PageContentBodyConnector
|
<PageContentBodyConnector
|
||||||
ref={this.setContentBodyRef}
|
registerScroller={this.setScrollerRef}
|
||||||
onScroll={this.onScroll}
|
onScroll={this.onScroll}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
|
@ -121,20 +119,18 @@ class ImportSeries extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
!rootFoldersError && rootFoldersPopulated && !!unmappedFolders.length && contentBody &&
|
!rootFoldersError && rootFoldersPopulated && !!unmappedFolders.length && scroller &&
|
||||||
<ImportSeriesTableConnector
|
<ImportSeriesTableConnector
|
||||||
rootFolderId={rootFolderId}
|
rootFolderId={rootFolderId}
|
||||||
unmappedFolders={unmappedFolders}
|
unmappedFolders={unmappedFolders}
|
||||||
allSelected={allSelected}
|
allSelected={allSelected}
|
||||||
allUnselected={allUnselected}
|
allUnselected={allUnselected}
|
||||||
selectedState={selectedState}
|
selectedState={selectedState}
|
||||||
contentBody={contentBody}
|
scroller={scroller}
|
||||||
showLanguageProfile={showLanguageProfile}
|
showLanguageProfile={showLanguageProfile}
|
||||||
scrollTop={this.state.scrollTop}
|
|
||||||
onSelectAllChange={this.onSelectAllChange}
|
onSelectAllChange={this.onSelectAllChange}
|
||||||
onSelectedChange={this.onSelectedChange}
|
onSelectedChange={this.onSelectedChange}
|
||||||
onRemoveSelectedStateItem={this.onRemoveSelectedStateItem}
|
onRemoveSelectedStateItem={this.onRemoveSelectedStateItem}
|
||||||
onScroll={this.onScroll}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</PageContentBodyConnector>
|
</PageContentBodyConnector>
|
||||||
|
|
|
@ -2,7 +2,6 @@ import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes } from 'Helpers/Props';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
import VirtualTableRow from 'Components/Table/VirtualTableRow';
|
|
||||||
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
|
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
|
||||||
import VirtualTableSelectCell from 'Components/Table/Cells/VirtualTableSelectCell';
|
import VirtualTableSelectCell from 'Components/Table/Cells/VirtualTableSelectCell';
|
||||||
import ImportSeriesSelectSeriesConnector from './SelectSeries/ImportSeriesSelectSeriesConnector';
|
import ImportSeriesSelectSeriesConnector from './SelectSeries/ImportSeriesSelectSeriesConnector';
|
||||||
|
@ -10,7 +9,6 @@ import styles from './ImportSeriesRow.css';
|
||||||
|
|
||||||
function ImportSeriesRow(props) {
|
function ImportSeriesRow(props) {
|
||||||
const {
|
const {
|
||||||
style,
|
|
||||||
id,
|
id,
|
||||||
monitor,
|
monitor,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
|
@ -26,7 +24,7 @@ function ImportSeriesRow(props) {
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VirtualTableRow style={style}>
|
<>
|
||||||
<VirtualTableSelectCell
|
<VirtualTableSelectCell
|
||||||
inputClassName={styles.selectInput}
|
inputClassName={styles.selectInput}
|
||||||
id={id}
|
id={id}
|
||||||
|
@ -93,12 +91,11 @@ function ImportSeriesRow(props) {
|
||||||
onInputChange={onInputChange}
|
onInputChange={onInputChange}
|
||||||
/>
|
/>
|
||||||
</VirtualTableRowCell>
|
</VirtualTableRowCell>
|
||||||
</VirtualTableRow>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportSeriesRow.propTypes = {
|
ImportSeriesRow.propTypes = {
|
||||||
style: PropTypes.object.isRequired,
|
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
monitor: PropTypes.string.isRequired,
|
monitor: PropTypes.string.isRequired,
|
||||||
qualityProfileId: PropTypes.number.isRequired,
|
qualityProfileId: PropTypes.number.isRequired,
|
||||||
|
|
|
@ -2,6 +2,7 @@ import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import VirtualTable from 'Components/Table/VirtualTable';
|
import VirtualTable from 'Components/Table/VirtualTable';
|
||||||
|
import VirtualTableRow from 'Components/Table/VirtualTableRow';
|
||||||
import ImportSeriesHeader from './ImportSeriesHeader';
|
import ImportSeriesHeader from './ImportSeriesHeader';
|
||||||
import ImportSeriesRowConnector from './ImportSeriesRowConnector';
|
import ImportSeriesRowConnector from './ImportSeriesRowConnector';
|
||||||
|
|
||||||
|
@ -112,15 +113,19 @@ class ImportSeriesTable extends Component {
|
||||||
const item = items[rowIndex];
|
const item = items[rowIndex];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ImportSeriesRowConnector
|
<VirtualTableRow
|
||||||
key={key}
|
key={key}
|
||||||
style={style}
|
style={style}
|
||||||
rootFolderId={rootFolderId}
|
>
|
||||||
showLanguageProfile={showLanguageProfile}
|
<ImportSeriesRowConnector
|
||||||
isSelected={selectedState[item.id]}
|
key={item.id}
|
||||||
onSelectedChange={onSelectedChange}
|
rootFolderId={rootFolderId}
|
||||||
id={item.id}
|
showLanguageProfile={showLanguageProfile}
|
||||||
/>
|
isSelected={selectedState[item.id]}
|
||||||
|
onSelectedChange={onSelectedChange}
|
||||||
|
id={item.id}
|
||||||
|
/>
|
||||||
|
</VirtualTableRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,12 +138,10 @@ class ImportSeriesTable extends Component {
|
||||||
allSelected,
|
allSelected,
|
||||||
allUnselected,
|
allUnselected,
|
||||||
isSmallScreen,
|
isSmallScreen,
|
||||||
contentBody,
|
scroller,
|
||||||
showLanguageProfile,
|
showLanguageProfile,
|
||||||
scrollTop,
|
|
||||||
selectedState,
|
selectedState,
|
||||||
onSelectAllChange,
|
onSelectAllChange
|
||||||
onScroll
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!items.length) {
|
if (!items.length) {
|
||||||
|
@ -148,10 +151,9 @@ class ImportSeriesTable extends Component {
|
||||||
return (
|
return (
|
||||||
<VirtualTable
|
<VirtualTable
|
||||||
items={items}
|
items={items}
|
||||||
contentBody={contentBody}
|
scroller={scroller}
|
||||||
isSmallScreen={isSmallScreen}
|
isSmallScreen={isSmallScreen}
|
||||||
rowHeight={52}
|
rowHeight={52}
|
||||||
scrollTop={scrollTop}
|
|
||||||
overscanRowCount={2}
|
overscanRowCount={2}
|
||||||
rowRenderer={this.rowRenderer}
|
rowRenderer={this.rowRenderer}
|
||||||
header={
|
header={
|
||||||
|
@ -163,7 +165,6 @@ class ImportSeriesTable extends Component {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
selectedState={selectedState}
|
selectedState={selectedState}
|
||||||
onScroll={onScroll}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -183,15 +184,13 @@ ImportSeriesTable.propTypes = {
|
||||||
selectedState: PropTypes.object.isRequired,
|
selectedState: PropTypes.object.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
allSeries: PropTypes.arrayOf(PropTypes.object),
|
allSeries: PropTypes.arrayOf(PropTypes.object),
|
||||||
contentBody: PropTypes.object.isRequired,
|
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||||
showLanguageProfile: PropTypes.bool.isRequired,
|
showLanguageProfile: PropTypes.bool.isRequired,
|
||||||
scrollTop: PropTypes.number.isRequired,
|
|
||||||
onSelectAllChange: PropTypes.func.isRequired,
|
onSelectAllChange: PropTypes.func.isRequired,
|
||||||
onSelectedChange: PropTypes.func.isRequired,
|
onSelectedChange: PropTypes.func.isRequired,
|
||||||
onRemoveSelectedStateItem: PropTypes.func.isRequired,
|
onRemoveSelectedStateItem: PropTypes.func.isRequired,
|
||||||
onSeriesLookup: PropTypes.func.isRequired,
|
onSeriesLookup: PropTypes.func.isRequired,
|
||||||
onSetImportSeriesValue: PropTypes.func.isRequired,
|
onSetImportSeriesValue: PropTypes.func.isRequired
|
||||||
onScroll: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ImportSeriesTable;
|
export default ImportSeriesTable;
|
||||||
|
|
|
@ -37,6 +37,10 @@ class OverlayScroller extends Component {
|
||||||
|
|
||||||
_setScrollRef = (ref) => {
|
_setScrollRef = (ref) => {
|
||||||
this._scroller = ref;
|
this._scroller = ref;
|
||||||
|
|
||||||
|
if (ref) {
|
||||||
|
this.props.registerScroller(ref.view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderThumb = (props) => {
|
_renderThumb = (props) => {
|
||||||
|
@ -157,7 +161,8 @@ OverlayScroller.propTypes = {
|
||||||
autoHide: PropTypes.bool.isRequired,
|
autoHide: PropTypes.bool.isRequired,
|
||||||
autoScroll: PropTypes.bool.isRequired,
|
autoScroll: PropTypes.bool.isRequired,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
onScroll: PropTypes.func
|
onScroll: PropTypes.func,
|
||||||
|
registerScroller: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
OverlayScroller.defaultProps = {
|
OverlayScroller.defaultProps = {
|
||||||
|
@ -165,7 +170,8 @@ OverlayScroller.defaultProps = {
|
||||||
trackClassName: styles.thumb,
|
trackClassName: styles.thumb,
|
||||||
scrollDirection: scrollDirections.VERTICAL,
|
scrollDirection: scrollDirections.VERTICAL,
|
||||||
autoHide: false,
|
autoHide: false,
|
||||||
autoScroll: true
|
autoScroll: true,
|
||||||
|
registerScroller: () => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default OverlayScroller;
|
export default OverlayScroller;
|
||||||
|
|
|
@ -30,6 +30,8 @@ class Scroller extends Component {
|
||||||
|
|
||||||
_setScrollerRef = (ref) => {
|
_setScrollerRef = (ref) => {
|
||||||
this._scroller = ref;
|
this._scroller = ref;
|
||||||
|
|
||||||
|
this.props.registerScroller(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -43,6 +45,7 @@ class Scroller extends Component {
|
||||||
children,
|
children,
|
||||||
scrollTop,
|
scrollTop,
|
||||||
onScroll,
|
onScroll,
|
||||||
|
registerScroller,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -70,12 +73,14 @@ Scroller.propTypes = {
|
||||||
autoScroll: PropTypes.bool.isRequired,
|
autoScroll: PropTypes.bool.isRequired,
|
||||||
scrollTop: PropTypes.number,
|
scrollTop: PropTypes.number,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
onScroll: PropTypes.func
|
onScroll: PropTypes.func,
|
||||||
|
registerScroller: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
Scroller.defaultProps = {
|
Scroller.defaultProps = {
|
||||||
scrollDirection: scrollDirections.VERTICAL,
|
scrollDirection: scrollDirections.VERTICAL,
|
||||||
autoScroll: true
|
autoScroll: true,
|
||||||
|
registerScroller: () => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Scroller;
|
export default Scroller;
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
.tableContainer {
|
.tableContainer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tableBodyContainer {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import { WindowScroller } from 'react-virtualized';
|
|
||||||
import { isLocked } from 'Utilities/scrollLock';
|
|
||||||
import { scrollDirections } from 'Helpers/Props';
|
import { scrollDirections } from 'Helpers/Props';
|
||||||
import Measure from 'Components/Measure';
|
import Measure from 'Components/Measure';
|
||||||
import Scroller from 'Components/Scroller/Scroller';
|
import Scroller from 'Components/Scroller/Scroller';
|
||||||
import VirtualTableBody from './VirtualTableBody';
|
import { WindowScroller, Grid } from 'react-virtualized';
|
||||||
|
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
||||||
import styles from './VirtualTable.css';
|
import styles from './VirtualTable.css';
|
||||||
|
|
||||||
const ROW_HEIGHT = 38;
|
const ROW_HEIGHT = 38;
|
||||||
|
@ -44,28 +42,37 @@ class VirtualTable extends Component {
|
||||||
width: 0
|
width: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
this._isInitialized = false;
|
this._grid = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
this._contentBodyNode = ReactDOM.findDOMNode(this.props.contentBody);
|
const {
|
||||||
}
|
items,
|
||||||
|
scrollIndex
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
componentDidUpdate(prevProps, preState) {
|
const {
|
||||||
const { scrollIndex, rowHeight } = this.props;
|
width
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
if (this._grid && (prevState.width !== width || hasDifferentItemsOrOrder(prevProps.items, items))) {
|
||||||
|
// recomputeGridSize also forces Grid to discard its cache of rendered cells
|
||||||
|
this._grid.recomputeGridSize();
|
||||||
|
}
|
||||||
|
|
||||||
if (scrollIndex != null && scrollIndex !== prevProps.scrollIndex) {
|
if (scrollIndex != null && scrollIndex !== prevProps.scrollIndex) {
|
||||||
const scrollTop = (scrollIndex + 1) * rowHeight + 20;
|
this._grid.scrollToCell({
|
||||||
|
rowIndex: scrollIndex,
|
||||||
this.props.onScroll({ scrollTop });
|
columnIndex: 0
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Control
|
// Control
|
||||||
|
|
||||||
rowGetter = ({ index }) => {
|
setGridRef = (ref) => {
|
||||||
return this.props.items[index];
|
this._grid = ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -77,36 +84,18 @@ class VirtualTable extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSectionRendered = () => {
|
|
||||||
if (!this._isInitialized && this._contentBodyNode) {
|
|
||||||
this.props.onRender();
|
|
||||||
this._isInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onScroll = (props) => {
|
|
||||||
if (isLocked()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { onScroll } = this.props;
|
|
||||||
|
|
||||||
onScroll(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
isSmallScreen,
|
||||||
className,
|
className,
|
||||||
items,
|
items,
|
||||||
isSmallScreen,
|
scroller,
|
||||||
header,
|
header,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
scrollTop,
|
|
||||||
rowRenderer,
|
rowRenderer,
|
||||||
onScroll,
|
|
||||||
...otherProps
|
...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -114,66 +103,89 @@ class VirtualTable extends Component {
|
||||||
width
|
width
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
|
const gridStyle = {
|
||||||
|
boxSizing: undefined,
|
||||||
|
direction: undefined,
|
||||||
|
height: undefined,
|
||||||
|
position: undefined,
|
||||||
|
willChange: undefined,
|
||||||
|
overflow: undefined,
|
||||||
|
width: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
const containerStyle = {
|
||||||
|
position: undefined
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Measure onMeasure={this.onMeasure}>
|
<WindowScroller
|
||||||
<WindowScroller
|
scrollElement={isSmallScreen ? undefined : scroller}
|
||||||
scrollElement={isSmallScreen ? undefined : this._contentBodyNode}
|
>
|
||||||
onScroll={this.onScroll}
|
{({ height, registerChild, onChildScroll, scrollTop }) => {
|
||||||
>
|
if (!height) {
|
||||||
{({ height, isScrolling }) => {
|
return null;
|
||||||
return (
|
}
|
||||||
|
return (
|
||||||
|
<Measure
|
||||||
|
whitelist={['width']}
|
||||||
|
onMeasure={this.onMeasure}
|
||||||
|
>
|
||||||
<Scroller
|
<Scroller
|
||||||
className={className}
|
className={className}
|
||||||
scrollDirection={scrollDirections.HORIZONTAL}
|
scrollDirection={scrollDirections.HORIZONTAL}
|
||||||
>
|
>
|
||||||
{header}
|
{header}
|
||||||
|
<div ref={registerChild}>
|
||||||
<VirtualTableBody
|
<Grid
|
||||||
autoContainerWidth={true}
|
ref={this.setGridRef}
|
||||||
width={width}
|
autoContainerWidth={true}
|
||||||
height={height}
|
autoHeight={true}
|
||||||
headerHeight={height - headerHeight}
|
autoWidth={true}
|
||||||
rowHeight={ROW_HEIGHT}
|
width={width}
|
||||||
rowCount={items.length}
|
height={height}
|
||||||
columnCount={1}
|
headerHeight={height - headerHeight}
|
||||||
scrollTop={scrollTop}
|
rowHeight={ROW_HEIGHT}
|
||||||
autoHeight={true}
|
rowCount={items.length}
|
||||||
overscanRowCount={2}
|
columnCount={1}
|
||||||
cellRenderer={rowRenderer}
|
columnWidth={width}
|
||||||
columnWidth={width}
|
scrollTop={scrollTop}
|
||||||
overscanIndicesGetter={overscanIndicesGetter}
|
onScroll={onChildScroll}
|
||||||
onSectionRendered={this.onSectionRendered}
|
overscanRowCount={2}
|
||||||
{...otherProps}
|
cellRenderer={rowRenderer}
|
||||||
/>
|
overscanIndicesGetter={overscanIndicesGetter}
|
||||||
|
scrollToAlignment={'start'}
|
||||||
|
isScrollingOptout={true}
|
||||||
|
className={styles.tableBodyContainer}
|
||||||
|
style={gridStyle}
|
||||||
|
containerStyle={containerStyle}
|
||||||
|
{...otherProps}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Scroller>
|
</Scroller>
|
||||||
);
|
</Measure>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
</WindowScroller>
|
}
|
||||||
</Measure>
|
</WindowScroller>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualTable.propTypes = {
|
VirtualTable.propTypes = {
|
||||||
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
className: PropTypes.string.isRequired,
|
className: PropTypes.string.isRequired,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
scrollTop: PropTypes.number.isRequired,
|
|
||||||
scrollIndex: PropTypes.number,
|
scrollIndex: PropTypes.number,
|
||||||
contentBody: PropTypes.object.isRequired,
|
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
|
||||||
header: PropTypes.node.isRequired,
|
header: PropTypes.node.isRequired,
|
||||||
headerHeight: PropTypes.number.isRequired,
|
headerHeight: PropTypes.number.isRequired,
|
||||||
rowRenderer: PropTypes.func.isRequired,
|
rowRenderer: PropTypes.func.isRequired,
|
||||||
rowHeight: PropTypes.number.isRequired,
|
rowHeight: PropTypes.number.isRequired
|
||||||
onRender: PropTypes.func.isRequired,
|
|
||||||
onScroll: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VirtualTable.defaultProps = {
|
VirtualTable.defaultProps = {
|
||||||
className: styles.tableContainer,
|
className: styles.tableContainer,
|
||||||
headerHeight: 38,
|
headerHeight: 38
|
||||||
onRender: () => {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default VirtualTable;
|
export default VirtualTable;
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
.tableBodyContainer {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { Grid } from 'react-virtualized';
|
|
||||||
import styles from './VirtualTableBody.css';
|
|
||||||
|
|
||||||
class VirtualTableBody extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Grid
|
|
||||||
{...this.props}
|
|
||||||
style={{
|
|
||||||
boxSizing: undefined,
|
|
||||||
direction: undefined,
|
|
||||||
height: undefined,
|
|
||||||
position: undefined,
|
|
||||||
willChange: undefined,
|
|
||||||
overflow: undefined,
|
|
||||||
width: undefined
|
|
||||||
}}
|
|
||||||
containerStyle={{
|
|
||||||
position: undefined
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualTableBody.propTypes = {
|
|
||||||
className: PropTypes.string.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
VirtualTableBody.defaultProps = {
|
|
||||||
className: styles.tableBodyContainer
|
|
||||||
};
|
|
||||||
|
|
||||||
export default VirtualTableBody;
|
|
|
@ -1,12 +1,9 @@
|
||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import { Grid, WindowScroller } from 'react-virtualized';
|
import { Grid, WindowScroller } from 'react-virtualized';
|
||||||
import getIndexOfFirstCharacter from 'Utilities/Array/getIndexOfFirstCharacter';
|
import getIndexOfFirstCharacter from 'Utilities/Array/getIndexOfFirstCharacter';
|
||||||
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
||||||
import dimensions from 'Styles/Variables/dimensions';
|
import dimensions from 'Styles/Variables/dimensions';
|
||||||
import { sortDirections } from 'Helpers/Props';
|
|
||||||
import Measure from 'Components/Measure';
|
import Measure from 'Components/Measure';
|
||||||
import SeriesIndexItemConnector from 'Series/Index/SeriesIndexItemConnector';
|
import SeriesIndexItemConnector from 'Series/Index/SeriesIndexItemConnector';
|
||||||
import SeriesIndexOverview from './SeriesIndexOverview';
|
import SeriesIndexOverview from './SeriesIndexOverview';
|
||||||
|
@ -66,56 +63,44 @@ class SeriesIndexOverviews extends Component {
|
||||||
rowHeight: calculateRowHeight(238, null, props.isSmallScreen, {})
|
rowHeight: calculateRowHeight(238, null, props.isSmallScreen, {})
|
||||||
};
|
};
|
||||||
|
|
||||||
this._isInitialized = false;
|
|
||||||
this._grid = null;
|
this._grid = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
this._contentBodyNode = ReactDOM.findDOMNode(this.props.contentBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
filters,
|
|
||||||
sortKey,
|
sortKey,
|
||||||
sortDirection,
|
|
||||||
overviewOptions,
|
overviewOptions,
|
||||||
jumpToCharacter
|
jumpToCharacter
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const itemsChanged = hasDifferentItemsOrOrder(prevProps.items, items);
|
const {
|
||||||
const overviewOptionsChanged = !_.isMatch(prevProps.overviewOptions, overviewOptions);
|
width,
|
||||||
|
rowHeight
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
if (
|
if (prevProps.sortKey !== sortKey ||
|
||||||
prevProps.sortKey !== sortKey ||
|
prevProps.overviewOptions !== overviewOptions) {
|
||||||
prevProps.overviewOptions !== overviewOptions ||
|
|
||||||
itemsChanged
|
|
||||||
) {
|
|
||||||
this.calculateGrid();
|
this.calculateGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (this._grid &&
|
||||||
prevProps.filters !== filters ||
|
(prevState.width !== width ||
|
||||||
prevProps.sortKey !== sortKey ||
|
prevState.rowHeight !== rowHeight ||
|
||||||
prevProps.sortDirection !== sortDirection ||
|
hasDifferentItemsOrOrder(prevProps.items, items))) {
|
||||||
itemsChanged ||
|
// recomputeGridSize also forces Grid to discard its cache of rendered cells
|
||||||
overviewOptionsChanged
|
|
||||||
) {
|
|
||||||
this._grid.recomputeGridSize();
|
this._grid.recomputeGridSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jumpToCharacter != null && jumpToCharacter !== prevProps.jumpToCharacter) {
|
if (jumpToCharacter != null && jumpToCharacter !== prevProps.jumpToCharacter) {
|
||||||
const index = getIndexOfFirstCharacter(items, jumpToCharacter);
|
const index = getIndexOfFirstCharacter(items, jumpToCharacter);
|
||||||
|
|
||||||
if (index != null) {
|
if (this._grid && index != null) {
|
||||||
const {
|
|
||||||
rowHeight
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const scrollTop = rowHeight * index;
|
this._grid.scrollToCell({
|
||||||
|
rowIndex: index,
|
||||||
this.props.onScroll({ scrollTop });
|
columnIndex: 0
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,21 +108,6 @@ class SeriesIndexOverviews extends Component {
|
||||||
//
|
//
|
||||||
// Control
|
// Control
|
||||||
|
|
||||||
scrollToFirstCharacter(character) {
|
|
||||||
const items = this.props.items;
|
|
||||||
const {
|
|
||||||
rowHeight
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const index = getIndexOfFirstCharacter(items, character);
|
|
||||||
|
|
||||||
if (index != null) {
|
|
||||||
const scrollTop = rowHeight * index;
|
|
||||||
|
|
||||||
this.props.onScroll({ scrollTop });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setGridRef = (ref) => {
|
setGridRef = (ref) => {
|
||||||
this._grid = ref;
|
this._grid = ref;
|
||||||
}
|
}
|
||||||
|
@ -219,22 +189,14 @@ class SeriesIndexOverviews extends Component {
|
||||||
this.calculateGrid(width, this.props.isSmallScreen);
|
this.calculateGrid(width, this.props.isSmallScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSectionRendered = () => {
|
|
||||||
if (!this._isInitialized && this._contentBodyNode) {
|
|
||||||
this.props.onRender();
|
|
||||||
this._isInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
scroller,
|
||||||
items,
|
items,
|
||||||
scrollTop,
|
isSmallScreen
|
||||||
isSmallScreen,
|
|
||||||
onScroll
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -243,29 +205,38 @@ class SeriesIndexOverviews extends Component {
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Measure onMeasure={this.onMeasure}>
|
<Measure
|
||||||
|
whitelist={['width']}
|
||||||
|
onMeasure={this.onMeasure}
|
||||||
|
>
|
||||||
<WindowScroller
|
<WindowScroller
|
||||||
scrollElement={isSmallScreen ? undefined : this._contentBodyNode}
|
scrollElement={isSmallScreen ? undefined : scroller}
|
||||||
onScroll={onScroll}
|
|
||||||
>
|
>
|
||||||
{({ height, isScrolling }) => {
|
{({ height, registerChild, onChildScroll, scrollTop }) => {
|
||||||
|
if (!height) {
|
||||||
|
return <div />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid
|
<div ref={registerChild}>
|
||||||
ref={this.setGridRef}
|
<Grid
|
||||||
className={styles.grid}
|
ref={this.setGridRef}
|
||||||
autoHeight={true}
|
className={styles.grid}
|
||||||
height={height}
|
autoHeight={true}
|
||||||
columnCount={1}
|
height={height}
|
||||||
columnWidth={width}
|
columnCount={1}
|
||||||
rowCount={items.length}
|
columnWidth={width}
|
||||||
rowHeight={rowHeight}
|
rowCount={items.length}
|
||||||
width={width}
|
rowHeight={rowHeight}
|
||||||
scrollTop={scrollTop}
|
width={width}
|
||||||
overscanRowCount={2}
|
onScroll={onChildScroll}
|
||||||
cellRenderer={this.cellRenderer}
|
scrollTop={scrollTop}
|
||||||
onSectionRendered={this.onSectionRendered}
|
overscanRowCount={2}
|
||||||
isScrollingOptOut={true}
|
cellRenderer={this.cellRenderer}
|
||||||
/>
|
scrollToAlignment={'start'}
|
||||||
|
isScrollingOptOut={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,20 +248,15 @@ class SeriesIndexOverviews extends Component {
|
||||||
|
|
||||||
SeriesIndexOverviews.propTypes = {
|
SeriesIndexOverviews.propTypes = {
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
sortKey: PropTypes.string,
|
sortKey: PropTypes.string,
|
||||||
sortDirection: PropTypes.oneOf(sortDirections.all),
|
|
||||||
overviewOptions: PropTypes.object.isRequired,
|
overviewOptions: PropTypes.object.isRequired,
|
||||||
scrollTop: PropTypes.number.isRequired,
|
|
||||||
jumpToCharacter: PropTypes.string,
|
jumpToCharacter: PropTypes.string,
|
||||||
contentBody: PropTypes.object.isRequired,
|
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||||
showRelativeDates: PropTypes.bool.isRequired,
|
showRelativeDates: PropTypes.bool.isRequired,
|
||||||
shortDateFormat: PropTypes.string.isRequired,
|
shortDateFormat: PropTypes.string.isRequired,
|
||||||
longDateFormat: PropTypes.string.isRequired,
|
longDateFormat: PropTypes.string.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
timeFormat: PropTypes.string.isRequired,
|
timeFormat: PropTypes.string.isRequired
|
||||||
onRender: PropTypes.func.isRequired,
|
|
||||||
onScroll: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SeriesIndexOverviews;
|
export default SeriesIndexOverviews;
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import { Grid, WindowScroller } from 'react-virtualized';
|
import { Grid, WindowScroller } from 'react-virtualized';
|
||||||
import getIndexOfFirstCharacter from 'Utilities/Array/getIndexOfFirstCharacter';
|
import getIndexOfFirstCharacter from 'Utilities/Array/getIndexOfFirstCharacter';
|
||||||
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
||||||
import dimensions from 'Styles/Variables/dimensions';
|
import dimensions from 'Styles/Variables/dimensions';
|
||||||
import { sortDirections } from 'Helpers/Props';
|
|
||||||
import Measure from 'Components/Measure';
|
import Measure from 'Components/Measure';
|
||||||
import SeriesIndexItemConnector from 'Series/Index/SeriesIndexItemConnector';
|
import SeriesIndexItemConnector from 'Series/Index/SeriesIndexItemConnector';
|
||||||
import SeriesIndexPoster from './SeriesIndexPoster';
|
import SeriesIndexPoster from './SeriesIndexPoster';
|
||||||
|
@ -110,52 +108,46 @@ class SeriesIndexPosters extends Component {
|
||||||
this._grid = null;
|
this._grid = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
this._contentBodyNode = ReactDOM.findDOMNode(this.props.contentBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
filters,
|
|
||||||
sortKey,
|
sortKey,
|
||||||
sortDirection,
|
|
||||||
posterOptions,
|
posterOptions,
|
||||||
jumpToCharacter
|
jumpToCharacter
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const itemsChanged = hasDifferentItemsOrOrder(prevProps.items, items);
|
const {
|
||||||
|
width,
|
||||||
|
columnWidth,
|
||||||
|
columnCount,
|
||||||
|
rowHeight
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
if (
|
if (prevProps.sortKey !== sortKey ||
|
||||||
prevProps.sortKey !== sortKey ||
|
prevProps.posterOptions !== posterOptions) {
|
||||||
prevProps.posterOptions !== posterOptions ||
|
|
||||||
itemsChanged
|
|
||||||
) {
|
|
||||||
this.calculateGrid();
|
this.calculateGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (this._grid &&
|
||||||
prevProps.filters !== filters ||
|
(prevState.width !== width ||
|
||||||
prevProps.sortKey !== sortKey ||
|
prevState.columnWidth !== columnWidth ||
|
||||||
prevProps.sortDirection !== sortDirection ||
|
prevState.columnCount !== columnCount ||
|
||||||
itemsChanged
|
prevState.rowHeight !== rowHeight ||
|
||||||
) {
|
hasDifferentItemsOrOrder(prevProps.items, items))) {
|
||||||
|
// recomputeGridSize also forces Grid to discard its cache of rendered cells
|
||||||
this._grid.recomputeGridSize();
|
this._grid.recomputeGridSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jumpToCharacter != null && jumpToCharacter !== prevProps.jumpToCharacter) {
|
if (jumpToCharacter != null && jumpToCharacter !== prevProps.jumpToCharacter) {
|
||||||
const index = getIndexOfFirstCharacter(items, jumpToCharacter);
|
const index = getIndexOfFirstCharacter(items, jumpToCharacter);
|
||||||
|
|
||||||
if (index != null) {
|
if (this._grid && index != null) {
|
||||||
const {
|
|
||||||
columnCount,
|
|
||||||
rowHeight
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const row = Math.floor(index / columnCount);
|
const row = Math.floor(index / columnCount);
|
||||||
const scrollTop = rowHeight * row;
|
|
||||||
|
|
||||||
this.props.onScroll({ scrollTop });
|
this._grid.scrollToCell({
|
||||||
|
rowIndex: row,
|
||||||
|
columnIndex: 0
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,22 +246,14 @@ class SeriesIndexPosters extends Component {
|
||||||
this.calculateGrid(width, this.props.isSmallScreen);
|
this.calculateGrid(width, this.props.isSmallScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSectionRendered = () => {
|
|
||||||
if (!this._isInitialized && this._contentBodyNode) {
|
|
||||||
this.props.onRender();
|
|
||||||
this._isInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
scroller,
|
||||||
items,
|
items,
|
||||||
scrollTop,
|
isSmallScreen
|
||||||
isSmallScreen,
|
|
||||||
onScroll
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -282,29 +266,38 @@ class SeriesIndexPosters extends Component {
|
||||||
const rowCount = Math.ceil(items.length / columnCount);
|
const rowCount = Math.ceil(items.length / columnCount);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Measure onMeasure={this.onMeasure}>
|
<Measure
|
||||||
|
whitelist={['width']}
|
||||||
|
onMeasure={this.onMeasure}
|
||||||
|
>
|
||||||
<WindowScroller
|
<WindowScroller
|
||||||
scrollElement={isSmallScreen ? undefined : this._contentBodyNode}
|
scrollElement={isSmallScreen ? undefined : scroller}
|
||||||
onScroll={onScroll}
|
|
||||||
>
|
>
|
||||||
{({ height, isScrolling }) => {
|
{({ height, registerChild, onChildScroll, scrollTop }) => {
|
||||||
|
if (!height) {
|
||||||
|
return <div />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid
|
<div ref={registerChild}>
|
||||||
ref={this.setGridRef}
|
<Grid
|
||||||
className={styles.grid}
|
ref={this.setGridRef}
|
||||||
autoHeight={true}
|
className={styles.grid}
|
||||||
height={height}
|
autoHeight={true}
|
||||||
columnCount={columnCount}
|
height={height}
|
||||||
columnWidth={columnWidth}
|
columnCount={columnCount}
|
||||||
rowCount={rowCount}
|
columnWidth={columnWidth}
|
||||||
rowHeight={rowHeight}
|
rowCount={rowCount}
|
||||||
width={width}
|
rowHeight={rowHeight}
|
||||||
scrollTop={scrollTop}
|
width={width}
|
||||||
overscanRowCount={2}
|
onScroll={onChildScroll}
|
||||||
cellRenderer={this.cellRenderer}
|
scrollTop={scrollTop}
|
||||||
onSectionRendered={this.onSectionRendered}
|
overscanRowCount={2}
|
||||||
isScrollingOptOut={true}
|
cellRenderer={this.cellRenderer}
|
||||||
/>
|
scrollToAlignment={'start'}
|
||||||
|
isScrollingOptOut={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,19 +309,14 @@ class SeriesIndexPosters extends Component {
|
||||||
|
|
||||||
SeriesIndexPosters.propTypes = {
|
SeriesIndexPosters.propTypes = {
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
sortKey: PropTypes.string,
|
sortKey: PropTypes.string,
|
||||||
sortDirection: PropTypes.oneOf(sortDirections.all),
|
|
||||||
posterOptions: PropTypes.object.isRequired,
|
posterOptions: PropTypes.object.isRequired,
|
||||||
scrollTop: PropTypes.number.isRequired,
|
|
||||||
jumpToCharacter: PropTypes.string,
|
jumpToCharacter: PropTypes.string,
|
||||||
contentBody: PropTypes.object.isRequired,
|
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||||
showRelativeDates: PropTypes.bool.isRequired,
|
showRelativeDates: PropTypes.bool.isRequired,
|
||||||
shortDateFormat: PropTypes.string.isRequired,
|
shortDateFormat: PropTypes.string.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
timeFormat: PropTypes.string.isRequired,
|
timeFormat: PropTypes.string.isRequired
|
||||||
onRender: PropTypes.func.isRequired,
|
|
||||||
onScroll: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SeriesIndexPosters;
|
export default SeriesIndexPosters;
|
||||||
|
|
|
@ -46,12 +46,11 @@ class SeriesIndex extends Component {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
contentBody: null,
|
scroller: null,
|
||||||
jumpBarItems: { order: [] },
|
jumpBarItems: { order: [] },
|
||||||
jumpToCharacter: null,
|
jumpToCharacter: null,
|
||||||
isPosterOptionsModalOpen: false,
|
isPosterOptionsModalOpen: false,
|
||||||
isOverviewOptionsModalOpen: false,
|
isOverviewOptionsModalOpen: false
|
||||||
isRendered: false
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +62,7 @@ class SeriesIndex extends Component {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
sortKey,
|
sortKey,
|
||||||
sortDirection,
|
sortDirection
|
||||||
scrollTop
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (sortKey !== prevProps.sortKey ||
|
if (sortKey !== prevProps.sortKey ||
|
||||||
|
@ -74,7 +72,7 @@ class SeriesIndex extends Component {
|
||||||
this.setJumpBarItems();
|
this.setJumpBarItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.jumpToCharacter != null && scrollTop !== prevProps.scrollTop) {
|
if (this.state.jumpToCharacter != null) {
|
||||||
this.setState({ jumpToCharacter: null });
|
this.setState({ jumpToCharacter: null });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,8 +80,8 @@ class SeriesIndex extends Component {
|
||||||
//
|
//
|
||||||
// Control
|
// Control
|
||||||
|
|
||||||
setContentBodyRef = (ref) => {
|
setScrollerRef = (ref) => {
|
||||||
this.setState({ contentBody: ref });
|
this.setState({ scroller: ref });
|
||||||
}
|
}
|
||||||
|
|
||||||
setJumpBarItems() {
|
setJumpBarItems() {
|
||||||
|
@ -153,27 +151,6 @@ class SeriesIndex extends Component {
|
||||||
this.setState({ jumpToCharacter });
|
this.setState({ jumpToCharacter });
|
||||||
}
|
}
|
||||||
|
|
||||||
onRender = () => {
|
|
||||||
this.setState({ isRendered: true }, () => {
|
|
||||||
const {
|
|
||||||
scrollTop,
|
|
||||||
isSmallScreen
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if (isSmallScreen) {
|
|
||||||
// Seems to result in the view being off by 125px (distance to the top of the page)
|
|
||||||
// document.documentElement.scrollTop = document.body.scrollTop = scrollTop;
|
|
||||||
|
|
||||||
// This works, but then jumps another 1px after scrolling
|
|
||||||
document.documentElement.scrollTop = scrollTop;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onScroll = ({ scrollTop }) => {
|
|
||||||
this.props.onScroll({ scrollTop });
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
|
|
||||||
|
@ -193,7 +170,7 @@ class SeriesIndex extends Component {
|
||||||
view,
|
view,
|
||||||
isRefreshingSeries,
|
isRefreshingSeries,
|
||||||
isRssSyncExecuting,
|
isRssSyncExecuting,
|
||||||
scrollTop,
|
onScroll,
|
||||||
onSortSelect,
|
onSortSelect,
|
||||||
onFilterSelect,
|
onFilterSelect,
|
||||||
onViewSelect,
|
onViewSelect,
|
||||||
|
@ -203,16 +180,15 @@ class SeriesIndex extends Component {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
contentBody,
|
scroller,
|
||||||
jumpBarItems,
|
jumpBarItems,
|
||||||
jumpToCharacter,
|
jumpToCharacter,
|
||||||
isPosterOptionsModalOpen,
|
isPosterOptionsModalOpen,
|
||||||
isOverviewOptionsModalOpen,
|
isOverviewOptionsModalOpen
|
||||||
isRendered
|
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const ViewComponent = getViewComponent(view);
|
const ViewComponent = getViewComponent(view);
|
||||||
const isLoaded = !!(!error && isPopulated && items.length && contentBody);
|
const isLoaded = !!(!error && isPopulated && items.length && scroller);
|
||||||
const hasNoSeries = !totalItems;
|
const hasNoSeries = !totalItems;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -309,11 +285,10 @@ class SeriesIndex extends Component {
|
||||||
|
|
||||||
<div className={styles.pageContentBodyWrapper}>
|
<div className={styles.pageContentBodyWrapper}>
|
||||||
<PageContentBodyConnector
|
<PageContentBodyConnector
|
||||||
ref={this.setContentBodyRef}
|
registerScroller={this.setScrollerRef}
|
||||||
className={styles.contentBody}
|
className={styles.contentBody}
|
||||||
innerClassName={styles[`${view}InnerContentBody`]}
|
innerClassName={styles[`${view}InnerContentBody`]}
|
||||||
scrollTop={isRendered ? scrollTop : 0}
|
onScroll={onScroll}
|
||||||
onScroll={this.onScroll}
|
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
isFetching && !isPopulated &&
|
isFetching && !isPopulated &&
|
||||||
|
@ -329,14 +304,12 @@ class SeriesIndex extends Component {
|
||||||
isLoaded &&
|
isLoaded &&
|
||||||
<div className={styles.contentBodyContainer}>
|
<div className={styles.contentBodyContainer}>
|
||||||
<ViewComponent
|
<ViewComponent
|
||||||
contentBody={contentBody}
|
scroller={scroller}
|
||||||
items={items}
|
items={items}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
sortKey={sortKey}
|
sortKey={sortKey}
|
||||||
sortDirection={sortDirection}
|
sortDirection={sortDirection}
|
||||||
scrollTop={scrollTop}
|
|
||||||
jumpToCharacter={jumpToCharacter}
|
jumpToCharacter={jumpToCharacter}
|
||||||
onRender={this.onRender}
|
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -388,7 +361,6 @@ SeriesIndex.propTypes = {
|
||||||
view: PropTypes.string.isRequired,
|
view: PropTypes.string.isRequired,
|
||||||
isRefreshingSeries: PropTypes.bool.isRequired,
|
isRefreshingSeries: PropTypes.bool.isRequired,
|
||||||
isRssSyncExecuting: PropTypes.bool.isRequired,
|
isRssSyncExecuting: PropTypes.bool.isRequired,
|
||||||
scrollTop: PropTypes.number.isRequired,
|
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
onSortSelect: PropTypes.func.isRequired,
|
onSortSelect: PropTypes.func.isRequired,
|
||||||
onFilterSelect: PropTypes.func.isRequired,
|
onFilterSelect: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -3,7 +3,6 @@ import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createSeriesClientSideCollectionItemsSelector from 'Store/Selectors/createSeriesClientSideCollectionItemsSelector';
|
import createSeriesClientSideCollectionItemsSelector from 'Store/Selectors/createSeriesClientSideCollectionItemsSelector';
|
||||||
import dimensions from 'Styles/Variables/dimensions';
|
|
||||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||||
import scrollPositions from 'Store/scrollPositions';
|
import scrollPositions from 'Store/scrollPositions';
|
||||||
|
@ -13,29 +12,6 @@ import * as commandNames from 'Commands/commandNames';
|
||||||
import withScrollPosition from 'Components/withScrollPosition';
|
import withScrollPosition from 'Components/withScrollPosition';
|
||||||
import SeriesIndex from './SeriesIndex';
|
import SeriesIndex from './SeriesIndex';
|
||||||
|
|
||||||
const POSTERS_PADDING = 15;
|
|
||||||
const POSTERS_PADDING_SMALL_SCREEN = 5;
|
|
||||||
const TABLE_PADDING = parseInt(dimensions.pageContentBodyPadding);
|
|
||||||
const TABLE_PADDING_SMALL_SCREEN = parseInt(dimensions.pageContentBodyPaddingSmallScreen);
|
|
||||||
|
|
||||||
// If the scrollTop is greater than zero it needs to be offset
|
|
||||||
// by the padding so when it is set initially so it is correct
|
|
||||||
// after React Virtualized takes the padding into account.
|
|
||||||
|
|
||||||
function getScrollTop(view, scrollTop, isSmallScreen) {
|
|
||||||
if (scrollTop === 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let padding = isSmallScreen ? TABLE_PADDING_SMALL_SCREEN : TABLE_PADDING;
|
|
||||||
|
|
||||||
if (view === 'posters') {
|
|
||||||
padding = isSmallScreen ? POSTERS_PADDING_SMALL_SCREEN : POSTERS_PADDING;
|
|
||||||
}
|
|
||||||
|
|
||||||
return scrollTop + padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createSeriesClientSideCollectionItemsSelector('seriesIndex'),
|
createSeriesClientSideCollectionItemsSelector('seriesIndex'),
|
||||||
|
@ -92,39 +68,15 @@ function createMapDispatchToProps(dispatch, props) {
|
||||||
|
|
||||||
class SeriesIndexConnector extends Component {
|
class SeriesIndexConnector extends Component {
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
const {
|
|
||||||
view,
|
|
||||||
scrollTop,
|
|
||||||
isSmallScreen
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
scrollTop: getScrollTop(view, scrollTop, isSmallScreen)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onViewSelect = (view) => {
|
onViewSelect = (view) => {
|
||||||
// Reset the scroll position before changing the view
|
this.props.dispatchSetSeriesView(view);
|
||||||
this.setState({ scrollTop: 0 }, () => {
|
|
||||||
this.props.dispatchSetSeriesView(view);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onScroll = ({ scrollTop }) => {
|
onScroll = ({ scrollTop }) => {
|
||||||
this.setState({
|
scrollPositions.seriesIndex = scrollTop;
|
||||||
scrollTop
|
|
||||||
}, () => {
|
|
||||||
scrollPositions.seriesIndex = scrollTop;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -134,7 +86,6 @@ class SeriesIndexConnector extends Component {
|
||||||
return (
|
return (
|
||||||
<SeriesIndex
|
<SeriesIndex
|
||||||
{...this.props}
|
{...this.props}
|
||||||
scrollTop={this.state.scrollTop}
|
|
||||||
onViewSelect={this.onViewSelect}
|
onViewSelect={this.onViewSelect}
|
||||||
onScroll={this.onScroll}
|
onScroll={this.onScroll}
|
||||||
/>
|
/>
|
||||||
|
@ -145,7 +96,6 @@ class SeriesIndexConnector extends Component {
|
||||||
SeriesIndexConnector.propTypes = {
|
SeriesIndexConnector.propTypes = {
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
view: PropTypes.string.isRequired,
|
view: PropTypes.string.isRequired,
|
||||||
scrollTop: PropTypes.number.isRequired,
|
|
||||||
dispatchSetSeriesView: PropTypes.func.isRequired
|
dispatchSetSeriesView: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,12 @@ class SeriesIndexTable extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const jumpToCharacter = this.props.jumpToCharacter;
|
const {
|
||||||
|
items,
|
||||||
|
jumpToCharacter
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if (jumpToCharacter != null && jumpToCharacter !== prevProps.jumpToCharacter) {
|
if (jumpToCharacter != null && jumpToCharacter !== prevProps.jumpToCharacter) {
|
||||||
const items = this.props.items;
|
|
||||||
|
|
||||||
const scrollIndex = getIndexOfFirstCharacter(items, jumpToCharacter);
|
const scrollIndex = getIndexOfFirstCharacter(items, jumpToCharacter);
|
||||||
|
|
||||||
|
@ -75,25 +77,20 @@ class SeriesIndexTable extends Component {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
columns,
|
columns,
|
||||||
filters,
|
|
||||||
sortKey,
|
sortKey,
|
||||||
sortDirection,
|
sortDirection,
|
||||||
showBanners,
|
showBanners,
|
||||||
isSmallScreen,
|
isSmallScreen,
|
||||||
scrollTop,
|
|
||||||
contentBody,
|
|
||||||
onSortPress,
|
onSortPress,
|
||||||
onRender,
|
scroller
|
||||||
onScroll
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VirtualTable
|
<VirtualTable
|
||||||
className={styles.tableContainer}
|
className={styles.tableContainer}
|
||||||
items={items}
|
items={items}
|
||||||
scrollTop={scrollTop}
|
|
||||||
scrollIndex={this.state.scrollIndex}
|
scrollIndex={this.state.scrollIndex}
|
||||||
contentBody={contentBody}
|
scroller={scroller}
|
||||||
isSmallScreen={isSmallScreen}
|
isSmallScreen={isSmallScreen}
|
||||||
rowHeight={showBanners ? 70 : 38}
|
rowHeight={showBanners ? 70 : 38}
|
||||||
overscanRowCount={2}
|
overscanRowCount={2}
|
||||||
|
@ -108,12 +105,6 @@ class SeriesIndexTable extends Component {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
filters={filters}
|
|
||||||
sortKey={sortKey}
|
|
||||||
sortDirection={sortDirection}
|
|
||||||
onRender={onRender}
|
|
||||||
onScroll={onScroll}
|
|
||||||
isScrollingOptOut={true}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -122,17 +113,13 @@ class SeriesIndexTable extends Component {
|
||||||
SeriesIndexTable.propTypes = {
|
SeriesIndexTable.propTypes = {
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
sortKey: PropTypes.string,
|
sortKey: PropTypes.string,
|
||||||
sortDirection: PropTypes.oneOf(sortDirections.all),
|
sortDirection: PropTypes.oneOf(sortDirections.all),
|
||||||
showBanners: PropTypes.bool.isRequired,
|
showBanners: PropTypes.bool.isRequired,
|
||||||
scrollTop: PropTypes.number.isRequired,
|
|
||||||
jumpToCharacter: PropTypes.string,
|
jumpToCharacter: PropTypes.string,
|
||||||
contentBody: PropTypes.object.isRequired,
|
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
onSortPress: PropTypes.func.isRequired,
|
onSortPress: PropTypes.func.isRequired
|
||||||
onRender: PropTypes.func.isRequired,
|
|
||||||
onScroll: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SeriesIndexTable;
|
export default SeriesIndexTable;
|
||||||
|
|
Loading…
Reference in New Issue