mirror of
https://github.com/element-hq/element-web.git
synced 2024-11-30 15:19:39 +03:00
Update the scroll offset when images load
In order to deal with image-loading reshaping the DOM, wire up ScrollPanel.checkScroll to the image load events. Fixes https://github.com/vector-im/vector-web/issues/984
This commit is contained in:
parent
26e66326a2
commit
99d2392b6f
6 changed files with 57 additions and 12 deletions
|
@ -921,6 +921,15 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// once images in the search results load, make the scrollPanel check
|
||||||
|
// the scroll offsets.
|
||||||
|
var onImageLoad = () => {
|
||||||
|
var scrollPanel = this.refs.searchResultsPanel;
|
||||||
|
if (scrollPanel) {
|
||||||
|
scrollPanel.checkScroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var lastRoomId;
|
var lastRoomId;
|
||||||
|
|
||||||
for (var i = this.state.searchResults.results.length - 1; i >= 0; i--) {
|
for (var i = this.state.searchResults.results.length - 1; i >= 0; i--) {
|
||||||
|
@ -957,19 +966,28 @@ module.exports = React.createClass({
|
||||||
ret.push(<SearchResultTile key={mxEv.getId()}
|
ret.push(<SearchResultTile key={mxEv.getId()}
|
||||||
searchResult={result}
|
searchResult={result}
|
||||||
searchHighlights={this.state.searchHighlights}
|
searchHighlights={this.state.searchHighlights}
|
||||||
resultLink={resultLink}/>);
|
resultLink={resultLink}
|
||||||
|
onImageLoad={onImageLoad}/>);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
||||||
getEventTiles: function() {
|
getEventTiles: function() {
|
||||||
var DateSeparator = sdk.getComponent('messages.DateSeparator');
|
var DateSeparator = sdk.getComponent('messages.DateSeparator');
|
||||||
|
var EventTile = sdk.getComponent('rooms.EventTile');
|
||||||
|
|
||||||
|
// once images in the events load, make the scrollPanel check the
|
||||||
|
// scroll offsets.
|
||||||
|
var onImageLoad = () => {
|
||||||
|
var scrollPanel = this.refs.messagePanel;
|
||||||
|
if (scrollPanel) {
|
||||||
|
scrollPanel.checkScroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var ret = [];
|
var ret = [];
|
||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
var EventTile = sdk.getComponent('rooms.EventTile');
|
|
||||||
|
|
||||||
var prevEvent = null; // the last event we showed
|
var prevEvent = null; // the last event we showed
|
||||||
var ghostIndex;
|
var ghostIndex;
|
||||||
var readMarkerIndex;
|
var readMarkerIndex;
|
||||||
|
@ -1056,7 +1074,8 @@ module.exports = React.createClass({
|
||||||
ref={this._collectEventNode.bind(this, eventId)}
|
ref={this._collectEventNode.bind(this, eventId)}
|
||||||
data-scroll-token={scrollToken}>
|
data-scroll-token={scrollToken}>
|
||||||
<EventTile mxEvent={mxEv} continuation={continuation}
|
<EventTile mxEvent={mxEv} continuation={continuation}
|
||||||
last={last} isSelectedEvent={highlight}/>
|
last={last} isSelectedEvent={highlight}
|
||||||
|
onImageLoad={onImageLoad} />
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -124,10 +124,9 @@ module.exports = React.createClass({
|
||||||
// after adding event tiles, we may need to tweak the scroll (either to
|
// after adding event tiles, we may need to tweak the scroll (either to
|
||||||
// keep at the bottom of the timeline, or to maintain the view after
|
// keep at the bottom of the timeline, or to maintain the view after
|
||||||
// adding events to the top).
|
// adding events to the top).
|
||||||
this._restoreSavedScrollState();
|
//
|
||||||
|
// This will also re-check the fill state, in case the paginate was inadequate
|
||||||
// we also re-check the fill state, in case the paginate was inadequate
|
this.checkScroll();
|
||||||
this.checkFillState();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
|
@ -178,6 +177,13 @@ module.exports = React.createClass({
|
||||||
this.checkFillState();
|
this.checkFillState();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// after an update to the contents of the panel, check that the scroll is
|
||||||
|
// where it ought to be, and set off pagination requests if necessary.
|
||||||
|
checkScroll: function() {
|
||||||
|
this._restoreSavedScrollState();
|
||||||
|
this.checkFillState();
|
||||||
|
},
|
||||||
|
|
||||||
// return true if the content is fully scrolled down right now; else false.
|
// return true if the content is fully scrolled down right now; else false.
|
||||||
//
|
//
|
||||||
// note that this is independent of the 'stuckAtBottom' state - it is simply
|
// note that this is independent of the 'stuckAtBottom' state - it is simply
|
||||||
|
|
|
@ -27,6 +27,14 @@ var dis = require("../../../dispatcher");
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'MImageBody',
|
displayName: 'MImageBody',
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
/* the MatrixEvent to show */
|
||||||
|
mxEvent: React.PropTypes.object.isRequired,
|
||||||
|
|
||||||
|
/* callback called when images in events are loaded */
|
||||||
|
onImageLoad: React.PropTypes.func,
|
||||||
|
},
|
||||||
|
|
||||||
thumbHeight: function(fullWidth, fullHeight, thumbWidth, thumbHeight) {
|
thumbHeight: function(fullWidth, fullHeight, thumbWidth, thumbHeight) {
|
||||||
if (!fullWidth || !fullHeight) {
|
if (!fullWidth || !fullHeight) {
|
||||||
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
|
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
|
||||||
|
@ -116,7 +124,8 @@ module.exports = React.createClass({
|
||||||
<img className="mx_MImageBody_thumbnail" src={thumbUrl}
|
<img className="mx_MImageBody_thumbnail" src={thumbUrl}
|
||||||
alt={content.body} style={imgStyle}
|
alt={content.body} style={imgStyle}
|
||||||
onMouseEnter={this.onImageEnter}
|
onMouseEnter={this.onImageEnter}
|
||||||
onMouseLeave={this.onImageLeave} />
|
onMouseLeave={this.onImageLeave}
|
||||||
|
onLoad={this.props.onImageLoad} />
|
||||||
</a>
|
</a>
|
||||||
<div className="mx_MImageBody_download">
|
<div className="mx_MImageBody_download">
|
||||||
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
||||||
|
|
|
@ -37,6 +37,9 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
/* link URL for the highlights */
|
/* link URL for the highlights */
|
||||||
highlightLink: React.PropTypes.string,
|
highlightLink: React.PropTypes.string,
|
||||||
|
|
||||||
|
/* callback called when images in events are loaded */
|
||||||
|
onImageLoad: React.PropTypes.func,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +63,7 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
return <TileType mxEvent={this.props.mxEvent} highlights={this.props.highlights}
|
return <TileType mxEvent={this.props.mxEvent} highlights={this.props.highlights}
|
||||||
highlightLink={this.props.highlightLink} />;
|
highlightLink={this.props.highlightLink}
|
||||||
|
onImageLoad={this.props.onImageLoad} />;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -102,6 +102,9 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
/* is this the focussed event */
|
/* is this the focussed event */
|
||||||
isSelectedEvent: React.PropTypes.bool,
|
isSelectedEvent: React.PropTypes.bool,
|
||||||
|
|
||||||
|
/* callback called when images in events are loaded */
|
||||||
|
onImageLoad: React.PropTypes.func,
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
|
@ -323,7 +326,8 @@ module.exports = React.createClass({
|
||||||
{ sender }
|
{ sender }
|
||||||
<div className="mx_EventTile_line">
|
<div className="mx_EventTile_line">
|
||||||
<EventTileType mxEvent={this.props.mxEvent} highlights={this.props.highlights}
|
<EventTileType mxEvent={this.props.mxEvent} highlights={this.props.highlights}
|
||||||
highlightLink={this.props.highlightLink}/>
|
highlightLink={this.props.highlightLink}
|
||||||
|
onImageLoad={this.props.onImageLoad} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -31,6 +31,8 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
// href for the highlights in this result
|
// href for the highlights in this result
|
||||||
resultLink: React.PropTypes.string,
|
resultLink: React.PropTypes.string,
|
||||||
|
|
||||||
|
onImageLoad: React.PropTypes.func,
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
@ -53,7 +55,8 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
if (EventTile.haveTileForEvent(ev)) {
|
if (EventTile.haveTileForEvent(ev)) {
|
||||||
ret.push(<EventTile key={eventId+"+"+j} mxEvent={ev} contextual={contextual} highlights={highlights}
|
ret.push(<EventTile key={eventId+"+"+j} mxEvent={ev} contextual={contextual} highlights={highlights}
|
||||||
highlightLink={this.props.resultLink}/>);
|
highlightLink={this.props.resultLink}
|
||||||
|
onImageLoad={this.props.onImageLoad} />);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in a new issue