Combine data-scroll-token and -contained-scroll-tokens

- Instead of using one attribute, use one that might just contain one token
 - Use the first token when tracking a child
 - Mandate that no commas can be in individual tokens
This commit is contained in:
Luke Barnard 2017-05-04 10:00:13 +01:00
parent 4febc63aee
commit bfa3123f9b
5 changed files with 24 additions and 29 deletions

View file

@ -472,7 +472,7 @@ module.exports = React.createClass({
ret.push( ret.push(
<li key={eventId} <li key={eventId}
ref={this._collectEventNode.bind(this, eventId)} ref={this._collectEventNode.bind(this, eventId)}
data-scroll-token={scrollToken}> data-scroll-tokens={scrollToken}>
<EventTile mxEvent={mxEv} continuation={continuation} <EventTile mxEvent={mxEv} continuation={continuation}
isRedacted={mxEv.isRedacted()} isRedacted={mxEv.isRedacted()}
onWidgetLoad={this._onWidgetLoad} onWidgetLoad={this._onWidgetLoad}

View file

@ -46,13 +46,13 @@ if (DEBUG_SCROLL) {
* It also provides a hook which allows parents to provide more list elements * It also provides a hook which allows parents to provide more list elements
* when we get close to the start or end of the list. * when we get close to the start or end of the list.
* *
* Each child element should have a 'data-scroll-token'. This token is used to * Each child element should have a 'data-scroll-tokens'. This string of
* serialise the scroll state, and returned as the 'trackedScrollToken' * comma-separated tokens may contain a single token or many, where many indicates
* attribute by getScrollState(). * that the element contains elements that have scroll tokens themselves. The first
* token in 'data-scroll-tokens' is used to serialise the scroll state, and returned
* as the 'trackedScrollToken' attribute by getScrollState().
* *
* Child elements that contain elements that have scroll tokens must declare the * IMPORTANT: INDIVIDUAL TOKENS WITHIN 'data-scroll-tokens' MUST NOT CONTAIN COMMAS.
* contained scroll tokens using 'data-contained-scroll-tokens`. When scrolling
* to a contained scroll token, the ScrollPanel will scroll to the container.
* *
* Some notes about the implementation: * Some notes about the implementation:
* *
@ -353,8 +353,8 @@ module.exports = React.createClass({
// Subtract height of tile as if it were unpaginated // Subtract height of tile as if it were unpaginated
excessHeight -= tile.clientHeight; excessHeight -= tile.clientHeight;
// The tile may not have a scroll token, so guard it // The tile may not have a scroll token, so guard it
if (tile.dataset.scrollToken) { if (tile.dataset.scrollTokens) {
markerScrollToken = tile.dataset.scrollToken; markerScrollToken = tile.dataset.scrollTokens.split(',')[0];
} }
if (tile.clientHeight > excessHeight) { if (tile.clientHeight > excessHeight) {
break; break;
@ -423,7 +423,8 @@ module.exports = React.createClass({
* scroll. false if we are tracking a particular child. * scroll. false if we are tracking a particular child.
* *
* string trackedScrollToken: undefined if stuckAtBottom is true; if it is * string trackedScrollToken: undefined if stuckAtBottom is true; if it is
* false, the data-scroll-token of the child which we are tracking. * false, the fist token in data-scroll-tokens of the child which we are
* tracking.
* *
* number pixelOffset: undefined if stuckAtBottom is true; if it is false, * number pixelOffset: undefined if stuckAtBottom is true; if it is false,
* the number of pixels the bottom of the tracked child is above the * the number of pixels the bottom of the tracked child is above the
@ -555,16 +556,10 @@ module.exports = React.createClass({
var messages = this.refs.itemlist.children; var messages = this.refs.itemlist.children;
for (var i = messages.length-1; i >= 0; --i) { for (var i = messages.length-1; i >= 0; --i) {
var m = messages[i]; var m = messages[i];
// 'data-contained-scroll-tokens' has been set, indicating that a child // 'data-scroll-tokens' is a DOMString of comma-separated scroll tokens
// element contains elements that each have a token. Check this array of // There might only be one scroll token
// tokens for `scrollToken`. if (m.dataset.scrollTokens &&
if (m.dataset.containedScrollTokens && m.dataset.scrollTokens.split(',').indexOf(scrollToken) !== -1) {
m.dataset.containedScrollTokens.indexOf(scrollToken) !== -1) {
node = m;
break;
}
if (!m.dataset.scrollToken) continue;
if (m.dataset.scrollToken == scrollToken) {
node = m; node = m;
break; break;
} }
@ -580,7 +575,7 @@ module.exports = React.createClass({
var boundingRect = node.getBoundingClientRect(); var boundingRect = node.getBoundingClientRect();
var scrollDelta = boundingRect.bottom + pixelOffset - wrapperRect.bottom; var scrollDelta = boundingRect.bottom + pixelOffset - wrapperRect.bottom;
debuglog("ScrollPanel: scrolling to token '" + node.dataset.scrollToken + "'+" + debuglog("ScrollPanel: scrolling to token '" + scrollToken + "'+" +
pixelOffset + " (delta: "+scrollDelta+")"); pixelOffset + " (delta: "+scrollDelta+")");
if(scrollDelta != 0) { if(scrollDelta != 0) {
@ -603,12 +598,12 @@ module.exports = React.createClass({
for (var i = messages.length-1; i >= 0; --i) { for (var i = messages.length-1; i >= 0; --i) {
var node = messages[i]; var node = messages[i];
if (!node.dataset.scrollToken) continue; if (!node.dataset.scrollTokens) continue;
var boundingRect = node.getBoundingClientRect(); var boundingRect = node.getBoundingClientRect();
newScrollState = { newScrollState = {
stuckAtBottom: false, stuckAtBottom: false,
trackedScrollToken: node.dataset.scrollToken, trackedScrollToken: node.dataset.scrollTokens.split(',')[0],
pixelOffset: wrapperRect.bottom - boundingRect.bottom, pixelOffset: wrapperRect.bottom - boundingRect.bottom,
}; };
// If the bottom of the panel intersects the ClientRect of node, use this node // If the bottom of the panel intersects the ClientRect of node, use this node
@ -620,7 +615,7 @@ module.exports = React.createClass({
break; break;
} }
} }
// This is only false if there were no nodes with `node.dataset.scrollToken` set. // This is only false if there were no nodes with `node.dataset.scrollTokens` set.
if (newScrollState) { if (newScrollState) {
this.scrollState = newScrollState; this.scrollState = newScrollState;
debuglog("ScrollPanel: saved scroll state", this.scrollState); debuglog("ScrollPanel: saved scroll state", this.scrollState);

View file

@ -369,7 +369,7 @@ module.exports = React.createClass({
render: function() { render: function() {
const eventsToRender = this.props.events; const eventsToRender = this.props.events;
const eventIds = eventsToRender.map(e => e.getId()); const eventIds = eventsToRender.map(e => e.getId()).join(',');
const fewEvents = eventsToRender.length < this.props.threshold; const fewEvents = eventsToRender.length < this.props.threshold;
const expanded = this.state.expanded || fewEvents; const expanded = this.state.expanded || fewEvents;
@ -380,7 +380,7 @@ module.exports = React.createClass({
if (fewEvents) { if (fewEvents) {
return ( return (
<div className="mx_MemberEventListSummary" data-contained-scroll-tokens={eventIds}> <div className="mx_MemberEventListSummary" data-scroll-tokens={eventIds}>
{expandedEvents} {expandedEvents}
</div> </div>
); );
@ -438,7 +438,7 @@ module.exports = React.createClass({
); );
return ( return (
<div className="mx_MemberEventListSummary" data-contained-scroll-tokens={eventIds}> <div className="mx_MemberEventListSummary" data-scroll-tokens={eventIds}>
{toggleButton} {toggleButton}
{summaryContainer} {summaryContainer}
{expanded ? <div className="mx_MemberEventListSummary_line">&nbsp;</div> : null} {expanded ? <div className="mx_MemberEventListSummary_line">&nbsp;</div> : null}

View file

@ -60,7 +60,7 @@ module.exports = React.createClass({
} }
} }
return ( return (
<li data-scroll-token={eventId+"+"+j}> <li data-scroll-tokens={eventId+"+"+j}>
{ret} {ret}
</li>); </li>);
}, },

View file

@ -115,7 +115,7 @@ var Tester = React.createClass({
// //
// there is an extra 50 pixels of margin at the bottom. // there is an extra 50 pixels of margin at the bottom.
return ( return (
<li key={key} data-scroll-token={key}> <li key={key} data-scroll-tokens={key}>
<div style={{height: '98px', margin: '50px', border: '1px solid black', <div style={{height: '98px', margin: '50px', border: '1px solid black',
backgroundColor: '#fff8dc' }}> backgroundColor: '#fff8dc' }}>
{key} {key}