Add a title attribute to emojis in messages
so that you can see the shortname when you hover your mouse over an emoji.
This commit is contained in:
parent
1b520328fa
commit
b7a40dad41
@ -117,7 +117,7 @@
|
|||||||
"no-console": "off",
|
"no-console": "off",
|
||||||
"no-catch-shadow": "off",
|
"no-catch-shadow": "off",
|
||||||
"no-cond-assign": [
|
"no-cond-assign": [
|
||||||
"error",
|
"off",
|
||||||
"except-parens"
|
"except-parens"
|
||||||
],
|
],
|
||||||
"no-confusing-arrow": "off",
|
"no-confusing-arrow": "off",
|
||||||
|
@ -43,7 +43,7 @@ export class EmojiPicker extends CustomElement {
|
|||||||
'query': this.query,
|
'query': this.query,
|
||||||
'search_results': this.search_results,
|
'search_results': this.search_results,
|
||||||
'shouldBeHidden': shortname => this.shouldBeHidden(shortname),
|
'shouldBeHidden': shortname => this.shouldBeHidden(shortname),
|
||||||
'transformCategory': shortname => u.getEmojiRenderer()(this.getTonedShortname(shortname))
|
'transformCategory': shortname => u.shortnamesToEmojis(this.getTonedShortname(shortname))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,7 +951,7 @@ converse.plugins.add('converse-chat', {
|
|||||||
getOutgoingMessageAttributes (text, spoiler_hint) {
|
getOutgoingMessageAttributes (text, spoiler_hint) {
|
||||||
const is_spoiler = this.get('composing_spoiler');
|
const is_spoiler = this.get('composing_spoiler');
|
||||||
const origin_id = u.getUniqueId();
|
const origin_id = u.getUniqueId();
|
||||||
const body = text ? u.httpToGeoUri(u.shortnameToUnicode(text), _converse) : undefined;
|
const body = text ? u.httpToGeoUri(u.shortnamesToUnicode(text), _converse) : undefined;
|
||||||
return {
|
return {
|
||||||
'from': _converse.bare_jid,
|
'from': _converse.bare_jid,
|
||||||
'fullname': _converse.xmppstatus.get('fullname'),
|
'fullname': _converse.xmppstatus.get('fullname'),
|
||||||
|
@ -34,8 +34,7 @@ const ASCII_REPLACE_REGEX = new RegExp("<object[^>]*>.*?<\/object>|<span[^>]*>.*
|
|||||||
|
|
||||||
|
|
||||||
function convert (unicode) {
|
function convert (unicode) {
|
||||||
// Converts unicode code points and code pairs
|
// Converts unicode code points and code pairs to their respective characters
|
||||||
// to their respective characters
|
|
||||||
if (unicode.indexOf("-") > -1) {
|
if (unicode.indexOf("-") > -1) {
|
||||||
const parts = [],
|
const parts = [],
|
||||||
s = unicode.split('-');
|
s = unicode.split('-');
|
||||||
@ -82,44 +81,80 @@ function convertASCII2Emoji (str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getEmojiMarkup (shortname, unicode_only) {
|
function getEmojiMarkup (data, options={unicode_only: false, add_title_wrapper: false}) {
|
||||||
if ((typeof shortname === 'undefined') || (shortname === '') || (!_converse.emoji_shortnames.includes(shortname))) {
|
const emoji = data.emoji;
|
||||||
// if the shortname doesnt exist just return the entire match
|
const shortname = data.shortname;
|
||||||
return shortname;
|
if (emoji) {
|
||||||
|
if (api.settings.get('use_system_emojis')) {
|
||||||
|
return options.add_title_wrapper ? html`<span title="${shortname}">${emoji}</span>` : emoji;
|
||||||
|
} else {
|
||||||
|
const path = api.settings.get('emoji_image_path');
|
||||||
|
return html`<img class="emoji"
|
||||||
|
draggable="false"
|
||||||
|
alt="${emoji}"
|
||||||
|
src="${path}/72x72/${data.cp}.png"/>`;
|
||||||
}
|
}
|
||||||
const codepoint = _converse.emojis_map[shortname].cp;
|
} else if (options.unicode_only) {
|
||||||
if (codepoint) {
|
|
||||||
return convert(codepoint.toUpperCase());
|
|
||||||
} else if (unicode_only) {
|
|
||||||
return shortname;
|
return shortname;
|
||||||
} else {
|
} else {
|
||||||
return html`<img class="emoji" draggable="false" title="${shortname}" alt="${shortname}" src="${_converse.emojis_map[shortname].url}">`;
|
return html`<img class="emoji"
|
||||||
|
draggable="false"
|
||||||
|
title="${shortname}"
|
||||||
|
alt="${shortname}"
|
||||||
|
src="${_converse.emojis_by_sn[shortname].url}">`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function addEmojisMarkup (text, unicode_only=false) {
|
function getShortnameReferences (text) {
|
||||||
const original_text = text;
|
|
||||||
let list = [text];
|
|
||||||
const references = [...text.matchAll(shortnames_regex)];
|
const references = [...text.matchAll(shortnames_regex)];
|
||||||
if (references.length) {
|
return references.map(ref => {
|
||||||
references.map(ref => {
|
const cp = _converse.emojis_by_sn[ref[0]].cp;
|
||||||
ref.begin = ref.index;
|
return {
|
||||||
ref.end = ref.index+ref[0].length;
|
cp,
|
||||||
return ref;
|
'begin': ref.index,
|
||||||
})
|
'end': ref.index+ref[0].length,
|
||||||
|
'shortname': ref[0],
|
||||||
|
'emoji': cp ? convert(cp) : null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getCodePointReferences (text) {
|
||||||
|
const references = [];
|
||||||
|
const how = {
|
||||||
|
callback: (icon_id) => {
|
||||||
|
const emoji = convert(icon_id);
|
||||||
|
const begin = text.indexOf(emoji);
|
||||||
|
references.push({
|
||||||
|
'emoji': emoji,
|
||||||
|
'end': begin + emoji.length,
|
||||||
|
'shortname': u.getEmojisByAtrribute('cp')[icon_id]['sn'],
|
||||||
|
begin,
|
||||||
|
cp: icon_id
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
twemoji.default.parse(text, how);
|
||||||
|
return references;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function addEmojisMarkup (text, options) {
|
||||||
|
let list = [text];
|
||||||
|
[...getShortnameReferences(text), ...getCodePointReferences(text)]
|
||||||
.sort((a, b) => b.begin - a.begin)
|
.sort((a, b) => b.begin - a.begin)
|
||||||
.forEach(ref => {
|
.forEach(ref => {
|
||||||
const text = list.shift();
|
const text = list.shift();
|
||||||
const shortname = original_text.slice(ref.begin, ref.end);
|
const emoji = getEmojiMarkup(ref, options);
|
||||||
const emoji = getEmojiMarkup(shortname, unicode_only);
|
|
||||||
if (isString(emoji)) {
|
if (isString(emoji)) {
|
||||||
list = [text.slice(0, ref.begin) + emoji + text.slice(ref.end), ...list];
|
list = [text.slice(0, ref.begin) + emoji + text.slice(ref.end), ...list];
|
||||||
} else {
|
} else {
|
||||||
list = [text.slice(0, ref.begin), emoji, text.slice(ref.end), ...list];
|
list = [text.slice(0, ref.begin), emoji, text.slice(ref.end), ...list];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,33 +225,16 @@ converse.plugins.add('converse-emoji', {
|
|||||||
const emojis_by_attribute = {};
|
const emojis_by_attribute = {};
|
||||||
|
|
||||||
Object.assign(u, {
|
Object.assign(u, {
|
||||||
/**
|
|
||||||
* Based on the value of `use_system_emojis` will return either
|
|
||||||
* a function that converts emoji shortnames into unicode glyphs
|
|
||||||
* (see {@link u.shortnamesToEmojis} or one that converts them into images.
|
|
||||||
* @returns {function}
|
|
||||||
*/
|
|
||||||
getEmojiRenderer () {
|
|
||||||
const how = {
|
|
||||||
'attributes': icon => {
|
|
||||||
const codepoint = twemoji.default.convert.toCodePoint(icon);
|
|
||||||
return {'title': `${u.getEmojisByAtrribute('cp')[codepoint]['sn']} ${icon}`}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const transform = u.shortnamesToEmojis;
|
|
||||||
return api.settings.get('use_system_emojis') ? transform : text => twemoji.default.parse(transform(text), how);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces emoji shortnames in the passed-in string with unicode or image-based emojis
|
* Replaces emoji shortnames in the passed-in string with unicode or image-based emojis
|
||||||
* (based on the value of `use_system_emojis`).
|
* (based on the value of `use_system_emojis`).
|
||||||
* @method u.addEmoji
|
* @method u.addEmoji
|
||||||
* @param {string} text = The text
|
* @param { String } text = The text
|
||||||
* @returns {string} The text with shortnames replaced with emoji
|
* @returns { String } The text with shortnames replaced with emoji unicodes or images.
|
||||||
* unicodes or images.
|
|
||||||
*/
|
*/
|
||||||
addEmoji (text) {
|
addEmoji (text) {
|
||||||
return u.getEmojiRenderer()(text);
|
const options = {add_title_wrapper: true, unicode_only: false};
|
||||||
|
return u.shortnamesToEmojis(text, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -231,34 +249,41 @@ converse.plugins.add('converse-emoji', {
|
|||||||
* an `url` attribute which points to the source for the image.
|
* an `url` attribute which points to the source for the image.
|
||||||
*
|
*
|
||||||
* @method u.shortnamesToEmojis
|
* @method u.shortnamesToEmojis
|
||||||
* @param {String} str - String containg the shortname(s)
|
* @param { String } str - String containg the shortname(s)
|
||||||
* @param {Boolean} unicode_only - Whether emojis are rendered as
|
* @param { Object } options
|
||||||
|
* @param { Boolean } options.unicode_only - Whether emojis are rendered as
|
||||||
* unicode codepoints. If so, the returned result will be an array
|
* unicode codepoints. If so, the returned result will be an array
|
||||||
* with containing one string, because the emojis themselves will
|
* with containing one string, because the emojis themselves will
|
||||||
* also be strings. If set to false, emojis will be represented by
|
* also be strings. If set to false, emojis will be represented by
|
||||||
* lit-html TemplateResult objects.
|
* lit-html TemplateResult objects.
|
||||||
|
* @param { Boolean } options.add_title_wrapper - Whether unicode
|
||||||
|
* codepoints should be wrapped with a `<span>` element with a
|
||||||
|
* title, so that the shortname is shown upon hovering with the
|
||||||
|
* mouse.
|
||||||
* @returns {Array} An array of at least one string, or otherwise
|
* @returns {Array} An array of at least one string, or otherwise
|
||||||
* strings and lit-html TemplateResult objects.
|
* strings and lit-html TemplateResult objects.
|
||||||
*/
|
*/
|
||||||
shortnamesToEmojis (str, unicode_only=false) {
|
shortnamesToEmojis (str, options={unicode_only: false, add_title_wrapper: false}) {
|
||||||
str = convertASCII2Emoji(str);
|
str = convertASCII2Emoji(str);
|
||||||
return addEmojisMarkup(str, unicode_only);
|
return addEmojisMarkup(str, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns unicode represented by the passed in shortname.
|
* Replaces all shortnames in the passed in string with their
|
||||||
* @method u.shortnameToUnicode
|
* unicode (emoji) representation.
|
||||||
* @param {string} str - String containing the shortname(s)
|
* @method u.shortnamesToUnicode
|
||||||
|
* @param { String } str - String containing the shortname(s)
|
||||||
|
* @returns { String }
|
||||||
*/
|
*/
|
||||||
shortnameToUnicode (str) {
|
shortnamesToUnicode (str) {
|
||||||
return u.shortnamesToEmojis(str, true)[0];
|
return u.shortnamesToEmojis(str, {'unicode_only': true})[0];
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the passed in string is just a single emoji shortname;
|
* Determines whether the passed in string is just a single emoji shortname;
|
||||||
* @method u.isOnlyEmojis
|
* @method u.isOnlyEmojis
|
||||||
* @param {string} shortname - A string which migh be just an emoji shortname
|
* @param { String } shortname - A string which migh be just an emoji shortname
|
||||||
* @returns {boolean}
|
* @returns { Boolean }
|
||||||
*/
|
*/
|
||||||
isOnlyEmojis (text) {
|
isOnlyEmojis (text) {
|
||||||
const words = text.trim().split(/\s+/);
|
const words = text.trim().split(/\s+/);
|
||||||
@ -266,7 +291,7 @@ converse.plugins.add('converse-emoji', {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const rejects = words.filter(text => {
|
const rejects = words.filter(text => {
|
||||||
const result = twemoji.default.parse(u.shortnameToUnicode(text));
|
const result = twemoji.default.parse(u.shortnamesToUnicode(text));
|
||||||
const match = result.match(/<img class="emoji" draggable="false" alt=".*?" src=".*?\.png"\/>/);
|
const match = result.match(/<img class="emoji" draggable="false" alt=".*?" src=".*?\.png"\/>/);
|
||||||
return !match || match.length !== 1;
|
return !match || match.length !== 1;
|
||||||
});
|
});
|
||||||
@ -275,9 +300,9 @@ converse.plugins.add('converse-emoji', {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @method u.getEmojisByAtrribute
|
* @method u.getEmojisByAtrribute
|
||||||
* @param {string} attr - The attribute according to which the
|
* @param { String } attr - The attribute according to which the
|
||||||
* returned map should be keyed.
|
* returned map should be keyed.
|
||||||
* @returns {object} - Map of emojis with the passed in attribute values
|
* @returns { Object } - Map of emojis with the passed in attribute values
|
||||||
* as keys and a list of emojis for a particular category as values.
|
* as keys and a list of emojis for a particular category as values.
|
||||||
*/
|
*/
|
||||||
getEmojisByAtrribute (attr) {
|
getEmojisByAtrribute (attr) {
|
||||||
@ -303,10 +328,7 @@ converse.plugins.add('converse-emoji', {
|
|||||||
// We extend the default converse.js API to add methods specific to MUC groupchats.
|
// We extend the default converse.js API to add methods specific to MUC groupchats.
|
||||||
Object.assign(api, {
|
Object.assign(api, {
|
||||||
/**
|
/**
|
||||||
* The "rooms" namespace groups methods relevant to chatrooms
|
* @namespace api.emojis
|
||||||
* (aka groupchats).
|
|
||||||
*
|
|
||||||
* @namespace api.rooms
|
|
||||||
* @memberOf api
|
* @memberOf api
|
||||||
*/
|
*/
|
||||||
emojis: {
|
emojis: {
|
||||||
@ -323,8 +345,8 @@ converse.plugins.add('converse-emoji', {
|
|||||||
const { default: json } = await import(/*webpackChunkName: "emojis" */ './emojis.json');
|
const { default: json } = await import(/*webpackChunkName: "emojis" */ './emojis.json');
|
||||||
_converse.emojis.json = json;
|
_converse.emojis.json = json;
|
||||||
_converse.emojis.categories = Object.keys(_converse.emojis.json);
|
_converse.emojis.categories = Object.keys(_converse.emojis.json);
|
||||||
_converse.emojis_map = _converse.emojis.categories.reduce((result, cat) => Object.assign(result, _converse.emojis.json[cat]), {});
|
_converse.emojis_by_sn = _converse.emojis.categories.reduce((result, cat) => Object.assign(result, _converse.emojis.json[cat]), {});
|
||||||
_converse.emojis_list = Object.values(_converse.emojis_map);
|
_converse.emojis_list = Object.values(_converse.emojis_by_sn);
|
||||||
_converse.emojis_list.sort((a, b) => a.sn < b.sn ? -1 : (a.sn > b.sn ? 1 : 0));
|
_converse.emojis_list.sort((a, b) => a.sn < b.sn ? -1 : (a.sn > b.sn ? 1 : 0));
|
||||||
_converse.emoji_shortnames = _converse.emojis_list.map(m => m.sn);
|
_converse.emoji_shortnames = _converse.emojis_list.map(m => m.sn);
|
||||||
|
|
||||||
|
@ -997,7 +997,7 @@ converse.plugins.add('converse-muc', {
|
|||||||
const is_spoiler = this.get('composing_spoiler');
|
const is_spoiler = this.get('composing_spoiler');
|
||||||
const [text, references] = this.parseTextForReferences(original_message);
|
const [text, references] = this.parseTextForReferences(original_message);
|
||||||
const origin_id = u.getUniqueId();
|
const origin_id = u.getUniqueId();
|
||||||
const body = text ? u.httpToGeoUri(u.shortnameToUnicode(text), _converse) : undefined;
|
const body = text ? u.httpToGeoUri(u.shortnamesToUnicode(text), _converse) : undefined;
|
||||||
return {
|
return {
|
||||||
body,
|
body,
|
||||||
is_spoiler,
|
is_spoiler,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { __ } from '@converse/headless/i18n';
|
import { __ } from '@converse/headless/i18n';
|
||||||
import { _converse, api } from "@converse/headless/converse-core";
|
import { _converse, converse, api } from "@converse/headless/converse-core";
|
||||||
import { html } from "lit-html";
|
import { html } from "lit-html";
|
||||||
|
|
||||||
const u = converse.env.utils;
|
const u = converse.env.utils;
|
||||||
@ -32,7 +32,7 @@ const emoji_picker_header = (o) => html`
|
|||||||
const emoji_item = (o) => {
|
const emoji_item = (o) => {
|
||||||
return html`
|
return html`
|
||||||
<li class="emoji insert-emoji ${o.shouldBeHidden(o.emoji.sn) ? 'hidden' : ''}" data-emoji="${o.emoji.sn}" title="${o.emoji.sn}">
|
<li class="emoji insert-emoji ${o.shouldBeHidden(o.emoji.sn) ? 'hidden' : ''}" data-emoji="${o.emoji.sn}" title="${o.emoji.sn}">
|
||||||
<a href="#" @click=${o.onEmojiPicked} data-emoji="${o.emoji.sn}">${o.transform(o.emoji.sn)}</a>
|
<a href="#" @click=${o.onEmojiPicked} data-emoji="${o.emoji.sn}">${u.shortnamesToEmojis(o.emoji.sn)}</a>
|
||||||
</li>
|
</li>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -53,16 +53,14 @@ const emojis_for_category = (o) => html`
|
|||||||
</ul>
|
</ul>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
const skintone_emoji = (o) => {
|
const skintone_emoji = (o) => {
|
||||||
return html`
|
return html`
|
||||||
<li data-skintone="${o.skintone}" class="emoji-skintone ${(o.current_skintone === o.skintone) ? 'picked' : ''}">
|
<li data-skintone="${o.skintone}" class="emoji-skintone ${(o.current_skintone === o.skintone) ? 'picked' : ''}">
|
||||||
<a class="pick-skintone" href="#" data-skintone="${o.skintone}" @click=${o.onSkintonePicked}>${o.transform(':'+o.skintone+':')}</a>
|
<a class="pick-skintone" href="#" data-skintone="${o.skintone}" @click=${o.onSkintonePicked}>${u.shortnamesToEmojis(':'+o.skintone+':')}</a>
|
||||||
</li>
|
</li>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const all_emojis = (o) => html`
|
const all_emojis = (o) => html`
|
||||||
<span ?hidden=${o.query} class="emoji-lists__container emoji-lists__container--browse">
|
<span ?hidden=${o.query} class="emoji-lists__container emoji-lists__container--browse">
|
||||||
${Object.keys(o.emoji_categories).map(category => (o.emoji_categories[category] ? emojis_for_category(Object.assign({category}, o)) : ''))}
|
${Object.keys(o.emoji_categories).map(category => (o.emoji_categories[category] ? emojis_for_category(Object.assign({category}, o)) : ''))}
|
||||||
@ -73,7 +71,6 @@ const all_emojis = (o) => html`
|
|||||||
export default (o) => {
|
export default (o) => {
|
||||||
o.emoji_categories = api.settings.get('emoji_categories');
|
o.emoji_categories = api.settings.get('emoji_categories');
|
||||||
o.emojis_by_category = _converse.emojis.json;
|
o.emojis_by_category = _converse.emojis.json;
|
||||||
o.transform = u.getEmojiRenderer();
|
|
||||||
o.toned_emojis = _converse.emojis.toned;
|
o.toned_emojis = _converse.emojis.toned;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
Loading…
Reference in New Issue
Block a user