From fdfa0cbd0e7683408ba6c7e861faa69e2ff6ecb3 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 30 Oct 2015 04:10:37 +0000 Subject: [PATCH] display search results correct; support HTML markup --- package.json | 3 +- src/skins/vector/css/molecules/EventTile.css | 11 ++++ src/skins/vector/css/molecules/MTextTile.css | 1 - src/skins/vector/views/molecules/EventTile.js | 5 +- .../vector/views/molecules/MNoticeTile.js | 51 ++++++++++++++++++- src/skins/vector/views/molecules/MTextTile.js | 50 +++++++++++++++++- .../vector/views/molecules/MessageTile.js | 2 +- 7 files changed, 116 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 275ef4c293..3cfbab52df 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "matrix-react-sdk": "^0.0.1", "q": "^1.4.1", "react": "^0.13.3", - "react-loader": "^1.4.0" + "react-loader": "^1.4.0", + "sanitize-html": "^1.11.1" }, "devDependencies": { "babel": "^5.8.23", diff --git a/src/skins/vector/css/molecules/EventTile.css b/src/skins/vector/css/molecules/EventTile.css index 3717ff54cb..eb59711e81 100644 --- a/src/skins/vector/css/molecules/EventTile.css +++ b/src/skins/vector/css/molecules/EventTile.css @@ -66,6 +66,13 @@ limitations under the License. margin-right: 100px; } +.mx_MessageTile_searchHighlight { + background-color: #76cfa6; + color: #fff; + border-radius: 5px; + padding: 4px; +} + .mx_EventTile_sending { color: #ddd; } @@ -78,6 +85,10 @@ limitations under the License. color: #FF0064; } +.mx_EventTile_contextual { + opacity: 0.4; +} + .mx_EventTile_msgOption { float: right; } diff --git a/src/skins/vector/css/molecules/MTextTile.css b/src/skins/vector/css/molecules/MTextTile.css index 5b117e41b8..96a9d1db48 100644 --- a/src/skins/vector/css/molecules/MTextTile.css +++ b/src/skins/vector/css/molecules/MTextTile.css @@ -17,4 +17,3 @@ limitations under the License. .mx_MTextTile { white-space: pre-wrap; } - diff --git a/src/skins/vector/views/molecules/EventTile.js b/src/skins/vector/views/molecules/EventTile.js index bdd5c57bc8..3be02a5df5 100644 --- a/src/skins/vector/views/molecules/EventTile.js +++ b/src/skins/vector/views/molecules/EventTile.js @@ -91,7 +91,8 @@ module.exports = React.createClass({ mx_EventTile_highlight: this.shouldHighlight(), mx_EventTile_continuation: this.props.continuation, mx_EventTile_last: this.props.last, - menu: this.state.menu + mx_EventTile_contextual: this.props.contextual, + menu: this.state.menu, }); var timestamp = var editButton = ( @@ -126,7 +127,7 @@ module.exports = React.createClass({
{ timestamp } { editButton } - +
); diff --git a/src/skins/vector/views/molecules/MNoticeTile.js b/src/skins/vector/views/molecules/MNoticeTile.js index aa88612784..e9ca85eab2 100644 --- a/src/skins/vector/views/molecules/MNoticeTile.js +++ b/src/skins/vector/views/molecules/MNoticeTile.js @@ -17,18 +17,67 @@ limitations under the License. 'use strict'; var React = require('react'); +var sanitizeHtml = require('sanitize-html'); var MNoticeTileController = require('matrix-react-sdk/lib/controllers/molecules/MNoticeTile') +var allowedAttributes = sanitizeHtml.defaults.allowedAttributes; +allowedAttributes['font'] = ['color']; +var sanitizeHtmlParams = { + allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'font' ]), + allowedAttributes: allowedAttributes, +}; + module.exports = React.createClass({ displayName: 'MNoticeTile', mixins: [MNoticeTileController], + // FIXME: this entire class is copy-pasted from MTextTile :( render: function() { var content = this.props.mxEvent.getContent(); + var body = content.body; + + if (content.format === "org.matrix.custom.html") { + body = sanitizeHtml(content.formatted_body, sanitizeHtmlParams); + } + + if (this.props.searchTerm) { + var lastOffset = 0; + var bodyList = []; + var k = 0; + var offset; + // XXX: this probably doesn't handle stemming very well. + while ((offset = body.indexOf(this.props.searchTerm, lastOffset)) >= 0) { + if (content.format === "org.matrix.custom.html") { + // FIXME: we need to apply the search highlighting to only the text elements of HTML, which means + // hooking into the sanitizer parser rather than treating it as a string. Otherwise + // the act of highlighting a or whatever will break the HTML badly. + bodyList.push(); + bodyList.push(); + } + else { + bodyList.push({ body.substring(lastOffset, offset) }); + bodyList.push({ this.props.searchTerm }); + } + lastOffset = offset + this.props.searchTerm.length; + } + if (content.format === "org.matrix.custom.html") { + bodyList.push(); + } + else { + bodyList.push({ body.substring(lastOffset) }); + } + body = bodyList; + } + else { + if (content.format === "org.matrix.custom.html") { + body = ; + } + } + return ( - {content.body} + { body } ); }, diff --git a/src/skins/vector/views/molecules/MTextTile.js b/src/skins/vector/views/molecules/MTextTile.js index 50555f949f..6e04088eb8 100644 --- a/src/skins/vector/views/molecules/MTextTile.js +++ b/src/skins/vector/views/molecules/MTextTile.js @@ -17,18 +17,66 @@ limitations under the License. 'use strict'; var React = require('react'); +var sanitizeHtml = require('sanitize-html'); var MTextTileController = require('matrix-react-sdk/lib/controllers/molecules/MTextTile') +var allowedAttributes = sanitizeHtml.defaults.allowedAttributes; +allowedAttributes['font'] = ['color']; +var sanitizeHtmlParams = { + allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'font' ]), + allowedAttributes: allowedAttributes, +}; + module.exports = React.createClass({ displayName: 'MTextTile', mixins: [MTextTileController], render: function() { var content = this.props.mxEvent.getContent(); + var body = content.body; + + if (content.format === "org.matrix.custom.html") { + body = sanitizeHtml(content.formatted_body, sanitizeHtmlParams); + } + + if (this.props.searchTerm) { + var lastOffset = 0; + var bodyList = []; + var k = 0; + var offset; + // XXX: this probably doesn't handle stemming very well. + while ((offset = body.indexOf(this.props.searchTerm, lastOffset)) >= 0) { + if (content.format === "org.matrix.custom.html") { + // FIXME: we need to apply the search highlighting to only the text elements of HTML, which means + // hooking into the sanitizer parser rather than treating it as a string. Otherwise + // the act of highlighting a or whatever will break the HTML badly. + bodyList.push(); + bodyList.push(); + } + else { + bodyList.push({ body.substring(lastOffset, offset) }); + bodyList.push({ this.props.searchTerm }); + } + lastOffset = offset + this.props.searchTerm.length; + } + if (content.format === "org.matrix.custom.html") { + bodyList.push(); + } + else { + bodyList.push({ body.substring(lastOffset) }); + } + body = bodyList; + } + else { + if (content.format === "org.matrix.custom.html") { + body = ; + } + } + return ( - {content.body} + { body } ); }, diff --git a/src/skins/vector/views/molecules/MessageTile.js b/src/skins/vector/views/molecules/MessageTile.js index 44f5b63564..4386c13fd1 100644 --- a/src/skins/vector/views/molecules/MessageTile.js +++ b/src/skins/vector/views/molecules/MessageTile.js @@ -52,6 +52,6 @@ module.exports = React.createClass({ TileType = tileTypes[msgtype]; } - return ; + return ; }, });