mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-19 21:13:28 -07:00
Fixed: Rework Artist Index and VirtualTable
This commit is contained in:
parent
4036b2ade2
commit
9902434057
17 changed files with 315 additions and 503 deletions
|
@ -22,16 +22,15 @@ class ImportArtist extends Component {
|
||||||
allUnselected: false,
|
allUnselected: false,
|
||||||
lastToggled: null,
|
lastToggled: null,
|
||||||
selectedState: {},
|
selectedState: {},
|
||||||
contentBody: null,
|
scroller: null
|
||||||
scrollTop: 0
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Control
|
// Control
|
||||||
|
|
||||||
setContentBodyRef = (ref) => {
|
setScrollerRef = (ref) => {
|
||||||
this.setState({ contentBody: ref });
|
this.setState({ scroller: ref });
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -72,10 +71,6 @@ class ImportArtist extends Component {
|
||||||
this.props.onImportPress(this.getSelectedIds());
|
this.props.onImportPress(this.getSelectedIds());
|
||||||
}
|
}
|
||||||
|
|
||||||
onScroll = ({ scrollTop }) => {
|
|
||||||
this.setState({ scrollTop });
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
|
|
||||||
|
@ -94,13 +89,13 @@ class ImportArtist extends Component {
|
||||||
allSelected,
|
allSelected,
|
||||||
allUnselected,
|
allUnselected,
|
||||||
selectedState,
|
selectedState,
|
||||||
contentBody
|
scroller
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent title="Import Artist">
|
<PageContent title="Import Artist">
|
||||||
<PageContentBodyConnector
|
<PageContentBodyConnector
|
||||||
ref={this.setContentBodyRef}
|
registerScroller={this.setScrollerRef}
|
||||||
onScroll={this.onScroll}
|
onScroll={this.onScroll}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
|
@ -121,20 +116,18 @@ class ImportArtist extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
!rootFoldersError && rootFoldersPopulated && !!unmappedFolders.length && contentBody &&
|
!rootFoldersError && rootFoldersPopulated && !!unmappedFolders.length && scroller &&
|
||||||
<ImportArtistTableConnector
|
<ImportArtistTableConnector
|
||||||
rootFolderId={rootFolderId}
|
rootFolderId={rootFolderId}
|
||||||
unmappedFolders={unmappedFolders}
|
unmappedFolders={unmappedFolders}
|
||||||
allSelected={allSelected}
|
allSelected={allSelected}
|
||||||
allUnselected={allUnselected}
|
allUnselected={allUnselected}
|
||||||
selectedState={selectedState}
|
selectedState={selectedState}
|
||||||
contentBody={contentBody}
|
scroller={scroller}
|
||||||
showMetadataProfile={showMetadataProfile}
|
showMetadataProfile={showMetadataProfile}
|
||||||
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 ImportArtistSelectArtistConnector from './SelectArtist/ImportArtistSelectArtistConnector';
|
import ImportArtistSelectArtistConnector from './SelectArtist/ImportArtistSelectArtistConnector';
|
||||||
|
@ -10,7 +9,6 @@ import styles from './ImportArtistRow.css';
|
||||||
|
|
||||||
function ImportArtistRow(props) {
|
function ImportArtistRow(props) {
|
||||||
const {
|
const {
|
||||||
style,
|
|
||||||
id,
|
id,
|
||||||
monitor,
|
monitor,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
|
@ -25,7 +23,7 @@ function ImportArtistRow(props) {
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VirtualTableRow style={style}>
|
<>
|
||||||
<VirtualTableSelectCell
|
<VirtualTableSelectCell
|
||||||
inputClassName={styles.selectInput}
|
inputClassName={styles.selectInput}
|
||||||
id={id}
|
id={id}
|
||||||
|
@ -82,12 +80,11 @@ function ImportArtistRow(props) {
|
||||||
isExistingArtist={isExistingArtist}
|
isExistingArtist={isExistingArtist}
|
||||||
/>
|
/>
|
||||||
</VirtualTableRowCell>
|
</VirtualTableRowCell>
|
||||||
</VirtualTableRow>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportArtistRow.propTypes = {
|
ImportArtistRow.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 ImportArtistHeader from './ImportArtistHeader';
|
import ImportArtistHeader from './ImportArtistHeader';
|
||||||
import ImportArtistRowConnector from './ImportArtistRowConnector';
|
import ImportArtistRowConnector from './ImportArtistRowConnector';
|
||||||
|
|
||||||
|
@ -110,15 +111,20 @@ class ImportArtistTable extends Component {
|
||||||
const item = items[rowIndex];
|
const item = items[rowIndex];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ImportArtistRowConnector
|
<VirtualTableRow
|
||||||
key={key}
|
key={key}
|
||||||
style={style}
|
style={style}
|
||||||
rootFolderId={rootFolderId}
|
>
|
||||||
showMetadataProfile={showMetadataProfile}
|
<ImportArtistRowConnector
|
||||||
isSelected={selectedState[item.id]}
|
key={item.id}
|
||||||
onSelectedChange={onSelectedChange}
|
style={style}
|
||||||
id={item.id}
|
rootFolderId={rootFolderId}
|
||||||
/>
|
showMetadataProfile={showMetadataProfile}
|
||||||
|
isSelected={selectedState[item.id]}
|
||||||
|
onSelectedChange={onSelectedChange}
|
||||||
|
id={item.id}
|
||||||
|
/>
|
||||||
|
</VirtualTableRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,12 +137,10 @@ class ImportArtistTable extends Component {
|
||||||
allSelected,
|
allSelected,
|
||||||
allUnselected,
|
allUnselected,
|
||||||
isSmallScreen,
|
isSmallScreen,
|
||||||
contentBody,
|
|
||||||
showMetadataProfile,
|
showMetadataProfile,
|
||||||
scrollTop,
|
scroller,
|
||||||
selectedState,
|
selectedState,
|
||||||
onSelectAllChange,
|
onSelectAllChange
|
||||||
onScroll
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!items.length) {
|
if (!items.length) {
|
||||||
|
@ -146,10 +150,9 @@ class ImportArtistTable extends Component {
|
||||||
return (
|
return (
|
||||||
<VirtualTable
|
<VirtualTable
|
||||||
items={items}
|
items={items}
|
||||||
contentBody={contentBody}
|
|
||||||
isSmallScreen={isSmallScreen}
|
isSmallScreen={isSmallScreen}
|
||||||
|
scroller={scroller}
|
||||||
rowHeight={52}
|
rowHeight={52}
|
||||||
scrollTop={scrollTop}
|
|
||||||
overscanRowCount={2}
|
overscanRowCount={2}
|
||||||
rowRenderer={this.rowRenderer}
|
rowRenderer={this.rowRenderer}
|
||||||
header={
|
header={
|
||||||
|
@ -161,7 +164,6 @@ class ImportArtistTable extends Component {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
selectedState={selectedState}
|
selectedState={selectedState}
|
||||||
onScroll={onScroll}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -180,15 +182,14 @@ ImportArtistTable.propTypes = {
|
||||||
selectedState: PropTypes.object.isRequired,
|
selectedState: PropTypes.object.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
allArtists: PropTypes.arrayOf(PropTypes.object),
|
allArtists: PropTypes.arrayOf(PropTypes.object),
|
||||||
contentBody: PropTypes.object.isRequired,
|
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||||
showMetadataProfile: PropTypes.bool.isRequired,
|
showMetadataProfile: PropTypes.bool.isRequired,
|
||||||
scrollTop: PropTypes.number.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,
|
||||||
onArtistLookup: PropTypes.func.isRequired,
|
onArtistLookup: PropTypes.func.isRequired,
|
||||||
onSetImportArtistValue: PropTypes.func.isRequired,
|
onSetImportArtistValue: PropTypes.func.isRequired
|
||||||
onScroll: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ImportArtistTable;
|
export default ImportArtistTable;
|
||||||
|
|
|
@ -53,13 +53,12 @@ class ArtistIndex 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,
|
||||||
isBannerOptionsModalOpen: false,
|
isBannerOptionsModalOpen: false,
|
||||||
isOverviewOptionsModalOpen: false,
|
isOverviewOptionsModalOpen: false
|
||||||
isRendered: false
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,8 +70,7 @@ class ArtistIndex extends Component {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
sortKey,
|
sortKey,
|
||||||
sortDirection,
|
sortDirection
|
||||||
scrollTop
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (sortKey !== prevProps.sortKey ||
|
if (sortKey !== prevProps.sortKey ||
|
||||||
|
@ -82,7 +80,7 @@ class ArtistIndex 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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,8 +88,8 @@ class ArtistIndex extends Component {
|
||||||
//
|
//
|
||||||
// Control
|
// Control
|
||||||
|
|
||||||
setContentBodyRef = (ref) => {
|
setScrollerRef = (ref) => {
|
||||||
this.setState({ contentBody: ref });
|
this.setState({ scroller: ref });
|
||||||
}
|
}
|
||||||
|
|
||||||
setJumpBarItems() {
|
setJumpBarItems() {
|
||||||
|
@ -169,27 +167,6 @@ class ArtistIndex 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
|
||||||
|
|
||||||
|
@ -209,7 +186,7 @@ class ArtistIndex extends Component {
|
||||||
view,
|
view,
|
||||||
isRefreshingArtist,
|
isRefreshingArtist,
|
||||||
isRssSyncExecuting,
|
isRssSyncExecuting,
|
||||||
scrollTop,
|
onScroll,
|
||||||
onSortSelect,
|
onSortSelect,
|
||||||
onFilterSelect,
|
onFilterSelect,
|
||||||
onViewSelect,
|
onViewSelect,
|
||||||
|
@ -219,17 +196,16 @@ class ArtistIndex extends Component {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
contentBody,
|
scroller,
|
||||||
jumpBarItems,
|
jumpBarItems,
|
||||||
jumpToCharacter,
|
jumpToCharacter,
|
||||||
isPosterOptionsModalOpen,
|
isPosterOptionsModalOpen,
|
||||||
isBannerOptionsModalOpen,
|
isBannerOptionsModalOpen,
|
||||||
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 hasNoArtist = !totalItems;
|
const hasNoArtist = !totalItems;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -338,11 +314,10 @@ class ArtistIndex 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 &&
|
||||||
|
@ -360,14 +335,12 @@ class ArtistIndex 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}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -426,7 +399,6 @@ ArtistIndex.propTypes = {
|
||||||
view: PropTypes.string.isRequired,
|
view: PropTypes.string.isRequired,
|
||||||
isRefreshingArtist: PropTypes.bool.isRequired,
|
isRefreshingArtist: 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,
|
||||||
|
|
|
@ -4,7 +4,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 createArtistClientSideCollectionItemsSelector from 'Store/Selectors/createArtistClientSideCollectionItemsSelector';
|
import createArtistClientSideCollectionItemsSelector from 'Store/Selectors/createArtistClientSideCollectionItemsSelector';
|
||||||
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';
|
||||||
|
@ -14,35 +13,6 @@ import * as commandNames from 'Commands/commandNames';
|
||||||
import withScrollPosition from 'Components/withScrollPosition';
|
import withScrollPosition from 'Components/withScrollPosition';
|
||||||
import ArtistIndex from './ArtistIndex';
|
import ArtistIndex from './ArtistIndex';
|
||||||
|
|
||||||
const POSTERS_PADDING = 15;
|
|
||||||
const POSTERS_PADDING_SMALL_SCREEN = 5;
|
|
||||||
const BANNERS_PADDING = 15;
|
|
||||||
const BANNERS_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view === 'banners') {
|
|
||||||
padding = isSmallScreen ? BANNERS_PADDING_SMALL_SCREEN : BANNERS_PADDING;
|
|
||||||
}
|
|
||||||
|
|
||||||
return scrollTop + padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistClientSideCollectionItemsSelector('artistIndex'),
|
createArtistClientSideCollectionItemsSelector('artistIndex'),
|
||||||
|
@ -99,39 +69,15 @@ function createMapDispatchToProps(dispatch, props) {
|
||||||
|
|
||||||
class ArtistIndexConnector extends Component {
|
class ArtistIndexConnector 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.dispatchSetArtistView(view);
|
||||||
this.setState({ scrollTop: 0 }, () => {
|
|
||||||
this.props.dispatchSetArtistView(view);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onScroll = ({ scrollTop }) => {
|
onScroll = ({ scrollTop }) => {
|
||||||
this.setState({
|
scrollPositions.artistIndex = scrollTop;
|
||||||
scrollTop
|
|
||||||
}, () => {
|
|
||||||
scrollPositions.artistIndex = scrollTop;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -141,7 +87,6 @@ class ArtistIndexConnector extends Component {
|
||||||
return (
|
return (
|
||||||
<ArtistIndex
|
<ArtistIndex
|
||||||
{...this.props}
|
{...this.props}
|
||||||
scrollTop={this.state.scrollTop}
|
|
||||||
onViewSelect={this.onViewSelect}
|
onViewSelect={this.onViewSelect}
|
||||||
onScroll={this.onScroll}
|
onScroll={this.onScroll}
|
||||||
/>
|
/>
|
||||||
|
@ -152,7 +97,6 @@ class ArtistIndexConnector extends Component {
|
||||||
ArtistIndexConnector.propTypes = {
|
ArtistIndexConnector.propTypes = {
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
view: PropTypes.string.isRequired,
|
view: PropTypes.string.isRequired,
|
||||||
scrollTop: PropTypes.number.isRequired,
|
|
||||||
dispatchSetArtistView: PropTypes.func.isRequired
|
dispatchSetArtistView: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 ArtistIndexItemConnector from 'Artist/Index/ArtistIndexItemConnector';
|
import ArtistIndexItemConnector from 'Artist/Index/ArtistIndexItemConnector';
|
||||||
import ArtistIndexBanner from './ArtistIndexBanner';
|
import ArtistIndexBanner from './ArtistIndexBanner';
|
||||||
|
@ -109,52 +107,46 @@ class ArtistIndexBanners 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,
|
|
||||||
bannerOptions,
|
bannerOptions,
|
||||||
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.bannerOptions !== bannerOptions) {
|
||||||
prevProps.bannerOptions !== bannerOptions ||
|
|
||||||
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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,22 +243,14 @@ class ArtistIndexBanners 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 {
|
||||||
items,
|
items,
|
||||||
scrollTop,
|
|
||||||
isSmallScreen,
|
isSmallScreen,
|
||||||
onScroll
|
scroller
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -279,12 +263,18 @@ class ArtistIndexBanners 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
|
<Grid
|
||||||
ref={this.setGridRef}
|
ref={this.setGridRef}
|
||||||
|
@ -296,10 +286,11 @@ class ArtistIndexBanners extends Component {
|
||||||
rowCount={rowCount}
|
rowCount={rowCount}
|
||||||
rowHeight={rowHeight}
|
rowHeight={rowHeight}
|
||||||
width={width}
|
width={width}
|
||||||
|
onScroll={onChildScroll}
|
||||||
scrollTop={scrollTop}
|
scrollTop={scrollTop}
|
||||||
overscanRowCount={2}
|
overscanRowCount={2}
|
||||||
cellRenderer={this.cellRenderer}
|
cellRenderer={this.cellRenderer}
|
||||||
onSectionRendered={this.onSectionRendered}
|
scrollToAlignment={'start'}
|
||||||
isScrollingOptOut={true}
|
isScrollingOptOut={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -313,19 +304,14 @@ class ArtistIndexBanners extends Component {
|
||||||
|
|
||||||
ArtistIndexBanners.propTypes = {
|
ArtistIndexBanners.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),
|
|
||||||
bannerOptions: PropTypes.object.isRequired,
|
bannerOptions: 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 ArtistIndexBanners;
|
export default ArtistIndexBanners;
|
||||||
|
|
|
@ -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 ArtistIndexItemConnector from 'Artist/Index/ArtistIndexItemConnector';
|
import ArtistIndexItemConnector from 'Artist/Index/ArtistIndexItemConnector';
|
||||||
import ArtistIndexOverview from './ArtistIndexOverview';
|
import ArtistIndexOverview from './ArtistIndexOverview';
|
||||||
|
@ -66,56 +63,44 @@ class ArtistIndexOverviews 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 ArtistIndexOverviews 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;
|
||||||
}
|
}
|
||||||
|
@ -217,22 +187,14 @@ class ArtistIndexOverviews 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 {
|
||||||
items,
|
items,
|
||||||
scrollTop,
|
|
||||||
isSmallScreen,
|
isSmallScreen,
|
||||||
onScroll
|
scroller
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -241,29 +203,39 @@ class ArtistIndexOverviews 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}
|
||||||
/>
|
onSectionRendered={this.onSectionRendered}
|
||||||
|
scrollToAlignment={'start'}
|
||||||
|
isScrollingOptOut={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,20 +247,16 @@ class ArtistIndexOverviews extends Component {
|
||||||
|
|
||||||
ArtistIndexOverviews.propTypes = {
|
ArtistIndexOverviews.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,
|
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 ArtistIndexOverviews;
|
export default ArtistIndexOverviews;
|
||||||
|
|
|
@ -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 ArtistIndexItemConnector from 'Artist/Index/ArtistIndexItemConnector';
|
import ArtistIndexItemConnector from 'Artist/Index/ArtistIndexItemConnector';
|
||||||
import ArtistIndexPoster from './ArtistIndexPoster';
|
import ArtistIndexPoster from './ArtistIndexPoster';
|
||||||
|
@ -109,52 +107,46 @@ class ArtistIndexPosters 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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,22 +244,14 @@ class ArtistIndexPosters 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 {
|
||||||
items,
|
items,
|
||||||
scrollTop,
|
|
||||||
isSmallScreen,
|
isSmallScreen,
|
||||||
onScroll
|
scroller
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -280,29 +264,38 @@ class ArtistIndexPosters 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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,19 +307,14 @@ class ArtistIndexPosters extends Component {
|
||||||
|
|
||||||
ArtistIndexPosters.propTypes = {
|
ArtistIndexPosters.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 ArtistIndexPosters;
|
export default ArtistIndexPosters;
|
||||||
|
|
|
@ -23,10 +23,12 @@ class ArtistIndexTable 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);
|
||||||
|
|
||||||
|
@ -76,26 +78,21 @@ class ArtistIndexTable 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}
|
|
||||||
isSmallScreen={isSmallScreen}
|
isSmallScreen={isSmallScreen}
|
||||||
|
scroller={scroller}
|
||||||
rowHeight={showBanners ? 70 : 38}
|
rowHeight={showBanners ? 70 : 38}
|
||||||
overscanRowCount={2}
|
overscanRowCount={2}
|
||||||
rowRenderer={this.rowRenderer}
|
rowRenderer={this.rowRenderer}
|
||||||
|
@ -109,12 +106,8 @@ class ArtistIndexTable extends Component {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
filters={filters}
|
|
||||||
sortKey={sortKey}
|
sortKey={sortKey}
|
||||||
sortDirection={sortDirection}
|
sortDirection={sortDirection}
|
||||||
onRender={onRender}
|
|
||||||
onScroll={onScroll}
|
|
||||||
isScrollingOptOut={true}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -123,17 +116,13 @@ class ArtistIndexTable extends Component {
|
||||||
ArtistIndexTable.propTypes = {
|
ArtistIndexTable.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 ArtistIndexTable;
|
export default ArtistIndexTable;
|
||||||
|
|
|
@ -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,39 @@ 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 = this.props.scrollIndex;
|
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) * ROW_HEIGHT + 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 +86,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,65 +105,88 @@ 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
|
||||||
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;
|
|
|
@ -3,6 +3,7 @@ import React, { Component } from 'react';
|
||||||
import { align, icons, sortDirections } from 'Helpers/Props';
|
import { align, icons, sortDirections } from 'Helpers/Props';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import VirtualTable from 'Components/Table/VirtualTable';
|
import VirtualTable from 'Components/Table/VirtualTable';
|
||||||
|
import VirtualTableRow from 'Components/Table/VirtualTableRow';
|
||||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
|
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
|
||||||
|
@ -21,16 +22,15 @@ class UnmappedFilesTable extends Component {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
contentBody: null,
|
scroller: null
|
||||||
scrollTop: 0
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Control
|
// Control
|
||||||
|
|
||||||
setContentBodyRef = (ref) => {
|
setScrollerRef = (ref) => {
|
||||||
this.setState({ contentBody: ref });
|
this.setState({ scroller: ref });
|
||||||
}
|
}
|
||||||
|
|
||||||
rowRenderer = ({ key, rowIndex, style }) => {
|
rowRenderer = ({ key, rowIndex, style }) => {
|
||||||
|
@ -43,23 +43,20 @@ class UnmappedFilesTable extends Component {
|
||||||
const item = items[rowIndex];
|
const item = items[rowIndex];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UnmappedFilesTableRow
|
<VirtualTableRow
|
||||||
style={style}
|
|
||||||
key={key}
|
key={key}
|
||||||
columns={columns}
|
style={style}
|
||||||
deleteUnmappedFile={deleteUnmappedFile}
|
>
|
||||||
{...item}
|
<UnmappedFilesTableRow
|
||||||
/>
|
key={item.id}
|
||||||
|
columns={columns}
|
||||||
|
deleteUnmappedFile={deleteUnmappedFile}
|
||||||
|
{...item}
|
||||||
|
/>
|
||||||
|
</VirtualTableRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onScroll = ({ scrollTop }) => {
|
|
||||||
this.setState({ scrollTop });
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -77,8 +74,7 @@ class UnmappedFilesTable extends Component {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
scrollTop,
|
scroller
|
||||||
contentBody
|
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -100,8 +96,7 @@ class UnmappedFilesTable extends Component {
|
||||||
</PageToolbar>
|
</PageToolbar>
|
||||||
|
|
||||||
<PageContentBodyConnector
|
<PageContentBodyConnector
|
||||||
ref={this.setContentBodyRef}
|
registerScroller={this.setScrollerRef}
|
||||||
onScroll={this.onScroll}
|
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
isFetching && !isPopulated &&
|
isFetching && !isPopulated &&
|
||||||
|
@ -116,14 +111,12 @@ class UnmappedFilesTable extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isPopulated && !error && !!items.length && contentBody &&
|
isPopulated && !error && !!items.length && scroller &&
|
||||||
<VirtualTable
|
<VirtualTable
|
||||||
items={items}
|
items={items}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
contentBody={contentBody}
|
scroller={scroller}
|
||||||
isSmallScreen={false}
|
isSmallScreen={false}
|
||||||
scrollTop={scrollTop}
|
|
||||||
onScroll={this.onScroll}
|
|
||||||
overscanRowCount={10}
|
overscanRowCount={10}
|
||||||
rowRenderer={this.rowRenderer}
|
rowRenderer={this.rowRenderer}
|
||||||
header={
|
header={
|
||||||
|
|
|
@ -5,7 +5,6 @@ import formatBytes from 'Utilities/Number/formatBytes';
|
||||||
import IconButton from 'Components/Link/IconButton';
|
import IconButton from 'Components/Link/IconButton';
|
||||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||||
import VirtualTableRow from 'Components/Table/VirtualTableRow';
|
|
||||||
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
|
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
|
||||||
import TrackQuality from 'Album/TrackQuality';
|
import TrackQuality from 'Album/TrackQuality';
|
||||||
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
|
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
|
||||||
|
@ -64,7 +63,6 @@ class UnmappedFilesTableRow extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
style,
|
|
||||||
id,
|
id,
|
||||||
path,
|
path,
|
||||||
size,
|
size,
|
||||||
|
@ -82,9 +80,7 @@ class UnmappedFilesTableRow extends Component {
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VirtualTableRow
|
<>
|
||||||
style={style}
|
|
||||||
>
|
|
||||||
{
|
{
|
||||||
columns.map((column) => {
|
columns.map((column) => {
|
||||||
const {
|
const {
|
||||||
|
@ -198,14 +194,13 @@ class UnmappedFilesTableRow extends Component {
|
||||||
onCancel={this.onConfirmDeleteModalClose}
|
onCancel={this.onConfirmDeleteModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</VirtualTableRow>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UnmappedFilesTableRow.propTypes = {
|
UnmappedFilesTableRow.propTypes = {
|
||||||
style: PropTypes.object.isRequired,
|
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
size: PropTypes.number.isRequired,
|
size: PropTypes.number.isRequired,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue