From 4388334e30dd2505165676effeb924c8caacdd39 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 2 Apr 2016 00:36:19 +0100 Subject: [PATCH] fix up scroll behaviour when loading widgets --- src/components/structures/MessagePanel.js | 10 ++++++ src/components/structures/RoomView.js | 6 ++-- src/components/views/messages/MImageBody.js | 32 ++++--------------- src/components/views/messages/MessageEvent.js | 4 +-- src/components/views/messages/TextualBody.js | 5 ++- src/components/views/rooms/EventTile.js | 6 ++-- .../views/rooms/LinkPreviewWidget.js | 32 +++++++++++++++---- .../views/rooms/SearchResultTile.js | 4 +-- 8 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index aaa00934cb..dff3e9e514 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -302,6 +302,7 @@ module.exports = React.createClass({ ref={this._collectEventNode.bind(this, eventId)} data-scroll-token={scrollToken}> ); @@ -368,6 +369,15 @@ module.exports = React.createClass({ this.eventNodes[eventId] = node; }, + // once dynamic content in the events load, make the scrollPanel check the + // scroll offsets. + _onWidgetLoad: function() { + var scrollPanel = this.refs.scrollPanel; + if (scrollPanel) { + scrollPanel.checkScroll(); + } + }, + onResize: function() { dis.dispatch({ action: 'timeline_resize' }, true); }, diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index b5c34de20d..7fdb9f437a 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -798,9 +798,9 @@ module.exports = React.createClass({ } } - // once images in the search results load, make the scrollPanel check + // once dynamic content in the search results load, make the scrollPanel check // the scroll offsets. - var onImageLoad = () => { + var onWidgetLoad = () => { var scrollPanel = this.refs.searchResultsPanel; if (scrollPanel) { scrollPanel.checkScroll(); @@ -844,7 +844,7 @@ module.exports = React.createClass({ searchResult={result} searchHighlights={this.state.searchHighlights} resultLink={resultLink} - onImageLoad={onImageLoad}/>); + onWidgetLoad={onWidgetLoad}/>); } return ret; }, diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index ff05cf8609..01cd7cc637 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -20,6 +20,7 @@ var React = require('react'); var filesize = require('filesize'); var MatrixClientPeg = require('../../../MatrixClientPeg'); +var ImageUtils = require('../../../ImageUtils'); var Modal = require('../../../Modal'); var sdk = require('../../../index'); var dis = require("../../../dispatcher"); @@ -32,29 +33,7 @@ module.exports = React.createClass({ mxEvent: React.PropTypes.object.isRequired, /* callback called when images in events are loaded */ - onImageLoad: React.PropTypes.func, - }, - - thumbHeight: function(fullWidth, fullHeight, thumbWidth, thumbHeight) { - if (!fullWidth || !fullHeight) { - // Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even - // log this because it's spammy - return undefined; - } - if (fullWidth < thumbWidth && fullHeight < thumbHeight) { - // no scaling needs to be applied - return fullHeight; - } - var widthMulti = thumbWidth / fullWidth; - var heightMulti = thumbHeight / fullHeight; - if (widthMulti < heightMulti) { - // width is the dominant dimension so scaling will be fixed on that - return Math.floor(widthMulti * fullHeight); - } - else { - // height is the dominant dimension so scaling will be fixed on that - return Math.floor(heightMulti * fullHeight); - } + onWidgetLoad: React.PropTypes.func, }, onClick: function onClick(ev) { @@ -134,7 +113,9 @@ module.exports = React.createClass({ // 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); + if (content.info) { + thumbHeight = ImageUtils.thumbHeight(content.info.w, content.info.h, timelineWidth, maxHeight); + } this.refs.image.style.height = thumbHeight + "px"; // console.log("Image height now", thumbHeight); }, @@ -152,8 +133,7 @@ module.exports = React.createClass({ {content.body} + onMouseLeave={this.onImageLeave} />
diff --git a/src/components/views/messages/MessageEvent.js b/src/components/views/messages/MessageEvent.js index 34d6d53924..48512dad22 100644 --- a/src/components/views/messages/MessageEvent.js +++ b/src/components/views/messages/MessageEvent.js @@ -39,7 +39,7 @@ module.exports = React.createClass({ highlightLink: React.PropTypes.string, /* callback called when images in events are loaded */ - onImageLoad: React.PropTypes.func, + onWidgetLoad: React.PropTypes.func, }, @@ -64,6 +64,6 @@ module.exports = React.createClass({ return ; + onWidgetLoad={this.props.onWidgetLoad} />; }, }); diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index d93b4bac9b..5a98119dac 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -38,6 +38,9 @@ module.exports = React.createClass({ /* link URL for the highlights */ highlightLink: React.PropTypes.string, + + /* callback for when our widget has loaded */ + onWidgetLoad: React.PropTypes.func, }, getInitialState: function() { @@ -88,7 +91,7 @@ module.exports = React.createClass({ var widget; if (this.state.link) { var LinkPreviewWidget = sdk.getComponent('rooms.LinkPreviewWidget'); - widget = ; + widget = ; } switch (content.msgtype) { diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index 8771afac36..08cefda67a 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -105,8 +105,8 @@ module.exports = React.createClass({ /* is this the focused event */ isSelectedEvent: React.PropTypes.bool, - /* callback called when images in events are loaded */ - onImageLoad: React.PropTypes.func, + /* callback called when dynamic content in events are loaded */ + onWidgetLoad: React.PropTypes.func, }, getInitialState: function() { @@ -345,7 +345,7 @@ module.exports = React.createClass({
+ onWidgetLoad={this.props.onWidgetLoad} />
); diff --git a/src/components/views/rooms/LinkPreviewWidget.js b/src/components/views/rooms/LinkPreviewWidget.js index d55d2e9a9d..3391745a9a 100644 --- a/src/components/views/rooms/LinkPreviewWidget.js +++ b/src/components/views/rooms/LinkPreviewWidget.js @@ -19,6 +19,7 @@ limitations under the License. var React = require('react'); var MatrixClientPeg = require('../../../MatrixClientPeg'); +var ImageUtils = require('../../../ImageUtils'); var linkify = require('linkifyjs'); var linkifyElement = require('linkifyjs/element'); @@ -29,7 +30,8 @@ module.exports = React.createClass({ displayName: 'LinkPreviewWidget', propTypes: { - link: React.PropTypes.string.isRequired + link: React.PropTypes.string.isRequired, + onWidgetLoad: React.PropTypes.func, }, getInitialState: function() { @@ -41,6 +43,7 @@ module.exports = React.createClass({ componentWillMount: function() { MatrixClientPeg.get().getUrlPreview(this.props.link).then((res)=>{ this.setState({ preview: res }); + this.props.onWidgetLoad(); }, (error)=>{ console.error("Failed to get preview for " + this.props.link + " " + error); }); @@ -59,13 +62,28 @@ module.exports = React.createClass({ render: function() { var p = this.state.preview; if (!p) return
; - var img = p["og:image"] - if (img && img.startsWith("mxc://")) img = MatrixClientPeg.get().mxcUrlToHttp(img, 100, 100) + + var image = p["og:image"]; + var imageMaxWidth = 100, imageMaxHeight = 100; + if (image && image.startsWith("mxc://")) { + image = MatrixClientPeg.get().mxcUrlToHttp(image, imageMaxWidth, imageMaxHeight); + } + + var thumbHeight = imageMaxHeight; + if (p["og:image:width"] && p["og:image:height"]) { + thumbHeight = ImageUtils.thumbHeight(p["og:image:width"], p["og:image:height"], imageMaxWidth, imageMaxHeight); + } + + var img; + if (image) { + img =
+ +
+ } + return ( -
-
- -
+
+ { img }
{ p["og:site_name"] ? (" - " + p["og:site_name"]) : null }
diff --git a/src/components/views/rooms/SearchResultTile.js b/src/components/views/rooms/SearchResultTile.js index 1fc0384433..7fac244481 100644 --- a/src/components/views/rooms/SearchResultTile.js +++ b/src/components/views/rooms/SearchResultTile.js @@ -32,7 +32,7 @@ module.exports = React.createClass({ // href for the highlights in this result resultLink: React.PropTypes.string, - onImageLoad: React.PropTypes.func, + onWidgetLoad: React.PropTypes.func, }, render: function() { @@ -56,7 +56,7 @@ module.exports = React.createClass({ if (EventTile.haveTileForEvent(ev)) { ret.push(); + onWidgetLoad={this.props.onWidgetLoad} />); } } return (