fix(emoji): Replace message emoji in DOM, not in html string

This commit is contained in:
Ben Gotow 2016-05-02 12:32:51 -07:00
parent 80f7cdab71
commit d9bdd90599
2 changed files with 63 additions and 5 deletions

View file

@ -1,14 +1,61 @@
/* eslint no-cond-assign:0 */
import {MessageViewExtension, RegExpUtils} from 'nylas-exports';
import EmojiStore from './emoji-store';
import emoji from 'node-emoji';
function makeIntoEmojiTag(node, emojiName) {
node.src = EmojiStore.getImagePath(emojiName);
node.className = `emoji ${emojiName}`;
node.width = 14;
node.height = 14;
node.style = '';
node.style.marginTop = '-5px';
}
class EmojiMessageExtension extends MessageViewExtension {
static formatMessageBody({message}) {
message.body = message.body.replace(RegExpUtils.emojiRegex(), (match) =>
`<img class="emoji ${emoji.which(match)}" src="${EmojiStore.getImagePath(emoji.which(match))}" width="14" height="14" style="margin-top: -5px;">`
);
static renderedMessageBodyIntoDocument({document}) {
const emojiRegex = RegExpUtils.emojiRegex();
// special case: Find outlook-style emoji, where it's an image with an emoji alt-text.
// <img alt="😊" class="EmojiInsert">
const emojiImageTags = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, {
acceptNode: (node) => {
if ((node.nodeName === 'IMG') && node.alt) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
},
});
while (emojiImageTags.nextNode()) {
const node = emojiImageTags.currentNode;
const emojiNameForAlt = emoji.which(node.alt);
if (emojiNameForAlt) {
makeIntoEmojiTag(node, emojiNameForAlt);
}
}
// general case: look for emoji in the content of text nodes
const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
while (treeWalker.nextNode()) {
emojiRegex.lastIndex = 0;
const node = treeWalker.currentNode;
let match = null;
while (match = emojiRegex.exec(node.textContent)) {
const matchEmojiName = emoji.which(match[0]);
if (matchEmojiName) {
const matchNode = (match.index === 0) ? node : node.splitText(match.index);
matchNode.splitText(match[0].length);
const imageNode = document.createElement('img');
makeIntoEmojiTag(imageNode, matchEmojiName);
matchNode.parentNode.replaceChild(imageNode, matchNode);
}
}
}
}
}

View file

@ -2,7 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import _ from "underscore";
import {EventedIFrame} from 'nylas-component-kit';
import {Utils, QuotedHTMLTransformer} from 'nylas-exports';
import {Utils, QuotedHTMLTransformer, MessageStore} from 'nylas-exports';
import {autolink} from './autolinker';
import {autoscaleImages} from './autoscale-images';
import EmailFrameStylesStore from './email-frame-styles-store';
@ -69,6 +69,17 @@ export default class EmailFrame extends React.Component {
autolink(doc, {async: true});
autoscaleImages(doc);
for (const extension of MessageStore.extensions()) {
if (!extension.renderedMessageBodyIntoDocument) {
continue;
}
try {
extension.renderedMessageBodyIntoDocument({document: doc});
} catch (e) {
NylasEnv.reportError(e);
}
}
// Notify the EventedIFrame that we've replaced it's document (with `open`)
// so it can attach event listeners again.
this.refs.iframe.didReplaceDocument();