You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
382 lines
14 KiB
382 lines
14 KiB
'use strict';
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
var _extends2 = require('babel-runtime/helpers/extends');
|
|
|
|
var _extends3 = _interopRequireDefault(_extends2);
|
|
|
|
var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties');
|
|
|
|
var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
|
|
|
|
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
|
|
|
|
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
|
|
|
var _createClass2 = require('babel-runtime/helpers/createClass');
|
|
|
|
var _createClass3 = _interopRequireDefault(_createClass2);
|
|
|
|
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
|
|
|
|
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
|
|
|
var _inherits2 = require('babel-runtime/helpers/inherits');
|
|
|
|
var _inherits3 = _interopRequireDefault(_inherits2);
|
|
|
|
var _react = require('react');
|
|
|
|
var _react2 = _interopRequireDefault(_react);
|
|
|
|
var _propTypes = require('prop-types');
|
|
|
|
var _propTypes2 = _interopRequireDefault(_propTypes);
|
|
|
|
var _reactDom = require('react-dom');
|
|
|
|
var _reactDom2 = _interopRequireDefault(_reactDom);
|
|
|
|
var _ListViewDataSource = require('./ListViewDataSource');
|
|
|
|
var _ListViewDataSource2 = _interopRequireDefault(_ListViewDataSource);
|
|
|
|
var _ScrollView = require('./ScrollView');
|
|
|
|
var _ScrollView2 = _interopRequireDefault(_ScrollView);
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
|
|
|
|
var DEFAULT_PAGE_SIZE = 1; /* eslint no-unused-vars: 0, react/no-multi-comp: 0
|
|
react/prop-types: 0, react/sort-comp: 0, no-unused-expressions: 0 */
|
|
|
|
var DEFAULT_INITIAL_ROWS = 10;
|
|
var DEFAULT_SCROLL_RENDER_AHEAD = 1000;
|
|
var DEFAULT_END_REACHED_THRESHOLD = 1000;
|
|
var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
|
|
// const SCROLLVIEW_REF = 'ListViewRef';
|
|
|
|
var StaticRenderer = function (_React$Component) {
|
|
(0, _inherits3['default'])(StaticRenderer, _React$Component);
|
|
|
|
function StaticRenderer() {
|
|
(0, _classCallCheck3['default'])(this, StaticRenderer);
|
|
return (0, _possibleConstructorReturn3['default'])(this, (StaticRenderer.__proto__ || Object.getPrototypeOf(StaticRenderer)).apply(this, arguments));
|
|
}
|
|
|
|
(0, _createClass3['default'])(StaticRenderer, [{
|
|
key: 'shouldComponentUpdate',
|
|
value: function shouldComponentUpdate(nextProps) {
|
|
return nextProps.shouldUpdate;
|
|
}
|
|
}, {
|
|
key: 'render',
|
|
value: function render() {
|
|
return this.props.render();
|
|
}
|
|
}]);
|
|
return StaticRenderer;
|
|
}(_react2['default'].Component);
|
|
// https://github.com/facebook/react-native/blob/0.26-stable/Libraries/CustomComponents/ListView/ListView.js
|
|
|
|
|
|
var ListView = function (_React$Component2) {
|
|
(0, _inherits3['default'])(ListView, _React$Component2);
|
|
|
|
function ListView() {
|
|
var _ref;
|
|
|
|
var _temp, _this2, _ret;
|
|
|
|
(0, _classCallCheck3['default'])(this, ListView);
|
|
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
return _ret = (_temp = (_this2 = (0, _possibleConstructorReturn3['default'])(this, (_ref = ListView.__proto__ || Object.getPrototypeOf(ListView)).call.apply(_ref, [this].concat(args))), _this2), _initialiseProps.call(_this2), _temp), (0, _possibleConstructorReturn3['default'])(_this2, _ret);
|
|
}
|
|
|
|
/**
|
|
* Exports some data, e.g. for perf investigations or analytics.
|
|
*/
|
|
|
|
|
|
(0, _createClass3['default'])(ListView, [{
|
|
key: 'componentWillMount',
|
|
value: function componentWillMount() {
|
|
// this data should never trigger a render pass, so don't put in state
|
|
this.scrollProperties = {
|
|
visibleLength: null,
|
|
contentLength: null,
|
|
offset: 0
|
|
};
|
|
this._childFrames = [];
|
|
this._visibleRows = {};
|
|
this._prevRenderedRowsCount = 0;
|
|
this._sentEndForContentLength = null;
|
|
}
|
|
}, {
|
|
key: 'componentWillReceiveProps',
|
|
value: function componentWillReceiveProps(nextProps) {
|
|
var _this3 = this;
|
|
|
|
if (this.props.dataSource !== nextProps.dataSource || this.props.initialListSize !== nextProps.initialListSize) {
|
|
this.setState(function (state, props) {
|
|
_this3._prevRenderedRowsCount = 0;
|
|
return {
|
|
curRenderedRowsCount: Math.min(Math.max(state.curRenderedRowsCount, nextProps.initialListSize // for preact
|
|
), nextProps.dataSource.getRowCount() // for preact
|
|
)
|
|
};
|
|
}, function () {
|
|
return _this3._renderMoreRowsIfNeeded();
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: 'render',
|
|
value: function render() {
|
|
var _this4 = this;
|
|
|
|
var dataSource = this.props.dataSource;
|
|
var allRowIDs = dataSource.rowIdentities;
|
|
var bodyComponents = [];
|
|
var rowCount = 0;
|
|
|
|
for (var sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) {
|
|
var sectionID = dataSource.sectionIdentities[sectionIdx];
|
|
var rowIDs = allRowIDs[sectionIdx];
|
|
if (rowIDs.length === 0) {
|
|
continue;
|
|
}
|
|
|
|
var renderSectionHeader = void 0;
|
|
if (this.props.renderSectionHeader) {
|
|
var shouldUpdateHeader = rowCount >= this._prevRenderedRowsCount && dataSource.sectionHeaderShouldUpdate(sectionIdx);
|
|
|
|
renderSectionHeader = _react2['default'].createElement(StaticRenderer, {
|
|
key: 's_' + sectionID,
|
|
shouldUpdate: !!shouldUpdateHeader,
|
|
render: this.props.renderSectionHeader.bind(null, dataSource.getSectionHeaderData(sectionIdx), sectionID)
|
|
});
|
|
}
|
|
|
|
var sectionBody = [];
|
|
for (var rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) {
|
|
var rowID = rowIDs[rowIdx];
|
|
var comboID = sectionID + '_' + rowID;
|
|
var shouldUpdateRow = rowCount >= this._prevRenderedRowsCount && dataSource.rowShouldUpdate(sectionIdx, rowIdx);
|
|
var row = _react2['default'].createElement(StaticRenderer, {
|
|
key: 'r_' + comboID,
|
|
shouldUpdate: !!shouldUpdateRow,
|
|
render: this.props.renderRow.bind(null, dataSource.getRowData(sectionIdx, rowIdx), sectionID, rowID, this.onRowHighlighted)
|
|
});
|
|
sectionBody.push(row);
|
|
|
|
if (this.props.renderSeparator && (rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)) {
|
|
var adjacentRowHighlighted = this.state.highlightedRow.sectionID === sectionID && (this.state.highlightedRow.rowID === rowID || this.state.highlightedRow.rowID === rowIDs[rowIdx + 1]);
|
|
var separator = this.props.renderSeparator(sectionID, rowID, adjacentRowHighlighted);
|
|
if (separator) {
|
|
sectionBody.push(separator);
|
|
}
|
|
}
|
|
if (++rowCount === this.state.curRenderedRowsCount) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
var rowsAndSeparators = _react2['default'].cloneElement(this.props.renderSectionBodyWrapper(sectionID), {
|
|
className: this.props.sectionBodyClassName
|
|
}, sectionBody);
|
|
|
|
if (this.props.renderSectionWrapper) {
|
|
bodyComponents.push(_react2['default'].cloneElement(this.props.renderSectionWrapper(sectionID), {}, renderSectionHeader, rowsAndSeparators));
|
|
} else {
|
|
bodyComponents.push(renderSectionHeader);
|
|
bodyComponents.push(rowsAndSeparators);
|
|
}
|
|
if (rowCount >= this.state.curRenderedRowsCount) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
var _props = this.props,
|
|
renderScrollComponent = _props.renderScrollComponent,
|
|
props = (0, _objectWithoutProperties3['default'])(_props, ['renderScrollComponent']);
|
|
|
|
|
|
return _react2['default'].cloneElement(renderScrollComponent((0, _extends3['default'])({}, props, { onScroll: this._onScroll })), {
|
|
ref: function ref(el) {
|
|
return _this4.ListViewRef = el;
|
|
},
|
|
onContentSizeChange: this._onContentSizeChange,
|
|
onLayout: this._onLayout
|
|
}, this.props.renderHeader ? this.props.renderHeader() : null, _react2['default'].cloneElement(props.renderBodyComponent(), {}, bodyComponents), this.props.renderFooter ? this.props.renderFooter() : null, props.children);
|
|
}
|
|
}]);
|
|
return ListView;
|
|
}(_react2['default'].Component);
|
|
|
|
ListView.DataSource = _ListViewDataSource2['default'];
|
|
ListView.propTypes = (0, _extends3['default'])({}, _ScrollView2['default'].propTypes, {
|
|
dataSource: _propTypes2['default'].instanceOf(_ListViewDataSource2['default']).isRequired,
|
|
renderSeparator: _propTypes2['default'].func,
|
|
renderRow: _propTypes2['default'].func.isRequired,
|
|
initialListSize: _propTypes2['default'].number,
|
|
onEndReached: _propTypes2['default'].func,
|
|
onEndReachedThreshold: _propTypes2['default'].number,
|
|
pageSize: _propTypes2['default'].number,
|
|
renderFooter: _propTypes2['default'].func,
|
|
renderHeader: _propTypes2['default'].func,
|
|
renderSectionHeader: _propTypes2['default'].func,
|
|
renderScrollComponent: _propTypes2['default'].func,
|
|
scrollRenderAheadDistance: _propTypes2['default'].number,
|
|
onChangeVisibleRows: _propTypes2['default'].func,
|
|
scrollEventThrottle: _propTypes2['default'].number,
|
|
// another added
|
|
renderBodyComponent: _propTypes2['default'].func,
|
|
renderSectionWrapper: _propTypes2['default'].func,
|
|
renderSectionBodyWrapper: _propTypes2['default'].func,
|
|
sectionBodyClassName: _propTypes2['default'].string,
|
|
listViewPrefixCls: _propTypes2['default'].string,
|
|
useBodyScroll: _propTypes2['default'].bool
|
|
});
|
|
ListView.defaultProps = {
|
|
initialListSize: DEFAULT_INITIAL_ROWS,
|
|
pageSize: DEFAULT_PAGE_SIZE,
|
|
renderScrollComponent: function renderScrollComponent(props) {
|
|
return _react2['default'].createElement(_ScrollView2['default'], props);
|
|
},
|
|
renderBodyComponent: function renderBodyComponent() {
|
|
return _react2['default'].createElement('div', null);
|
|
},
|
|
renderSectionBodyWrapper: function renderSectionBodyWrapper(sectionID) {
|
|
return _react2['default'].createElement('div', { key: sectionID });
|
|
},
|
|
sectionBodyClassName: 'list-view-section-body',
|
|
listViewPrefixCls: 'rmc-list-view',
|
|
scrollRenderAheadDistance: DEFAULT_SCROLL_RENDER_AHEAD,
|
|
onEndReachedThreshold: DEFAULT_END_REACHED_THRESHOLD,
|
|
scrollEventThrottle: DEFAULT_SCROLL_CALLBACK_THROTTLE,
|
|
scrollerOptions: {}
|
|
};
|
|
|
|
var _initialiseProps = function _initialiseProps() {
|
|
var _this5 = this;
|
|
|
|
this.state = {
|
|
curRenderedRowsCount: this.props.initialListSize,
|
|
highlightedRow: {} };
|
|
|
|
this.getMetrics = function () {
|
|
return {
|
|
contentLength: _this5.scrollProperties.contentLength,
|
|
totalRows: _this5.props.dataSource.getRowCount(),
|
|
renderedRows: _this5.state.curRenderedRowsCount,
|
|
visibleRows: Object.keys(_this5._visibleRows).length
|
|
};
|
|
};
|
|
|
|
this.getInnerViewNode = function () {
|
|
return _this5.ListViewRef.getInnerViewNode();
|
|
};
|
|
|
|
this.scrollTo = function () {
|
|
var _ListViewRef;
|
|
|
|
_this5.ListViewRef && _this5.ListViewRef.scrollTo && (_ListViewRef = _this5.ListViewRef).scrollTo.apply(_ListViewRef, arguments);
|
|
};
|
|
|
|
this.onRowHighlighted = function (sectionID, rowID) {
|
|
_this5.setState({ highlightedRow: { sectionID: sectionID, rowID: rowID } });
|
|
};
|
|
|
|
this._onContentSizeChange = function (width, height) {
|
|
var contentLength = !_this5.props.horizontal ? height : width;
|
|
if (contentLength !== _this5.scrollProperties.contentLength) {
|
|
_this5.scrollProperties.contentLength = contentLength;
|
|
_this5._renderMoreRowsIfNeeded();
|
|
}
|
|
_this5.props.onContentSizeChange && _this5.props.onContentSizeChange(width, height);
|
|
};
|
|
|
|
this._onLayout = function (event) {
|
|
var _event$nativeEvent$la = event.nativeEvent.layout,
|
|
width = _event$nativeEvent$la.width,
|
|
height = _event$nativeEvent$la.height;
|
|
|
|
var visibleLength = !_this5.props.horizontal ? height : width;
|
|
if (visibleLength !== _this5.scrollProperties.visibleLength) {
|
|
_this5.scrollProperties.visibleLength = visibleLength;
|
|
_this5._renderMoreRowsIfNeeded();
|
|
}
|
|
_this5.props.onLayout && _this5.props.onLayout(event);
|
|
};
|
|
|
|
this._maybeCallOnEndReached = function (event) {
|
|
// console.log(this.scrollProperties, this._getDistanceFromEnd(this.scrollProperties));
|
|
if (_this5.props.onEndReached && _this5.scrollProperties.contentLength !== _this5._sentEndForContentLength && _this5._getDistanceFromEnd(_this5.scrollProperties) < _this5.props.onEndReachedThreshold && _this5.state.curRenderedRowsCount === _this5.props.dataSource.getRowCount()) {
|
|
_this5._sentEndForContentLength = _this5.scrollProperties.contentLength;
|
|
_this5.props.onEndReached(event);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
this._renderMoreRowsIfNeeded = function () {
|
|
if (_this5.scrollProperties.contentLength === null || _this5.scrollProperties.visibleLength === null || _this5.state.curRenderedRowsCount === _this5.props.dataSource.getRowCount()) {
|
|
_this5._maybeCallOnEndReached();
|
|
return;
|
|
}
|
|
|
|
var distanceFromEnd = _this5._getDistanceFromEnd(_this5.scrollProperties);
|
|
// console.log(distanceFromEnd, this.props.scrollRenderAheadDistance);
|
|
if (distanceFromEnd < _this5.props.scrollRenderAheadDistance) {
|
|
_this5._pageInNewRows();
|
|
}
|
|
};
|
|
|
|
this._pageInNewRows = function () {
|
|
_this5.setState(function (state, props) {
|
|
var rowsToRender = Math.min(state.curRenderedRowsCount + props.pageSize, props.dataSource.getRowCount());
|
|
_this5._prevRenderedRowsCount = state.curRenderedRowsCount;
|
|
return {
|
|
curRenderedRowsCount: rowsToRender
|
|
};
|
|
}, function () {
|
|
_this5._prevRenderedRowsCount = _this5.state.curRenderedRowsCount;
|
|
});
|
|
};
|
|
|
|
this._getDistanceFromEnd = function (scrollProperties) {
|
|
return scrollProperties.contentLength - scrollProperties.visibleLength - scrollProperties.offset;
|
|
};
|
|
|
|
this._onScroll = function (e, metrics) {
|
|
// when the ListView is destroyed,
|
|
// but also will trigger scroll event after `scrollEventThrottle`
|
|
if (!_this5.ListViewRef) {
|
|
return;
|
|
}
|
|
|
|
_this5.scrollProperties = metrics;
|
|
|
|
if (!_this5._maybeCallOnEndReached(e)) {
|
|
_this5._renderMoreRowsIfNeeded();
|
|
}
|
|
|
|
if (_this5.props.onEndReached && _this5._getDistanceFromEnd(_this5.scrollProperties) > _this5.props.onEndReachedThreshold) {
|
|
// Scrolled out of the end zone, so it should be able to trigger again.
|
|
_this5._sentEndForContentLength = null;
|
|
}
|
|
|
|
_this5.props.onScroll && _this5.props.onScroll(e);
|
|
};
|
|
};
|
|
|
|
exports['default'] = ListView;
|
|
module.exports = exports['default']; |