1
0
mirror of https://github.com/twitter/twemoji.git synced 2024-07-03 03:18:58 +00:00

adding assets version 1 based on V2 API for testing and comparison purpose

This commit is contained in:
Andrea Giammarchi 2016-03-02 19:42:03 +00:00
parent 39e0a526f8
commit 0c1b4ddfd7
11 changed files with 4716 additions and 0 deletions

55
1/templates/preview.html Normal file
View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Twitter Emoji (Twemoji) Preview</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<style>
ul.emoji-list * {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
ul.emoji-list li {
font-size: 36px;
float: left;
display: inline-block;
padding: 2px;
margin: 4px;
}
img.emoji {
cursor: pointer;
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
</style>
<script src="https://twemoji.maxcdn.com/1/twemoji.min.js"></script>
</head>
<body>
<ul class="emoji-list">
{{emoji-list}}
</ul>
<script>
var ul = document.getElementsByTagName('ul')[0];
var total = ul.getElementsByTagName('li').length;
var elapsed = +new Date;
twemoji.parse(ul, {{emoji-options}});
elapsed = (+new Date) - elapsed;
document.body.insertBefore(
document.createTextNode(total + ' emoji parsed in ' + elapsed + 'ms'),
document.body.firstChild
);
(function (img, metaKey, i) {
function copyToClipboard(e) {
prompt('Copy to clipboard via ' + metaKey + '+C and Enter', this.alt);
}
for (i = 0; i < img.length; img[i++].onclick = copyToClipboard) {}
}(
document.getElementsByTagName('img'),
/\b(?:Mac |i)OS\b/i.test(navigator.userAgent) ? 'Command' : 'Ctrl'
));
</script>
</body>
</html>

928
1/test/preview-svg.html Normal file
View File

@ -0,0 +1,928 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Twitter Emoji (Twemoji) Preview</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<style>
ul.emoji-list * {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
ul.emoji-list li {
font-size: 36px;
float: left;
display: inline-block;
padding: 2px;
margin: 4px;
}
img.emoji {
cursor: pointer;
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
</style>
<script src="https://twemoji.maxcdn.com/1/twemoji.min.js"></script>
</head>
<body>
<ul class="emoji-list">
<li>&#x1F004;</li>
<li>&#x1F0CF;</li>
<li>&#x1F170;</li>
<li>&#x1F171;</li>
<li>&#x1F17E;</li>
<li>&#x1F17F;</li>
<li>&#x1F18E;</li>
<li>&#x1F191;</li>
<li>&#x1F192;</li>
<li>&#x1F193;</li>
<li>&#x1F194;</li>
<li>&#x1F195;</li>
<li>&#x1F196;</li>
<li>&#x1F197;</li>
<li>&#x1F198;</li>
<li>&#x1F199;</li>
<li>&#x1F19A;</li>
<li>&#x1F1E6;</li>
<li>&#x1F1E7;</li>
<li>&#x1F1E8;&#x1F1F3;</li>
<li>&#x1F1E8;</li>
<li>&#x1F1E9;&#x1F1EA;</li>
<li>&#x1F1E9;</li>
<li>&#x1F1EA;&#x1F1F8;</li>
<li>&#x1F1EA;</li>
<li>&#x1F1EB;&#x1F1F7;</li>
<li>&#x1F1EB;</li>
<li>&#x1F1EC;&#x1F1E7;</li>
<li>&#x1F1EC;</li>
<li>&#x1F1ED;</li>
<li>&#x1F1EE;&#x1F1F9;</li>
<li>&#x1F1EE;</li>
<li>&#x1F1EF;&#x1F1F5;</li>
<li>&#x1F1EF;</li>
<li>&#x1F1F0;&#x1F1F7;</li>
<li>&#x1F1F0;</li>
<li>&#x1F1F1;</li>
<li>&#x1F1F2;</li>
<li>&#x1F1F3;</li>
<li>&#x1F1F4;</li>
<li>&#x1F1F5;</li>
<li>&#x1F1F6;</li>
<li>&#x1F1F7;&#x1F1FA;</li>
<li>&#x1F1F7;</li>
<li>&#x1F1F8;</li>
<li>&#x1F1F9;</li>
<li>&#x1F1FA;&#x1F1F8;</li>
<li>&#x1F1FA;</li>
<li>&#x1F1FB;</li>
<li>&#x1F1FC;</li>
<li>&#x1F1FD;</li>
<li>&#x1F1FE;</li>
<li>&#x1F1FF;</li>
<li>&#x1F201;</li>
<li>&#x1F202;</li>
<li>&#x1F21A;</li>
<li>&#x1F22F;</li>
<li>&#x1F232;</li>
<li>&#x1F233;</li>
<li>&#x1F234;</li>
<li>&#x1F235;</li>
<li>&#x1F236;</li>
<li>&#x1F237;</li>
<li>&#x1F238;</li>
<li>&#x1F239;</li>
<li>&#x1F23A;</li>
<li>&#x1F250;</li>
<li>&#x1F251;</li>
<li>&#x1F300;</li>
<li>&#x1F301;</li>
<li>&#x1F302;</li>
<li>&#x1F303;</li>
<li>&#x1F304;</li>
<li>&#x1F305;</li>
<li>&#x1F306;</li>
<li>&#x1F307;</li>
<li>&#x1F308;</li>
<li>&#x1F309;</li>
<li>&#x1F30A;</li>
<li>&#x1F30B;</li>
<li>&#x1F30C;</li>
<li>&#x1F30D;</li>
<li>&#x1F30E;</li>
<li>&#x1F30F;</li>
<li>&#x1F310;</li>
<li>&#x1F311;</li>
<li>&#x1F312;</li>
<li>&#x1F313;</li>
<li>&#x1F314;</li>
<li>&#x1F315;</li>
<li>&#x1F316;</li>
<li>&#x1F317;</li>
<li>&#x1F318;</li>
<li>&#x1F319;</li>
<li>&#x1F31A;</li>
<li>&#x1F31B;</li>
<li>&#x1F31C;</li>
<li>&#x1F31D;</li>
<li>&#x1F31E;</li>
<li>&#x1F31F;</li>
<li>&#x1F320;</li>
<li>&#x1F330;</li>
<li>&#x1F331;</li>
<li>&#x1F332;</li>
<li>&#x1F333;</li>
<li>&#x1F334;</li>
<li>&#x1F335;</li>
<li>&#x1F337;</li>
<li>&#x1F338;</li>
<li>&#x1F339;</li>
<li>&#x1F33A;</li>
<li>&#x1F33B;</li>
<li>&#x1F33C;</li>
<li>&#x1F33D;</li>
<li>&#x1F33E;</li>
<li>&#x1F33F;</li>
<li>&#x1F340;</li>
<li>&#x1F341;</li>
<li>&#x1F342;</li>
<li>&#x1F343;</li>
<li>&#x1F344;</li>
<li>&#x1F345;</li>
<li>&#x1F346;</li>
<li>&#x1F347;</li>
<li>&#x1F348;</li>
<li>&#x1F349;</li>
<li>&#x1F34A;</li>
<li>&#x1F34B;</li>
<li>&#x1F34C;</li>
<li>&#x1F34D;</li>
<li>&#x1F34E;</li>
<li>&#x1F34F;</li>
<li>&#x1F350;</li>
<li>&#x1F351;</li>
<li>&#x1F352;</li>
<li>&#x1F353;</li>
<li>&#x1F354;</li>
<li>&#x1F355;</li>
<li>&#x1F356;</li>
<li>&#x1F357;</li>
<li>&#x1F358;</li>
<li>&#x1F359;</li>
<li>&#x1F35A;</li>
<li>&#x1F35B;</li>
<li>&#x1F35C;</li>
<li>&#x1F35D;</li>
<li>&#x1F35E;</li>
<li>&#x1F35F;</li>
<li>&#x1F360;</li>
<li>&#x1F361;</li>
<li>&#x1F362;</li>
<li>&#x1F363;</li>
<li>&#x1F364;</li>
<li>&#x1F365;</li>
<li>&#x1F366;</li>
<li>&#x1F367;</li>
<li>&#x1F368;</li>
<li>&#x1F369;</li>
<li>&#x1F36A;</li>
<li>&#x1F36B;</li>
<li>&#x1F36C;</li>
<li>&#x1F36D;</li>
<li>&#x1F36E;</li>
<li>&#x1F36F;</li>
<li>&#x1F370;</li>
<li>&#x1F371;</li>
<li>&#x1F372;</li>
<li>&#x1F373;</li>
<li>&#x1F374;</li>
<li>&#x1F375;</li>
<li>&#x1F376;</li>
<li>&#x1F377;</li>
<li>&#x1F378;</li>
<li>&#x1F379;</li>
<li>&#x1F37A;</li>
<li>&#x1F37B;</li>
<li>&#x1F37C;</li>
<li>&#x1F380;</li>
<li>&#x1F381;</li>
<li>&#x1F382;</li>
<li>&#x1F383;</li>
<li>&#x1F384;</li>
<li>&#x1F385;</li>
<li>&#x1F386;</li>
<li>&#x1F387;</li>
<li>&#x1F388;</li>
<li>&#x1F389;</li>
<li>&#x1F38A;</li>
<li>&#x1F38B;</li>
<li>&#x1F38C;</li>
<li>&#x1F38D;</li>
<li>&#x1F38E;</li>
<li>&#x1F38F;</li>
<li>&#x1F390;</li>
<li>&#x1F391;</li>
<li>&#x1F392;</li>
<li>&#x1F393;</li>
<li>&#x1F3A0;</li>
<li>&#x1F3A1;</li>
<li>&#x1F3A2;</li>
<li>&#x1F3A3;</li>
<li>&#x1F3A4;</li>
<li>&#x1F3A5;</li>
<li>&#x1F3A6;</li>
<li>&#x1F3A7;</li>
<li>&#x1F3A8;</li>
<li>&#x1F3A9;</li>
<li>&#x1F3AA;</li>
<li>&#x1F3AB;</li>
<li>&#x1F3AC;</li>
<li>&#x1F3AD;</li>
<li>&#x1F3AE;</li>
<li>&#x1F3AF;</li>
<li>&#x1F3B0;</li>
<li>&#x1F3B1;</li>
<li>&#x1F3B2;</li>
<li>&#x1F3B3;</li>
<li>&#x1F3B4;</li>
<li>&#x1F3B5;</li>
<li>&#x1F3B6;</li>
<li>&#x1F3B7;</li>
<li>&#x1F3B8;</li>
<li>&#x1F3B9;</li>
<li>&#x1F3BA;</li>
<li>&#x1F3BB;</li>
<li>&#x1F3BC;</li>
<li>&#x1F3BD;</li>
<li>&#x1F3BE;</li>
<li>&#x1F3BF;</li>
<li>&#x1F3C0;</li>
<li>&#x1F3C1;</li>
<li>&#x1F3C2;</li>
<li>&#x1F3C3;</li>
<li>&#x1F3C4;</li>
<li>&#x1F3C6;</li>
<li>&#x1F3C7;</li>
<li>&#x1F3C8;</li>
<li>&#x1F3C9;</li>
<li>&#x1F3CA;</li>
<li>&#x1F3E0;</li>
<li>&#x1F3E1;</li>
<li>&#x1F3E2;</li>
<li>&#x1F3E3;</li>
<li>&#x1F3E4;</li>
<li>&#x1F3E5;</li>
<li>&#x1F3E6;</li>
<li>&#x1F3E7;</li>
<li>&#x1F3E8;</li>
<li>&#x1F3E9;</li>
<li>&#x1F3EA;</li>
<li>&#x1F3EB;</li>
<li>&#x1F3EC;</li>
<li>&#x1F3ED;</li>
<li>&#x1F3EE;</li>
<li>&#x1F3EF;</li>
<li>&#x1F3F0;</li>
<li>&#x1F400;</li>
<li>&#x1F401;</li>
<li>&#x1F402;</li>
<li>&#x1F403;</li>
<li>&#x1F404;</li>
<li>&#x1F405;</li>
<li>&#x1F406;</li>
<li>&#x1F407;</li>
<li>&#x1F408;</li>
<li>&#x1F409;</li>
<li>&#x1F40A;</li>
<li>&#x1F40B;</li>
<li>&#x1F40C;</li>
<li>&#x1F40D;</li>
<li>&#x1F40E;</li>
<li>&#x1F40F;</li>
<li>&#x1F410;</li>
<li>&#x1F411;</li>
<li>&#x1F412;</li>
<li>&#x1F413;</li>
<li>&#x1F414;</li>
<li>&#x1F415;</li>
<li>&#x1F416;</li>
<li>&#x1F417;</li>
<li>&#x1F418;</li>
<li>&#x1F419;</li>
<li>&#x1F41A;</li>
<li>&#x1F41B;</li>
<li>&#x1F41C;</li>
<li>&#x1F41D;</li>
<li>&#x1F41E;</li>
<li>&#x1F41F;</li>
<li>&#x1F420;</li>
<li>&#x1F421;</li>
<li>&#x1F422;</li>
<li>&#x1F423;</li>
<li>&#x1F424;</li>
<li>&#x1F425;</li>
<li>&#x1F426;</li>
<li>&#x1F427;</li>
<li>&#x1F428;</li>
<li>&#x1F429;</li>
<li>&#x1F42A;</li>
<li>&#x1F42B;</li>
<li>&#x1F42C;</li>
<li>&#x1F42D;</li>
<li>&#x1F42E;</li>
<li>&#x1F42F;</li>
<li>&#x1F430;</li>
<li>&#x1F431;</li>
<li>&#x1F432;</li>
<li>&#x1F433;</li>
<li>&#x1F434;</li>
<li>&#x1F435;</li>
<li>&#x1F436;</li>
<li>&#x1F437;</li>
<li>&#x1F438;</li>
<li>&#x1F439;</li>
<li>&#x1F43A;</li>
<li>&#x1F43B;</li>
<li>&#x1F43C;</li>
<li>&#x1F43D;</li>
<li>&#x1F43E;</li>
<li>&#x1F440;</li>
<li>&#x1F442;</li>
<li>&#x1F443;</li>
<li>&#x1F444;</li>
<li>&#x1F445;</li>
<li>&#x1F446;</li>
<li>&#x1F447;</li>
<li>&#x1F448;</li>
<li>&#x1F449;</li>
<li>&#x1F44A;</li>
<li>&#x1F44B;</li>
<li>&#x1F44C;</li>
<li>&#x1F44D;</li>
<li>&#x1F44E;</li>
<li>&#x1F44F;</li>
<li>&#x1F450;</li>
<li>&#x1F451;</li>
<li>&#x1F452;</li>
<li>&#x1F453;</li>
<li>&#x1F454;</li>
<li>&#x1F455;</li>
<li>&#x1F456;</li>
<li>&#x1F457;</li>
<li>&#x1F458;</li>
<li>&#x1F459;</li>
<li>&#x1F45A;</li>
<li>&#x1F45B;</li>
<li>&#x1F45C;</li>
<li>&#x1F45D;</li>
<li>&#x1F45E;</li>
<li>&#x1F45F;</li>
<li>&#x1F460;</li>
<li>&#x1F461;</li>
<li>&#x1F462;</li>
<li>&#x1F463;</li>
<li>&#x1F464;</li>
<li>&#x1F465;</li>
<li>&#x1F466;</li>
<li>&#x1F467;</li>
<li>&#x1F468;</li>
<li>&#x1F469;</li>
<li>&#x1F46A;</li>
<li>&#x1F46B;</li>
<li>&#x1F46C;</li>
<li>&#x1F46D;</li>
<li>&#x1F46E;</li>
<li>&#x1F46F;</li>
<li>&#x1F470;</li>
<li>&#x1F471;</li>
<li>&#x1F472;</li>
<li>&#x1F473;</li>
<li>&#x1F474;</li>
<li>&#x1F475;</li>
<li>&#x1F476;</li>
<li>&#x1F477;</li>
<li>&#x1F478;</li>
<li>&#x1F479;</li>
<li>&#x1F47A;</li>
<li>&#x1F47B;</li>
<li>&#x1F47C;</li>
<li>&#x1F47D;</li>
<li>&#x1F47E;</li>
<li>&#x1F47F;</li>
<li>&#x1F480;</li>
<li>&#x1F481;</li>
<li>&#x1F482;</li>
<li>&#x1F483;</li>
<li>&#x1F484;</li>
<li>&#x1F485;</li>
<li>&#x1F486;</li>
<li>&#x1F487;</li>
<li>&#x1F488;</li>
<li>&#x1F489;</li>
<li>&#x1F48A;</li>
<li>&#x1F48B;</li>
<li>&#x1F48C;</li>
<li>&#x1F48D;</li>
<li>&#x1F48E;</li>
<li>&#x1F48F;</li>
<li>&#x1F490;</li>
<li>&#x1F491;</li>
<li>&#x1F492;</li>
<li>&#x1F493;</li>
<li>&#x1F494;</li>
<li>&#x1F495;</li>
<li>&#x1F496;</li>
<li>&#x1F497;</li>
<li>&#x1F498;</li>
<li>&#x1F499;</li>
<li>&#x1F49A;</li>
<li>&#x1F49B;</li>
<li>&#x1F49C;</li>
<li>&#x1F49D;</li>
<li>&#x1F49E;</li>
<li>&#x1F49F;</li>
<li>&#x1F4A0;</li>
<li>&#x1F4A1;</li>
<li>&#x1F4A2;</li>
<li>&#x1F4A3;</li>
<li>&#x1F4A4;</li>
<li>&#x1F4A5;</li>
<li>&#x1F4A6;</li>
<li>&#x1F4A7;</li>
<li>&#x1F4A8;</li>
<li>&#x1F4A9;</li>
<li>&#x1F4AA;</li>
<li>&#x1F4AB;</li>
<li>&#x1F4AC;</li>
<li>&#x1F4AD;</li>
<li>&#x1F4AE;</li>
<li>&#x1F4AF;</li>
<li>&#x1F4B0;</li>
<li>&#x1F4B1;</li>
<li>&#x1F4B2;</li>
<li>&#x1F4B3;</li>
<li>&#x1F4B4;</li>
<li>&#x1F4B5;</li>
<li>&#x1F4B6;</li>
<li>&#x1F4B7;</li>
<li>&#x1F4B8;</li>
<li>&#x1F4B9;</li>
<li>&#x1F4BA;</li>
<li>&#x1F4BB;</li>
<li>&#x1F4BC;</li>
<li>&#x1F4BD;</li>
<li>&#x1F4BE;</li>
<li>&#x1F4BF;</li>
<li>&#x1F4C0;</li>
<li>&#x1F4C1;</li>
<li>&#x1F4C2;</li>
<li>&#x1F4C3;</li>
<li>&#x1F4C4;</li>
<li>&#x1F4C5;</li>
<li>&#x1F4C6;</li>
<li>&#x1F4C7;</li>
<li>&#x1F4C8;</li>
<li>&#x1F4C9;</li>
<li>&#x1F4CA;</li>
<li>&#x1F4CB;</li>
<li>&#x1F4CC;</li>
<li>&#x1F4CD;</li>
<li>&#x1F4CE;</li>
<li>&#x1F4CF;</li>
<li>&#x1F4D0;</li>
<li>&#x1F4D1;</li>
<li>&#x1F4D2;</li>
<li>&#x1F4D3;</li>
<li>&#x1F4D4;</li>
<li>&#x1F4D5;</li>
<li>&#x1F4D6;</li>
<li>&#x1F4D7;</li>
<li>&#x1F4D8;</li>
<li>&#x1F4D9;</li>
<li>&#x1F4DA;</li>
<li>&#x1F4DB;</li>
<li>&#x1F4DC;</li>
<li>&#x1F4DD;</li>
<li>&#x1F4DE;</li>
<li>&#x1F4DF;</li>
<li>&#x1F4E0;</li>
<li>&#x1F4E1;</li>
<li>&#x1F4E2;</li>
<li>&#x1F4E3;</li>
<li>&#x1F4E4;</li>
<li>&#x1F4E5;</li>
<li>&#x1F4E6;</li>
<li>&#x1F4E7;</li>
<li>&#x1F4E8;</li>
<li>&#x1F4E9;</li>
<li>&#x1F4EA;</li>
<li>&#x1F4EB;</li>
<li>&#x1F4EC;</li>
<li>&#x1F4ED;</li>
<li>&#x1F4EE;</li>
<li>&#x1F4EF;</li>
<li>&#x1F4F0;</li>
<li>&#x1F4F1;</li>
<li>&#x1F4F2;</li>
<li>&#x1F4F3;</li>
<li>&#x1F4F4;</li>
<li>&#x1F4F5;</li>
<li>&#x1F4F6;</li>
<li>&#x1F4F7;</li>
<li>&#x1F4F9;</li>
<li>&#x1F4FA;</li>
<li>&#x1F4FB;</li>
<li>&#x1F4FC;</li>
<li>&#x1F500;</li>
<li>&#x1F501;</li>
<li>&#x1F502;</li>
<li>&#x1F503;</li>
<li>&#x1F504;</li>
<li>&#x1F505;</li>
<li>&#x1F506;</li>
<li>&#x1F507;</li>
<li>&#x1F508;</li>
<li>&#x1F509;</li>
<li>&#x1F50A;</li>
<li>&#x1F50B;</li>
<li>&#x1F50C;</li>
<li>&#x1F50D;</li>
<li>&#x1F50E;</li>
<li>&#x1F50F;</li>
<li>&#x1F510;</li>
<li>&#x1F511;</li>
<li>&#x1F512;</li>
<li>&#x1F513;</li>
<li>&#x1F514;</li>
<li>&#x1F515;</li>
<li>&#x1F516;</li>
<li>&#x1F517;</li>
<li>&#x1F518;</li>
<li>&#x1F519;</li>
<li>&#x1F51A;</li>
<li>&#x1F51B;</li>
<li>&#x1F51C;</li>
<li>&#x1F51D;</li>
<li>&#x1F51E;</li>
<li>&#x1F51F;</li>
<li>&#x1F520;</li>
<li>&#x1F521;</li>
<li>&#x1F522;</li>
<li>&#x1F523;</li>
<li>&#x1F524;</li>
<li>&#x1F525;</li>
<li>&#x1F526;</li>
<li>&#x1F527;</li>
<li>&#x1F528;</li>
<li>&#x1F529;</li>
<li>&#x1F52A;</li>
<li>&#x1F52B;</li>
<li>&#x1F52C;</li>
<li>&#x1F52D;</li>
<li>&#x1F52E;</li>
<li>&#x1F52F;</li>
<li>&#x1F530;</li>
<li>&#x1F531;</li>
<li>&#x1F532;</li>
<li>&#x1F533;</li>
<li>&#x1F534;</li>
<li>&#x1F535;</li>
<li>&#x1F536;</li>
<li>&#x1F537;</li>
<li>&#x1F538;</li>
<li>&#x1F539;</li>
<li>&#x1F53A;</li>
<li>&#x1F53B;</li>
<li>&#x1F53C;</li>
<li>&#x1F53D;</li>
<li>&#x1F550;</li>
<li>&#x1F551;</li>
<li>&#x1F552;</li>
<li>&#x1F553;</li>
<li>&#x1F554;</li>
<li>&#x1F555;</li>
<li>&#x1F556;</li>
<li>&#x1F557;</li>
<li>&#x1F558;</li>
<li>&#x1F559;</li>
<li>&#x1F55A;</li>
<li>&#x1F55B;</li>
<li>&#x1F55C;</li>
<li>&#x1F55D;</li>
<li>&#x1F55E;</li>
<li>&#x1F55F;</li>
<li>&#x1F560;</li>
<li>&#x1F561;</li>
<li>&#x1F562;</li>
<li>&#x1F563;</li>
<li>&#x1F564;</li>
<li>&#x1F565;</li>
<li>&#x1F566;</li>
<li>&#x1F567;</li>
<li>&#x1F5FB;</li>
<li>&#x1F5FC;</li>
<li>&#x1F5FD;</li>
<li>&#x1F5FE;</li>
<li>&#x1F5FF;</li>
<li>&#x1F600;</li>
<li>&#x1F601;</li>
<li>&#x1F602;</li>
<li>&#x1F603;</li>
<li>&#x1F604;</li>
<li>&#x1F605;</li>
<li>&#x1F606;</li>
<li>&#x1F607;</li>
<li>&#x1F608;</li>
<li>&#x1F609;</li>
<li>&#x1F60A;</li>
<li>&#x1F60B;</li>
<li>&#x1F60C;</li>
<li>&#x1F60D;</li>
<li>&#x1F60E;</li>
<li>&#x1F60F;</li>
<li>&#x1F610;</li>
<li>&#x1F611;</li>
<li>&#x1F612;</li>
<li>&#x1F613;</li>
<li>&#x1F614;</li>
<li>&#x1F615;</li>
<li>&#x1F616;</li>
<li>&#x1F617;</li>
<li>&#x1F618;</li>
<li>&#x1F619;</li>
<li>&#x1F61A;</li>
<li>&#x1F61B;</li>
<li>&#x1F61C;</li>
<li>&#x1F61D;</li>
<li>&#x1F61E;</li>
<li>&#x1F61F;</li>
<li>&#x1F620;</li>
<li>&#x1F621;</li>
<li>&#x1F622;</li>
<li>&#x1F623;</li>
<li>&#x1F624;</li>
<li>&#x1F625;</li>
<li>&#x1F626;</li>
<li>&#x1F627;</li>
<li>&#x1F628;</li>
<li>&#x1F629;</li>
<li>&#x1F62A;</li>
<li>&#x1F62B;</li>
<li>&#x1F62C;</li>
<li>&#x1F62D;</li>
<li>&#x1F62E;</li>
<li>&#x1F62F;</li>
<li>&#x1F630;</li>
<li>&#x1F631;</li>
<li>&#x1F632;</li>
<li>&#x1F633;</li>
<li>&#x1F634;</li>
<li>&#x1F635;</li>
<li>&#x1F636;</li>
<li>&#x1F637;</li>
<li>&#x1F638;</li>
<li>&#x1F639;</li>
<li>&#x1F63A;</li>
<li>&#x1F63B;</li>
<li>&#x1F63C;</li>
<li>&#x1F63D;</li>
<li>&#x1F63E;</li>
<li>&#x1F63F;</li>
<li>&#x1F640;</li>
<li>&#x1F641;</li>
<li>&#x1F642;</li>
<li>&#x1F645;</li>
<li>&#x1F646;</li>
<li>&#x1F647;</li>
<li>&#x1F648;</li>
<li>&#x1F649;</li>
<li>&#x1F64A;</li>
<li>&#x1F64B;</li>
<li>&#x1F64C;</li>
<li>&#x1F64D;</li>
<li>&#x1F64E;</li>
<li>&#x1F64F;</li>
<li>&#x1F680;</li>
<li>&#x1F681;</li>
<li>&#x1F682;</li>
<li>&#x1F683;</li>
<li>&#x1F684;</li>
<li>&#x1F685;</li>
<li>&#x1F686;</li>
<li>&#x1F687;</li>
<li>&#x1F688;</li>
<li>&#x1F689;</li>
<li>&#x1F68A;</li>
<li>&#x1F68B;</li>
<li>&#x1F68C;</li>
<li>&#x1F68D;</li>
<li>&#x1F68E;</li>
<li>&#x1F68F;</li>
<li>&#x1F690;</li>
<li>&#x1F691;</li>
<li>&#x1F692;</li>
<li>&#x1F693;</li>
<li>&#x1F694;</li>
<li>&#x1F695;</li>
<li>&#x1F696;</li>
<li>&#x1F697;</li>
<li>&#x1F698;</li>
<li>&#x1F699;</li>
<li>&#x1F69A;</li>
<li>&#x1F69B;</li>
<li>&#x1F69C;</li>
<li>&#x1F69D;</li>
<li>&#x1F69E;</li>
<li>&#x1F69F;</li>
<li>&#x1F6A0;</li>
<li>&#x1F6A1;</li>
<li>&#x1F6A2;</li>
<li>&#x1F6A3;</li>
<li>&#x1F6A4;</li>
<li>&#x1F6A5;</li>
<li>&#x1F6A6;</li>
<li>&#x1F6A7;</li>
<li>&#x1F6A8;</li>
<li>&#x1F6A9;</li>
<li>&#x1F6AA;</li>
<li>&#x1F6AB;</li>
<li>&#x1F6AC;</li>
<li>&#x1F6AD;</li>
<li>&#x1F6AE;</li>
<li>&#x1F6AF;</li>
<li>&#x1F6B0;</li>
<li>&#x1F6B1;</li>
<li>&#x1F6B2;</li>
<li>&#x1F6B3;</li>
<li>&#x1F6B4;</li>
<li>&#x1F6B5;</li>
<li>&#x1F6B6;</li>
<li>&#x1F6B7;</li>
<li>&#x1F6B8;</li>
<li>&#x1F6B9;</li>
<li>&#x1F6BA;</li>
<li>&#x1F6BB;</li>
<li>&#x1F6BC;</li>
<li>&#x1F6BD;</li>
<li>&#x1F6BE;</li>
<li>&#x1F6BF;</li>
<li>&#x1F6C0;</li>
<li>&#x1F6C1;</li>
<li>&#x1F6C2;</li>
<li>&#x1F6C3;</li>
<li>&#x1F6C4;</li>
<li>&#x1F6C5;</li>
<li>&#x203C;</li>
<li>&#x2049;</li>
<li>&#x2122;</li>
<li>&#x2139;</li>
<li>&#x2194;</li>
<li>&#x2195;</li>
<li>&#x2196;</li>
<li>&#x2197;</li>
<li>&#x2198;</li>
<li>&#x2199;</li>
<li>&#x21A9;</li>
<li>&#x21AA;</li>
<li>&#x23;&#x20E3;</li>
<li>&#x231A;</li>
<li>&#x231B;</li>
<li>&#x23E9;</li>
<li>&#x23EA;</li>
<li>&#x23EB;</li>
<li>&#x23EC;</li>
<li>&#x23F0;</li>
<li>&#x23F3;</li>
<li>&#x24C2;</li>
<li>&#x25AA;</li>
<li>&#x25AB;</li>
<li>&#x25B6;</li>
<li>&#x25C0;</li>
<li>&#x25FB;</li>
<li>&#x25FC;</li>
<li>&#x25FD;</li>
<li>&#x25FE;</li>
<li>&#x2600;</li>
<li>&#x2601;</li>
<li>&#x260E;</li>
<li>&#x2611;</li>
<li>&#x2614;</li>
<li>&#x2615;</li>
<li>&#x261D;</li>
<li>&#x263A;</li>
<li>&#x2648;</li>
<li>&#x2649;</li>
<li>&#x264A;</li>
<li>&#x264B;</li>
<li>&#x264C;</li>
<li>&#x264D;</li>
<li>&#x264E;</li>
<li>&#x264F;</li>
<li>&#x2650;</li>
<li>&#x2651;</li>
<li>&#x2652;</li>
<li>&#x2653;</li>
<li>&#x2660;</li>
<li>&#x2663;</li>
<li>&#x2665;</li>
<li>&#x2666;</li>
<li>&#x2668;</li>
<li>&#x267B;</li>
<li>&#x267F;</li>
<li>&#x2693;</li>
<li>&#x26A0;</li>
<li>&#x26A1;</li>
<li>&#x26AA;</li>
<li>&#x26AB;</li>
<li>&#x26BD;</li>
<li>&#x26BE;</li>
<li>&#x26C4;</li>
<li>&#x26C5;</li>
<li>&#x26CE;</li>
<li>&#x26D4;</li>
<li>&#x26EA;</li>
<li>&#x26F2;</li>
<li>&#x26F3;</li>
<li>&#x26F5;</li>
<li>&#x26FA;</li>
<li>&#x26FD;</li>
<li>&#x2702;</li>
<li>&#x2705;</li>
<li>&#x2708;</li>
<li>&#x2709;</li>
<li>&#x270A;</li>
<li>&#x270B;</li>
<li>&#x270C;</li>
<li>&#x270F;</li>
<li>&#x2712;</li>
<li>&#x2714;</li>
<li>&#x2716;</li>
<li>&#x2728;</li>
<li>&#x2733;</li>
<li>&#x2734;</li>
<li>&#x2744;</li>
<li>&#x2747;</li>
<li>&#x274C;</li>
<li>&#x274E;</li>
<li>&#x2753;</li>
<li>&#x2754;</li>
<li>&#x2755;</li>
<li>&#x2757;</li>
<li>&#x2764;</li>
<li>&#x2795;</li>
<li>&#x2796;</li>
<li>&#x2797;</li>
<li>&#x27A1;</li>
<li>&#x27B0;</li>
<li>&#x27BF;</li>
<li>&#x2934;</li>
<li>&#x2935;</li>
<li>&#x2B05;</li>
<li>&#x2B06;</li>
<li>&#x2B07;</li>
<li>&#x2B1B;</li>
<li>&#x2B1C;</li>
<li>&#x2B50;</li>
<li>&#x2B55;</li>
<li>&#x30;&#x20E3;</li>
<li>&#x3030;</li>
<li>&#x303D;</li>
<li>&#x31;&#x20E3;</li>
<li>&#x32;&#x20E3;</li>
<li>&#x3297;</li>
<li>&#x3299;</li>
<li>&#x33;&#x20E3;</li>
<li>&#x34;&#x20E3;</li>
<li>&#x35;&#x20E3;</li>
<li>&#x36;&#x20E3;</li>
<li>&#x37;&#x20E3;</li>
<li>&#x38;&#x20E3;</li>
<li>&#x39;&#x20E3;</li>
<li>&#xA9;</li>
<li>&#xAE;</li>
<li>&#xE50A;</li>
</ul>
<script>
var ul = document.getElementsByTagName('ul')[0];
var total = ul.getElementsByTagName('li').length;
var elapsed = +new Date;
twemoji.parse(ul, {"folder":"../svg","ext":".svg","base":""});
elapsed = (+new Date) - elapsed;
document.body.insertBefore(
document.createTextNode(total + ' emoji parsed in ' + elapsed + 'ms'),
document.body.firstChild
);
(function (img, metaKey, i) {
function copyToClipboard(e) {
prompt('Copy to clipboard via ' + metaKey + '+C and Enter', this.alt);
}
for (i = 0; i < img.length; img[i++].onclick = copyToClipboard) {}
}(
document.getElementsByTagName('img'),
/\b(?:Mac |i)OS\b/i.test(navigator.userAgent) ? 'Command' : 'Ctrl'
));
</script>
</body>
</html>

928
1/test/preview.html Normal file
View File

@ -0,0 +1,928 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Twitter Emoji (Twemoji) Preview</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<style>
ul.emoji-list * {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
ul.emoji-list li {
font-size: 36px;
float: left;
display: inline-block;
padding: 2px;
margin: 4px;
}
img.emoji {
cursor: pointer;
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
</style>
<script src="https://twemoji.maxcdn.com/1/twemoji.min.js"></script>
</head>
<body>
<ul class="emoji-list">
<li>&#x1F004;</li>
<li>&#x1F0CF;</li>
<li>&#x1F170;</li>
<li>&#x1F171;</li>
<li>&#x1F17E;</li>
<li>&#x1F17F;</li>
<li>&#x1F18E;</li>
<li>&#x1F191;</li>
<li>&#x1F192;</li>
<li>&#x1F193;</li>
<li>&#x1F194;</li>
<li>&#x1F195;</li>
<li>&#x1F196;</li>
<li>&#x1F197;</li>
<li>&#x1F198;</li>
<li>&#x1F199;</li>
<li>&#x1F19A;</li>
<li>&#x1F1E6;</li>
<li>&#x1F1E7;</li>
<li>&#x1F1E8;&#x1F1F3;</li>
<li>&#x1F1E8;</li>
<li>&#x1F1E9;&#x1F1EA;</li>
<li>&#x1F1E9;</li>
<li>&#x1F1EA;&#x1F1F8;</li>
<li>&#x1F1EA;</li>
<li>&#x1F1EB;&#x1F1F7;</li>
<li>&#x1F1EB;</li>
<li>&#x1F1EC;&#x1F1E7;</li>
<li>&#x1F1EC;</li>
<li>&#x1F1ED;</li>
<li>&#x1F1EE;&#x1F1F9;</li>
<li>&#x1F1EE;</li>
<li>&#x1F1EF;&#x1F1F5;</li>
<li>&#x1F1EF;</li>
<li>&#x1F1F0;&#x1F1F7;</li>
<li>&#x1F1F0;</li>
<li>&#x1F1F1;</li>
<li>&#x1F1F2;</li>
<li>&#x1F1F3;</li>
<li>&#x1F1F4;</li>
<li>&#x1F1F5;</li>
<li>&#x1F1F6;</li>
<li>&#x1F1F7;&#x1F1FA;</li>
<li>&#x1F1F7;</li>
<li>&#x1F1F8;</li>
<li>&#x1F1F9;</li>
<li>&#x1F1FA;&#x1F1F8;</li>
<li>&#x1F1FA;</li>
<li>&#x1F1FB;</li>
<li>&#x1F1FC;</li>
<li>&#x1F1FD;</li>
<li>&#x1F1FE;</li>
<li>&#x1F1FF;</li>
<li>&#x1F201;</li>
<li>&#x1F202;</li>
<li>&#x1F21A;</li>
<li>&#x1F22F;</li>
<li>&#x1F232;</li>
<li>&#x1F233;</li>
<li>&#x1F234;</li>
<li>&#x1F235;</li>
<li>&#x1F236;</li>
<li>&#x1F237;</li>
<li>&#x1F238;</li>
<li>&#x1F239;</li>
<li>&#x1F23A;</li>
<li>&#x1F250;</li>
<li>&#x1F251;</li>
<li>&#x1F300;</li>
<li>&#x1F301;</li>
<li>&#x1F302;</li>
<li>&#x1F303;</li>
<li>&#x1F304;</li>
<li>&#x1F305;</li>
<li>&#x1F306;</li>
<li>&#x1F307;</li>
<li>&#x1F308;</li>
<li>&#x1F309;</li>
<li>&#x1F30A;</li>
<li>&#x1F30B;</li>
<li>&#x1F30C;</li>
<li>&#x1F30D;</li>
<li>&#x1F30E;</li>
<li>&#x1F30F;</li>
<li>&#x1F310;</li>
<li>&#x1F311;</li>
<li>&#x1F312;</li>
<li>&#x1F313;</li>
<li>&#x1F314;</li>
<li>&#x1F315;</li>
<li>&#x1F316;</li>
<li>&#x1F317;</li>
<li>&#x1F318;</li>
<li>&#x1F319;</li>
<li>&#x1F31A;</li>
<li>&#x1F31B;</li>
<li>&#x1F31C;</li>
<li>&#x1F31D;</li>
<li>&#x1F31E;</li>
<li>&#x1F31F;</li>
<li>&#x1F320;</li>
<li>&#x1F330;</li>
<li>&#x1F331;</li>
<li>&#x1F332;</li>
<li>&#x1F333;</li>
<li>&#x1F334;</li>
<li>&#x1F335;</li>
<li>&#x1F337;</li>
<li>&#x1F338;</li>
<li>&#x1F339;</li>
<li>&#x1F33A;</li>
<li>&#x1F33B;</li>
<li>&#x1F33C;</li>
<li>&#x1F33D;</li>
<li>&#x1F33E;</li>
<li>&#x1F33F;</li>
<li>&#x1F340;</li>
<li>&#x1F341;</li>
<li>&#x1F342;</li>
<li>&#x1F343;</li>
<li>&#x1F344;</li>
<li>&#x1F345;</li>
<li>&#x1F346;</li>
<li>&#x1F347;</li>
<li>&#x1F348;</li>
<li>&#x1F349;</li>
<li>&#x1F34A;</li>
<li>&#x1F34B;</li>
<li>&#x1F34C;</li>
<li>&#x1F34D;</li>
<li>&#x1F34E;</li>
<li>&#x1F34F;</li>
<li>&#x1F350;</li>
<li>&#x1F351;</li>
<li>&#x1F352;</li>
<li>&#x1F353;</li>
<li>&#x1F354;</li>
<li>&#x1F355;</li>
<li>&#x1F356;</li>
<li>&#x1F357;</li>
<li>&#x1F358;</li>
<li>&#x1F359;</li>
<li>&#x1F35A;</li>
<li>&#x1F35B;</li>
<li>&#x1F35C;</li>
<li>&#x1F35D;</li>
<li>&#x1F35E;</li>
<li>&#x1F35F;</li>
<li>&#x1F360;</li>
<li>&#x1F361;</li>
<li>&#x1F362;</li>
<li>&#x1F363;</li>
<li>&#x1F364;</li>
<li>&#x1F365;</li>
<li>&#x1F366;</li>
<li>&#x1F367;</li>
<li>&#x1F368;</li>
<li>&#x1F369;</li>
<li>&#x1F36A;</li>
<li>&#x1F36B;</li>
<li>&#x1F36C;</li>
<li>&#x1F36D;</li>
<li>&#x1F36E;</li>
<li>&#x1F36F;</li>
<li>&#x1F370;</li>
<li>&#x1F371;</li>
<li>&#x1F372;</li>
<li>&#x1F373;</li>
<li>&#x1F374;</li>
<li>&#x1F375;</li>
<li>&#x1F376;</li>
<li>&#x1F377;</li>
<li>&#x1F378;</li>
<li>&#x1F379;</li>
<li>&#x1F37A;</li>
<li>&#x1F37B;</li>
<li>&#x1F37C;</li>
<li>&#x1F380;</li>
<li>&#x1F381;</li>
<li>&#x1F382;</li>
<li>&#x1F383;</li>
<li>&#x1F384;</li>
<li>&#x1F385;</li>
<li>&#x1F386;</li>
<li>&#x1F387;</li>
<li>&#x1F388;</li>
<li>&#x1F389;</li>
<li>&#x1F38A;</li>
<li>&#x1F38B;</li>
<li>&#x1F38C;</li>
<li>&#x1F38D;</li>
<li>&#x1F38E;</li>
<li>&#x1F38F;</li>
<li>&#x1F390;</li>
<li>&#x1F391;</li>
<li>&#x1F392;</li>
<li>&#x1F393;</li>
<li>&#x1F3A0;</li>
<li>&#x1F3A1;</li>
<li>&#x1F3A2;</li>
<li>&#x1F3A3;</li>
<li>&#x1F3A4;</li>
<li>&#x1F3A5;</li>
<li>&#x1F3A6;</li>
<li>&#x1F3A7;</li>
<li>&#x1F3A8;</li>
<li>&#x1F3A9;</li>
<li>&#x1F3AA;</li>
<li>&#x1F3AB;</li>
<li>&#x1F3AC;</li>
<li>&#x1F3AD;</li>
<li>&#x1F3AE;</li>
<li>&#x1F3AF;</li>
<li>&#x1F3B0;</li>
<li>&#x1F3B1;</li>
<li>&#x1F3B2;</li>
<li>&#x1F3B3;</li>
<li>&#x1F3B4;</li>
<li>&#x1F3B5;</li>
<li>&#x1F3B6;</li>
<li>&#x1F3B7;</li>
<li>&#x1F3B8;</li>
<li>&#x1F3B9;</li>
<li>&#x1F3BA;</li>
<li>&#x1F3BB;</li>
<li>&#x1F3BC;</li>
<li>&#x1F3BD;</li>
<li>&#x1F3BE;</li>
<li>&#x1F3BF;</li>
<li>&#x1F3C0;</li>
<li>&#x1F3C1;</li>
<li>&#x1F3C2;</li>
<li>&#x1F3C3;</li>
<li>&#x1F3C4;</li>
<li>&#x1F3C6;</li>
<li>&#x1F3C7;</li>
<li>&#x1F3C8;</li>
<li>&#x1F3C9;</li>
<li>&#x1F3CA;</li>
<li>&#x1F3E0;</li>
<li>&#x1F3E1;</li>
<li>&#x1F3E2;</li>
<li>&#x1F3E3;</li>
<li>&#x1F3E4;</li>
<li>&#x1F3E5;</li>
<li>&#x1F3E6;</li>
<li>&#x1F3E7;</li>
<li>&#x1F3E8;</li>
<li>&#x1F3E9;</li>
<li>&#x1F3EA;</li>
<li>&#x1F3EB;</li>
<li>&#x1F3EC;</li>
<li>&#x1F3ED;</li>
<li>&#x1F3EE;</li>
<li>&#x1F3EF;</li>
<li>&#x1F3F0;</li>
<li>&#x1F400;</li>
<li>&#x1F401;</li>
<li>&#x1F402;</li>
<li>&#x1F403;</li>
<li>&#x1F404;</li>
<li>&#x1F405;</li>
<li>&#x1F406;</li>
<li>&#x1F407;</li>
<li>&#x1F408;</li>
<li>&#x1F409;</li>
<li>&#x1F40A;</li>
<li>&#x1F40B;</li>
<li>&#x1F40C;</li>
<li>&#x1F40D;</li>
<li>&#x1F40E;</li>
<li>&#x1F40F;</li>
<li>&#x1F410;</li>
<li>&#x1F411;</li>
<li>&#x1F412;</li>
<li>&#x1F413;</li>
<li>&#x1F414;</li>
<li>&#x1F415;</li>
<li>&#x1F416;</li>
<li>&#x1F417;</li>
<li>&#x1F418;</li>
<li>&#x1F419;</li>
<li>&#x1F41A;</li>
<li>&#x1F41B;</li>
<li>&#x1F41C;</li>
<li>&#x1F41D;</li>
<li>&#x1F41E;</li>
<li>&#x1F41F;</li>
<li>&#x1F420;</li>
<li>&#x1F421;</li>
<li>&#x1F422;</li>
<li>&#x1F423;</li>
<li>&#x1F424;</li>
<li>&#x1F425;</li>
<li>&#x1F426;</li>
<li>&#x1F427;</li>
<li>&#x1F428;</li>
<li>&#x1F429;</li>
<li>&#x1F42A;</li>
<li>&#x1F42B;</li>
<li>&#x1F42C;</li>
<li>&#x1F42D;</li>
<li>&#x1F42E;</li>
<li>&#x1F42F;</li>
<li>&#x1F430;</li>
<li>&#x1F431;</li>
<li>&#x1F432;</li>
<li>&#x1F433;</li>
<li>&#x1F434;</li>
<li>&#x1F435;</li>
<li>&#x1F436;</li>
<li>&#x1F437;</li>
<li>&#x1F438;</li>
<li>&#x1F439;</li>
<li>&#x1F43A;</li>
<li>&#x1F43B;</li>
<li>&#x1F43C;</li>
<li>&#x1F43D;</li>
<li>&#x1F43E;</li>
<li>&#x1F440;</li>
<li>&#x1F442;</li>
<li>&#x1F443;</li>
<li>&#x1F444;</li>
<li>&#x1F445;</li>
<li>&#x1F446;</li>
<li>&#x1F447;</li>
<li>&#x1F448;</li>
<li>&#x1F449;</li>
<li>&#x1F44A;</li>
<li>&#x1F44B;</li>
<li>&#x1F44C;</li>
<li>&#x1F44D;</li>
<li>&#x1F44E;</li>
<li>&#x1F44F;</li>
<li>&#x1F450;</li>
<li>&#x1F451;</li>
<li>&#x1F452;</li>
<li>&#x1F453;</li>
<li>&#x1F454;</li>
<li>&#x1F455;</li>
<li>&#x1F456;</li>
<li>&#x1F457;</li>
<li>&#x1F458;</li>
<li>&#x1F459;</li>
<li>&#x1F45A;</li>
<li>&#x1F45B;</li>
<li>&#x1F45C;</li>
<li>&#x1F45D;</li>
<li>&#x1F45E;</li>
<li>&#x1F45F;</li>
<li>&#x1F460;</li>
<li>&#x1F461;</li>
<li>&#x1F462;</li>
<li>&#x1F463;</li>
<li>&#x1F464;</li>
<li>&#x1F465;</li>
<li>&#x1F466;</li>
<li>&#x1F467;</li>
<li>&#x1F468;</li>
<li>&#x1F469;</li>
<li>&#x1F46A;</li>
<li>&#x1F46B;</li>
<li>&#x1F46C;</li>
<li>&#x1F46D;</li>
<li>&#x1F46E;</li>
<li>&#x1F46F;</li>
<li>&#x1F470;</li>
<li>&#x1F471;</li>
<li>&#x1F472;</li>
<li>&#x1F473;</li>
<li>&#x1F474;</li>
<li>&#x1F475;</li>
<li>&#x1F476;</li>
<li>&#x1F477;</li>
<li>&#x1F478;</li>
<li>&#x1F479;</li>
<li>&#x1F47A;</li>
<li>&#x1F47B;</li>
<li>&#x1F47C;</li>
<li>&#x1F47D;</li>
<li>&#x1F47E;</li>
<li>&#x1F47F;</li>
<li>&#x1F480;</li>
<li>&#x1F481;</li>
<li>&#x1F482;</li>
<li>&#x1F483;</li>
<li>&#x1F484;</li>
<li>&#x1F485;</li>
<li>&#x1F486;</li>
<li>&#x1F487;</li>
<li>&#x1F488;</li>
<li>&#x1F489;</li>
<li>&#x1F48A;</li>
<li>&#x1F48B;</li>
<li>&#x1F48C;</li>
<li>&#x1F48D;</li>
<li>&#x1F48E;</li>
<li>&#x1F48F;</li>
<li>&#x1F490;</li>
<li>&#x1F491;</li>
<li>&#x1F492;</li>
<li>&#x1F493;</li>
<li>&#x1F494;</li>
<li>&#x1F495;</li>
<li>&#x1F496;</li>
<li>&#x1F497;</li>
<li>&#x1F498;</li>
<li>&#x1F499;</li>
<li>&#x1F49A;</li>
<li>&#x1F49B;</li>
<li>&#x1F49C;</li>
<li>&#x1F49D;</li>
<li>&#x1F49E;</li>
<li>&#x1F49F;</li>
<li>&#x1F4A0;</li>
<li>&#x1F4A1;</li>
<li>&#x1F4A2;</li>
<li>&#x1F4A3;</li>
<li>&#x1F4A4;</li>
<li>&#x1F4A5;</li>
<li>&#x1F4A6;</li>
<li>&#x1F4A7;</li>
<li>&#x1F4A8;</li>
<li>&#x1F4A9;</li>
<li>&#x1F4AA;</li>
<li>&#x1F4AB;</li>
<li>&#x1F4AC;</li>
<li>&#x1F4AD;</li>
<li>&#x1F4AE;</li>
<li>&#x1F4AF;</li>
<li>&#x1F4B0;</li>
<li>&#x1F4B1;</li>
<li>&#x1F4B2;</li>
<li>&#x1F4B3;</li>
<li>&#x1F4B4;</li>
<li>&#x1F4B5;</li>
<li>&#x1F4B6;</li>
<li>&#x1F4B7;</li>
<li>&#x1F4B8;</li>
<li>&#x1F4B9;</li>
<li>&#x1F4BA;</li>
<li>&#x1F4BB;</li>
<li>&#x1F4BC;</li>
<li>&#x1F4BD;</li>
<li>&#x1F4BE;</li>
<li>&#x1F4BF;</li>
<li>&#x1F4C0;</li>
<li>&#x1F4C1;</li>
<li>&#x1F4C2;</li>
<li>&#x1F4C3;</li>
<li>&#x1F4C4;</li>
<li>&#x1F4C5;</li>
<li>&#x1F4C6;</li>
<li>&#x1F4C7;</li>
<li>&#x1F4C8;</li>
<li>&#x1F4C9;</li>
<li>&#x1F4CA;</li>
<li>&#x1F4CB;</li>
<li>&#x1F4CC;</li>
<li>&#x1F4CD;</li>
<li>&#x1F4CE;</li>
<li>&#x1F4CF;</li>
<li>&#x1F4D0;</li>
<li>&#x1F4D1;</li>
<li>&#x1F4D2;</li>
<li>&#x1F4D3;</li>
<li>&#x1F4D4;</li>
<li>&#x1F4D5;</li>
<li>&#x1F4D6;</li>
<li>&#x1F4D7;</li>
<li>&#x1F4D8;</li>
<li>&#x1F4D9;</li>
<li>&#x1F4DA;</li>
<li>&#x1F4DB;</li>
<li>&#x1F4DC;</li>
<li>&#x1F4DD;</li>
<li>&#x1F4DE;</li>
<li>&#x1F4DF;</li>
<li>&#x1F4E0;</li>
<li>&#x1F4E1;</li>
<li>&#x1F4E2;</li>
<li>&#x1F4E3;</li>
<li>&#x1F4E4;</li>
<li>&#x1F4E5;</li>
<li>&#x1F4E6;</li>
<li>&#x1F4E7;</li>
<li>&#x1F4E8;</li>
<li>&#x1F4E9;</li>
<li>&#x1F4EA;</li>
<li>&#x1F4EB;</li>
<li>&#x1F4EC;</li>
<li>&#x1F4ED;</li>
<li>&#x1F4EE;</li>
<li>&#x1F4EF;</li>
<li>&#x1F4F0;</li>
<li>&#x1F4F1;</li>
<li>&#x1F4F2;</li>
<li>&#x1F4F3;</li>
<li>&#x1F4F4;</li>
<li>&#x1F4F5;</li>
<li>&#x1F4F6;</li>
<li>&#x1F4F7;</li>
<li>&#x1F4F9;</li>
<li>&#x1F4FA;</li>
<li>&#x1F4FB;</li>
<li>&#x1F4FC;</li>
<li>&#x1F500;</li>
<li>&#x1F501;</li>
<li>&#x1F502;</li>
<li>&#x1F503;</li>
<li>&#x1F504;</li>
<li>&#x1F505;</li>
<li>&#x1F506;</li>
<li>&#x1F507;</li>
<li>&#x1F508;</li>
<li>&#x1F509;</li>
<li>&#x1F50A;</li>
<li>&#x1F50B;</li>
<li>&#x1F50C;</li>
<li>&#x1F50D;</li>
<li>&#x1F50E;</li>
<li>&#x1F50F;</li>
<li>&#x1F510;</li>
<li>&#x1F511;</li>
<li>&#x1F512;</li>
<li>&#x1F513;</li>
<li>&#x1F514;</li>
<li>&#x1F515;</li>
<li>&#x1F516;</li>
<li>&#x1F517;</li>
<li>&#x1F518;</li>
<li>&#x1F519;</li>
<li>&#x1F51A;</li>
<li>&#x1F51B;</li>
<li>&#x1F51C;</li>
<li>&#x1F51D;</li>
<li>&#x1F51E;</li>
<li>&#x1F51F;</li>
<li>&#x1F520;</li>
<li>&#x1F521;</li>
<li>&#x1F522;</li>
<li>&#x1F523;</li>
<li>&#x1F524;</li>
<li>&#x1F525;</li>
<li>&#x1F526;</li>
<li>&#x1F527;</li>
<li>&#x1F528;</li>
<li>&#x1F529;</li>
<li>&#x1F52A;</li>
<li>&#x1F52B;</li>
<li>&#x1F52C;</li>
<li>&#x1F52D;</li>
<li>&#x1F52E;</li>
<li>&#x1F52F;</li>
<li>&#x1F530;</li>
<li>&#x1F531;</li>
<li>&#x1F532;</li>
<li>&#x1F533;</li>
<li>&#x1F534;</li>
<li>&#x1F535;</li>
<li>&#x1F536;</li>
<li>&#x1F537;</li>
<li>&#x1F538;</li>
<li>&#x1F539;</li>
<li>&#x1F53A;</li>
<li>&#x1F53B;</li>
<li>&#x1F53C;</li>
<li>&#x1F53D;</li>
<li>&#x1F550;</li>
<li>&#x1F551;</li>
<li>&#x1F552;</li>
<li>&#x1F553;</li>
<li>&#x1F554;</li>
<li>&#x1F555;</li>
<li>&#x1F556;</li>
<li>&#x1F557;</li>
<li>&#x1F558;</li>
<li>&#x1F559;</li>
<li>&#x1F55A;</li>
<li>&#x1F55B;</li>
<li>&#x1F55C;</li>
<li>&#x1F55D;</li>
<li>&#x1F55E;</li>
<li>&#x1F55F;</li>
<li>&#x1F560;</li>
<li>&#x1F561;</li>
<li>&#x1F562;</li>
<li>&#x1F563;</li>
<li>&#x1F564;</li>
<li>&#x1F565;</li>
<li>&#x1F566;</li>
<li>&#x1F567;</li>
<li>&#x1F5FB;</li>
<li>&#x1F5FC;</li>
<li>&#x1F5FD;</li>
<li>&#x1F5FE;</li>
<li>&#x1F5FF;</li>
<li>&#x1F600;</li>
<li>&#x1F601;</li>
<li>&#x1F602;</li>
<li>&#x1F603;</li>
<li>&#x1F604;</li>
<li>&#x1F605;</li>
<li>&#x1F606;</li>
<li>&#x1F607;</li>
<li>&#x1F608;</li>
<li>&#x1F609;</li>
<li>&#x1F60A;</li>
<li>&#x1F60B;</li>
<li>&#x1F60C;</li>
<li>&#x1F60D;</li>
<li>&#x1F60E;</li>
<li>&#x1F60F;</li>
<li>&#x1F610;</li>
<li>&#x1F611;</li>
<li>&#x1F612;</li>
<li>&#x1F613;</li>
<li>&#x1F614;</li>
<li>&#x1F615;</li>
<li>&#x1F616;</li>
<li>&#x1F617;</li>
<li>&#x1F618;</li>
<li>&#x1F619;</li>
<li>&#x1F61A;</li>
<li>&#x1F61B;</li>
<li>&#x1F61C;</li>
<li>&#x1F61D;</li>
<li>&#x1F61E;</li>
<li>&#x1F61F;</li>
<li>&#x1F620;</li>
<li>&#x1F621;</li>
<li>&#x1F622;</li>
<li>&#x1F623;</li>
<li>&#x1F624;</li>
<li>&#x1F625;</li>
<li>&#x1F626;</li>
<li>&#x1F627;</li>
<li>&#x1F628;</li>
<li>&#x1F629;</li>
<li>&#x1F62A;</li>
<li>&#x1F62B;</li>
<li>&#x1F62C;</li>
<li>&#x1F62D;</li>
<li>&#x1F62E;</li>
<li>&#x1F62F;</li>
<li>&#x1F630;</li>
<li>&#x1F631;</li>
<li>&#x1F632;</li>
<li>&#x1F633;</li>
<li>&#x1F634;</li>
<li>&#x1F635;</li>
<li>&#x1F636;</li>
<li>&#x1F637;</li>
<li>&#x1F638;</li>
<li>&#x1F639;</li>
<li>&#x1F63A;</li>
<li>&#x1F63B;</li>
<li>&#x1F63C;</li>
<li>&#x1F63D;</li>
<li>&#x1F63E;</li>
<li>&#x1F63F;</li>
<li>&#x1F640;</li>
<li>&#x1F641;</li>
<li>&#x1F642;</li>
<li>&#x1F645;</li>
<li>&#x1F646;</li>
<li>&#x1F647;</li>
<li>&#x1F648;</li>
<li>&#x1F649;</li>
<li>&#x1F64A;</li>
<li>&#x1F64B;</li>
<li>&#x1F64C;</li>
<li>&#x1F64D;</li>
<li>&#x1F64E;</li>
<li>&#x1F64F;</li>
<li>&#x1F680;</li>
<li>&#x1F681;</li>
<li>&#x1F682;</li>
<li>&#x1F683;</li>
<li>&#x1F684;</li>
<li>&#x1F685;</li>
<li>&#x1F686;</li>
<li>&#x1F687;</li>
<li>&#x1F688;</li>
<li>&#x1F689;</li>
<li>&#x1F68A;</li>
<li>&#x1F68B;</li>
<li>&#x1F68C;</li>
<li>&#x1F68D;</li>
<li>&#x1F68E;</li>
<li>&#x1F68F;</li>
<li>&#x1F690;</li>
<li>&#x1F691;</li>
<li>&#x1F692;</li>
<li>&#x1F693;</li>
<li>&#x1F694;</li>
<li>&#x1F695;</li>
<li>&#x1F696;</li>
<li>&#x1F697;</li>
<li>&#x1F698;</li>
<li>&#x1F699;</li>
<li>&#x1F69A;</li>
<li>&#x1F69B;</li>
<li>&#x1F69C;</li>
<li>&#x1F69D;</li>
<li>&#x1F69E;</li>
<li>&#x1F69F;</li>
<li>&#x1F6A0;</li>
<li>&#x1F6A1;</li>
<li>&#x1F6A2;</li>
<li>&#x1F6A3;</li>
<li>&#x1F6A4;</li>
<li>&#x1F6A5;</li>
<li>&#x1F6A6;</li>
<li>&#x1F6A7;</li>
<li>&#x1F6A8;</li>
<li>&#x1F6A9;</li>
<li>&#x1F6AA;</li>
<li>&#x1F6AB;</li>
<li>&#x1F6AC;</li>
<li>&#x1F6AD;</li>
<li>&#x1F6AE;</li>
<li>&#x1F6AF;</li>
<li>&#x1F6B0;</li>
<li>&#x1F6B1;</li>
<li>&#x1F6B2;</li>
<li>&#x1F6B3;</li>
<li>&#x1F6B4;</li>
<li>&#x1F6B5;</li>
<li>&#x1F6B6;</li>
<li>&#x1F6B7;</li>
<li>&#x1F6B8;</li>
<li>&#x1F6B9;</li>
<li>&#x1F6BA;</li>
<li>&#x1F6BB;</li>
<li>&#x1F6BC;</li>
<li>&#x1F6BD;</li>
<li>&#x1F6BE;</li>
<li>&#x1F6BF;</li>
<li>&#x1F6C0;</li>
<li>&#x1F6C1;</li>
<li>&#x1F6C2;</li>
<li>&#x1F6C3;</li>
<li>&#x1F6C4;</li>
<li>&#x1F6C5;</li>
<li>&#x203C;</li>
<li>&#x2049;</li>
<li>&#x2122;</li>
<li>&#x2139;</li>
<li>&#x2194;</li>
<li>&#x2195;</li>
<li>&#x2196;</li>
<li>&#x2197;</li>
<li>&#x2198;</li>
<li>&#x2199;</li>
<li>&#x21A9;</li>
<li>&#x21AA;</li>
<li>&#x23;&#x20E3;</li>
<li>&#x231A;</li>
<li>&#x231B;</li>
<li>&#x23E9;</li>
<li>&#x23EA;</li>
<li>&#x23EB;</li>
<li>&#x23EC;</li>
<li>&#x23F0;</li>
<li>&#x23F3;</li>
<li>&#x24C2;</li>
<li>&#x25AA;</li>
<li>&#x25AB;</li>
<li>&#x25B6;</li>
<li>&#x25C0;</li>
<li>&#x25FB;</li>
<li>&#x25FC;</li>
<li>&#x25FD;</li>
<li>&#x25FE;</li>
<li>&#x2600;</li>
<li>&#x2601;</li>
<li>&#x260E;</li>
<li>&#x2611;</li>
<li>&#x2614;</li>
<li>&#x2615;</li>
<li>&#x261D;</li>
<li>&#x263A;</li>
<li>&#x2648;</li>
<li>&#x2649;</li>
<li>&#x264A;</li>
<li>&#x264B;</li>
<li>&#x264C;</li>
<li>&#x264D;</li>
<li>&#x264E;</li>
<li>&#x264F;</li>
<li>&#x2650;</li>
<li>&#x2651;</li>
<li>&#x2652;</li>
<li>&#x2653;</li>
<li>&#x2660;</li>
<li>&#x2663;</li>
<li>&#x2665;</li>
<li>&#x2666;</li>
<li>&#x2668;</li>
<li>&#x267B;</li>
<li>&#x267F;</li>
<li>&#x2693;</li>
<li>&#x26A0;</li>
<li>&#x26A1;</li>
<li>&#x26AA;</li>
<li>&#x26AB;</li>
<li>&#x26BD;</li>
<li>&#x26BE;</li>
<li>&#x26C4;</li>
<li>&#x26C5;</li>
<li>&#x26CE;</li>
<li>&#x26D4;</li>
<li>&#x26EA;</li>
<li>&#x26F2;</li>
<li>&#x26F3;</li>
<li>&#x26F5;</li>
<li>&#x26FA;</li>
<li>&#x26FD;</li>
<li>&#x2702;</li>
<li>&#x2705;</li>
<li>&#x2708;</li>
<li>&#x2709;</li>
<li>&#x270A;</li>
<li>&#x270B;</li>
<li>&#x270C;</li>
<li>&#x270F;</li>
<li>&#x2712;</li>
<li>&#x2714;</li>
<li>&#x2716;</li>
<li>&#x2728;</li>
<li>&#x2733;</li>
<li>&#x2734;</li>
<li>&#x2744;</li>
<li>&#x2747;</li>
<li>&#x274C;</li>
<li>&#x274E;</li>
<li>&#x2753;</li>
<li>&#x2754;</li>
<li>&#x2755;</li>
<li>&#x2757;</li>
<li>&#x2764;</li>
<li>&#x2795;</li>
<li>&#x2796;</li>
<li>&#x2797;</li>
<li>&#x27A1;</li>
<li>&#x27B0;</li>
<li>&#x27BF;</li>
<li>&#x2934;</li>
<li>&#x2935;</li>
<li>&#x2B05;</li>
<li>&#x2B06;</li>
<li>&#x2B07;</li>
<li>&#x2B1B;</li>
<li>&#x2B1C;</li>
<li>&#x2B50;</li>
<li>&#x2B55;</li>
<li>&#x30;&#x20E3;</li>
<li>&#x3030;</li>
<li>&#x303D;</li>
<li>&#x31;&#x20E3;</li>
<li>&#x32;&#x20E3;</li>
<li>&#x3297;</li>
<li>&#x3299;</li>
<li>&#x33;&#x20E3;</li>
<li>&#x34;&#x20E3;</li>
<li>&#x35;&#x20E3;</li>
<li>&#x36;&#x20E3;</li>
<li>&#x37;&#x20E3;</li>
<li>&#x38;&#x20E3;</li>
<li>&#x39;&#x20E3;</li>
<li>&#xA9;</li>
<li>&#xAE;</li>
<li>&#xE50A;</li>
</ul>
<script>
var ul = document.getElementsByTagName('ul')[0];
var total = ul.getElementsByTagName('li').length;
var elapsed = +new Date;
twemoji.parse(ul, {"size":72});
elapsed = (+new Date) - elapsed;
document.body.insertBefore(
document.createTextNode(total + ' emoji parsed in ' + elapsed + 'ms'),
document.body.firstChild
);
(function (img, metaKey, i) {
function copyToClipboard(e) {
prompt('Copy to clipboard via ' + metaKey + '+C and Enter', this.alt);
}
for (i = 0; i < img.length; img[i++].onclick = copyToClipboard) {}
}(
document.getElementsByTagName('img'),
/\b(?:Mac |i)OS\b/i.test(navigator.userAgent) ? 'Command' : 'Ctrl'
));
</script>
</body>
</html>

569
1/twemoji.amd.js Normal file
View File

@ -0,0 +1,569 @@
define(function () {
/*jslint indent: 2, browser: true, bitwise: true, plusplus: true */
var twemoji = (function (
/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*
https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
*/
// WARNING: this file is generated automatically via
// `node twemoji-generator.js`
// please update its `createTwemoji` function
// at the bottom of the same file instead.
) {
'use strict';
/*jshint maxparams:4 */
var
// the exported module object
twemoji = {
/////////////////////////
// properties //
/////////////////////////
// default assets url, by default will be Twitter Inc. CDN
base: 'https://twemoji.maxcdn.com/1/',
// default assets file extensions, by default '.png'
ext: '.png',
// default assets/folder size, by default "72x72"
// available via Twitter CDN: 72
size: '72x72',
// default class name, by default 'emoji'
className: 'emoji',
// basic utilities / helpers to convert code points
// to JavaScript surrogates and vice versa
convert: {
/**
* Given an HEX codepoint, returns UTF16 surrogate pairs.
*
* @param string generic codepoint, i.e. '1F4A9'
* @return string codepoint transformed into utf16 surrogates pair,
* i.e. \uD83D\uDCA9
*
* @example
* twemoji.convert.fromCodePoint('1f1e8');
* // "\ud83c\udde8"
*
* '1f1e8-1f1f3'.split('-').map(twemoji.convert.fromCodePoint).join('')
* // "\ud83c\udde8\ud83c\uddf3"
*/
fromCodePoint: fromCodePoint,
/**
* Given UTF16 surrogate pairs, returns the equivalent HEX codepoint.
*
* @param string generic utf16 surrogates pair, i.e. \uD83D\uDCA9
* @param string optional separator for double code points, default='-'
* @return string utf16 transformed into codepoint, i.e. '1F4A9'
*
* @example
* twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3');
* // "1f1e8-1f1f3"
*
* twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3', '~');
* // "1f1e8~1f1f3"
*/
toCodePoint: toCodePoint
},
/////////////////////////
// methods //
/////////////////////////
/**
* User first: used to remove missing images
* preserving the original text intent when
* a fallback for network problems is desired.
* Automatically added to Image nodes via DOM
* It could be recycled for string operations via:
* $('img.emoji').on('error', twemoji.onerror)
*/
onerror: function onerror() {
if (this.parentNode) {
this.parentNode.replaceChild(createText(this.alt), this);
}
},
/**
* Main method/logic to generate either <img> tags or HTMLImage nodes.
* "emojify" a generic text or DOM Element.
*
* @overloads
*
* String replacement for `innerHTML` or server side operations
* twemoji.parse(string);
* twemoji.parse(string, Function);
* twemoji.parse(string, Object);
*
* HTMLElement tree parsing for safer operations over existing DOM
* twemoji.parse(HTMLElement);
* twemoji.parse(HTMLElement, Function);
* twemoji.parse(HTMLElement, Object);
*
* @param string|HTMLElement the source to parse and enrich with emoji.
*
* string replace emoji matches with <img> tags.
* Mainly used to inject emoji via `innerHTML`
* It does **not** parse the string or validate it,
* it simply replaces found emoji with a tag.
* NOTE: be sure this won't affect security.
*
* HTMLElement walk through the DOM tree and find emoji
* that are inside **text node only** (nodeType === 3)
* Mainly used to put emoji in already generated DOM
* without compromising surrounding nodes and
* **avoiding** the usage of `innerHTML`.
* NOTE: Using DOM elements instead of strings should
* improve security without compromising too much
* performance compared with a less safe `innerHTML`.
*
* @param Function|Object [optional]
* either the callback that will be invoked or an object
* with all properties to use per each found emoji.
*
* Function if specified, this will be invoked per each emoji
* that has been found through the RegExp except
* those follwed by the invariant \uFE0E ("as text").
* Once invoked, parameters will be:
*
* iconId:string the lower case HEX code point
* i.e. "1f4a9"
*
* options:Object all info for this parsing operation
*
* variant:char the optional \uFE0F ("as image")
* variant, in case this info
* is anyhow meaningful.
* By default this is ignored.
*
* If such callback will return a falsy value instead
* of a valid `src` to use for the image, nothing will
* actually change for that specific emoji.
*
*
* Object if specified, an object containing the following properties
*
* callback Function the callback to invoke per each found emoji.
* base string the base url, by default twemoji.base
* ext string the image extension, by default twemoji.ext
* size string the assets size, by default twemoji.size
*
* @example
*
* twemoji.parse("I \u2764\uFE0F emoji!");
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/2764.gif"> emoji!
*
*
* twemoji.parse("I \u2764\uFE0F emoji!", function(iconId, options) {
* return '/assets/' + iconId + '.gif';
* });
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/2764.gif"> emoji!
*
*
* twemoji.parse("I \u2764\uFE0F emoji!", {
* size: 72,
* callback: function(iconId, options) {
* return '/assets/' + options.size + '/' + iconId + options.ext;
* }
* });
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/72x72/2764.png"> emoji!
*
*/
parse: parse,
/**
* Given a string, invokes the callback argument
* per each emoji found in such string.
* This is the most raw version used by
* the .parse(string) method itself.
*
* @param string generic string to parse
* @param Function a generic callback that will be
* invoked to replace the content.
* This calback wil receive standard
* String.prototype.replace(str, callback)
* arguments such:
* callback(
* rawText, // the emoji match
* );
*
* and others commonly received via replace.
*/
replace: replace,
/**
* Simplify string tests against emoji.
*
* @param string some text that might contain emoji
* @return boolean true if any emoji was found, false otherwise.
*
* @example
*
* if (twemoji.test(someContent)) {
* console.log("emoji All The Things!");
* }
*/
test: test
},
// used to escape HTML special chars in attributes
escaper = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
"'": '&#39;',
'"': '&quot;'
},
// RegExp based on emoji's official Unicode standards
// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
re = /(?:[\u0039\u0038\u0037\u0036\u0035\u0034\u0033\u0032\u0031\u0030\u0023])\ufe0f?\u20e3|\ud83c\udde8\ud83c\uddf3|\ud83c\udde9\ud83c\uddea|\ud83c\uddea\ud83c\uddf8|\ud83c\uddeb\ud83c\uddf7|\ud83c\uddec\ud83c\udde7|\ud83c\uddee\ud83c\uddf9|\ud83c\uddef\ud83c\uddf5|\ud83c\uddf0\ud83c\uddf7|\ud83c\uddf7\ud83c\uddfa|\ud83c\uddfa\ud83c\uddf8|\ud83d[\udc00-\udc3e\udc40\udc42-\udcf7\udcf9-\udcfc\udd00-\udd3d\udd50-\udd67\uddfb-\ude42\ude45-\ude4f\ude80-\udec5]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf30-\udf35\udf37-\udf7c\udf80-\udf93\udfa0-\udfc4\udfc6-\udfca\udfe0-\udff0]|[\ue50a\u27bf\u27b0\u2797\u2796\u2795\u2755\u2754\u2753\u274e\u274c\u2728\u270b\u270a\u2705\u26ce\u23f3\u23f0\u23ec\u23eb\u23ea\u23e9]|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37]|[\u3299\u3297\u303d\u3030\u2b55\u2b50\u2b1c\u2b1b\u2b07\u2b06\u2b05\u2935\u2934\u27a1\u2764\u2757\u2747\u2744\u2734\u2733\u2716\u2714\u2712\u270f\u270c\u2709\u2708\u2702\u26fd\u26fa\u26f5\u26f3\u26f2\u26ea\u26d4\u26c5\u26c4\u26be\u26bd\u26ab\u26aa\u26a1\u26a0\u2693\u267f\u267b\u2668\u2666\u2665\u2663\u2660\u2653\u2652\u2651\u2650\u264f\u264e\u264d\u264c\u264b\u264a\u2649\u2648\u263a\u261d\u2615\u2614\u2611\u260e\u2601\u2600\u25fe\u25fd\u25fc\u25fb\u25c0\u25b6\u25ab\u25aa\u24c2\u231b\u231a\u21aa\u21a9\u2199\u2198\u2197\u2196\u2195\u2194\u2139\u2122\u2049\u203c\u00ae\u00a9])(?:\ufe0f|(?!\ufe0e))/g,
// avoid runtime RegExp creation for not so smart,
// not JIT based, and old browsers / engines
UFE0Fg = /\uFE0F/g,
// avoid using a string literal like '\u200D' here because minifiers expand it inline
U200D = String.fromCharCode(0x200D),
// used to find HTML special chars in attributes
rescaper = /[&<>'"]/g,
// nodes with type 1 which should **not** be parsed (including lower case svg)
shouldntBeParsed = /IFRAME|NOFRAMES|NOSCRIPT|SCRIPT|SELECT|STYLE|TEXTAREA|[a-z]/,
// just a private shortcut
fromCharCode = String.fromCharCode;
return twemoji;
/////////////////////////
// private functions //
// declaration //
/////////////////////////
/**
* Shortcut to create text nodes
* @param string text used to create DOM text node
* @return Node a DOM node with that text
*/
function createText(text) {
return document.createTextNode(text);
}
/**
* Utility function to escape html attribute text
* @param string text use in HTML attribute
* @return string text encoded to use in HTML attribute
*/
function escapeHTML(s) {
return s.replace(rescaper, replacer);
}
/**
* Default callback used to generate emoji src
* based on Twitter CDN
* @param string the emoji codepoint string
* @param string the default size to use, i.e. "36x36"
* @return string the image source to use
*/
function defaultImageSrcGenerator(icon, options) {
return ''.concat(options.base, options.size, '/', icon, options.ext);
}
/**
* Given a generic DOM nodeType 1, walk through all children
* and store every nodeType 3 (#text) found in the tree.
* @param Element a DOM Element with probably some text in it
* @param Array the list of previously discovered text nodes
* @return Array same list with new discovered nodes, if any
*/
function grabAllTextNodes(node, allText) {
var
childNodes = node.childNodes,
length = childNodes.length,
subnode,
nodeType;
while (length--) {
subnode = childNodes[length];
nodeType = subnode.nodeType;
// parse emoji only in text nodes
if (nodeType === 3) {
// collect them to process emoji later
allText.push(subnode);
}
// ignore all nodes that are not type 1 or that
// should not be parsed as script, style, and others
else if (nodeType === 1 && !shouldntBeParsed.test(subnode.nodeName)) {
grabAllTextNodes(subnode, allText);
}
}
return allText;
}
/**
* 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
*/
function grabTheRightIcon(rawText) {
// if variant is present as \uFE0F
return toCodePoint(rawText.indexOf(U200D) < 0 ?
rawText.replace(UFE0Fg, '') :
rawText
);
}
/**
* DOM version of the same logic / parser:
* emojify all found sub-text nodes placing images node instead.
* @param Element generic DOM node with some text in some child node
* @param Object options containing info about how to parse
*
* .callback Function the callback to invoke per each found emoji.
* .base string the base url, by default twemoji.base
* .ext string the image extension, by default twemoji.ext
* .size string the assets size, by default twemoji.size
*
* @return Element same generic node with emoji in place, if any.
*/
function parseNode(node, options) {
var
allText = grabAllTextNodes(node, []),
length = allText.length,
attrib,
attrname,
modified,
fragment,
subnode,
text,
match,
i,
index,
img,
rawText,
iconId,
src;
while (length--) {
modified = false;
fragment = document.createDocumentFragment();
subnode = allText[length];
text = subnode.nodeValue;
i = 0;
while ((match = re.exec(text))) {
index = match.index;
if (index !== i) {
fragment.appendChild(
createText(text.slice(i, index))
);
}
rawText = match[0];
iconId = grabTheRightIcon(rawText);
i = index + rawText.length;
src = options.callback(iconId, options);
if (src) {
img = new Image();
img.onerror = options.onerror;
img.setAttribute('draggable', 'false');
attrib = options.attributes(rawText, iconId);
for (attrname in attrib) {
if (
attrib.hasOwnProperty(attrname) &&
// don't allow any handlers to be set + don't allow overrides
attrname.indexOf('on') !== 0 &&
!img.hasAttribute(attrname)
) {
img.setAttribute(attrname, attrib[attrname]);
}
}
img.className = options.className;
img.alt = rawText;
img.src = src;
modified = true;
fragment.appendChild(img);
}
if (!img) fragment.appendChild(createText(rawText));
img = null;
}
// is there actually anything to replace in here ?
if (modified) {
// any text left to be added ?
if (i < text.length) {
fragment.appendChild(
createText(text.slice(i))
);
}
// replace the text node only, leave intact
// anything else surrounding such text
subnode.parentNode.replaceChild(fragment, subnode);
}
}
return node;
}
/**
* String/HTML version of the same logic / parser:
* emojify a generic text placing images tags instead of surrogates pair.
* @param string generic string with possibly some emoji in it
* @param Object options containing info about how to parse
*
* .callback Function the callback to invoke per each found emoji.
* .base string the base url, by default twemoji.base
* .ext string the image extension, by default twemoji.ext
* .size string the assets size, by default twemoji.size
*
* @return the string with <img tags> replacing all found and parsed emoji
*/
function parseString(str, options) {
return replace(str, function (rawText) {
var
ret = rawText,
iconId = grabTheRightIcon(rawText),
src = options.callback(iconId, options),
attrib,
attrname;
if (src) {
// recycle the match string replacing the emoji
// with its image counter part
ret = '<img '.concat(
'class="', options.className, '" ',
'draggable="false" ',
// needs to preserve user original intent
// when variants should be copied and pasted too
'alt="',
rawText,
'"',
' src="',
src,
'"'
);
attrib = options.attributes(rawText, iconId);
for (attrname in attrib) {
if (
attrib.hasOwnProperty(attrname) &&
// don't allow any handlers to be set + don't allow overrides
attrname.indexOf('on') !== 0 &&
ret.indexOf(' ' + attrname + '=') === -1
) {
ret = ret.concat(' ', attrname, '="', escapeHTML(attrib[attrname]), '"');
}
}
ret = ret.concat('>');
}
return ret;
});
}
/**
* Function used to actually replace HTML special chars
* @param string HTML special char
* @return string encoded HTML special char
*/
function replacer(m) {
return escaper[m];
}
/**
* Default options.attribute callback
* @return null
*/
function returnNull() {
return null;
}
/**
* Given a generic value, creates its squared counterpart if it's a number.
* As example, number 36 will return '36x36'.
* @param any a generic value.
* @return any a string representing asset size, i.e. "36x36"
* only in case the value was a number.
* Returns initial value otherwise.
*/
function toSizeSquaredAsset(value) {
return typeof value === 'number' ?
value + 'x' + value :
value;
}
/////////////////////////
// exported functions //
// declaration //
/////////////////////////
function fromCodePoint(codepoint) {
var code = typeof codepoint === 'string' ?
parseInt(codepoint, 16) : codepoint;
if (code < 0x10000) {
return fromCharCode(code);
}
code -= 0x10000;
return fromCharCode(
0xD800 + (code >> 10),
0xDC00 + (code & 0x3FF)
);
}
function parse(what, how) {
if (!how || typeof how === 'function') {
how = {callback: how};
}
// if first argument is string, inject html <img> tags
// otherwise use the DOM tree and parse text nodes only
return (typeof what === 'string' ? parseString : parseNode)(what, {
callback: how.callback || defaultImageSrcGenerator,
attributes: typeof how.attributes === 'function' ? how.attributes : returnNull,
base: typeof how.base === 'string' ? how.base : twemoji.base,
ext: how.ext || twemoji.ext,
size: how.folder || toSizeSquaredAsset(how.size || twemoji.size),
className: how.className || twemoji.className,
onerror: how.onerror || twemoji.onerror
});
}
function replace(text, callback) {
return String(text).replace(re, callback);
}
function test(text) {
// IE6 needs a reset before too
re.lastIndex = 0;
var result = re.test(text);
re.lastIndex = 0;
return result;
}
function toCodePoint(unicodeSurrogates, sep) {
var
r = [],
c = 0,
p = 0,
i = 0;
while (i < unicodeSurrogates.length) {
c = unicodeSurrogates.charCodeAt(i++);
if (p) {
r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16));
p = 0;
} else if (0xD800 <= c && c <= 0xDBFF) {
p = c;
} else {
r.push(c.toString(16));
}
}
return r.join(sep || '-');
}
}());
return twemoji;
});

566
1/twemoji.js Normal file
View File

@ -0,0 +1,566 @@
/*jslint indent: 2, browser: true, bitwise: true, plusplus: true */
var twemoji = (function (
/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*
https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
*/
// WARNING: this file is generated automatically via
// `node twemoji-generator.js`
// please update its `createTwemoji` function
// at the bottom of the same file instead.
) {
'use strict';
/*jshint maxparams:4 */
var
// the exported module object
twemoji = {
/////////////////////////
// properties //
/////////////////////////
// default assets url, by default will be Twitter Inc. CDN
base: 'https://twemoji.maxcdn.com/1/',
// default assets file extensions, by default '.png'
ext: '.png',
// default assets/folder size, by default "72x72"
// available via Twitter CDN: 72
size: '72x72',
// default class name, by default 'emoji'
className: 'emoji',
// basic utilities / helpers to convert code points
// to JavaScript surrogates and vice versa
convert: {
/**
* Given an HEX codepoint, returns UTF16 surrogate pairs.
*
* @param string generic codepoint, i.e. '1F4A9'
* @return string codepoint transformed into utf16 surrogates pair,
* i.e. \uD83D\uDCA9
*
* @example
* twemoji.convert.fromCodePoint('1f1e8');
* // "\ud83c\udde8"
*
* '1f1e8-1f1f3'.split('-').map(twemoji.convert.fromCodePoint).join('')
* // "\ud83c\udde8\ud83c\uddf3"
*/
fromCodePoint: fromCodePoint,
/**
* Given UTF16 surrogate pairs, returns the equivalent HEX codepoint.
*
* @param string generic utf16 surrogates pair, i.e. \uD83D\uDCA9
* @param string optional separator for double code points, default='-'
* @return string utf16 transformed into codepoint, i.e. '1F4A9'
*
* @example
* twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3');
* // "1f1e8-1f1f3"
*
* twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3', '~');
* // "1f1e8~1f1f3"
*/
toCodePoint: toCodePoint
},
/////////////////////////
// methods //
/////////////////////////
/**
* User first: used to remove missing images
* preserving the original text intent when
* a fallback for network problems is desired.
* Automatically added to Image nodes via DOM
* It could be recycled for string operations via:
* $('img.emoji').on('error', twemoji.onerror)
*/
onerror: function onerror() {
if (this.parentNode) {
this.parentNode.replaceChild(createText(this.alt), this);
}
},
/**
* Main method/logic to generate either <img> tags or HTMLImage nodes.
* "emojify" a generic text or DOM Element.
*
* @overloads
*
* String replacement for `innerHTML` or server side operations
* twemoji.parse(string);
* twemoji.parse(string, Function);
* twemoji.parse(string, Object);
*
* HTMLElement tree parsing for safer operations over existing DOM
* twemoji.parse(HTMLElement);
* twemoji.parse(HTMLElement, Function);
* twemoji.parse(HTMLElement, Object);
*
* @param string|HTMLElement the source to parse and enrich with emoji.
*
* string replace emoji matches with <img> tags.
* Mainly used to inject emoji via `innerHTML`
* It does **not** parse the string or validate it,
* it simply replaces found emoji with a tag.
* NOTE: be sure this won't affect security.
*
* HTMLElement walk through the DOM tree and find emoji
* that are inside **text node only** (nodeType === 3)
* Mainly used to put emoji in already generated DOM
* without compromising surrounding nodes and
* **avoiding** the usage of `innerHTML`.
* NOTE: Using DOM elements instead of strings should
* improve security without compromising too much
* performance compared with a less safe `innerHTML`.
*
* @param Function|Object [optional]
* either the callback that will be invoked or an object
* with all properties to use per each found emoji.
*
* Function if specified, this will be invoked per each emoji
* that has been found through the RegExp except
* those follwed by the invariant \uFE0E ("as text").
* Once invoked, parameters will be:
*
* iconId:string the lower case HEX code point
* i.e. "1f4a9"
*
* options:Object all info for this parsing operation
*
* variant:char the optional \uFE0F ("as image")
* variant, in case this info
* is anyhow meaningful.
* By default this is ignored.
*
* If such callback will return a falsy value instead
* of a valid `src` to use for the image, nothing will
* actually change for that specific emoji.
*
*
* Object if specified, an object containing the following properties
*
* callback Function the callback to invoke per each found emoji.
* base string the base url, by default twemoji.base
* ext string the image extension, by default twemoji.ext
* size string the assets size, by default twemoji.size
*
* @example
*
* twemoji.parse("I \u2764\uFE0F emoji!");
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/2764.gif"> emoji!
*
*
* twemoji.parse("I \u2764\uFE0F emoji!", function(iconId, options) {
* return '/assets/' + iconId + '.gif';
* });
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/2764.gif"> emoji!
*
*
* twemoji.parse("I \u2764\uFE0F emoji!", {
* size: 72,
* callback: function(iconId, options) {
* return '/assets/' + options.size + '/' + iconId + options.ext;
* }
* });
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/72x72/2764.png"> emoji!
*
*/
parse: parse,
/**
* Given a string, invokes the callback argument
* per each emoji found in such string.
* This is the most raw version used by
* the .parse(string) method itself.
*
* @param string generic string to parse
* @param Function a generic callback that will be
* invoked to replace the content.
* This calback wil receive standard
* String.prototype.replace(str, callback)
* arguments such:
* callback(
* rawText, // the emoji match
* );
*
* and others commonly received via replace.
*/
replace: replace,
/**
* Simplify string tests against emoji.
*
* @param string some text that might contain emoji
* @return boolean true if any emoji was found, false otherwise.
*
* @example
*
* if (twemoji.test(someContent)) {
* console.log("emoji All The Things!");
* }
*/
test: test
},
// used to escape HTML special chars in attributes
escaper = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
"'": '&#39;',
'"': '&quot;'
},
// RegExp based on emoji's official Unicode standards
// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
re = /(?:[\u0039\u0038\u0037\u0036\u0035\u0034\u0033\u0032\u0031\u0030\u0023])\ufe0f?\u20e3|\ud83c\udde8\ud83c\uddf3|\ud83c\udde9\ud83c\uddea|\ud83c\uddea\ud83c\uddf8|\ud83c\uddeb\ud83c\uddf7|\ud83c\uddec\ud83c\udde7|\ud83c\uddee\ud83c\uddf9|\ud83c\uddef\ud83c\uddf5|\ud83c\uddf0\ud83c\uddf7|\ud83c\uddf7\ud83c\uddfa|\ud83c\uddfa\ud83c\uddf8|\ud83d[\udc00-\udc3e\udc40\udc42-\udcf7\udcf9-\udcfc\udd00-\udd3d\udd50-\udd67\uddfb-\ude42\ude45-\ude4f\ude80-\udec5]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf30-\udf35\udf37-\udf7c\udf80-\udf93\udfa0-\udfc4\udfc6-\udfca\udfe0-\udff0]|[\ue50a\u27bf\u27b0\u2797\u2796\u2795\u2755\u2754\u2753\u274e\u274c\u2728\u270b\u270a\u2705\u26ce\u23f3\u23f0\u23ec\u23eb\u23ea\u23e9]|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37]|[\u3299\u3297\u303d\u3030\u2b55\u2b50\u2b1c\u2b1b\u2b07\u2b06\u2b05\u2935\u2934\u27a1\u2764\u2757\u2747\u2744\u2734\u2733\u2716\u2714\u2712\u270f\u270c\u2709\u2708\u2702\u26fd\u26fa\u26f5\u26f3\u26f2\u26ea\u26d4\u26c5\u26c4\u26be\u26bd\u26ab\u26aa\u26a1\u26a0\u2693\u267f\u267b\u2668\u2666\u2665\u2663\u2660\u2653\u2652\u2651\u2650\u264f\u264e\u264d\u264c\u264b\u264a\u2649\u2648\u263a\u261d\u2615\u2614\u2611\u260e\u2601\u2600\u25fe\u25fd\u25fc\u25fb\u25c0\u25b6\u25ab\u25aa\u24c2\u231b\u231a\u21aa\u21a9\u2199\u2198\u2197\u2196\u2195\u2194\u2139\u2122\u2049\u203c\u00ae\u00a9])(?:\ufe0f|(?!\ufe0e))/g,
// avoid runtime RegExp creation for not so smart,
// not JIT based, and old browsers / engines
UFE0Fg = /\uFE0F/g,
// avoid using a string literal like '\u200D' here because minifiers expand it inline
U200D = String.fromCharCode(0x200D),
// used to find HTML special chars in attributes
rescaper = /[&<>'"]/g,
// nodes with type 1 which should **not** be parsed (including lower case svg)
shouldntBeParsed = /IFRAME|NOFRAMES|NOSCRIPT|SCRIPT|SELECT|STYLE|TEXTAREA|[a-z]/,
// just a private shortcut
fromCharCode = String.fromCharCode;
return twemoji;
/////////////////////////
// private functions //
// declaration //
/////////////////////////
/**
* Shortcut to create text nodes
* @param string text used to create DOM text node
* @return Node a DOM node with that text
*/
function createText(text) {
return document.createTextNode(text);
}
/**
* Utility function to escape html attribute text
* @param string text use in HTML attribute
* @return string text encoded to use in HTML attribute
*/
function escapeHTML(s) {
return s.replace(rescaper, replacer);
}
/**
* Default callback used to generate emoji src
* based on Twitter CDN
* @param string the emoji codepoint string
* @param string the default size to use, i.e. "36x36"
* @return string the image source to use
*/
function defaultImageSrcGenerator(icon, options) {
return ''.concat(options.base, options.size, '/', icon, options.ext);
}
/**
* Given a generic DOM nodeType 1, walk through all children
* and store every nodeType 3 (#text) found in the tree.
* @param Element a DOM Element with probably some text in it
* @param Array the list of previously discovered text nodes
* @return Array same list with new discovered nodes, if any
*/
function grabAllTextNodes(node, allText) {
var
childNodes = node.childNodes,
length = childNodes.length,
subnode,
nodeType;
while (length--) {
subnode = childNodes[length];
nodeType = subnode.nodeType;
// parse emoji only in text nodes
if (nodeType === 3) {
// collect them to process emoji later
allText.push(subnode);
}
// ignore all nodes that are not type 1 or that
// should not be parsed as script, style, and others
else if (nodeType === 1 && !shouldntBeParsed.test(subnode.nodeName)) {
grabAllTextNodes(subnode, allText);
}
}
return allText;
}
/**
* 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
*/
function grabTheRightIcon(rawText) {
// if variant is present as \uFE0F
return toCodePoint(rawText.indexOf(U200D) < 0 ?
rawText.replace(UFE0Fg, '') :
rawText
);
}
/**
* DOM version of the same logic / parser:
* emojify all found sub-text nodes placing images node instead.
* @param Element generic DOM node with some text in some child node
* @param Object options containing info about how to parse
*
* .callback Function the callback to invoke per each found emoji.
* .base string the base url, by default twemoji.base
* .ext string the image extension, by default twemoji.ext
* .size string the assets size, by default twemoji.size
*
* @return Element same generic node with emoji in place, if any.
*/
function parseNode(node, options) {
var
allText = grabAllTextNodes(node, []),
length = allText.length,
attrib,
attrname,
modified,
fragment,
subnode,
text,
match,
i,
index,
img,
rawText,
iconId,
src;
while (length--) {
modified = false;
fragment = document.createDocumentFragment();
subnode = allText[length];
text = subnode.nodeValue;
i = 0;
while ((match = re.exec(text))) {
index = match.index;
if (index !== i) {
fragment.appendChild(
createText(text.slice(i, index))
);
}
rawText = match[0];
iconId = grabTheRightIcon(rawText);
i = index + rawText.length;
src = options.callback(iconId, options);
if (src) {
img = new Image();
img.onerror = options.onerror;
img.setAttribute('draggable', 'false');
attrib = options.attributes(rawText, iconId);
for (attrname in attrib) {
if (
attrib.hasOwnProperty(attrname) &&
// don't allow any handlers to be set + don't allow overrides
attrname.indexOf('on') !== 0 &&
!img.hasAttribute(attrname)
) {
img.setAttribute(attrname, attrib[attrname]);
}
}
img.className = options.className;
img.alt = rawText;
img.src = src;
modified = true;
fragment.appendChild(img);
}
if (!img) fragment.appendChild(createText(rawText));
img = null;
}
// is there actually anything to replace in here ?
if (modified) {
// any text left to be added ?
if (i < text.length) {
fragment.appendChild(
createText(text.slice(i))
);
}
// replace the text node only, leave intact
// anything else surrounding such text
subnode.parentNode.replaceChild(fragment, subnode);
}
}
return node;
}
/**
* String/HTML version of the same logic / parser:
* emojify a generic text placing images tags instead of surrogates pair.
* @param string generic string with possibly some emoji in it
* @param Object options containing info about how to parse
*
* .callback Function the callback to invoke per each found emoji.
* .base string the base url, by default twemoji.base
* .ext string the image extension, by default twemoji.ext
* .size string the assets size, by default twemoji.size
*
* @return the string with <img tags> replacing all found and parsed emoji
*/
function parseString(str, options) {
return replace(str, function (rawText) {
var
ret = rawText,
iconId = grabTheRightIcon(rawText),
src = options.callback(iconId, options),
attrib,
attrname;
if (src) {
// recycle the match string replacing the emoji
// with its image counter part
ret = '<img '.concat(
'class="', options.className, '" ',
'draggable="false" ',
// needs to preserve user original intent
// when variants should be copied and pasted too
'alt="',
rawText,
'"',
' src="',
src,
'"'
);
attrib = options.attributes(rawText, iconId);
for (attrname in attrib) {
if (
attrib.hasOwnProperty(attrname) &&
// don't allow any handlers to be set + don't allow overrides
attrname.indexOf('on') !== 0 &&
ret.indexOf(' ' + attrname + '=') === -1
) {
ret = ret.concat(' ', attrname, '="', escapeHTML(attrib[attrname]), '"');
}
}
ret = ret.concat('>');
}
return ret;
});
}
/**
* Function used to actually replace HTML special chars
* @param string HTML special char
* @return string encoded HTML special char
*/
function replacer(m) {
return escaper[m];
}
/**
* Default options.attribute callback
* @return null
*/
function returnNull() {
return null;
}
/**
* Given a generic value, creates its squared counterpart if it's a number.
* As example, number 36 will return '36x36'.
* @param any a generic value.
* @return any a string representing asset size, i.e. "36x36"
* only in case the value was a number.
* Returns initial value otherwise.
*/
function toSizeSquaredAsset(value) {
return typeof value === 'number' ?
value + 'x' + value :
value;
}
/////////////////////////
// exported functions //
// declaration //
/////////////////////////
function fromCodePoint(codepoint) {
var code = typeof codepoint === 'string' ?
parseInt(codepoint, 16) : codepoint;
if (code < 0x10000) {
return fromCharCode(code);
}
code -= 0x10000;
return fromCharCode(
0xD800 + (code >> 10),
0xDC00 + (code & 0x3FF)
);
}
function parse(what, how) {
if (!how || typeof how === 'function') {
how = {callback: how};
}
// if first argument is string, inject html <img> tags
// otherwise use the DOM tree and parse text nodes only
return (typeof what === 'string' ? parseString : parseNode)(what, {
callback: how.callback || defaultImageSrcGenerator,
attributes: typeof how.attributes === 'function' ? how.attributes : returnNull,
base: typeof how.base === 'string' ? how.base : twemoji.base,
ext: how.ext || twemoji.ext,
size: how.folder || toSizeSquaredAsset(how.size || twemoji.size),
className: how.className || twemoji.className,
onerror: how.onerror || twemoji.onerror
});
}
function replace(text, callback) {
return String(text).replace(re, callback);
}
function test(text) {
// IE6 needs a reset before too
re.lastIndex = 0;
var result = re.test(text);
re.lastIndex = 0;
return result;
}
function toCodePoint(unicodeSurrogates, sep) {
var
r = [],
c = 0,
p = 0,
i = 0;
while (i < unicodeSurrogates.length) {
c = unicodeSurrogates.charCodeAt(i++);
if (p) {
r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16));
p = 0;
} else if (0xD800 <= c && c <= 0xDBFF) {
p = c;
} else {
r.push(c.toString(16));
}
}
return r.join(sep || '-');
}
}());

2
1/twemoji.min.js vendored Normal file

File diff suppressed because one or more lines are too long

571
1/twemoji.npm.js Normal file
View File

@ -0,0 +1,571 @@
var location = global.location || {};
/*jslint indent: 2, browser: true, bitwise: true, plusplus: true */
var twemoji = (function (
/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*
https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
*/
// WARNING: this file is generated automatically via
// `node twemoji-generator.js`
// please update its `createTwemoji` function
// at the bottom of the same file instead.
) {
'use strict';
/*jshint maxparams:4 */
var
// the exported module object
twemoji = {
/////////////////////////
// properties //
/////////////////////////
// default assets url, by default will be Twitter Inc. CDN
base: 'https://twemoji.maxcdn.com/1/',
// default assets file extensions, by default '.png'
ext: '.png',
// default assets/folder size, by default "72x72"
// available via Twitter CDN: 72
size: '72x72',
// default class name, by default 'emoji'
className: 'emoji',
// basic utilities / helpers to convert code points
// to JavaScript surrogates and vice versa
convert: {
/**
* Given an HEX codepoint, returns UTF16 surrogate pairs.
*
* @param string generic codepoint, i.e. '1F4A9'
* @return string codepoint transformed into utf16 surrogates pair,
* i.e. \uD83D\uDCA9
*
* @example
* twemoji.convert.fromCodePoint('1f1e8');
* // "\ud83c\udde8"
*
* '1f1e8-1f1f3'.split('-').map(twemoji.convert.fromCodePoint).join('')
* // "\ud83c\udde8\ud83c\uddf3"
*/
fromCodePoint: fromCodePoint,
/**
* Given UTF16 surrogate pairs, returns the equivalent HEX codepoint.
*
* @param string generic utf16 surrogates pair, i.e. \uD83D\uDCA9
* @param string optional separator for double code points, default='-'
* @return string utf16 transformed into codepoint, i.e. '1F4A9'
*
* @example
* twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3');
* // "1f1e8-1f1f3"
*
* twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3', '~');
* // "1f1e8~1f1f3"
*/
toCodePoint: toCodePoint
},
/////////////////////////
// methods //
/////////////////////////
/**
* User first: used to remove missing images
* preserving the original text intent when
* a fallback for network problems is desired.
* Automatically added to Image nodes via DOM
* It could be recycled for string operations via:
* $('img.emoji').on('error', twemoji.onerror)
*/
onerror: function onerror() {
if (this.parentNode) {
this.parentNode.replaceChild(createText(this.alt), this);
}
},
/**
* Main method/logic to generate either <img> tags or HTMLImage nodes.
* "emojify" a generic text or DOM Element.
*
* @overloads
*
* String replacement for `innerHTML` or server side operations
* twemoji.parse(string);
* twemoji.parse(string, Function);
* twemoji.parse(string, Object);
*
* HTMLElement tree parsing for safer operations over existing DOM
* twemoji.parse(HTMLElement);
* twemoji.parse(HTMLElement, Function);
* twemoji.parse(HTMLElement, Object);
*
* @param string|HTMLElement the source to parse and enrich with emoji.
*
* string replace emoji matches with <img> tags.
* Mainly used to inject emoji via `innerHTML`
* It does **not** parse the string or validate it,
* it simply replaces found emoji with a tag.
* NOTE: be sure this won't affect security.
*
* HTMLElement walk through the DOM tree and find emoji
* that are inside **text node only** (nodeType === 3)
* Mainly used to put emoji in already generated DOM
* without compromising surrounding nodes and
* **avoiding** the usage of `innerHTML`.
* NOTE: Using DOM elements instead of strings should
* improve security without compromising too much
* performance compared with a less safe `innerHTML`.
*
* @param Function|Object [optional]
* either the callback that will be invoked or an object
* with all properties to use per each found emoji.
*
* Function if specified, this will be invoked per each emoji
* that has been found through the RegExp except
* those follwed by the invariant \uFE0E ("as text").
* Once invoked, parameters will be:
*
* iconId:string the lower case HEX code point
* i.e. "1f4a9"
*
* options:Object all info for this parsing operation
*
* variant:char the optional \uFE0F ("as image")
* variant, in case this info
* is anyhow meaningful.
* By default this is ignored.
*
* If such callback will return a falsy value instead
* of a valid `src` to use for the image, nothing will
* actually change for that specific emoji.
*
*
* Object if specified, an object containing the following properties
*
* callback Function the callback to invoke per each found emoji.
* base string the base url, by default twemoji.base
* ext string the image extension, by default twemoji.ext
* size string the assets size, by default twemoji.size
*
* @example
*
* twemoji.parse("I \u2764\uFE0F emoji!");
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/2764.gif"> emoji!
*
*
* twemoji.parse("I \u2764\uFE0F emoji!", function(iconId, options) {
* return '/assets/' + iconId + '.gif';
* });
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/2764.gif"> emoji!
*
*
* twemoji.parse("I \u2764\uFE0F emoji!", {
* size: 72,
* callback: function(iconId, options) {
* return '/assets/' + options.size + '/' + iconId + options.ext;
* }
* });
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/72x72/2764.png"> emoji!
*
*/
parse: parse,
/**
* Given a string, invokes the callback argument
* per each emoji found in such string.
* This is the most raw version used by
* the .parse(string) method itself.
*
* @param string generic string to parse
* @param Function a generic callback that will be
* invoked to replace the content.
* This calback wil receive standard
* String.prototype.replace(str, callback)
* arguments such:
* callback(
* rawText, // the emoji match
* );
*
* and others commonly received via replace.
*/
replace: replace,
/**
* Simplify string tests against emoji.
*
* @param string some text that might contain emoji
* @return boolean true if any emoji was found, false otherwise.
*
* @example
*
* if (twemoji.test(someContent)) {
* console.log("emoji All The Things!");
* }
*/
test: test
},
// used to escape HTML special chars in attributes
escaper = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
"'": '&#39;',
'"': '&quot;'
},
// RegExp based on emoji's official Unicode standards
// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
re = /(?:[\u0039\u0038\u0037\u0036\u0035\u0034\u0033\u0032\u0031\u0030\u0023])\ufe0f?\u20e3|\ud83c\udde8\ud83c\uddf3|\ud83c\udde9\ud83c\uddea|\ud83c\uddea\ud83c\uddf8|\ud83c\uddeb\ud83c\uddf7|\ud83c\uddec\ud83c\udde7|\ud83c\uddee\ud83c\uddf9|\ud83c\uddef\ud83c\uddf5|\ud83c\uddf0\ud83c\uddf7|\ud83c\uddf7\ud83c\uddfa|\ud83c\uddfa\ud83c\uddf8|\ud83d[\udc00-\udc3e\udc40\udc42-\udcf7\udcf9-\udcfc\udd00-\udd3d\udd50-\udd67\uddfb-\ude42\ude45-\ude4f\ude80-\udec5]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf30-\udf35\udf37-\udf7c\udf80-\udf93\udfa0-\udfc4\udfc6-\udfca\udfe0-\udff0]|[\ue50a\u27bf\u27b0\u2797\u2796\u2795\u2755\u2754\u2753\u274e\u274c\u2728\u270b\u270a\u2705\u26ce\u23f3\u23f0\u23ec\u23eb\u23ea\u23e9]|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37]|[\u3299\u3297\u303d\u3030\u2b55\u2b50\u2b1c\u2b1b\u2b07\u2b06\u2b05\u2935\u2934\u27a1\u2764\u2757\u2747\u2744\u2734\u2733\u2716\u2714\u2712\u270f\u270c\u2709\u2708\u2702\u26fd\u26fa\u26f5\u26f3\u26f2\u26ea\u26d4\u26c5\u26c4\u26be\u26bd\u26ab\u26aa\u26a1\u26a0\u2693\u267f\u267b\u2668\u2666\u2665\u2663\u2660\u2653\u2652\u2651\u2650\u264f\u264e\u264d\u264c\u264b\u264a\u2649\u2648\u263a\u261d\u2615\u2614\u2611\u260e\u2601\u2600\u25fe\u25fd\u25fc\u25fb\u25c0\u25b6\u25ab\u25aa\u24c2\u231b\u231a\u21aa\u21a9\u2199\u2198\u2197\u2196\u2195\u2194\u2139\u2122\u2049\u203c\u00ae\u00a9])(?:\ufe0f|(?!\ufe0e))/g,
// avoid runtime RegExp creation for not so smart,
// not JIT based, and old browsers / engines
UFE0Fg = /\uFE0F/g,
// avoid using a string literal like '\u200D' here because minifiers expand it inline
U200D = String.fromCharCode(0x200D),
// used to find HTML special chars in attributes
rescaper = /[&<>'"]/g,
// nodes with type 1 which should **not** be parsed (including lower case svg)
shouldntBeParsed = /IFRAME|NOFRAMES|NOSCRIPT|SCRIPT|SELECT|STYLE|TEXTAREA|[a-z]/,
// just a private shortcut
fromCharCode = String.fromCharCode;
return twemoji;
/////////////////////////
// private functions //
// declaration //
/////////////////////////
/**
* Shortcut to create text nodes
* @param string text used to create DOM text node
* @return Node a DOM node with that text
*/
function createText(text) {
return document.createTextNode(text);
}
/**
* Utility function to escape html attribute text
* @param string text use in HTML attribute
* @return string text encoded to use in HTML attribute
*/
function escapeHTML(s) {
return s.replace(rescaper, replacer);
}
/**
* Default callback used to generate emoji src
* based on Twitter CDN
* @param string the emoji codepoint string
* @param string the default size to use, i.e. "36x36"
* @return string the image source to use
*/
function defaultImageSrcGenerator(icon, options) {
return ''.concat(options.base, options.size, '/', icon, options.ext);
}
/**
* Given a generic DOM nodeType 1, walk through all children
* and store every nodeType 3 (#text) found in the tree.
* @param Element a DOM Element with probably some text in it
* @param Array the list of previously discovered text nodes
* @return Array same list with new discovered nodes, if any
*/
function grabAllTextNodes(node, allText) {
var
childNodes = node.childNodes,
length = childNodes.length,
subnode,
nodeType;
while (length--) {
subnode = childNodes[length];
nodeType = subnode.nodeType;
// parse emoji only in text nodes
if (nodeType === 3) {
// collect them to process emoji later
allText.push(subnode);
}
// ignore all nodes that are not type 1 or that
// should not be parsed as script, style, and others
else if (nodeType === 1 && !shouldntBeParsed.test(subnode.nodeName)) {
grabAllTextNodes(subnode, allText);
}
}
return allText;
}
/**
* 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
*/
function grabTheRightIcon(rawText) {
// if variant is present as \uFE0F
return toCodePoint(rawText.indexOf(U200D) < 0 ?
rawText.replace(UFE0Fg, '') :
rawText
);
}
/**
* DOM version of the same logic / parser:
* emojify all found sub-text nodes placing images node instead.
* @param Element generic DOM node with some text in some child node
* @param Object options containing info about how to parse
*
* .callback Function the callback to invoke per each found emoji.
* .base string the base url, by default twemoji.base
* .ext string the image extension, by default twemoji.ext
* .size string the assets size, by default twemoji.size
*
* @return Element same generic node with emoji in place, if any.
*/
function parseNode(node, options) {
var
allText = grabAllTextNodes(node, []),
length = allText.length,
attrib,
attrname,
modified,
fragment,
subnode,
text,
match,
i,
index,
img,
rawText,
iconId,
src;
while (length--) {
modified = false;
fragment = document.createDocumentFragment();
subnode = allText[length];
text = subnode.nodeValue;
i = 0;
while ((match = re.exec(text))) {
index = match.index;
if (index !== i) {
fragment.appendChild(
createText(text.slice(i, index))
);
}
rawText = match[0];
iconId = grabTheRightIcon(rawText);
i = index + rawText.length;
src = options.callback(iconId, options);
if (src) {
img = new Image();
img.onerror = options.onerror;
img.setAttribute('draggable', 'false');
attrib = options.attributes(rawText, iconId);
for (attrname in attrib) {
if (
attrib.hasOwnProperty(attrname) &&
// don't allow any handlers to be set + don't allow overrides
attrname.indexOf('on') !== 0 &&
!img.hasAttribute(attrname)
) {
img.setAttribute(attrname, attrib[attrname]);
}
}
img.className = options.className;
img.alt = rawText;
img.src = src;
modified = true;
fragment.appendChild(img);
}
if (!img) fragment.appendChild(createText(rawText));
img = null;
}
// is there actually anything to replace in here ?
if (modified) {
// any text left to be added ?
if (i < text.length) {
fragment.appendChild(
createText(text.slice(i))
);
}
// replace the text node only, leave intact
// anything else surrounding such text
subnode.parentNode.replaceChild(fragment, subnode);
}
}
return node;
}
/**
* String/HTML version of the same logic / parser:
* emojify a generic text placing images tags instead of surrogates pair.
* @param string generic string with possibly some emoji in it
* @param Object options containing info about how to parse
*
* .callback Function the callback to invoke per each found emoji.
* .base string the base url, by default twemoji.base
* .ext string the image extension, by default twemoji.ext
* .size string the assets size, by default twemoji.size
*
* @return the string with <img tags> replacing all found and parsed emoji
*/
function parseString(str, options) {
return replace(str, function (rawText) {
var
ret = rawText,
iconId = grabTheRightIcon(rawText),
src = options.callback(iconId, options),
attrib,
attrname;
if (src) {
// recycle the match string replacing the emoji
// with its image counter part
ret = '<img '.concat(
'class="', options.className, '" ',
'draggable="false" ',
// needs to preserve user original intent
// when variants should be copied and pasted too
'alt="',
rawText,
'"',
' src="',
src,
'"'
);
attrib = options.attributes(rawText, iconId);
for (attrname in attrib) {
if (
attrib.hasOwnProperty(attrname) &&
// don't allow any handlers to be set + don't allow overrides
attrname.indexOf('on') !== 0 &&
ret.indexOf(' ' + attrname + '=') === -1
) {
ret = ret.concat(' ', attrname, '="', escapeHTML(attrib[attrname]), '"');
}
}
ret = ret.concat('>');
}
return ret;
});
}
/**
* Function used to actually replace HTML special chars
* @param string HTML special char
* @return string encoded HTML special char
*/
function replacer(m) {
return escaper[m];
}
/**
* Default options.attribute callback
* @return null
*/
function returnNull() {
return null;
}
/**
* Given a generic value, creates its squared counterpart if it's a number.
* As example, number 36 will return '36x36'.
* @param any a generic value.
* @return any a string representing asset size, i.e. "36x36"
* only in case the value was a number.
* Returns initial value otherwise.
*/
function toSizeSquaredAsset(value) {
return typeof value === 'number' ?
value + 'x' + value :
value;
}
/////////////////////////
// exported functions //
// declaration //
/////////////////////////
function fromCodePoint(codepoint) {
var code = typeof codepoint === 'string' ?
parseInt(codepoint, 16) : codepoint;
if (code < 0x10000) {
return fromCharCode(code);
}
code -= 0x10000;
return fromCharCode(
0xD800 + (code >> 10),
0xDC00 + (code & 0x3FF)
);
}
function parse(what, how) {
if (!how || typeof how === 'function') {
how = {callback: how};
}
// if first argument is string, inject html <img> tags
// otherwise use the DOM tree and parse text nodes only
return (typeof what === 'string' ? parseString : parseNode)(what, {
callback: how.callback || defaultImageSrcGenerator,
attributes: typeof how.attributes === 'function' ? how.attributes : returnNull,
base: typeof how.base === 'string' ? how.base : twemoji.base,
ext: how.ext || twemoji.ext,
size: how.folder || toSizeSquaredAsset(how.size || twemoji.size),
className: how.className || twemoji.className,
onerror: how.onerror || twemoji.onerror
});
}
function replace(text, callback) {
return String(text).replace(re, callback);
}
function test(text) {
// IE6 needs a reset before too
re.lastIndex = 0;
var result = re.test(text);
re.lastIndex = 0;
return result;
}
function toCodePoint(unicodeSurrogates, sep) {
var
r = [],
c = 0,
p = 0,
i = 0;
while (i < unicodeSurrogates.length) {
c = unicodeSurrogates.charCodeAt(i++);
if (p) {
r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16));
p = 0;
} else if (0xD800 <= c && c <= 0xDBFF) {
p = c;
} else {
r.push(c.toString(16));
}
}
return r.join(sep || '-');
}
}());
if (!location.protocol) {
twemoji.base = twemoji.base.replace(/^http:/, "");
}
module.exports = twemoji;

52
1/utils/create-dist Executable file
View File

@ -0,0 +1,52 @@
#!/usr/bin/env node
/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*
https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
*/
var fs = require('fs');
var path = require('path');
function file(which) {
return path.join(__dirname, '..', which);
}
fs.writeFileSync(
file('twemoji.npm.js'),
[
'var location = global.location || {};',
fs.readFileSync(file('twemoji.js')),
'if (!location.protocol) {',
' twemoji.base = twemoji.base.replace(/^http:/, "");',
'}',
'module.exports = twemoji;'
].join('\n')
);
fs.writeFileSync(
file('twemoji.amd.js'),
'define(function () {\n' +
fs.readFileSync(file('twemoji.js')).toString().replace(
/^(.)/gm, ' $1'
) +
'\n return twemoji;\n});'
);
require('child_process').spawn(
'node',
[
path.join(__dirname, '../../', 'node_modules/uglify-js/bin/uglifyjs'),
'--verbose',
file('twemoji.js'),
'-o',
file('twemoji.tmp.js')
]
).on('close', function () {
fs.writeFileSync(
file('twemoji.min.js'),
'/*! Copyright Twitter Inc. and other contributors. Licensed under MIT */\n' +
fs.readFileSync(file('twemoji.tmp.js'))
);
fs.unlink(file('twemoji.tmp.js'));
// gzip -c twemoji.min.js | wc -c
});

995
1/utils/generate Executable file
View File

@ -0,0 +1,995 @@
#!/usr/bin/env node
/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*
https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
*/
// dependencies
var fs = require('fs');
var http = require('http');
var path = require('path');
function file(which) {
return path.join(__dirname, '../..', which);
}
// Twitter assets by property name
var assets = {
'72x72': [],
'svg': []
};
// white spaces we don't want to catch via the RegExp
// there is no asset equivalent for these
var ignoreMissing = ['2002', '2003', '2005'];
// basic utility to organize async code
// see: http://webreflection.blogspot.co.uk/2012/03/tweet-sized-queue-system.html
// or: http://webreflection.blogspot.co.uk/2012/06/working-with-queues.html
function Queue(args, f) {
setTimeout(args.next = function next() {
return (f = args.shift()) ? !!f(args) || !0 : !1;
}, 0);
return args;
}
// main task
Queue([
// will populate assets arrays
function grabAllAssets(q) {
console.log('analyzing all assets ... ');
// per each path/folder
Object.keys(assets).forEach(function (path, i, paths) {
// grab all files in that folder
fs.readdir(file(path), function (err, files) {
// and add them to the assets path
assets[path].push.apply(
assets[path],
files.map(upperCaseWithoutExtension)
);
// once all assets arrays have been populated
if (paths.reduce(completed, true)) {
console.log('[INFO] assets contains ' + assets[path].length + ' emoji.');
q.next();
}
});
});
// drop extension + uppercase
function upperCaseWithoutExtension(file) {
return file.slice(0, file.lastIndexOf('.')).toUpperCase();
}
// returns true if all assets have been populated
function completed(p, c) {
return p && assets[c].length;
}
},
// will fetch and store all emoji from unicode.org
function fetchEmojiSources(q) {
console.log('fetching EmojiSources.txt ... ');
// grab all emoji and test them against them
http.get("http://www.unicode.org/Public/UNIDATA/EmojiSources.txt", function (res) {
var chunks = [];
// if all good ...
if (res.statusCode === 200) {
// grab all data
res.on('data', chunks.push.bind(chunks));
// once done ...
res.on('end', function () {
console.log('analyzing EmojiSources VS our assets ... ');
// store all missing assets in one object
var missing = {};
// will be used to store an array with all missing
var missingGrouped = {};
// will be needed later on
// parse it, clean it, and store it once
q.emojiSource = chunks
.join('')
.split(/\r\n|\r|\n/)
// filter once
.filter(function (line) {
return this.test(line);
}, /^[0-9A-F]/)
// take only emoji info
.map(function (codePoint) {
return codePoint
.slice(0, codePoint.indexOf(';'))
.toUpperCase()
// drop spaces
.replace(/\s+/g, '-')
// drop 0 padded prefixes
.replace(/^0+/g, '');
});
console.log('[INFO] parsed ' + q.emojiSource.length + ' standard emoji.');
// find out which one is missing from our assets
q.emojiSource.forEach(
function (emoji) {
// do not loop for emoji we know we should ignore
if (ignoreMissing.indexOf(emoji) < 0) {
// verify all others per each folder
this.forEach(function (path) {
if (assets[path].indexOf(emoji) < 0) {
(missing[path] || (missing[path] = [])).push(emoji);
missingGrouped[emoji] = true;
}
});
}
},
// and per each folder
Object.keys(assets)
);
// if some missing emoji has been found
if (Object.keys(missing).length) {
// warn and show which one is missing
console.warn('[WARNING] missing assets for:');
console.log(missing);
}
// create the array of all emoji we should ignore
q.ignore = ignoreMissing.concat(Object.keys(missingGrouped));
q.next();
});
} else {
console.error('[ERROR] unable to fetch emoji at unicode.org');
process.exit(1);
}
});
},
// grab the list of emoji that behave differently when
// variants such \uFE0E and \uFE0F are in place
function grabStandardVariants(q) {
console.log('fetching StandardizedVariants.txt ... ');
http.get(
"http://unicode.org/Public/UNIDATA/StandardizedVariants.txt",
function(res) {
var chunks = [];
if (res.statusCode == 200) {
res.on('data', chunks.push.bind(chunks));
res.on('end', function () {
// cleaning up parsing sensitive emoji
q.variantsSensitive = chunks
.join('') // all content
.split(/\r\n|\r|\n/) // split in lines
.filter(function (line) { // containing FE0E; info
return this.test(line); // avoiding duplicated with FE0F
}, / FE0E; text style/)
.map(function (line) { // cleaned up to grab
return line.replace(this, '$1') // only first unicode
.toUpperCase(); // normalized as uppercase
}, /^([0-9A-F]{4,}) FE0E;.+$/) // sensitive char
;
// iOS keyboard allows U+002A U+FE0F U+20E3 even though not a standardized variant (yet?)
q.variantsSensitive.push('002A');
// iOS keyboard allows U+2639 U+FE0F even though not a standardized variant (yet?)
q.variantsSensitive.push('2639');
console.log('[INFO] parsed ' + q.variantsSensitive.length + ' variant sensitive emoji.');
q.next();
});
} else {
console.error('[ERROR] unable to fetch standard variants at unicode.org');
process.exit(1);
}
}
);
},
// add our own assets that are not part of the Unicode standard
function addMissingEmoji(q) {
q.nonStandard = [];
Object.keys(assets).forEach(function (path, i) {
assets[path].forEach(function (emoji) {
if (
q.emojiSource.indexOf(emoji) < 0 &&
q.nonStandard.indexOf(emoji) < 0
) {
q.nonStandard.push(emoji);
}
});
});
if (q.nonStandard.length) {
console.warn('[WARNING] assets contain ' + q.nonStandard.length + ' non standard emoji:');
// console.log(q.nonStandard.join(', '));
}
q.emojiSource = q.emojiSource.concat(q.nonStandard)
q.next();
},
// detect complete sets of five skin tones and a base
function detectDiversityEmoji(q) {
var isPresent = {};
q.emojiSource.forEach(function (codePoints) {
isPresent[codePoints] = true;
});
q.diversityBase = q.emojiSource.filter(function (codePoints) {
// Start with the set of Emoji with the light skin tone
return /-1F3FB$/.test(codePoints);
}).map(function (codePoints) {
// Take the skin tone off
return codePoints.replace(/-1F3FB$/, '');
}).filter(function (baseCodePoints) {
// Verify that all other skin tones + no skin tone are present
return ['-1F3FC', '-1F3FD', '-1F3FE', '-1F3FF', ''].every(function (suffix) {
return isPresent[baseCodePoints + suffix];
});
});
console.log('[INFO] parsed ' + q.diversityBase.length + ' diversity emoji.');
q.next();
},
// with all info, generate a RegExp that will catch
// only standard emoji that are present in our assets
function generateRegExp(q) {
console.log('generating a RegExp for available assets');
var zwj = [];
var diversity = [];
var sensitive = [];
var sensitiveKeycaps = [];
var diversitySensitive = [];
var skinToneOptions = [
'\\ud83c\\udffb',
'\\ud83c\\udffc',
'\\ud83c\\udffd',
'\\ud83c\\udffe',
'\\ud83c\\udfff'
];
var regular = [];
q.emojiSource.forEach(function (codePoints) {
var u;
var codePointsWithoutKeycap;
codePoints = codePoints.replace(/\b[A-F0-9]+\b/g, function (hex) {
// Pad all hex numbers to have at least 4 digits to match variantsSensitive
return hex.length < 4 ? ('000' + hex).slice(-4) : hex;
});
if (q.ignore.indexOf(codePoints) < 0) {
u = toJSON(codePoints);
codePointsWithoutKeycap = codePoints.replace(/-20E3$/, '');
if (codePoints.indexOf('200D') >= 0) {
zwj.push(u);
} else if (codePoints != codePointsWithoutKeycap && q.variantsSensitive.indexOf(codePointsWithoutKeycap) >= 0) {
sensitiveKeycaps.push(toJSON(codePointsWithoutKeycap));
} else if (q.diversityBase.indexOf(codePoints.replace(/-1F3F[B-F]$/, '')) >= 0) {
// This is a diversity Emoji with or without a skin tone modifier
// Add it to the regex if this is the base without the modifier
if (q.diversityBase.indexOf(codePoints) >= 0) {
if (q.variantsSensitive.indexOf(codePoints) < 0) {
diversity.push(u);
} else {
diversitySensitive.push(u);
}
}
} else if (q.variantsSensitive.indexOf(codePoints) < 0) {
regular.push(u);
} else {
sensitive.push(u);
}
}
});
q.re = '';
// The Zero-width joiner Emojis, if present, need to come first
if (zwj.length) {
q.re += generateRegexPartial(zwj) + '|';
}
// Group the variant sensitive keycaps
if (sensitiveKeycaps.length) {
q.re += '(?:' + generateRegexPartial(sensitiveKeycaps) + ')\\ufe0f?\\u20e3|';
}
// Next, add the diversity enabled Emoji that may include a skin tone suffix
if (diversity.length + diversitySensitive.length) {
q.re += '(?:';
if (diversitySensitive.length) {
// Some diversity are sensitive to variants
q.re += '(?:' + generateRegexPartial(diversitySensitive) + ')(?:\\ufe0f|(?!\\ufe0e))';
if (diversity.length) {
q.re += '|';
}
}
q.re += generateRegexPartial(diversity) + ')(?:' + generateRegexPartial(skinToneOptions) + '|)|';
}
// Next, the normal Emoji
q.re += generateRegexPartial(regular) + '|';
// Finally, add the rest of the sensitive ones that may be followed by U+FE0F but not U+FE0E
q.re += '(?:' + generateRegexPartial(sensitive) + ')(?:\\ufe0f|(?!\\ufe0e))';
q.next();
// basic utilities to convert codepoints to JSON strings
function toJSON(codePoints) {
return codePoints.split('-').map(function (point) {
return UTF162JSON(fromCodePoint(point));
}).join('');
}
function fromCodePoint(codepoint) {
var code = typeof codepoint === 'string' ?
parseInt(codepoint, 16) : codepoint;
if (code < 0x10000) {
return String.fromCharCode(code);
}
code -= 0x10000;
return String.fromCharCode(
0xD800 + (code >> 10),
0xDC00 + (code & 0x3FF)
);
}
function UTF162JSON(text) {
for (var i = 0, r = []; i < text.length; i++) {
r.push('\\u' + ('000' + text.charCodeAt(i).toString(16)).slice(-4));
}
return r.join('');
}
// Items is an array of unicode sequences with \u escaping, like ["\u2963\ufe0f", "\u263a\ufe0f"]
// items get sorted by length (long to short), then unicode hex values (high to low)
// output is "or" ed together using | for regex
// ouput also combines adjacent items using character classes with ranges when they have common prefixes
// Example: "aab", "aac", "aad", "aag", "ba" becomes "aa[b-dg]|ba"
function generateRegexPartial(items) {
var currentPrefix = null;
var result = [];
var charClass = [];
var charRange = [];
items.map(function (item) {
// Convert from "\u2963\ufe0f" into ["2963", "fe0f"]
return item.split('\\u').slice(1);
}).sort(sortMethod).forEach(function (itemParts) {
var prefix = itemParts.slice(0, -1).join('\\u');
if (prefix) {
prefix = '\\u' + prefix;
}
var suffix = itemParts.slice(-1);
if (prefix !== currentPrefix) {
flushCharClass();
}
currentPrefix = prefix;
var suffixMinusOne = UTF162JSON(String.fromCharCode(parseInt(suffix, 16) - 1));
if (charRange.length && charRange.slice(-1)[0] !== suffixMinusOne) {
flushCharRange();
}
charRange.push('\\u' + suffix);
});
flushCharClass();
return result.join('|');
// a and b are arrays of hex UCS-2 units
function sortMethod(a, b) {
return !a.length ? 0 :
b.length - a.length ||
parseInt(b[0], 16) - parseInt(a[0], 16) ||
sortMethod(b.slice(1), a.slice(1)
);
}
function flushCharRange() {
charClass = charClass.concat((charRange.length < 3) ?
charRange :
[ charRange[0], '-', charRange.slice(-1)[0] ]
);
charRange = [];
}
function flushCharClass() {
flushCharRange();
if (charClass.length) {
result.push(currentPrefix + (charClass.length == 1 ?
charClass[0] :
'[' + charClass.join('') + ']'
));
}
charClass = [];
currentPrefix = null;
}
}
},
function generateFile(q) {
console.log('generating ./twemoji.js');
createTwemoji(q.re);
require('./create-dist');
}
]);
function createTwemoji(re) {
fs.writeFileSync(
file('1/twemoji.js'),
'/*jslint indent: 2, browser: true, bitwise: true, plusplus: true */\n' +
'var twemoji = (' +
function (
/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*
https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
*/
// WARNING: this file is generated automatically via
// `node twemoji-generator.js`
// please update its `createTwemoji` function
// at the bottom of the same file instead.
) {
'use strict';
/*jshint maxparams:4 */
var
// the exported module object
twemoji = {
/////////////////////////
// properties //
/////////////////////////
// default assets url, by default will be Twitter Inc. CDN
base: 'https://twemoji.maxcdn.com/1/',
// default assets file extensions, by default '.png'
ext: '.png',
// default assets/folder size, by default "72x72"
// available via Twitter CDN: 72
size: '72x72',
// default class name, by default 'emoji'
className: 'emoji',
// basic utilities / helpers to convert code points
// to JavaScript surrogates and vice versa
convert: {
/**
* Given an HEX codepoint, returns UTF16 surrogate pairs.
*
* @param string generic codepoint, i.e. '1F4A9'
* @return string codepoint transformed into utf16 surrogates pair,
* i.e. \uD83D\uDCA9
*
* @example
* twemoji.convert.fromCodePoint('1f1e8');
* // "\ud83c\udde8"
*
* '1f1e8-1f1f3'.split('-').map(twemoji.convert.fromCodePoint).join('')
* // "\ud83c\udde8\ud83c\uddf3"
*/
fromCodePoint: fromCodePoint,
/**
* Given UTF16 surrogate pairs, returns the equivalent HEX codepoint.
*
* @param string generic utf16 surrogates pair, i.e. \uD83D\uDCA9
* @param string optional separator for double code points, default='-'
* @return string utf16 transformed into codepoint, i.e. '1F4A9'
*
* @example
* twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3');
* // "1f1e8-1f1f3"
*
* twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3', '~');
* // "1f1e8~1f1f3"
*/
toCodePoint: toCodePoint
},
/////////////////////////
// methods //
/////////////////////////
/**
* User first: used to remove missing images
* preserving the original text intent when
* a fallback for network problems is desired.
* Automatically added to Image nodes via DOM
* It could be recycled for string operations via:
* $('img.emoji').on('error', twemoji.onerror)
*/
onerror: function onerror() {
if (this.parentNode) {
this.parentNode.replaceChild(createText(this.alt), this);
}
},
/**
* Main method/logic to generate either <img> tags or HTMLImage nodes.
* "emojify" a generic text or DOM Element.
*
* @overloads
*
* String replacement for `innerHTML` or server side operations
* twemoji.parse(string);
* twemoji.parse(string, Function);
* twemoji.parse(string, Object);
*
* HTMLElement tree parsing for safer operations over existing DOM
* twemoji.parse(HTMLElement);
* twemoji.parse(HTMLElement, Function);
* twemoji.parse(HTMLElement, Object);
*
* @param string|HTMLElement the source to parse and enrich with emoji.
*
* string replace emoji matches with <img> tags.
* Mainly used to inject emoji via `innerHTML`
* It does **not** parse the string or validate it,
* it simply replaces found emoji with a tag.
* NOTE: be sure this won't affect security.
*
* HTMLElement walk through the DOM tree and find emoji
* that are inside **text node only** (nodeType === 3)
* Mainly used to put emoji in already generated DOM
* without compromising surrounding nodes and
* **avoiding** the usage of `innerHTML`.
* NOTE: Using DOM elements instead of strings should
* improve security without compromising too much
* performance compared with a less safe `innerHTML`.
*
* @param Function|Object [optional]
* either the callback that will be invoked or an object
* with all properties to use per each found emoji.
*
* Function if specified, this will be invoked per each emoji
* that has been found through the RegExp except
* those follwed by the invariant \uFE0E ("as text").
* Once invoked, parameters will be:
*
* iconId:string the lower case HEX code point
* i.e. "1f4a9"
*
* options:Object all info for this parsing operation
*
* variant:char the optional \uFE0F ("as image")
* variant, in case this info
* is anyhow meaningful.
* By default this is ignored.
*
* If such callback will return a falsy value instead
* of a valid `src` to use for the image, nothing will
* actually change for that specific emoji.
*
*
* Object if specified, an object containing the following properties
*
* callback Function the callback to invoke per each found emoji.
* base string the base url, by default twemoji.base
* ext string the image extension, by default twemoji.ext
* size string the assets size, by default twemoji.size
*
* @example
*
* twemoji.parse("I \u2764\uFE0F emoji!");
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/2764.gif"> emoji!
*
*
* twemoji.parse("I \u2764\uFE0F emoji!", function(iconId, options) {
* return '/assets/' + iconId + '.gif';
* });
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/2764.gif"> emoji!
*
*
* twemoji.parse("I \u2764\uFE0F emoji!", {
* size: 72,
* callback: function(iconId, options) {
* return '/assets/' + options.size + '/' + iconId + options.ext;
* }
* });
* // I <img class="emoji" draggable="false" alt="❤️" src="/assets/72x72/2764.png"> emoji!
*
*/
parse: parse,
/**
* Given a string, invokes the callback argument
* per each emoji found in such string.
* This is the most raw version used by
* the .parse(string) method itself.
*
* @param string generic string to parse
* @param Function a generic callback that will be
* invoked to replace the content.
* This calback wil receive standard
* String.prototype.replace(str, callback)
* arguments such:
* callback(
* rawText, // the emoji match
* );
*
* and others commonly received via replace.
*/
replace: replace,
/**
* Simplify string tests against emoji.
*
* @param string some text that might contain emoji
* @return boolean true if any emoji was found, false otherwise.
*
* @example
*
* if (twemoji.test(someContent)) {
* console.log("emoji All The Things!");
* }
*/
test: test
},
// used to escape HTML special chars in attributes
escaper = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
"'": '&#39;',
'"': '&quot;'
},
// RegExp based on emoji's official Unicode standards
// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
re = /twemoji/,
// avoid runtime RegExp creation for not so smart,
// not JIT based, and old browsers / engines
UFE0Fg = /\uFE0F/g,
// avoid using a string literal like '\u200D' here because minifiers expand it inline
U200D = String.fromCharCode(0x200D),
// used to find HTML special chars in attributes
rescaper = /[&<>'"]/g,
// nodes with type 1 which should **not** be parsed (including lower case svg)
shouldntBeParsed = /IFRAME|NOFRAMES|NOSCRIPT|SCRIPT|SELECT|STYLE|TEXTAREA|[a-z]/,
// just a private shortcut
fromCharCode = String.fromCharCode;
return twemoji;
/////////////////////////
// private functions //
// declaration //
/////////////////////////
/**
* Shortcut to create text nodes
* @param string text used to create DOM text node
* @return Node a DOM node with that text
*/
function createText(text) {
return document.createTextNode(text);
}
/**
* Utility function to escape html attribute text
* @param string text use in HTML attribute
* @return string text encoded to use in HTML attribute
*/
function escapeHTML(s) {
return s.replace(rescaper, replacer);
}
/**
* Default callback used to generate emoji src
* based on Twitter CDN
* @param string the emoji codepoint string
* @param string the default size to use, i.e. "36x36"
* @return string the image source to use
*/
function defaultImageSrcGenerator(icon, options) {
return ''.concat(options.base, options.size, '/', icon, options.ext);
}
/**
* Given a generic DOM nodeType 1, walk through all children
* and store every nodeType 3 (#text) found in the tree.
* @param Element a DOM Element with probably some text in it
* @param Array the list of previously discovered text nodes
* @return Array same list with new discovered nodes, if any
*/
function grabAllTextNodes(node, allText) {
var
childNodes = node.childNodes,
length = childNodes.length,
subnode,
nodeType;
while (length--) {
subnode = childNodes[length];
nodeType = subnode.nodeType;
// parse emoji only in text nodes
if (nodeType === 3) {
// collect them to process emoji later
allText.push(subnode);
}
// ignore all nodes that are not type 1 or that
// should not be parsed as script, style, and others
else if (nodeType === 1 && !shouldntBeParsed.test(subnode.nodeName)) {
grabAllTextNodes(subnode, allText);
}
}
return allText;
}
/**
* 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
*/
function grabTheRightIcon(rawText) {
// if variant is present as \uFE0F
return toCodePoint(rawText.indexOf(U200D) < 0 ?
rawText.replace(UFE0Fg, '') :
rawText
);
}
/**
* DOM version of the same logic / parser:
* emojify all found sub-text nodes placing images node instead.
* @param Element generic DOM node with some text in some child node
* @param Object options containing info about how to parse
*
* .callback Function the callback to invoke per each found emoji.
* .base string the base url, by default twemoji.base
* .ext string the image extension, by default twemoji.ext
* .size string the assets size, by default twemoji.size
*
* @return Element same generic node with emoji in place, if any.
*/
function parseNode(node, options) {
var
allText = grabAllTextNodes(node, []),
length = allText.length,
attrib,
attrname,
modified,
fragment,
subnode,
text,
match,
i,
index,
img,
rawText,
iconId,
src;
while (length--) {
modified = false;
fragment = document.createDocumentFragment();
subnode = allText[length];
text = subnode.nodeValue;
i = 0;
while ((match = re.exec(text))) {
index = match.index;
if (index !== i) {
fragment.appendChild(
createText(text.slice(i, index))
);
}
rawText = match[0];
iconId = grabTheRightIcon(rawText);
i = index + rawText.length;
src = options.callback(iconId, options);
if (src) {
img = new Image();
img.onerror = options.onerror;
img.setAttribute('draggable', 'false');
attrib = options.attributes(rawText, iconId);
for (attrname in attrib) {
if (
attrib.hasOwnProperty(attrname) &&
// don't allow any handlers to be set + don't allow overrides
attrname.indexOf('on') !== 0 &&
!img.hasAttribute(attrname)
) {
img.setAttribute(attrname, attrib[attrname]);
}
}
img.className = options.className;
img.alt = rawText;
img.src = src;
modified = true;
fragment.appendChild(img);
}
if (!img) fragment.appendChild(createText(rawText));
img = null;
}
// is there actually anything to replace in here ?
if (modified) {
// any text left to be added ?
if (i < text.length) {
fragment.appendChild(
createText(text.slice(i))
);
}
// replace the text node only, leave intact
// anything else surrounding such text
subnode.parentNode.replaceChild(fragment, subnode);
}
}
return node;
}
/**
* String/HTML version of the same logic / parser:
* emojify a generic text placing images tags instead of surrogates pair.
* @param string generic string with possibly some emoji in it
* @param Object options containing info about how to parse
*
* .callback Function the callback to invoke per each found emoji.
* .base string the base url, by default twemoji.base
* .ext string the image extension, by default twemoji.ext
* .size string the assets size, by default twemoji.size
*
* @return the string with <img tags> replacing all found and parsed emoji
*/
function parseString(str, options) {
return replace(str, function (rawText) {
var
ret = rawText,
iconId = grabTheRightIcon(rawText),
src = options.callback(iconId, options),
attrib,
attrname;
if (src) {
// recycle the match string replacing the emoji
// with its image counter part
ret = '<img '.concat(
'class="', options.className, '" ',
'draggable="false" ',
// needs to preserve user original intent
// when variants should be copied and pasted too
'alt="',
rawText,
'"',
' src="',
src,
'"'
);
attrib = options.attributes(rawText, iconId);
for (attrname in attrib) {
if (
attrib.hasOwnProperty(attrname) &&
// don't allow any handlers to be set + don't allow overrides
attrname.indexOf('on') !== 0 &&
ret.indexOf(' ' + attrname + '=') === -1
) {
ret = ret.concat(' ', attrname, '="', escapeHTML(attrib[attrname]), '"');
}
}
ret = ret.concat('>');
}
return ret;
});
}
/**
* Function used to actually replace HTML special chars
* @param string HTML special char
* @return string encoded HTML special char
*/
function replacer(m) {
return escaper[m];
}
/**
* Default options.attribute callback
* @return null
*/
function returnNull() {
return null;
}
/**
* Given a generic value, creates its squared counterpart if it's a number.
* As example, number 36 will return '36x36'.
* @param any a generic value.
* @return any a string representing asset size, i.e. "36x36"
* only in case the value was a number.
* Returns initial value otherwise.
*/
function toSizeSquaredAsset(value) {
return typeof value === 'number' ?
value + 'x' + value :
value;
}
/////////////////////////
// exported functions //
// declaration //
/////////////////////////
function fromCodePoint(codepoint) {
var code = typeof codepoint === 'string' ?
parseInt(codepoint, 16) : codepoint;
if (code < 0x10000) {
return fromCharCode(code);
}
code -= 0x10000;
return fromCharCode(
0xD800 + (code >> 10),
0xDC00 + (code & 0x3FF)
);
}
function parse(what, how) {
if (!how || typeof how === 'function') {
how = {callback: how};
}
// if first argument is string, inject html <img> tags
// otherwise use the DOM tree and parse text nodes only
return (typeof what === 'string' ? parseString : parseNode)(what, {
callback: how.callback || defaultImageSrcGenerator,
attributes: typeof how.attributes === 'function' ? how.attributes : returnNull,
base: typeof how.base === 'string' ? how.base : twemoji.base,
ext: how.ext || twemoji.ext,
size: how.folder || toSizeSquaredAsset(how.size || twemoji.size),
className: how.className || twemoji.className,
onerror: how.onerror || twemoji.onerror
});
}
function replace(text, callback) {
return String(text).replace(re, callback);
}
function test(text) {
// IE6 needs a reset before too
re.lastIndex = 0;
var result = re.test(text);
re.lastIndex = 0;
return result;
}
function toCodePoint(unicodeSurrogates, sep) {
var
r = [],
c = 0,
p = 0,
i = 0;
while (i < unicodeSurrogates.length) {
c = unicodeSurrogates.charCodeAt(i++);
if (p) {
r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16));
p = 0;
} else if (0xD800 <= c && c <= 0xDBFF) {
p = c;
} else {
r.push(c.toString(16));
}
}
return r.join(sep || '-');
}
}.toString()
// drop current indentation
.replace(/^ /gm, '')
// add the RegExp in the right place
.replace('re = /twemoji/', 're = /' + re + '/g')
// add the full license
.replace('/*! (C) Twitter Inc. */',
'/*! (C) Twitter Inc. *//*\n' +
fs.readFileSync(path.join(__dirname, '../../', 'LICENSE')).toString().replace(
/^./gm, ' '
) +
'\n */'
) + '());');
}

44
1/utils/preview Executable file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env node
/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*
https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
*/
// dependencies
var fs = require('fs');
var path = require('path');
function file(which) {
return path.join(__dirname, '..', which);
}
fs.readdir(file('../assets'), function (err, files) {
var page = fs.readFileSync(file('templates/preview.html')).toString().replace(
'{{emoji-list}}',
'<li>' + files.map(function (file) {
return file.replace('.ai', '').split('-').map(function (hex) {
return '&#x' + hex.toUpperCase() + ';';
}).join('');
}).join('</li>\n <li>')+ '</li>'
);
fs.writeFileSync(
file('test/preview.html'),
page.replace(
'{{emoji-options}}',
JSON.stringify({
size: 72
})
)
);
fs.writeFileSync(
file('test/preview-svg.html'),
page.replace(
'{{emoji-options}}',
JSON.stringify({
folder: '../svg',
ext: '.svg',
base: ''
})
)
);
});

6
1/utils/size Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
echo "twemoji.js $(cat 1/twemoji.js | wc -c)"
echo "twemoji.js gzipped $(gzip -c 1/twemoji.js | wc -c)"
echo "twemoji.min.js $(cat 1/twemoji.min.js | wc -c)"
echo "twemoji.min.js gzipped $(gzip -c 1/twemoji.min.js | wc -c)"