|
@ -8,7 +8,7 @@ import { search as searchCategoryTag } from 'discourse/lib/category-tag-search'
|
|||
import { SEPARATOR } from 'discourse/lib/category-hashtags';
|
||||
import { cook } from 'discourse/lib/text';
|
||||
import { translations } from 'pretty-text/emoji/data';
|
||||
import { emojiSearch } from 'pretty-text/emoji';
|
||||
import { emojiSearch, isSkinTonableEmoji } from 'pretty-text/emoji';
|
||||
import { emojiUrlFor } from 'discourse/lib/text';
|
||||
import { getRegister } from 'discourse-common/lib/get-owner';
|
||||
import { findRawTemplate } from 'discourse/lib/raw-templates';
|
||||
|
@ -337,6 +337,11 @@ export default Ember.Component.extend({
|
|||
self.set('value', text);
|
||||
},
|
||||
|
||||
onKeyUp(text, cp) {
|
||||
const subtext = text.substring(0, cp);
|
||||
return subtext.match(/(:(?!:).?[\w-]*:?(?!:)(?:t\d?)?:?) ?$/gm);
|
||||
},
|
||||
|
||||
transformComplete(v) {
|
||||
if (v.code) {
|
||||
return `${v.code}:`;
|
||||
|
@ -372,6 +377,20 @@ export default Ember.Component.extend({
|
|||
return resolve([translations[full]]);
|
||||
}
|
||||
|
||||
const match = term.match(/^:?(.*?):t(\d)?$/);
|
||||
if (match) {
|
||||
let name = match[1];
|
||||
let scale = match[2];
|
||||
|
||||
if (isSkinTonableEmoji(name)) {
|
||||
if (scale) {
|
||||
return resolve([`${name}:t${scale}`]);
|
||||
} else {
|
||||
return resolve([2, 3, 4, 5, 6].map(x => `${name}:t${x}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = emojiSearch(term, {maxResults: 5});
|
||||
|
||||
return resolve(options);
|
||||
|
|
|
@ -360,8 +360,21 @@ export default function(options) {
|
|||
|
||||
var cp = caretPosition(me[0]);
|
||||
|
||||
if (options.key && completeStart === null && cp > 0) {
|
||||
var key = me[0].value[cp-1];
|
||||
if (!options.key) return;
|
||||
|
||||
const key = me[0].value[cp-1];
|
||||
|
||||
if (options.onKeyUp && key !== options.key) {
|
||||
var match = options.onKeyUp(me.val(), cp);
|
||||
if (match) {
|
||||
completeStart = cp - match[0].length;
|
||||
completeEnd = completeStart + match[0].length - 1;
|
||||
let term = match[0].substring(1, match[0].length);
|
||||
updateAutoComplete(dataSource(term, options));
|
||||
}
|
||||
}
|
||||
|
||||
if (completeStart === null && cp > 0) {
|
||||
if (key === options.key) {
|
||||
var prevChar = me.val().charAt(cp-2);
|
||||
if (checkTriggerRule() && (!prevChar || allowedLettersRegex.test(prevChar))) {
|
||||
|
@ -370,7 +383,7 @@ export default function(options) {
|
|||
}
|
||||
}
|
||||
} else if (completeStart !== null) {
|
||||
var term = me.val().substring(completeStart + (options.key ? 1 : 0), cp);
|
||||
let term = me.val().substring(completeStart + (options.key ? 1 : 0), cp);
|
||||
updateAutoComplete(dataSource(term, options));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { emoji, aliases, translations } from 'pretty-text/emoji/data';
|
||||
import { emojis, aliases, translations, tonableEmojis } from 'pretty-text/emoji/data';
|
||||
|
||||
// bump up this number to expire all emojis
|
||||
export const IMAGE_VERSION = "3";
|
||||
export const IMAGE_VERSION = "5";
|
||||
|
||||
const extendedEmoji = {};
|
||||
|
||||
|
@ -11,7 +11,7 @@ export function registerEmoji(code, url) {
|
|||
}
|
||||
|
||||
export function emojiList() {
|
||||
const result = emoji.slice(0);
|
||||
const result = emojis.slice(0);
|
||||
_.each(extendedEmoji, (v,k) => result.push(k));
|
||||
return result;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export function emojiList() {
|
|||
const emojiHash = {};
|
||||
|
||||
// add all default emojis
|
||||
emoji.forEach(code => emojiHash[code] = true);
|
||||
emojis.forEach(code => emojiHash[code] = true);
|
||||
|
||||
// and their aliases
|
||||
const aliasHash = {};
|
||||
|
@ -30,7 +30,7 @@ Object.keys(aliases).forEach(name => {
|
|||
export function performEmojiUnescape(string, opts) {
|
||||
// this can be further improved by supporting matches of emoticons that don't begin with a colon
|
||||
if (string.indexOf(":") >= 0) {
|
||||
return string.replace(/\B:[^\s:]+:?\B/g, m => {
|
||||
return string.replace(/\B:[^\s:]+(?::t\d)?:?\B/g, m => {
|
||||
const isEmoticon = !!translations[m];
|
||||
const emojiVal = isEmoticon ? translations[m] : m.slice(1, m.length - 1);
|
||||
const hasEndingColon = m.lastIndexOf(":") === m.length - 1;
|
||||
|
@ -64,8 +64,9 @@ export function buildEmojiUrl(code, opts) {
|
|||
url = opts.customEmoji[code];
|
||||
}
|
||||
|
||||
if (!url && emojiHash.hasOwnProperty(code)) {
|
||||
url = opts.getURL(`/images/emoji/${opts.emojiSet}/${code}.png`);
|
||||
const noToneMatch = code.match(/(.?[\w-]*)?:?/);
|
||||
if (noToneMatch && !url && (emojiHash.hasOwnProperty(noToneMatch[1]) || aliasHash.hasOwnProperty(noToneMatch[1]))) {
|
||||
url = opts.getURL(`/images/emoji/${opts.emojiSet}/${code.replace(/:t/, '/')}.png`);
|
||||
}
|
||||
|
||||
if (url) {
|
||||
|
@ -77,7 +78,7 @@ export function buildEmojiUrl(code, opts) {
|
|||
|
||||
export function emojiExists(code) {
|
||||
code = code.toLowerCase();
|
||||
return !!(extendedEmoji.hasOwnProperty(code) || emojiHash.hasOwnProperty(code));
|
||||
return !!(extendedEmoji.hasOwnProperty(code) || emojiHash.hasOwnProperty(code) || aliasHash.hasOwnProperty(code));
|
||||
};
|
||||
|
||||
let toSearch;
|
||||
|
@ -113,3 +114,12 @@ export function emojiSearch(term, options) {
|
|||
|
||||
return results;
|
||||
};
|
||||
|
||||
export function isSkinTonableEmoji(term) {
|
||||
let match = term.match(/^:?(.*?):?$/);
|
||||
if (match) {
|
||||
return tonableEmojis.indexOf(match[1]) !== -1;
|
||||
} else {
|
||||
return tonableEmojis.indexOf(term) !== -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export const emoji = <%= Emoji.standard.map(&:name).flatten.inspect %>;
|
||||
export const emojis = <%= Emoji.standard.map(&:name).flatten.inspect %>;
|
||||
export const tonableEmojis = <%= Emoji.tonable_emojis.flatten.inspect %>;
|
||||
export const aliases = <%= Emoji.aliases.inspect.gsub("=>", ":") %>;
|
||||
export const translations = {
|
||||
':)' : 'slight_smile',
|
||||
|
|
|
@ -81,11 +81,17 @@ export function setup(helper) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Simple find and replace from our array
|
||||
const between = text.slice(1, endPos);
|
||||
let between;
|
||||
const emojiNameMatch = text.match(/(?:.*?)(:(?!:).?[\w-]*(?::t\d)?:)/);
|
||||
if (emojiNameMatch) {
|
||||
between = emojiNameMatch[0].slice(1, -1);
|
||||
} else {
|
||||
between = text.slice(1, -1);
|
||||
}
|
||||
|
||||
const contents = imageFor(between);
|
||||
if (contents) {
|
||||
return [endPos+1, contents];
|
||||
return [text.indexOf(between, 1) + between.length + 1, contents];
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Emoji
|
||||
# update this to clear the cache
|
||||
EMOJI_VERSION = "v3"
|
||||
EMOJI_VERSION = "v5"
|
||||
|
||||
include ActiveModel::SerializerSupport
|
||||
|
||||
|
@ -23,13 +23,17 @@ class Emoji
|
|||
end
|
||||
|
||||
def self.aliases
|
||||
Discourse.cache.fetch(cache_key("aliases_emojis")) { load_aliases }
|
||||
Discourse.cache.fetch(cache_key("aliases_emojis")) { db['aliases'] }
|
||||
end
|
||||
|
||||
def self.custom
|
||||
Discourse.cache.fetch(cache_key("custom_emojis")) { load_custom }
|
||||
end
|
||||
|
||||
def self.tonable_emojis
|
||||
Discourse.cache.fetch(cache_key("tonable_emojis")) { db['tonableEmojis'] }
|
||||
end
|
||||
|
||||
def self.exists?(name)
|
||||
Emoji[name].present?
|
||||
end
|
||||
|
@ -63,32 +67,13 @@ class Emoji
|
|||
end
|
||||
|
||||
def self.db
|
||||
return @db if @db
|
||||
@db = File.open(db_file, "r:UTF-8") { |f| JSON.parse(f.read) }
|
||||
|
||||
# Small tweak to `emoji.json` from Emoji one
|
||||
@db['emojis'] << {"code" => "1f44d", "name" => "+1", "filename" => "thumbsup"}
|
||||
@db['emojis'] << {"code" => "1f44e", "name" => "-1", "filename" => "thumbsdown"}
|
||||
|
||||
@db
|
||||
@db ||= File.open(db_file, "r:UTF-8") { |f| JSON.parse(f.read) }
|
||||
end
|
||||
|
||||
def self.load_standard
|
||||
db['emojis'].map {|e| Emoji.create_from_db_item(e) }
|
||||
end
|
||||
|
||||
def self.load_aliases
|
||||
return @aliases if @aliases
|
||||
|
||||
@aliases ||= db['aliases']
|
||||
|
||||
# Fix how `slightly_smiling` was mislabeled
|
||||
@aliases['slight_smile'] ||= []
|
||||
@aliases['slight_smile'] << 'slightly_smiling'
|
||||
|
||||
@aliases
|
||||
end
|
||||
|
||||
def self.load_custom
|
||||
result = []
|
||||
|
||||
|
@ -159,11 +144,20 @@ class Emoji
|
|||
def self.lookup_unicode(name)
|
||||
@reverse_map ||= begin
|
||||
map = {}
|
||||
|
||||
db['emojis'].each do |e|
|
||||
next if e['name'] == 'tm'
|
||||
code = replacement_code(e['code'])
|
||||
map[e['name']] = code if code
|
||||
end
|
||||
|
||||
Emoji.aliases.each do |key, alias_names|
|
||||
next unless alias_code = map[key]
|
||||
alias_names.each do |alias_name|
|
||||
map[alias_name] = alias_code
|
||||
end
|
||||
end
|
||||
|
||||
map
|
||||
end
|
||||
@reverse_map[name]
|
||||
|
|
9823
lib/emoji/db.json
2740
lib/tasks/emoji.rake
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 962 B |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 875 B After Width: | Height: | Size: 876 B |
Before Width: | Height: | Size: 894 B After Width: | Height: | Size: 957 B |
Before Width: | Height: | Size: 900 B After Width: | Height: | Size: 976 B |
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 978 B |
Before Width: | Height: | Size: 912 B After Width: | Height: | Size: 934 B |
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 926 B |
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 993 B |
Before Width: | Height: | Size: 973 B After Width: | Height: | Size: 1007 B |
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 907 B After Width: | Height: | Size: 898 B |
Before Width: | Height: | Size: 914 B After Width: | Height: | Size: 891 B |
Before Width: | Height: | Size: 910 B After Width: | Height: | Size: 947 B |
Before Width: | Height: | Size: 929 B After Width: | Height: | Size: 1014 B |
Before Width: | Height: | Size: 897 B After Width: | Height: | Size: 933 B |
Before Width: | Height: | Size: 1000 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 872 B After Width: | Height: | Size: 930 B |
Before Width: | Height: | Size: 870 B After Width: | Height: | Size: 945 B |
Before Width: | Height: | Size: 814 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1001 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1003 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |