Various fixes and improvements to emojification.

- Use locally hosted emoji
- Emojify SenderProfile and m.emote
- Add emoji shortcodes as titles
This commit is contained in:
Aviral Dasgupta 2016-08-09 21:40:05 +05:30
parent 4b8ad3c102
commit dbbea63227
5 changed files with 83 additions and 6 deletions

View file

@ -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 = `<img class="emojione" title="${title}" alt="${alt}" src="${emojione.imagePathSVG}${unicode}.svg${emojione.cacheBustParam}"/>`;
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)),
};

View file

@ -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');

View file

@ -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 (
<div className="mx_RoomStatusBar_typingBar">
{typingString}
<span dangerouslySetInnerHTML={typingHtml} />
</div>
);
}

View file

@ -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 <span />; // emote message must include the name so don't duplicate it
}
return (
<span className="mx_SenderProfile"
dangerouslySetInnerHTML={emojifyText(`${name || ''} ${props.aux || ''}`)}
onClick={props.onClick}>
</span>
);
}
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,
};

View file

@ -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 (
<span ref="content" className="mx_MEmoteBody mx_EventTile_content">
* { name } { body }
* <span dangerouslySetInnerHTML={nameHtml} /> { body }
{ widgets }
</span>
);