add basic spoiler support

pull/21833/head
Sorunome 2019-05-22 20:41:27 +02:00
parent 8844706e5f
commit d8f4512439
No known key found for this signature in database
GPG Key ID: 63E31F7B5993A9C4
4 changed files with 90 additions and 1 deletions

View File

@ -280,6 +280,33 @@ limitations under the License.
overflow-y: hidden;
}
/* Spoiler stuff */
.mx_EventTile_spoiler {
cursor: pointer;
}
.mx_EventTile_spoiler_reason {
color: $event-timestamp-color;
font-size: 11px;
}
.mx_EventTile_spoiler_content {
background-color: black;
}
.mx_EventTile_spoiler_content > span {
visibility: hidden;
}
.mx_EventTile_spoiler.visible > .mx_EventTile_spoiler_content {
background-color: initial;
}
.mx_EventTile_spoiler.visible > .mx_EventTile_spoiler_content > span {
visibility: visible;
}
/* End to end encryption stuff */
.mx_EventTile:hover .mx_EventTile_e2eIcon {
opacity: 1;

View File

@ -250,7 +250,7 @@ const sanitizeHtmlParams = {
allowedAttributes: {
// custom ones first:
font: ['color', 'data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
span: ['data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
span: ['data-mx-bg-color', 'data-mx-color', 'data-mx-spoiler', 'style'], // custom to matrix
a: ['href', 'name', 'target', 'rel'], // remote target: custom to matrix
img: ['src', 'width', 'height', 'alt', 'title'],
ol: ['start'],

View File

@ -0,0 +1,32 @@
'use strict';
import React from 'react';
module.exports = React.createClass({
displayName: 'Spoiler',
getInitialState() {
return {
visible: false,
};
},
toggleVisible() {
this.setState({ visible: !this.state.visible });
},
render: function() {
const reason = this.props.reason ? (
<span className="mx_EventTile_spoiler_reason">{"(" + this.props.reason + ")"}</span>
) : null;
return (
<span className={"mx_EventTile_spoiler" + (this.state.visible ? " visible" : "")} onClick={this.toggleVisible.bind(this)}>
{ reason }
&nbsp;
<span className="mx_EventTile_spoiler_content">
<span dangerouslySetInnerHTML={{ __html: this.props.contentHtml }} />
</span>
</span>
);
}
})

View File

@ -96,6 +96,8 @@ module.exports = React.createClass({
},
_applyFormatting() {
this.activateSpoilers(this.refs.content.children);
// pillifyLinks BEFORE linkifyElement because plain room/user URLs in the composer
// are still sent as plaintext URLs. If these are ever pillified in the composer,
// we should be pillify them here by doing the linkifying BEFORE the pillifying.
@ -184,6 +186,34 @@ module.exports = React.createClass({
}
},
activateSpoilers: function(nodes) {
let node = nodes[0];
while (node) {
if (node.tagName === "SPAN" && typeof node.getAttribute("data-mx-spoiler") === "string") {
const spoilerContainer = document.createElement('span');
const reason = node.getAttribute("data-mx-spoiler");
const Spoiler = sdk.getComponent('elements.Spoiler');
node.removeAttribute("data-mx-spoiler"); // we don't want to recurse
const spoiler = <Spoiler
reason={reason}
contentHtml={node.outerHTML}
/>;
ReactDOM.render(spoiler, spoilerContainer);
node.parentNode.replaceChild(spoilerContainer, node);
node = spoilerContainer;
}
if (node.childNodes && node.childNodes.length) {
this.activateSpoilers(node.childNodes);
}
node = node.nextSibling;
}
},
pillifyLinks: function(nodes) {
const shouldShowPillAvatar = SettingsStore.getValue("Pill.shouldShowPillAvatar");
let node = nodes[0];