mirror of https://github.com/zulip/zulip.git
emoji: Migrate bugdown emoji to use sprite sheets.
This commit switches to use sprite sheets for rendering emojis in all the remaining places, i.e., message bodies and composebox typeahead. This commit also includes some changes to notifications.py file so that the spans used for rendering emojis can be converted to corresponding image tags so that we don't break the emoji rendering in missed message emails since we can't use sprite sheets there. As part of switching the bugdown system to use sprite sheets, we need to switch the name_to_codepoint mappings to match the new sprite sheets. This has the side effect of fixing a bunch of emoji like numbers and flag emoji in the emoji pickers. Fixes: #3895. Fixes: #3972.
This commit is contained in:
parent
d3bfc132fb
commit
5b5bcce098
|
@ -44,7 +44,10 @@ set_global('$', global.make_zjquery());
|
|||
set_global('page_params', {});
|
||||
set_global('channel', {});
|
||||
|
||||
set_global('emoji', {emojis: emoji_list});
|
||||
set_global('emoji', {
|
||||
active_realm_emojis: {},
|
||||
emojis: emoji_list,
|
||||
});
|
||||
set_global('pygments_data', {langs:
|
||||
{python: 0, javscript: 1, html: 2, css: 3},
|
||||
});
|
||||
|
@ -832,14 +835,13 @@ global.people.add(deactivated_user);
|
|||
|
||||
(function test_content_highlighter() {
|
||||
var fake_this = { completing: 'emoji' };
|
||||
var item = { emoji_name: 'person shrugging', emoji_url: '¯\_(ツ)_/¯' };
|
||||
var emoji = { emoji_name: 'person shrugging', emoji_url: '¯\_(ツ)_/¯' };
|
||||
var th_render_typeahead_item_called = false;
|
||||
typeahead_helper.render_typeahead_item = function (item) {
|
||||
assert.equal(item.primary, 'person shrugging');
|
||||
assert.equal(item.img_src, '¯\_(ツ)_/¯');
|
||||
typeahead_helper.render_emoji = function (item) {
|
||||
assert.deepEqual(item, emoji);
|
||||
th_render_typeahead_item_called = true;
|
||||
};
|
||||
ct.content_highlighter.call(fake_this, item);
|
||||
ct.content_highlighter.call(fake_this, emoji);
|
||||
|
||||
fake_this = { completing: 'mention' };
|
||||
var th_render_person_called = false;
|
||||
|
|
|
@ -229,9 +229,9 @@ var bugdown_data = JSON.parse(fs.readFileSync(path.join(__dirname, '../../zerver
|
|||
{input: 'mmm...:burrito:s',
|
||||
expected: '<p>mmm...<img alt=":burrito:" class="emoji" src="/static/generated/emoji/images/emoji/burrito.png" title="burrito">s</p>'},
|
||||
{input: 'This is an :poop: message',
|
||||
expected: '<p>This is an <img alt=":poop:" class="emoji" src="/static/generated/emoji/images/emoji/unicode/1f4a9.png" title="poop"> message</p>'},
|
||||
expected: '<p>This is an <span class="emoji emoji-1f4a9" title="poop">:poop:</span> message</p>'},
|
||||
{input: "\ud83d\udca9",
|
||||
expected: '<p><img alt=":poop:" class="emoji" src="/static/generated/emoji/images/emoji/unicode/1f4a9.png" title="poop"></p>'},
|
||||
expected: '<p><span class="emoji emoji-1f4a9" title="poop">:poop:</span></p>'},
|
||||
{input: '\u{1f937}',
|
||||
expected: '<p>\u{1f937}</p>' },
|
||||
// Test only those realm filters which don't return True for
|
||||
|
|
|
@ -38,6 +38,12 @@ set_global('page_params', {user_id: 5});
|
|||
|
||||
set_global('channel', {});
|
||||
set_global('templates', {});
|
||||
set_global('emoji_codes', {
|
||||
name_to_codepoint: {
|
||||
alien: '1f47d',
|
||||
smile: '1f604',
|
||||
},
|
||||
});
|
||||
set_global('emoji_picker', {
|
||||
hide_emoji_popover: function () {},
|
||||
});
|
||||
|
|
|
@ -1176,6 +1176,7 @@ function render(template_name, args) {
|
|||
primary: 'primary-text',
|
||||
secondary: 'secondary-text',
|
||||
img_src: 'https://zulip.org',
|
||||
is_emoji: true,
|
||||
has_image: true,
|
||||
has_secondary: true,
|
||||
};
|
||||
|
|
|
@ -441,6 +441,57 @@ _.each(matches, function (person) {
|
|||
assert(rendered);
|
||||
}());
|
||||
|
||||
(function test_render_emoji() {
|
||||
// Test render_emoji with normal emoji.
|
||||
var rendered = false;
|
||||
var emoji = {
|
||||
emoji_name: 'thumbs_up',
|
||||
codepoint: '1f44d',
|
||||
};
|
||||
set_global('emoji', {
|
||||
active_realm_emojis: {
|
||||
realm_emoji: 'TBD',
|
||||
},
|
||||
});
|
||||
|
||||
global.templates.render = function (template_name, args) {
|
||||
assert.equal(template_name, 'typeahead_list_item');
|
||||
assert.deepEqual(args, {
|
||||
primary: 'thumbs up',
|
||||
codepoint: '1f44d',
|
||||
is_emoji: true,
|
||||
has_image: false,
|
||||
has_secondary: false,
|
||||
});
|
||||
rendered = true;
|
||||
return 'typeahead-item-stub';
|
||||
};
|
||||
assert.equal(th.render_emoji(emoji), 'typeahead-item-stub');
|
||||
assert(rendered);
|
||||
|
||||
// Test render_emoji with normal emoji.
|
||||
rendered = false;
|
||||
emoji = {
|
||||
emoji_name: 'realm_emoji',
|
||||
emoji_url: 'TBD',
|
||||
};
|
||||
|
||||
global.templates.render = function (template_name, args) {
|
||||
assert.equal(template_name, 'typeahead_list_item');
|
||||
assert.deepEqual(args, {
|
||||
primary: 'realm emoji',
|
||||
img_src: 'TBD',
|
||||
is_emoji: true,
|
||||
has_image: true,
|
||||
has_secondary: false,
|
||||
});
|
||||
rendered = true;
|
||||
return 'typeahead-item-stub';
|
||||
};
|
||||
assert.equal(th.render_emoji(emoji), 'typeahead-item-stub');
|
||||
assert(rendered);
|
||||
}());
|
||||
|
||||
(function test_sort_emojis() {
|
||||
var emoji_list = [
|
||||
{ emoji_name: '+1' },
|
||||
|
|
|
@ -314,10 +314,7 @@ exports.compose_content_begins_typeahead = function (query) {
|
|||
|
||||
exports.content_highlighter = function (item) {
|
||||
if (this.completing === 'emoji') {
|
||||
return typeahead_helper.render_typeahead_item({
|
||||
primary: item.emoji_name.split("_").join(" "),
|
||||
img_src: item.emoji_url,
|
||||
});
|
||||
return typeahead_helper.render_emoji(item);
|
||||
} else if (this.completing === 'mention') {
|
||||
return typeahead_helper.render_person(item);
|
||||
} else if (this.completing === 'stream') {
|
||||
|
|
|
@ -71,8 +71,7 @@ exports.initialize = function initialize() {
|
|||
_.each(emoji_codes.names, function (value) {
|
||||
var base_name = emoji_codes.name_to_codepoint[value];
|
||||
default_emojis.push({emoji_name: value,
|
||||
codepoint: emoji_codes.name_to_codepoint[value],
|
||||
emoji_url: "/static/generated/emoji/images/emoji/unicode/" + base_name + ".png"});
|
||||
codepoint: emoji_codes.name_to_codepoint[value]});
|
||||
|
||||
if (exports.default_emoji_aliases.hasOwnProperty(base_name)) {
|
||||
exports.default_emoji_aliases[base_name].push(value);
|
||||
|
@ -82,8 +81,7 @@ exports.initialize = function initialize() {
|
|||
});
|
||||
_.each(emoji_codes.codepoints, function (value) {
|
||||
default_unicode_emojis.push({emoji_name: value,
|
||||
codepoint: value,
|
||||
emoji_url: "/static/generated/emoji/images/emoji/unicode/" + value + ".png"});
|
||||
codepoint: value});
|
||||
});
|
||||
|
||||
exports.update_emojis(page_params.realm_emoji);
|
||||
|
|
|
@ -117,35 +117,33 @@ function escape(html, encode) {
|
|||
}
|
||||
|
||||
function handleUnicodeEmoji(unicode_emoji) {
|
||||
var hex_value = unicode_emoji.codePointAt(0).toString(16);
|
||||
if (emoji.emojis_by_unicode.hasOwnProperty(hex_value)) {
|
||||
var emoji_url = emoji.emojis_by_unicode[hex_value];
|
||||
var emoji_name = emoji_codes.codepoint_to_name[hex_value];
|
||||
var codepoint = unicode_emoji.codePointAt(0).toString(16);
|
||||
if (emoji_codes.codepoint_to_name.hasOwnProperty(codepoint)) {
|
||||
var emoji_name = emoji_codes.codepoint_to_name[codepoint];
|
||||
var alt_text = ':' + emoji_name + ':';
|
||||
var title = emoji_name.split("_").join(" ");
|
||||
return '<img alt="' + alt_text + '"' +
|
||||
' class="emoji" src="' + emoji_url + '"' +
|
||||
' title="' + title + '">';
|
||||
return '<span class="emoji emoji-' + codepoint + '"' +
|
||||
' title="' + title + '">' + alt_text +
|
||||
'</span>';
|
||||
}
|
||||
return unicode_emoji;
|
||||
}
|
||||
|
||||
function handleEmoji(emoji_name) {
|
||||
var input_emoji = ':' + emoji_name + ':';
|
||||
var alt_text = ':' + emoji_name + ':';
|
||||
var title = emoji_name.split("_").join(" ");
|
||||
var emoji_url;
|
||||
if (emoji.active_realm_emojis.hasOwnProperty(emoji_name)) {
|
||||
emoji_url = emoji.active_realm_emojis[emoji_name].emoji_url;
|
||||
return '<img alt="' + input_emoji + '"' +
|
||||
' class="emoji" src="' + emoji_url + '"' +
|
||||
' title="' + title + '">';
|
||||
} else if (emoji.emojis_by_name.hasOwnProperty(emoji_name)) {
|
||||
emoji_url = emoji.emojis_by_name[emoji_name];
|
||||
return '<img alt="' + input_emoji + '"' +
|
||||
var emoji_url = emoji.active_realm_emojis[emoji_name].emoji_url;
|
||||
return '<img alt="' + alt_text + '"' +
|
||||
' class="emoji" src="' + emoji_url + '"' +
|
||||
' title="' + title + '">';
|
||||
} else if (emoji_codes.name_to_codepoint.hasOwnProperty(emoji_name)) {
|
||||
var codepoint = emoji_codes.name_to_codepoint[emoji_name];
|
||||
return '<span class="emoji emoji-' + codepoint + '"' +
|
||||
' title="' + title + '">' + alt_text +
|
||||
'</span>';
|
||||
}
|
||||
return input_emoji;
|
||||
return alt_text;
|
||||
}
|
||||
|
||||
function handleAvatar(email) {
|
||||
|
|
|
@ -14,7 +14,7 @@ exports.open_reactions_popover = function () {
|
|||
};
|
||||
|
||||
function send_reaction_ajax(message_id, emoji_name, operation) {
|
||||
if (!emoji.emojis_by_name[emoji_name] && !emoji.active_realm_emojis[emoji_name]) {
|
||||
if (!emoji_codes.name_to_codepoint[emoji_name] && !emoji.active_realm_emojis[emoji_name]) {
|
||||
// Emoji doesn't exist
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -114,6 +114,19 @@ exports.render_stream = function (stream) {
|
|||
return html;
|
||||
};
|
||||
|
||||
exports.render_emoji = function (item) {
|
||||
var args = {
|
||||
is_emoji: true,
|
||||
primary: item.emoji_name.split("_").join(" "),
|
||||
};
|
||||
if (emoji.active_realm_emojis.hasOwnProperty(item.emoji_name)) {
|
||||
args.img_src = item.emoji_url;
|
||||
} else {
|
||||
args.codepoint = item.codepoint;
|
||||
}
|
||||
return exports.render_typeahead_item(args);
|
||||
};
|
||||
|
||||
exports.sorter = function (query, objs, get_item) {
|
||||
var results = util.prefix_sort(query, objs, get_item);
|
||||
return results.matches.concat(results.rest);
|
||||
|
|
|
@ -14,7 +14,7 @@ exports.actively_scrolling = function () {
|
|||
|
||||
exports.replace_emoji_with_text = function (element) {
|
||||
element.find(".emoji").replaceWith(function () {
|
||||
return $(this).attr("alt");
|
||||
return $(this).text();
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
{{#if is_emoji}}
|
||||
{{#if has_image}}
|
||||
<img class="emoji" src="{{ img_src }}" />
|
||||
{{else}}
|
||||
<span class='emoji emoji-{{ codepoint }}' />
|
||||
{{/if}}
|
||||
|
||||
{{/if~}}
|
||||
{{/if}}
|
||||
<strong>
|
||||
{{~ primary ~}}
|
||||
</strong>
|
||||
|
|
|
@ -216,12 +216,13 @@ def generate_map_files(cache_path, emoji_map, emoji_data, emoji_catalog, unified
|
|||
if name in emoji_map:
|
||||
patched_css_classes[str(name)] = str(emoji['unified'].lower())
|
||||
|
||||
name_to_codepoint = {name: unified_reactions_data[name] for name in names}
|
||||
codepoint_to_name = generate_codepoint_to_name_map(names, unified_reactions_data)
|
||||
|
||||
emoji_codes_file.write(EMOJI_CODES_FILE_TEMPLATE % {
|
||||
'names': names,
|
||||
'codepoints': sorted([str(code_point) for code_point in set(emoji_map.values())]),
|
||||
'name_to_codepoint': {str(key): str(emoji_map[key]) for key in emoji_map},
|
||||
'name_to_codepoint': name_to_codepoint,
|
||||
'codepoint_to_name': codepoint_to_name,
|
||||
'emoji_catalog': emoji_catalog,
|
||||
'patched_css_classes': patched_css_classes
|
||||
|
@ -231,7 +232,7 @@ def generate_map_files(cache_path, emoji_map, emoji_data, emoji_catalog, unified
|
|||
NAME_TO_CODEPOINT_PATH = os.path.join(cache_path, 'name_to_codepoint.json')
|
||||
name_to_codepoint_file = open(NAME_TO_CODEPOINT_PATH, 'w')
|
||||
|
||||
name_to_codepoint_file.write(ujson.dumps(emoji_map))
|
||||
name_to_codepoint_file.write(ujson.dumps(name_to_codepoint))
|
||||
name_to_codepoint_file.close()
|
||||
|
||||
CODEPOINT_TO_NAME_PATH = os.path.join(cache_path, 'codepoint_to_name.json')
|
||||
|
|
|
@ -243,13 +243,13 @@
|
|||
{
|
||||
"name": "many_emoji",
|
||||
"input": "test :smile: again :poop:\n:) foo:)bar x::y::z :wasted waste: :fakeemojithisshouldnotrender:",
|
||||
"expected_output": "<p>test <img alt=\":smile:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f604.png\" title=\"smile\"> again <img alt=\":poop:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f4a9.png\" title=\"poop\"><br>\n:) foo:)bar x::y::z :wasted waste: :fakeemojithisshouldnotrender:</p>",
|
||||
"expected_output": "<p>test <span class=\"emoji emoji-1f604\" title=\"smile\">:smile:</span> again <span class=\"emoji emoji-1f4a9\" title=\"poop\">:poop:</span><br>\n:) foo:)bar x::y::z :wasted waste: :fakeemojithisshouldnotrender:</p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "random_emoji_1",
|
||||
"input": ":airplane:",
|
||||
"expected_output": "<p><img alt=\":airplane:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/2708.png\" title=\"airplane\"></p>",
|
||||
"expected_output": "<p><span class=\"emoji emoji-2708\" title=\"airplane\">:airplane:</span></p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
|
@ -261,19 +261,19 @@
|
|||
{
|
||||
"name": "random_emoji_2",
|
||||
"input": ":poop:",
|
||||
"expected_output": "<p><img alt=\":poop:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f4a9.png\" title=\"poop\"></p>",
|
||||
"expected_output": "<p><span class=\"emoji emoji-1f4a9\" title=\"poop\">:poop:</span></p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "emojis_without_space",
|
||||
"input": ":cat:hello:dog::rabbit:",
|
||||
"expected_output": "<p><img alt=\":cat:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f408.png\" title=\"cat\">hello<img alt=\":dog:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f415.png\" title=\"dog\"><img alt=\":rabbit:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f407.png\" title=\"rabbit\"></p>",
|
||||
"expected_output": "<p><span class=\"emoji emoji-1f431\" title=\"cat\">:cat:</span>hello<span class=\"emoji emoji-1f436\" title=\"dog\">:dog:</span><span class=\"emoji emoji-1f430\" title=\"rabbit\">:rabbit:</span></p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "emojis_newline",
|
||||
"input": ":cat:\n:dog:",
|
||||
"expected_output": "<p><img alt=\":cat:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f408.png\" title=\"cat\"><br>\n<img alt=\":dog:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f415.png\" title=\"dog\"></p>",
|
||||
"expected_output": "<p><span class=\"emoji emoji-1f431\" title=\"cat\">:cat:</span><br>\n<span class=\"emoji emoji-1f436\" title=\"dog\">:dog:</span></p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
|
@ -285,61 +285,61 @@
|
|||
{
|
||||
"name": "unicode_emoji",
|
||||
"input": "\ud83d\udca9",
|
||||
"expected_output":"<p><img alt=\":poop:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f4a9.png\" title=\"poop\"><\/p>",
|
||||
"expected_output":"<p><span class=\"emoji emoji-1f4a9\" title=\"poop\">:poop:</span></p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "two_unicode_emoji",
|
||||
"input": "\ud83d\udca9\ud83d\udca9",
|
||||
"expected_output":"<p><img alt=\":poop:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f4a9.png\" title=\"poop\"><img alt=\":poop:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f4a9.png\" title=\"poop\"><\/p>",
|
||||
"expected_output":"<p><span class=\"emoji emoji-1f4a9\" title=\"poop\">:poop:</span><span class=\"emoji emoji-1f4a9\" title=\"poop\">:poop:</span><\/p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "two_unicode_emoji_separated_by_text",
|
||||
"input": "\ud83d\udca9 word \ud83d\udca9",
|
||||
"expected_output":"<p><img alt=\":poop:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f4a9.png\" title=\"poop\"> word <img alt=\":poop:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f4a9.png\" title=\"poop\"><\/p>",
|
||||
"expected_output":"<p><span class=\"emoji emoji-1f4a9\" title=\"poop\">:poop:</span> word <span class=\"emoji emoji-1f4a9\" title=\"poop\">:poop:</span><\/p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "miscellaneous_symbols_and_pictographs",
|
||||
"input": "Merry Christmas!!\ud83c\udf84",
|
||||
"expected_output":"<p>Merry Christmas!!<img alt=\":christmas_tree:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f384.png\" title=\"christmas tree\"><\/p>",
|
||||
"expected_output":"<p>Merry Christmas!!<span class=\"emoji emoji-1f384\" title=\"christmas tree\">:christmas_tree:</span><\/p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "miscellaneous_and_dingbats_emoji",
|
||||
"input": "\u2693\u2797",
|
||||
"expected_output":"<p><img alt=\":anchor:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/2693.png\" title=\"anchor\"><img alt=\":heavy_division_sign:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/2797.png\" title=\"heavy division sign\"><\/p>",
|
||||
"expected_output":"<p><span class=\"emoji emoji-2693\" title=\"anchor\">:anchor:</span><span class=\"emoji emoji-2797\" title=\"heavy division sign\">:heavy_division_sign:</span><\/p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "supplemental_symbols_and_pictographs",
|
||||
"input": "I am a robot \ud83e\udd16.",
|
||||
"expected_output":"<p>I am a robot <img alt=\":robot_face:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f916.png\" title=\"robot face\">.<\/p>",
|
||||
"expected_output":"<p>I am a robot <span class=\"emoji emoji-1f916\" title=\"robot face\">:robot_face:</span>.<\/p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "miscellaneous_symbols_and_arrows",
|
||||
"input": "Black upward arrow \u2b06",
|
||||
"expected_output":"<p>Black upward arrow <img alt=\":arrow_up:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/2b06.png\" title=\"arrow up\"><\/p>",
|
||||
"expected_output":"<p>Black upward arrow <span class=\"emoji emoji-2b06\" title=\"arrow up\">:arrow_up:</span><\/p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "unicode_emoji_without_space",
|
||||
"input": "Extra\ud83d\udc7dTerrestrial",
|
||||
"expected_output":"<p>Extra<img alt=\":alien:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f47d.png\" title=\"alien\">Terrestrial<\/p>",
|
||||
"expected_output":"<p>Extra<span class=\"emoji emoji-1f47d\" title=\"alien\">:alien:</span>Terrestrial<\/p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "unicode_emojis_new_line",
|
||||
"input": "\ud83d\udc7d\n\ud83d\udc7d",
|
||||
"expected_output":"<p><img alt=\":alien:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f47d.png\" title=\"alien\"><br>\n<img alt=\":alien:\" class=\"emoji\" src=\"\/static\/generated\/emoji\/images\/emoji\/unicode\/1f47d.png\" title=\"alien\"><\/p>",
|
||||
"expected_output":"<p><span class=\"emoji emoji-1f47d\" title=\"alien\">:alien:</span><br>\n<span class=\"emoji emoji-1f47d\" title=\"alien\">:alien:</span></p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
"name": "emoji_alongside_punctuation",
|
||||
"input": ":smile:, :smile:; :smile:",
|
||||
"expected_output": "<p><img alt=\":smile:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f604.png\" title=\"smile\">, <img alt=\":smile:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f604.png\" title=\"smile\">; <img alt=\":smile:\" class=\"emoji\" src=\"/static/generated/emoji/images/emoji/unicode/1f604.png\" title=\"smile\"></p>",
|
||||
"expected_output": "<p><span class=\"emoji emoji-1f604\" title=\"smile\">:smile:</span>, <span class=\"emoji emoji-1f604\" title=\"smile\">:smile:</span>; <span class=\"emoji emoji-1f604\" title=\"smile\">:smile:</span></p>",
|
||||
"bugdown_matches_marked": true
|
||||
},
|
||||
{
|
||||
|
|
|
@ -802,16 +802,13 @@ unicode_emoji_regex = u'(?P<syntax>['\
|
|||
|
||||
def make_emoji(codepoint, display_string):
|
||||
# type: (Text, Text) -> Element
|
||||
src = '/static/generated/emoji/images/emoji/unicode/%s.png' % (codepoint,)
|
||||
# Replace underscore in emoji's title with space
|
||||
title = display_string[1:-1].replace("_", " ")
|
||||
|
||||
elt = markdown.util.etree.Element('img')
|
||||
elt.set('src', src)
|
||||
elt.set('class', 'emoji')
|
||||
elt.set("alt", display_string)
|
||||
elt.set("title", title)
|
||||
return elt
|
||||
span = markdown.util.etree.Element('span')
|
||||
span.set('class', 'emoji emoji-%s' % (codepoint,))
|
||||
span.set('title', title)
|
||||
span.text = display_string
|
||||
return span
|
||||
|
||||
def make_realm_emoji(src, display_string):
|
||||
# type: (Text, Text) -> Element
|
||||
|
|
|
@ -89,11 +89,10 @@ def relative_to_full_url(base_url, content):
|
|||
content = re.sub(
|
||||
r"<img src=(\S+)/user_uploads/(\S+)>", "", content)
|
||||
|
||||
# URLs for emoji are of the form
|
||||
# "static/generated/emoji/images/emoji/snowflake.png".
|
||||
# Convert the zulip emoji's relative url to absolute one.
|
||||
content = re.sub(
|
||||
r"(?<=\=['\"])/static/generated/emoji/images/emoji/(?=[^<]+>)",
|
||||
base_url + r"/static/generated/emoji/images/emoji/",
|
||||
r"(?<=\=['\"])/static/generated/emoji/images/emoji/unicode/zulip.png(?=[^<]+>)",
|
||||
base_url + r"/static/generated/emoji/images/emoji/unicode/zulip.png",
|
||||
content)
|
||||
|
||||
# Realm emoji should use absolute URLs when referenced in missed-message emails.
|
||||
|
@ -110,6 +109,18 @@ def relative_to_full_url(base_url, content):
|
|||
|
||||
return content
|
||||
|
||||
def fix_emojis(content, base_url):
|
||||
# type: (Text, Text) -> Text
|
||||
# Convert the emoji spans to img tags.
|
||||
content = re.sub(
|
||||
r'<span class=\"emoji emoji-(\S+)\" title=\"([^\"]+)\">(\S+)</span>',
|
||||
r'<img src="' + base_url + r'/static/generated/emoji/images-google-64/\1.png" ' +
|
||||
r'title="\2" alt="\3" style="height: 20px;">',
|
||||
content)
|
||||
content = content.replace(' class="emoji"', ' style="height: 20px;"')
|
||||
|
||||
return content
|
||||
|
||||
def build_message_list(user_profile, messages):
|
||||
# type: (UserProfile, List[Message]) -> List[Dict[str, Any]]
|
||||
"""
|
||||
|
@ -133,10 +144,6 @@ def build_message_list(user_profile, messages):
|
|||
# with a simple hyperlink.
|
||||
return re.sub(r"\[(\S*)\]\((\S*)\)", r"\2", content)
|
||||
|
||||
def fix_emojis(html):
|
||||
# type: (Text) -> Text
|
||||
return html.replace(' class="emoji"', ' height="20px" style="position: relative;top: 6px;"')
|
||||
|
||||
def build_message_payload(message):
|
||||
# type: (Message) -> Dict[str, Text]
|
||||
plain = message.content
|
||||
|
@ -153,7 +160,7 @@ def build_message_list(user_profile, messages):
|
|||
assert message.rendered_content is not None
|
||||
html = message.rendered_content
|
||||
html = relative_to_full_url(user_profile.realm.uri, html)
|
||||
html = fix_emojis(html)
|
||||
html = fix_emojis(html, user_profile.realm.uri)
|
||||
|
||||
return {'plain': plain, 'html': html}
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ class BugdownTest(ZulipTestCase):
|
|||
media_tweet_html = ('<a href="http://t.co/xo7pAhK6n3" target="_blank" title="http://t.co/xo7pAhK6n3">'
|
||||
'http://twitter.com/NEVNBoston/status/421654515616849920/photo/1</a>')
|
||||
|
||||
emoji_in_tweet_html = """Zulip is <img alt=":hundred_points:" class="emoji" src="/static/generated/emoji/images/emoji/unicode/1f4af.png" title="hundred points">% open-source!"""
|
||||
emoji_in_tweet_html = """Zulip is <span class="emoji emoji-1f4af" title="hundred points">:hundred_points:</span>% open-source!"""
|
||||
|
||||
def make_inline_twitter_preview(url, tweet_html, image_html=''):
|
||||
# type: (Text, Text, Text) -> Text
|
||||
|
@ -541,11 +541,11 @@ class BugdownTest(ZulipTestCase):
|
|||
# type: () -> None
|
||||
msg = u'\u2615' # ☕
|
||||
converted = bugdown_convert(msg)
|
||||
self.assertEqual(converted, u'<p><img alt=":coffee:" class="emoji" src="/static/generated/emoji/images/emoji/unicode/2615.png" title="coffee"></p>')
|
||||
self.assertEqual(converted, u'<p><span class="emoji emoji-2615" title="coffee">:coffee:</span></p>')
|
||||
|
||||
msg = u'\u2615\u2615' # ☕☕
|
||||
converted = bugdown_convert(msg)
|
||||
self.assertEqual(converted, u'<p><img alt=":coffee:" class="emoji" src="/static/generated/emoji/images/emoji/unicode/2615.png" title="coffee"><img alt=":coffee:" class="emoji" src="/static/generated/emoji/images/emoji/unicode/2615.png" title="coffee"></p>')
|
||||
self.assertEqual(converted, u'<p><span class="emoji emoji-2615" title="coffee">:coffee:</span><span class="emoji emoji-2615" title="coffee">:coffee:</span></p>')
|
||||
|
||||
def test_same_markup(self):
|
||||
# type: () -> None
|
||||
|
|
|
@ -13,8 +13,8 @@ from mock import patch, MagicMock
|
|||
from six.moves import range
|
||||
from typing import Any, Dict, List, Text
|
||||
|
||||
from zerver.lib.notifications import handle_missedmessage_emails, \
|
||||
relative_to_full_url
|
||||
from zerver.lib.notifications import fix_emojis, \
|
||||
handle_missedmessage_emails, relative_to_full_url
|
||||
from zerver.lib.actions import do_update_message
|
||||
from zerver.lib.message import access_message
|
||||
from zerver.lib.test_classes import ZulipTestCase
|
||||
|
@ -338,7 +338,7 @@ class TestMissedMessages(ZulipTestCase):
|
|||
msg_id = self.send_message(self.example_email('othello'), self.example_email('hamlet'),
|
||||
Recipient.PERSONAL,
|
||||
'Extremely personal message with a realm emoji :green_tick:!')
|
||||
body = '<img alt=":green_tick:" height="20px" style="position: relative;top: 6px;" src="http://zulip.testserver/user_avatars/1/emoji/green_tick.png" title="green tick">'
|
||||
body = '<img alt=":green_tick:" style="height: 20px;" src="http://zulip.testserver/user_avatars/1/emoji/green_tick.png" title="green tick">'
|
||||
subject = 'Othello, the Moor of Venice sent you a message'
|
||||
self._test_cases(tokens, msg_id, body, subject, send_as_user=False, verify_html_body=True)
|
||||
|
||||
|
@ -403,12 +403,6 @@ class TestMissedMessages(ZulipTestCase):
|
|||
|
||||
# Specific test cases.
|
||||
|
||||
# A path to an emoji image
|
||||
test_data = '<a href="/static/generated/emoji/images/emoji/">emoji</a>'
|
||||
actual_output = relative_to_full_url("http://example.com", test_data)
|
||||
expected_output = '<a href="http://example.com/static/generated/emoji/images/emoji/">emoji</a>'
|
||||
self.assertEqual(actual_output, expected_output)
|
||||
|
||||
# A path similar to our emoji path, but not in a link:
|
||||
test_data = "<p>Check out the file at: '/static/generated/emoji/images/emoji/'</p>"
|
||||
actual_output = relative_to_full_url("http://example.com", test_data)
|
||||
|
@ -427,3 +421,14 @@ class TestMissedMessages(ZulipTestCase):
|
|||
actual_output = relative_to_full_url("http://example.com", test_data)
|
||||
expected_output = '<p>Set src="/avatar/username@example.com?s=30"</p>'
|
||||
self.assertEqual(actual_output, expected_output)
|
||||
|
||||
def test_fix_emoji(self):
|
||||
# type: () -> None
|
||||
# An emoji.
|
||||
test_data = '<p>See <span class="emoji emoji-26c8" title="cloud with lightning and rain">' + \
|
||||
':cloud_with_lightning_and_rain:</span>.</p>'
|
||||
actual_output = fix_emojis(test_data, "http://example.com")
|
||||
expected_output = '<p>See <img src="http://example.com/static/generated/emoji/images-google-64/26c8.png" ' + \
|
||||
'title="cloud with lightning and rain" alt=":cloud_with_lightning_and_rain:" ' + \
|
||||
'style="height: 20px;">.</p>'
|
||||
self.assertEqual(actual_output, expected_output)
|
||||
|
|
Loading…
Reference in New Issue