diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 2ab635081f..c0792e6d14 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -24,8 +24,39 @@ import escape from 'lodash/escape'; import emojione from 'emojione'; import classNames from 'classnames'; +emojione.imagePathSVG = 'emojione/svg/'; +emojione.imageType = 'svg'; + const EMOJI_REGEX = new RegExp(emojione.unicodeRegexp+"+", "gi"); +/* modified from https://github.com/Ranks/emojione/blob/master/lib/js/emojione.js + * because we want to include emoji shortnames in title text + */ +export function unicodeToImage(str) { + let replaceWith, unicode, alt; + const mappedUnicode = emojione.mapUnicodeToShort(); + + str = str.replace(emojione.regUnicode, function(unicodeChar) { + if ( (typeof unicodeChar === 'undefined') || (unicodeChar === '') || (!(unicodeChar in emojione.jsEscapeMap)) ) { + // if the unicodeChar doesnt exist just return the entire match + return unicodeChar; + } + else { + // get the unicode codepoint from the actual char + unicode = emojione.jsEscapeMap[unicodeChar]; + + // depending on the settings, we'll either add the native unicode as the alt tag, otherwise the shortname + alt = (emojione.unicodeAlt) ? emojione.convert(unicode.toUpperCase()) : mappedUnicode[unicode]; + const title = mappedUnicode[unicode]; + + replaceWith = `${alt}`; + return replaceWith; + } + }); + + return str; +}; + var sanitizeHtmlParams = { allowedTags: [ 'font', // custom to matrix for IRC-style font coloring @@ -211,8 +242,7 @@ module.exports = { }; } safeBody = sanitizeHtml(body, sanitizeHtmlParams); - emojione.imageType = 'svg'; - safeBody = emojione.unicodeToImage(safeBody); + safeBody = unicodeToImage(safeBody); } finally { delete sanitizeHtmlParams.textFilter; @@ -239,7 +269,6 @@ module.exports = { }, emojifyText: function(text) { - emojione.imageType = 'svg'; return { __html: emojione.unicodeToImage(escape(text)), }; diff --git a/src/component-index.js b/src/component-index.js index 97f8882b82..d4bf2a7aab 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -72,6 +72,7 @@ module.exports.components['views.messages.MFileBody'] = require('./components/vi module.exports.components['views.messages.MImageBody'] = require('./components/views/messages/MImageBody'); module.exports.components['views.messages.MVideoBody'] = require('./components/views/messages/MVideoBody'); module.exports.components['views.messages.MessageEvent'] = require('./components/views/messages/MessageEvent'); +module.exports.components['views.messages.SenderProfile'] = require('./components/views/messages/SenderProfile'); module.exports.components['views.messages.TextualBody'] = require('./components/views/messages/TextualBody'); module.exports.components['views.messages.TextualEvent'] = require('./components/views/messages/TextualEvent'); module.exports.components['views.messages.UnknownBody'] = require('./components/views/messages/UnknownBody'); diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js index 9a0d3dbbdd..245117387e 100644 --- a/src/components/structures/RoomStatusBar.js +++ b/src/components/structures/RoomStatusBar.js @@ -19,6 +19,7 @@ var sdk = require('../../index'); var dis = require("../../dispatcher"); var WhoIsTyping = require("../../WhoIsTyping"); var MatrixClientPeg = require("../../MatrixClientPeg"); +import {emojifyText} from '../../HtmlUtils'; module.exports = React.createClass({ displayName: 'RoomStatusBar', @@ -259,10 +260,11 @@ module.exports = React.createClass({ } var typingString = this.state.whoisTypingString; + const typingHtml = emojifyText(typingString); if (typingString) { return (
- {typingString} +
); } diff --git a/src/components/views/messages/SenderProfile.js b/src/components/views/messages/SenderProfile.js new file mode 100644 index 0000000000..e331e9843c --- /dev/null +++ b/src/components/views/messages/SenderProfile.js @@ -0,0 +1,43 @@ +/* + Copyright 2015, 2016 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'; + +import React from 'react'; +import {emojifyText} from '../../../HtmlUtils'; + +export default function SenderProfile(props) { + const {mxEvent} = props; + const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); + const {msgtype} = mxEvent.getContent(); + + if (msgtype === 'm.emote') { + return ; // emote message must include the name so don't duplicate it + } + + return ( + + + ); +} + +SenderProfile.propTypes = { + mxEvent: React.PropTypes.object.isRequired, // event whose sender we're showing + aux: React.PropTypes.string, // stuff to go after the sender name, if anything + onClick: React.PropTypes.func, +}; diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 8c6cf455dc..3c5d173e33 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -23,6 +23,7 @@ var linkify = require('linkifyjs'); var linkifyElement = require('linkifyjs/element'); var linkifyMatrix = require('../../../linkify-matrix'); var sdk = require('../../../index'); +import {emojifyText} from '../../../HtmlUtils'; linkifyMatrix(linkify); @@ -200,10 +201,11 @@ module.exports = React.createClass({ switch (content.msgtype) { case "m.emote": - var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); + const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); + const nameHtml = emojifyText(name); return ( - * { name } { body } + * { body } { widgets } );