mirror of
https://github.com/twitter/twemoji.git
synced 2025-01-30 15:32:39 +00:00
Merge pull request #73 from twitter/derekmooney-gh-pages
Derekmooney gh pages
This commit is contained in:
commit
398533a464
14
README.md
14
README.md
@ -148,6 +148,7 @@ Here the list of properties accepted by the optional object that could be passed
|
|||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
callback: Function, // default the common replacer
|
callback: Function, // default the common replacer
|
||||||
|
attributes: Function, // default returns {}
|
||||||
base: string, // default MaxCDN
|
base: string, // default MaxCDN
|
||||||
ext: string, // default ".png"
|
ext: string, // default ".png"
|
||||||
className: string, // default "emoji"
|
className: string, // default "emoji"
|
||||||
@ -173,6 +174,19 @@ function imageSourceGenerator(icon, options) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### attributes
|
||||||
|
The function to invoke in order to generate additional, custom attributes for the image tag.
|
||||||
|
|
||||||
|
By default it is a function like the following one:
|
||||||
|
```js
|
||||||
|
function attributesCallback(icon, variant) {
|
||||||
|
return {
|
||||||
|
title: 'Emoji: ' + icon + variant
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Event handlers cannot be specified via this method, and twemoji-provided attributes (src, alt, className, draggable) cannot be re-defined.
|
||||||
|
|
||||||
##### base
|
##### base
|
||||||
The default url is the same as `twemoji.base`, so if you modify the former, it will reflect as default for all parsed strings or nodes.
|
The default url is the same as `twemoji.base`, so if you modify the former, it will reflect as default for all parsed strings or nodes.
|
||||||
|
96
test.js
96
test.js
@ -306,6 +306,102 @@ wru.test([{
|
|||||||
div.getElementsByTagName('img')[0].className === className
|
div.getElementsByTagName('img')[0].className === className
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
name: 'string parsing + attributes callback',
|
||||||
|
test: function () {
|
||||||
|
wru.assert(
|
||||||
|
'custom attributes are inserted',
|
||||||
|
'I <img class="emoji" draggable="false" alt="\u2764" src="' + base + '36x36/2764.png" title="Emoji: \u2764" data-test="We all <3 emoji"> emoji!' ===
|
||||||
|
twemoji.parse(
|
||||||
|
'I \u2764 emoji!',
|
||||||
|
{
|
||||||
|
attributes: function(icon) {
|
||||||
|
return {
|
||||||
|
title: 'Emoji: ' + icon,
|
||||||
|
'data-test': 'We all <3 emoji'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'string parsing + attributes callback content properly encoded',
|
||||||
|
test: function () {
|
||||||
|
wru.assert(
|
||||||
|
'custom attributes are inserted',
|
||||||
|
'I <img class="emoji" draggable="false" alt="\u2764" src="' + base + '36x36/2764.png" title="&amp;lt;script&amp;gt;alert("yo")&amp;lt;/script&amp;gt;"> emoji!' ===
|
||||||
|
twemoji.parse(
|
||||||
|
'I \u2764 emoji!',
|
||||||
|
{
|
||||||
|
attributes: function(icon) {
|
||||||
|
return {
|
||||||
|
title: '&lt;script&gt;alert("yo")&lt;/script&gt;'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'string parsing + attributes callback "on" attributes are omitted',
|
||||||
|
test: function () {
|
||||||
|
wru.assert(
|
||||||
|
'custom attributes are inserted',
|
||||||
|
'I <img class="emoji" draggable="false" alt="❤" src="' + base + '36x36/2764.png" title="test"> emoji!' ===
|
||||||
|
twemoji.parse(
|
||||||
|
'I \u2764 emoji!',
|
||||||
|
{
|
||||||
|
attributes: function(icon) {
|
||||||
|
return {
|
||||||
|
title: 'test',
|
||||||
|
onsomething: 'whoops!',
|
||||||
|
onclick: 'nope',
|
||||||
|
onmousedown: 'nada'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'DOM parsing + attributes callback',
|
||||||
|
test: function () {
|
||||||
|
var img,
|
||||||
|
// without variant
|
||||||
|
div = document.createElement('div');
|
||||||
|
div.appendChild(document.createTextNode('I \u2764 emoji!'));
|
||||||
|
twemoji.parse(
|
||||||
|
div, {
|
||||||
|
attributes: function(icon) {
|
||||||
|
return {
|
||||||
|
title: 'Emoji: ' + icon,
|
||||||
|
'data-test': 'We all <3 emoji',
|
||||||
|
onclick: 'nope',
|
||||||
|
onmousedown: 'nada'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
);
|
||||||
|
wru.assert('default parsing works creating 3 nodes', div.childNodes.length === 3);
|
||||||
|
wru.assert('first child is the expected one', div.removeChild(div.firstChild).nodeValue === 'I ');
|
||||||
|
img = div.removeChild(div.firstChild);
|
||||||
|
wru.assert('second child is the image', img.nodeName === 'IMG');
|
||||||
|
wru.assert('img attributes are OK',
|
||||||
|
img.className === 'emoji' &&
|
||||||
|
img.getAttribute('draggable') === 'false' &&
|
||||||
|
img.src === base + '36x36/2764.png' &&
|
||||||
|
img.alt === '\u2764' &&
|
||||||
|
img.onerror === twemoji.onerror &&
|
||||||
|
img.getAttribute('title') === 'Emoji: \u2764' &&
|
||||||
|
img.getAttribute('data-test') === 'We all <3 emoji'
|
||||||
|
);
|
||||||
|
wru.assert('img on attributes are omitted',
|
||||||
|
img.onclick === null &&
|
||||||
|
img.onmousedown === null
|
||||||
|
);
|
||||||
|
}
|
||||||
},{
|
},{
|
||||||
name: 'folder option',
|
name: 'folder option',
|
||||||
test: function () {
|
test: function () {
|
||||||
|
@ -500,10 +500,22 @@ function createTwemoji(re) {
|
|||||||
test: test
|
test: test
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// used to escape HTML special chars in attributes
|
||||||
|
escaper = {
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
"'": ''',
|
||||||
|
'"': '"'
|
||||||
|
},
|
||||||
|
|
||||||
// RegExp based on emoji's official Unicode standards
|
// RegExp based on emoji's official Unicode standards
|
||||||
// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
|
// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
|
||||||
re = /twemoji/,
|
re = /twemoji/,
|
||||||
|
|
||||||
|
// used to find HTML special chars in attributes
|
||||||
|
rescaper = /[&<>'"]/g,
|
||||||
|
|
||||||
// nodes with type 1 which should **not** be parsed
|
// nodes with type 1 which should **not** be parsed
|
||||||
shouldntBeParsed = /IFRAME|NOFRAMES|NOSCRIPT|SCRIPT|SELECT|STYLE|TEXTAREA/,
|
shouldntBeParsed = /IFRAME|NOFRAMES|NOSCRIPT|SCRIPT|SELECT|STYLE|TEXTAREA/,
|
||||||
|
|
||||||
@ -527,6 +539,15 @@ function createTwemoji(re) {
|
|||||||
return document.createTextNode(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
|
* Default callback used to generate emoji src
|
||||||
* based on Twitter CDN
|
* based on Twitter CDN
|
||||||
@ -604,6 +625,8 @@ function createTwemoji(re) {
|
|||||||
var
|
var
|
||||||
allText = grabAllTextNodes(node, []),
|
allText = grabAllTextNodes(node, []),
|
||||||
length = allText.length,
|
length = allText.length,
|
||||||
|
attrib,
|
||||||
|
attrname,
|
||||||
modified,
|
modified,
|
||||||
fragment,
|
fragment,
|
||||||
subnode,
|
subnode,
|
||||||
@ -642,8 +665,19 @@ function createTwemoji(re) {
|
|||||||
if (src) {
|
if (src) {
|
||||||
img = new Image();
|
img = new Image();
|
||||||
img.onerror = twemoji.onerror;
|
img.onerror = twemoji.onerror;
|
||||||
img.className = options.className;
|
|
||||||
img.setAttribute('draggable', 'false');
|
img.setAttribute('draggable', 'false');
|
||||||
|
attrib = options.attributes(icon, variant);
|
||||||
|
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 = alt;
|
img.alt = alt;
|
||||||
img.src = src;
|
img.src = src;
|
||||||
modified = true;
|
modified = true;
|
||||||
@ -684,7 +718,11 @@ function createTwemoji(re) {
|
|||||||
*/
|
*/
|
||||||
function parseString(str, options) {
|
function parseString(str, options) {
|
||||||
return replace(str, function (match, icon, variant) {
|
return replace(str, function (match, icon, variant) {
|
||||||
var src;
|
var
|
||||||
|
ret = match,
|
||||||
|
attrib,
|
||||||
|
attrname,
|
||||||
|
src;
|
||||||
// verify the variant is not the FE0E one
|
// verify the variant is not the FE0E one
|
||||||
// this variant means "emoji as text" and should not
|
// this variant means "emoji as text" and should not
|
||||||
// require any action/replacement
|
// require any action/replacement
|
||||||
@ -698,7 +736,7 @@ function createTwemoji(re) {
|
|||||||
if (src) {
|
if (src) {
|
||||||
// recycle the match string replacing the emoji
|
// recycle the match string replacing the emoji
|
||||||
// with its image counter part
|
// with its image counter part
|
||||||
match = '<img '.concat(
|
ret = '<img '.concat(
|
||||||
'class="', options.className, '" ',
|
'class="', options.className, '" ',
|
||||||
'draggable="false" ',
|
'draggable="false" ',
|
||||||
// needs to preserve user original intent
|
// needs to preserve user original intent
|
||||||
@ -708,15 +746,43 @@ function createTwemoji(re) {
|
|||||||
'"',
|
'"',
|
||||||
' src="',
|
' src="',
|
||||||
src,
|
src,
|
||||||
'"',
|
'"'
|
||||||
'>'
|
|
||||||
);
|
);
|
||||||
|
attrib = options.attributes(icon, variant);
|
||||||
|
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]), '"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return match;
|
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.
|
* Given a generic value, creates its squared counterpart if it's a number.
|
||||||
* As example, number 36 will return '36x36'.
|
* As example, number 36 will return '36x36'.
|
||||||
@ -758,6 +824,7 @@ function createTwemoji(re) {
|
|||||||
// otherwise use the DOM tree and parse text nodes only
|
// otherwise use the DOM tree and parse text nodes only
|
||||||
return (typeof what === 'string' ? parseString : parseNode)(what, {
|
return (typeof what === 'string' ? parseString : parseNode)(what, {
|
||||||
callback: how.callback || defaultImageSrcGenerator,
|
callback: how.callback || defaultImageSrcGenerator,
|
||||||
|
attributes: typeof how.attributes === 'function' ? how.attributes : returnNull,
|
||||||
base: typeof how.base === 'string' ? how.base : twemoji.base,
|
base: typeof how.base === 'string' ? how.base : twemoji.base,
|
||||||
ext: how.ext || twemoji.ext,
|
ext: how.ext || twemoji.ext,
|
||||||
size: how.folder || toSizeSquaredAsset(how.size || twemoji.size),
|
size: how.folder || toSizeSquaredAsset(how.size || twemoji.size),
|
||||||
|
File diff suppressed because one or more lines are too long
79
twemoji.js
79
twemoji.js
File diff suppressed because one or more lines are too long
2
twemoji.min.js
vendored
2
twemoji.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user