Merge pull request #248 from matrix-org/matthew/fix-image-load-popping
Fix scroll offset popping around during image load by putting explicit height back on images
This commit is contained in:
commit
e068a92cde
4 changed files with 59 additions and 21 deletions
|
@ -16,6 +16,7 @@ limitations under the License.
|
|||
|
||||
var React = require('react');
|
||||
var ReactDOM = require("react-dom");
|
||||
var dis = require("../../dispatcher");
|
||||
var sdk = require('../../index');
|
||||
|
||||
/* (almost) stateless UI component which builds the event tiles in the room timeline.
|
||||
|
@ -301,8 +302,7 @@ module.exports = React.createClass({
|
|||
ref={this._collectEventNode.bind(this, eventId)}
|
||||
data-scroll-token={scrollToken}>
|
||||
<EventTile mxEvent={mxEv} continuation={continuation}
|
||||
last={last} isSelectedEvent={highlight}
|
||||
onImageLoad={this._onImageLoad} />
|
||||
last={last} isSelectedEvent={highlight} />
|
||||
</li>
|
||||
);
|
||||
|
||||
|
@ -368,14 +368,8 @@ module.exports = React.createClass({
|
|||
this.eventNodes[eventId] = node;
|
||||
},
|
||||
|
||||
|
||||
// once images in the events load, make the scrollPanel check the
|
||||
// scroll offsets.
|
||||
_onImageLoad: function() {
|
||||
var scrollPanel = this.refs.scrollPanel;
|
||||
if (scrollPanel) {
|
||||
scrollPanel.checkScroll();
|
||||
}
|
||||
onResize: function() {
|
||||
dis.dispatch({ action: 'timeline_resize' }, true);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@ -392,6 +386,7 @@ module.exports = React.createClass({
|
|||
return (
|
||||
<ScrollPanel ref="scrollPanel" className="mx_RoomView_messagePanel"
|
||||
onScroll={ this.props.onScroll }
|
||||
onResize={ this.onResize }
|
||||
onFillRequest={ this.props.onFillRequest }
|
||||
style={ this.props.hidden ? { display: 'none' } : {} }
|
||||
stickyBottom={ this.props.stickyBottom }>
|
||||
|
|
|
@ -485,6 +485,10 @@ module.exports = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
onSearchResultsResize: function() {
|
||||
dis.dispatch({ action: 'timeline_resize' }, true);
|
||||
},
|
||||
|
||||
onSearchResultsFillRequest: function(backwards) {
|
||||
if (!backwards)
|
||||
return q(false);
|
||||
|
@ -1361,7 +1365,7 @@ module.exports = React.createClass({
|
|||
if (this.state.searchResults) {
|
||||
searchResultsPanel = (
|
||||
<ScrollPanel ref="searchResultsPanel" className="mx_RoomView_messagePanel mx_RoomView_searchResultsPanel"
|
||||
onFillRequest={ this.onSearchResultsFillRequest }>
|
||||
onFillRequest={ this.onSearchResultsFillRequest } onResize={ this.onSearchResultsResize }>
|
||||
<li className={scrollheader_classes}></li>
|
||||
{this.getSearchResultTiles()}
|
||||
</ScrollPanel>
|
||||
|
|
|
@ -94,6 +94,11 @@ module.exports = React.createClass({
|
|||
*/
|
||||
onScroll: React.PropTypes.func,
|
||||
|
||||
/* onResize: a callback which is called whenever the Gemini scroll
|
||||
* panel is resized
|
||||
*/
|
||||
onResize: React.PropTypes.func,
|
||||
|
||||
/* className: classnames to add to the top-level div
|
||||
*/
|
||||
className: React.PropTypes.string,
|
||||
|
@ -181,6 +186,12 @@ module.exports = React.createClass({
|
|||
this.checkFillState();
|
||||
},
|
||||
|
||||
onResize: function() {
|
||||
this.props.onResize();
|
||||
this.checkScroll();
|
||||
this.refs.geminiPanel.forceUpdate();
|
||||
},
|
||||
|
||||
// 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() {
|
||||
|
@ -481,7 +492,7 @@ module.exports = React.createClass({
|
|||
// reflect the fact that we don't necessarily contain a list of messages.
|
||||
// it's not obvious why we have a separate div and ol anyway.
|
||||
return (<GeminiScrollbar autoshow={true} ref="geminiPanel"
|
||||
onScroll={this.onScroll} onResize={this.checkScroll}
|
||||
onScroll={this.onScroll} onResize={this.onResize}
|
||||
className={this.props.className} style={this.props.style}>
|
||||
<div className="mx_RoomView_messageListWrapper">
|
||||
<ol ref="itemlist" className="mx_RoomView_MessageList" aria-live="polite">
|
||||
|
|
|
@ -105,24 +105,52 @@ module.exports = React.createClass({
|
|||
return MatrixClientPeg.get().mxcUrlToHttp(content.url, 800, 600);
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
this.fixupHeight();
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
},
|
||||
|
||||
onAction: function(payload) {
|
||||
if (payload.action === "timeline_resize") {
|
||||
this.fixupHeight();
|
||||
}
|
||||
},
|
||||
|
||||
fixupHeight: function() {
|
||||
if (!this.refs.image) {
|
||||
console.warn("Refusing to fix up height on MImageBody with no image element");
|
||||
return;
|
||||
}
|
||||
|
||||
var content = this.props.mxEvent.getContent();
|
||||
|
||||
var thumbHeight = null;
|
||||
var timelineWidth = this.refs.body.offsetWidth;
|
||||
var maxHeight = 600; // let images take up as much width as they can so long as the height doesn't exceed 600px.
|
||||
// the alternative here would be 600*timelineWidth/800; to scale them down to fit inside a 4:3 bounding box
|
||||
|
||||
//console.log("trying to fit image into timelineWidth of " + this.refs.body.offsetWidth + " or " + this.refs.body.clientWidth);
|
||||
if (content.info) thumbHeight = this.thumbHeight(content.info.w, content.info.h, timelineWidth, maxHeight);
|
||||
this.refs.image.style.height = thumbHeight + "px";
|
||||
// console.log("Image height now", thumbHeight);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||
var content = this.props.mxEvent.getContent();
|
||||
var cli = MatrixClientPeg.get();
|
||||
|
||||
var thumbHeight = null;
|
||||
if (content.info) thumbHeight = this.thumbHeight(content.info.w, content.info.h, 800, 600);
|
||||
|
||||
var imgStyle = {};
|
||||
if (thumbHeight) imgStyle['maxHeight'] = thumbHeight;
|
||||
|
||||
var thumbUrl = this._getThumbUrl();
|
||||
if (thumbUrl) {
|
||||
return (
|
||||
<span className="mx_MImageBody">
|
||||
<span className="mx_MImageBody" ref="body">
|
||||
<a href={cli.mxcUrlToHttp(content.url)} onClick={ this.onClick }>
|
||||
<img className="mx_MImageBody_thumbnail" src={thumbUrl}
|
||||
alt={content.body} style={imgStyle}
|
||||
<img className="mx_MImageBody_thumbnail" src={thumbUrl} ref="image"
|
||||
alt={content.body}
|
||||
onMouseEnter={this.onImageEnter}
|
||||
onMouseLeave={this.onImageLeave}
|
||||
onLoad={this.props.onImageLoad} />
|
||||
|
|
Loading…
Reference in a new issue