diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js
new file mode 100644
index 000000000..ff7af1214
--- /dev/null
+++ b/src/HtmlUtils.js
@@ -0,0 +1,79 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+
+var React = require('react');
+var sanitizeHtml = require('sanitize-html');
+
+var allowedAttributes = sanitizeHtml.defaults.allowedAttributes;
+allowedAttributes['font'] = ['color'];
+var sanitizeHtmlParams = {
+ allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'font', 'h1', 'h2' ]),
+ allowedAttributes: allowedAttributes,
+};
+
+module.exports = {
+ bodyToHtml: function(content, searchTerm) {
+ var originalBody = content.body;
+ var body;
+
+ if (searchTerm) {
+ var lastOffset = 0;
+ var bodyList = [];
+ var k = 0;
+ var offset;
+
+ // XXX: rather than searching for the search term in the body,
+ // we should be looking at the match delimiters returned by the FTS engine
+ if (content.format === "org.matrix.custom.html") {
+
+ var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
+ var safeSearchTerm = sanitizeHtml(searchTerm, sanitizeHtmlParams);
+ while ((offset = safeBody.indexOf(safeSearchTerm, lastOffset)) >= 0) {
+ // 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();
+ lastOffset = offset + safeSearchTerm.length;
+ }
+ bodyList.push();
+ }
+ else {
+ while ((offset = originalBody.indexOf(searchTerm, lastOffset)) >= 0) {
+ bodyList.push({ originalBody.substring(lastOffset, offset) });
+ bodyList.push({ searchTerm });
+ lastOffset = offset + searchTerm.length;
+ }
+ bodyList.push({ originalBody.substring(lastOffset) });
+ }
+ body = bodyList;
+ }
+ else {
+ if (content.format === "org.matrix.custom.html") {
+ var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
+ body = ;
+ }
+ else {
+ body = originalBody;
+ }
+ }
+
+ return body;
+ }
+}
+
diff --git a/src/skins/vector/views/molecules/MNoticeTile.js b/src/skins/vector/views/molecules/MNoticeTile.js
index a0cedb1dd..8d8c77927 100644
--- a/src/skins/vector/views/molecules/MNoticeTile.js
+++ b/src/skins/vector/views/molecules/MNoticeTile.js
@@ -17,67 +17,18 @@ limitations under the License.
'use strict';
var React = require('react');
-var sanitizeHtml = require('sanitize-html');
+var HtmlUtils = require('../../../../HtmlUtils');
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 :(
+ // XXX: fix horrible duplication with MTextTile
render: function() {
var content = this.props.mxEvent.getContent();
- var originalBody = content.body;
- var body;
-
- if (this.props.searchTerm) {
- var lastOffset = 0;
- var bodyList = [];
- var k = 0;
- var offset;
-
- // XXX: rather than searching for the search term in the body,
- // we should be looking at the match delimiters returned by the FTS engine
- if (content.format === "org.matrix.custom.html") {
- var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
- var safeSearchTerm = sanitizeHtml(this.props.searchTerm, sanitizeHtmlParams);
- while ((offset = safeBody.indexOf(safeSearchTerm, lastOffset)) >= 0) {
- // 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();
- lastOffset = offset + safeSearchTerm.length;
- }
- bodyList.push();
- }
- else {
- while ((offset = originalBody.indexOf(this.props.searchTerm, lastOffset)) >= 0) {
- bodyList.push({ originalBody.substring(lastOffset, offset) });
- bodyList.push({ this.props.searchTerm });
- lastOffset = offset + this.props.searchTerm.length;
- }
- bodyList.push({ originalBody.substring(lastOffset) });
- }
- body = bodyList;
- }
- else {
- if (content.format === "org.matrix.custom.html") {
- var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
- body = ;
- }
- else {
- body = originalBody;
- }
- }
+ var body = HtmlUtils.bodyToHtml(content, this.props.searchTerm);
return (
diff --git a/src/skins/vector/views/molecules/MTextTile.js b/src/skins/vector/views/molecules/MTextTile.js
index 12bafa37b..aa5291d79 100644
--- a/src/skins/vector/views/molecules/MTextTile.js
+++ b/src/skins/vector/views/molecules/MTextTile.js
@@ -17,67 +17,17 @@ limitations under the License.
'use strict';
var React = require('react');
-var sanitizeHtml = require('sanitize-html');
+var HtmlUtils = require('../../../../HtmlUtils');
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],
- // FIXME: this entire class is copy-pasted from MTextTile :(
render: function() {
var content = this.props.mxEvent.getContent();
- var originalBody = content.body;
- var body;
-
- if (this.props.searchTerm) {
- var lastOffset = 0;
- var bodyList = [];
- var k = 0;
- var offset;
-
- // XXX: rather than searching for the search term in the body,
- // we should be looking at the match delimiters returned by the FTS engine
- if (content.format === "org.matrix.custom.html") {
- var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
- var safeSearchTerm = sanitizeHtml(this.props.searchTerm, sanitizeHtmlParams);
- while ((offset = safeBody.indexOf(safeSearchTerm, lastOffset)) >= 0) {
- // 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();
- lastOffset = offset + safeSearchTerm.length;
- }
- bodyList.push();
- }
- else {
- while ((offset = originalBody.indexOf(this.props.searchTerm, lastOffset)) >= 0) {
- bodyList.push({ originalBody.substring(lastOffset, offset) });
- bodyList.push({ this.props.searchTerm });
- lastOffset = offset + this.props.searchTerm.length;
- }
- bodyList.push({ originalBody.substring(lastOffset) });
- }
- body = bodyList;
- }
- else {
- if (content.format === "org.matrix.custom.html") {
- var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
- body = ;
- }
- else {
- body = originalBody;
- }
- }
+ var body = HtmlUtils.bodyToHtml(content, this.props.searchTerm);
return (