Merge pull request #290 from matrix-org/matthew/multipreview

multiple URL preview support
This commit is contained in:
Matthew Hodgson 2016-05-31 19:42:21 +01:00
commit b74d690035

View File

@ -45,9 +45,9 @@ module.exports = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
// the URL (if any) to be previewed with a LinkPreviewWidget // the URLs (if any) to be previewed with a LinkPreviewWidget
// inside this TextualBody. // inside this TextualBody.
link: null, links: [],
// track whether the preview widget is hidden // track whether the preview widget is hidden
widgetHidden: false, widgetHidden: false,
@ -57,9 +57,11 @@ module.exports = React.createClass({
componentDidMount: function() { componentDidMount: function() {
linkifyElement(this.refs.content, linkifyMatrix.options); linkifyElement(this.refs.content, linkifyMatrix.options);
var link = this.findLink(this.refs.content.children); var links = this.findLinks(this.refs.content.children);
if (link) { if (links.length) {
this.setState({ link: link.getAttribute("href") }); this.setState({ links: links.map((link)=>{
return link.getAttribute("href");
})});
// lazy-load the hidden state of the preview widget from localstorage // lazy-load the hidden state of the preview widget from localstorage
if (global.localStorage) { if (global.localStorage) {
@ -74,27 +76,32 @@ module.exports = React.createClass({
shouldComponentUpdate: function(nextProps, nextState) { shouldComponentUpdate: function(nextProps, nextState) {
// exploit that events are immutable :) // exploit that events are immutable :)
// ...and that .links is only ever set in componentDidMount and never changes
return (nextProps.mxEvent.getId() !== this.props.mxEvent.getId() || return (nextProps.mxEvent.getId() !== this.props.mxEvent.getId() ||
nextProps.highlights !== this.props.highlights || nextProps.highlights !== this.props.highlights ||
nextProps.highlightLink !== this.props.highlightLink || nextProps.highlightLink !== this.props.highlightLink ||
nextState.link !== this.state.link || nextState.links !== this.state.links ||
nextState.widgetHidden !== this.state.widgetHidden); nextState.widgetHidden !== this.state.widgetHidden);
}, },
findLink: function(nodes) { findLinks: function(nodes) {
var links = [];
for (var i = 0; i < nodes.length; i++) { for (var i = 0; i < nodes.length; i++) {
var node = nodes[i]; var node = nodes[i];
if (node.tagName === "A" && node.getAttribute("href")) if (node.tagName === "A" && node.getAttribute("href"))
{ {
return this.isLinkPreviewable(node) ? node : undefined; if (this.isLinkPreviewable(node)) {
links.push(node);
}
} }
else if (node.tagName === "PRE" || node.tagName === "CODE") { else if (node.tagName === "PRE" || node.tagName === "CODE") {
return; continue;
} }
else if (node.children && node.children.length) { else if (node.children && node.children.length) {
return this.findLink(node.children) links = links.concat(this.findLinks(node.children));
} }
} }
return links;
}, },
isLinkPreviewable: function(node) { isLinkPreviewable: function(node) {
@ -160,14 +167,17 @@ module.exports = React.createClass({
{highlightLink: this.props.highlightLink}); {highlightLink: this.props.highlightLink});
var widget; var widgets;
if (this.state.link && !this.state.widgetHidden) { if (this.state.links.length && !this.state.widgetHidden) {
var LinkPreviewWidget = sdk.getComponent('rooms.LinkPreviewWidget'); var LinkPreviewWidget = sdk.getComponent('rooms.LinkPreviewWidget');
widget = <LinkPreviewWidget widgets = this.state.links.map((link)=>{
link={ this.state.link } return <LinkPreviewWidget
key={ link }
link={ link }
mxEvent={ this.props.mxEvent } mxEvent={ this.props.mxEvent }
onCancelClick={ this.onCancelClick } onCancelClick={ this.onCancelClick }
onWidgetLoad={ this.props.onWidgetLoad }/>; onWidgetLoad={ this.props.onWidgetLoad }/>;
});
} }
switch (content.msgtype) { switch (content.msgtype) {
@ -176,21 +186,21 @@ module.exports = React.createClass({
return ( return (
<span ref="content" className="mx_MEmoteBody mx_EventTile_content"> <span ref="content" className="mx_MEmoteBody mx_EventTile_content">
* { name } { body } * { name } { body }
{ widget } { widgets }
</span> </span>
); );
case "m.notice": case "m.notice":
return ( return (
<span ref="content" className="mx_MNoticeBody mx_EventTile_content"> <span ref="content" className="mx_MNoticeBody mx_EventTile_content">
{ body } { body }
{ widget } { widgets }
</span> </span>
); );
default: // including "m.text" default: // including "m.text"
return ( return (
<span ref="content" className="mx_MTextBody mx_EventTile_content"> <span ref="content" className="mx_MTextBody mx_EventTile_content">
{ body } { body }
{ widget } { widgets }
</span> </span>
); );
} }