mirror of
https://github.com/flarum/framework.git
synced 2024-11-29 04:33:47 +08:00
use twemoji (#16)
* use twemoji * insert emoji instead of shortcode * cleanups * generate emojiMap using emojibase * remove redunant spaces * remove dead codes * use prebuild and prewatch * update dependencies
This commit is contained in:
parent
680c5c3784
commit
ab44c2b629
|
@ -19,18 +19,14 @@ return [
|
|||
|
||||
(new Extend\Formatter)
|
||||
->configure(function (Configurator $config) {
|
||||
$config->Emoji->useEmojiOne();
|
||||
$config->Emoji->omitImageSize();
|
||||
$config->Emoji->useSVG();
|
||||
|
||||
$config->Emoji->addAlias(':)', '🙂');
|
||||
$config->Emoji->addAlias(':D', '😃');
|
||||
$config->Emoji->addAlias(':P', '😛');
|
||||
$config->Emoji->addAlias(':(', '🙁');
|
||||
$config->Emoji->addAlias(':|', '😐');
|
||||
$config->Emoji->addAlias(';)', '😉');
|
||||
$config->Emoji->addAlias(':\'(', '😢');
|
||||
$config->Emoji->addAlias(':O', '😮');
|
||||
$config->Emoji->addAlias('>:(', '😡');
|
||||
$config->Emoticons->add(':)', '🙂');
|
||||
$config->Emoticons->add(':D', '😃');
|
||||
$config->Emoticons->add(':P', '😛');
|
||||
$config->Emoticons->add(':(', '🙁');
|
||||
$config->Emoticons->add(':|', '😐');
|
||||
$config->Emoticons->add(';)', '😉');
|
||||
$config->Emoticons->add(':\'(', '😢');
|
||||
$config->Emoticons->add(':O', '😮');
|
||||
$config->Emoticons->add('>:(', '😡');
|
||||
})
|
||||
];
|
||||
|
|
10
extensions/emoji/js/package-lock.json
generated
10
extensions/emoji/js/package-lock.json
generated
|
@ -1726,6 +1726,11 @@
|
|||
"minimalistic-crypto-utils": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"emojibase-data": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/emojibase-data/-/emojibase-data-3.1.0.tgz",
|
||||
"integrity": "sha1-XRKHADz/s7wTMGThto272slA/yA="
|
||||
},
|
||||
"emojis-list": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
|
||||
|
@ -4296,6 +4301,11 @@
|
|||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||
"integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
|
||||
},
|
||||
"twemoji": {
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/twemoji/-/twemoji-11.0.1.tgz",
|
||||
"integrity": "sha512-Z0bRyZ1yO7cqa69oRhLZWmaLM0e9eeTugUXbnNQY3XPgRHJcSF8PKfp/dx3vHWtz9Y6o8fi3Ryjfpq4vBCeXjA=="
|
||||
},
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
|
|
|
@ -2,13 +2,18 @@
|
|||
"name": "@flarum/flarum-ext-emoji",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"emojibase-data": "^3.1.0",
|
||||
"flarum-webpack-config": "0.1.0-beta.9",
|
||||
"textarea-caret": "^3.1.0",
|
||||
"twemoji": "^11.0.1",
|
||||
"webpack": "^4.19.1",
|
||||
"webpack-cli": "^3.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --mode production",
|
||||
"watch": "webpack --mode development --watch"
|
||||
"watch": "webpack --mode development --watch",
|
||||
"prebuild": "npm run generate-emoji-map",
|
||||
"prewatch": "npm run generate-emoji-map",
|
||||
"generate-emoji-map": "node ./scripts/generate-emoji-map.js"
|
||||
}
|
||||
}
|
||||
|
|
45
extensions/emoji/js/scripts/generate-emoji-map.js
Normal file
45
extensions/emoji/js/scripts/generate-emoji-map.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const twemoji = require('twemoji/2/twemoji.npm');
|
||||
|
||||
const outputPath = './src/forum/generated/emojiMap.json';
|
||||
const data = require('emojibase-data/en/data.json');
|
||||
const twemojiFileNames = fs.readdirSync('./node_modules/twemoji/2/svg')
|
||||
.map(name => path.basename(name, '.svg'));
|
||||
|
||||
const alternative = {
|
||||
"👁️🗨️" : "👁🗨",
|
||||
};
|
||||
|
||||
const emojis = {};
|
||||
|
||||
for (let e of data) {
|
||||
const emoji = alternative[e.emoji] || e.emoji;
|
||||
const emojiCode = getEmojiIconCode(emoji);
|
||||
|
||||
if (!checkExistanceInTwemoji(emojiCode)) {
|
||||
console.error('Can not find', emoji, emojiCode);
|
||||
continue;
|
||||
}
|
||||
|
||||
emojis[emoji] = e.shortcodes;
|
||||
}
|
||||
|
||||
const outputDir = path.dirname(outputPath);
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir);
|
||||
}
|
||||
|
||||
fs.writeFileSync(outputPath, JSON.stringify(emojis));
|
||||
|
||||
function checkExistanceInTwemoji(code) {
|
||||
return twemojiFileNames.indexOf(code) != -1;
|
||||
}
|
||||
|
||||
function getEmojiIconCode(emoji) {
|
||||
const U200D = String.fromCharCode(0x200D);
|
||||
return twemoji.convert.toCodePoint(emoji.indexOf(U200D) < 0 ?
|
||||
emoji.replace(/\uFE0F/g, '') :
|
||||
emoji
|
||||
);
|
||||
}
|
|
@ -2,7 +2,8 @@ import getCaretCoordinates from 'textarea-caret';
|
|||
|
||||
import { extend } from 'flarum/extend';
|
||||
import ComposerBody from 'flarum/components/ComposerBody';
|
||||
import emojiMap from './helpers/emojiMap';
|
||||
import emojiMap from './generated/emojiMap.json';
|
||||
import getEmojiIconCode from './helpers/getEmojiIconCode';
|
||||
import KeyboardNavigatable from 'flarum/utils/KeyboardNavigatable';
|
||||
|
||||
import AutocompleteDropdown from './components/AutocompleteDropdown';
|
||||
|
@ -75,25 +76,22 @@ export default function addComposerAutocomplete() {
|
|||
if (emojiStart) {
|
||||
typed = value.substring(emojiStart, cursor).toLowerCase();
|
||||
|
||||
const makeSuggestion = function(key) {
|
||||
const code = ':' + key + ':';
|
||||
const imageName = emojiMap[key];
|
||||
const makeSuggestion = function({emoji, name, code}) {
|
||||
return (
|
||||
<button
|
||||
key={key}
|
||||
onclick={() => applySuggestion(code)}
|
||||
key={emoji}
|
||||
onclick={() => applySuggestion(emoji)}
|
||||
onmouseenter={function() {
|
||||
dropdown.setIndex($(this).parent().index());
|
||||
}}>
|
||||
<img alt={code} class="emoji" draggable="false" src={'//cdn.jsdelivr.net/emojione/assets/png/' + imageName + '.png'}/>
|
||||
{key}
|
||||
<img alt={emoji} class="emoji" draggable="false" src={'//twemoji.maxcdn.com/2/72x72/' + code + '.png'}/>
|
||||
{name}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const buildSuggestions = () => {
|
||||
const suggestions = [];
|
||||
let similarEmoji = [];
|
||||
const similarEmoji = [];
|
||||
|
||||
// Build a regular expression to do a fuzzy match of the given input string
|
||||
const fuzzyRegexp = function(str) {
|
||||
|
@ -107,9 +105,16 @@ export default function addComposerAutocomplete() {
|
|||
const findMatchingEmojis = matcher => {
|
||||
for (let i = 0; i < emojiKeys.length && maxSuggestions > 0; i++) {
|
||||
const curEmoji = emojiKeys[i];
|
||||
if (matcher(curEmoji) && similarEmoji.indexOf(curEmoji) === -1) {
|
||||
|
||||
if (similarEmoji.indexOf(curEmoji) === -1) {
|
||||
const names = emojiMap[curEmoji];
|
||||
for (let name of names) {
|
||||
if (matcher(name)) {
|
||||
--maxSuggestions;
|
||||
similarEmoji.push(emojiKeys[i]);
|
||||
similarEmoji.push(curEmoji);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -120,13 +125,13 @@ export default function addComposerAutocomplete() {
|
|||
// If there are still suggestions left, try for some fuzzy matches
|
||||
findMatchingEmojis(emoji => regTyped.test(emoji));
|
||||
|
||||
similarEmoji = similarEmoji.sort((a, b) => {
|
||||
return a.length - b.length
|
||||
});
|
||||
|
||||
for (let key of similarEmoji) {
|
||||
suggestions.push(makeSuggestion(key));
|
||||
}
|
||||
const suggestions = similarEmoji.map(emoji => ({
|
||||
emoji,
|
||||
name: emojiMap[emoji][0],
|
||||
code: getEmojiIconCode(emoji),
|
||||
})).sort((a, b) => {
|
||||
return a.name.length - b.name.length;
|
||||
}).map(makeSuggestion);
|
||||
|
||||
if (suggestions.length) {
|
||||
dropdown.props.items = suggestions;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
26
extensions/emoji/js/src/forum/helpers/getEmojiIconCode.js
Normal file
26
extensions/emoji/js/src/forum/helpers/getEmojiIconCode.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*
|
||||
https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
|
||||
*/
|
||||
|
||||
import twemoji from 'twemoji/2/twemoji.npm';
|
||||
|
||||
// avoid using a string literal like '\u200D' here because minifiers expand it inline
|
||||
const U200D = String.fromCharCode(0x200D);
|
||||
|
||||
// avoid runtime RegExp creation for not so smart,
|
||||
// not JIT based, and old browsers / engines
|
||||
const UFE0Fg = /\uFE0F/g;
|
||||
|
||||
/**
|
||||
* Used to both remove the possible variant
|
||||
* and to convert utf16 into code points.
|
||||
* If there is a zero-width-joiner (U+200D), leave the variants in.
|
||||
* @param string the raw text of the emoji match
|
||||
* @return string the code point
|
||||
*/
|
||||
export default function getEmojiIconCode(emoji) {
|
||||
return twemoji.convert.toCodePoint(emoji.indexOf(U200D) < 0 ?
|
||||
emoji.replace(UFE0Fg, '') :
|
||||
emoji
|
||||
);
|
||||
}
|
|
@ -3,9 +3,13 @@ import app from 'flarum/app';
|
|||
import Post from 'flarum/models/Post';
|
||||
|
||||
import addComposerAutocomplete from './addComposerAutocomplete';
|
||||
import renderEmoji from './renderEmoji';
|
||||
|
||||
app.initializers.add('flarum-emoji', () => {
|
||||
// After typing ':' in the composer, show a dropdown suggesting a bunch of
|
||||
// emoji that the user could use.
|
||||
addComposerAutocomplete();
|
||||
|
||||
// render emoji as image in Posts content and title.
|
||||
renderEmoji();
|
||||
});
|
||||
|
|
25
extensions/emoji/js/src/forum/renderEmoji.js
Normal file
25
extensions/emoji/js/src/forum/renderEmoji.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*global s9e*/
|
||||
|
||||
import twemoji from 'twemoji/2/twemoji.npm';
|
||||
|
||||
import { override } from 'flarum/extend';
|
||||
import Post from 'flarum/models/Post';
|
||||
|
||||
export default function renderEmoji() {
|
||||
override(Post.prototype, 'contentHtml', function(original) {
|
||||
const contentHtml = original();
|
||||
|
||||
if (this.oldContentHtml !== contentHtml) {
|
||||
this.emojifiedContentHtml = twemoji.parse(contentHtml);
|
||||
this.oldContentHtml = contentHtml;
|
||||
}
|
||||
|
||||
return this.emojifiedContentHtml;
|
||||
});
|
||||
|
||||
override(s9e.TextFormatter, 'preview', (original, text, element) => {
|
||||
original(text, element);
|
||||
|
||||
twemoji.parse(element);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user