Chat with emoji

HTML

<div id="m"></div>
	<div>๐Ÿ˜€ ๐Ÿ˜ฌ ๐Ÿ˜ ๐Ÿ˜‚ ๐Ÿ˜ƒ ๐Ÿ˜„ ๐Ÿ˜… ๐Ÿ˜† ๐Ÿ˜‡ ๐Ÿ˜‰ ๐Ÿ˜Š ๐Ÿ™‚ ๐Ÿ™ƒ โ˜บ๏ธ ๐Ÿ˜‹ ๐Ÿ˜Œ ๐Ÿ˜ ๐Ÿ˜˜ ๐Ÿ˜— ๐Ÿ˜™ ๐Ÿ˜š ๐Ÿ˜œ ๐Ÿ˜ ๐Ÿ˜› ๐Ÿค‘ ๐Ÿค“ ๐Ÿ˜Ž ๐Ÿค— ๐Ÿ˜ ๐Ÿ˜ถ ๐Ÿ˜ ๐Ÿ˜‘ ๐Ÿ˜’ ๐Ÿ™„ ๐Ÿค” ๐Ÿ˜ณ ๐Ÿ˜ž ๐Ÿ˜Ÿ ๐Ÿ˜  ๐Ÿ˜ก ๐Ÿ˜” ๐Ÿ˜• ๐Ÿ™ โ˜น๏ธ ๐Ÿ˜ฃ ๐Ÿ˜– ๐Ÿ˜ซ ๐Ÿ˜ฉ ๐Ÿ˜ค ๐Ÿ˜ฎ ๐Ÿ˜ฑ ๐Ÿ˜จ ๐Ÿ˜ฐ ๐Ÿ˜ฏ ๐Ÿ˜ฆ ๐Ÿ˜ง ๐Ÿ˜ข ๐Ÿ˜ฅ ๐Ÿ˜ช ๐Ÿ˜“ ๐Ÿ˜ญ ๐Ÿ˜ต ๐Ÿ˜ฒ ๐Ÿค ๐Ÿ˜ท ๐Ÿค’ ๐Ÿค• ๐Ÿ˜ด</div>
	<div id="t" contenteditable="true" data-placeholder="ะ’ะฒะตะดะธั‚ะต ัะพะพะฑั‰ะตะฝะธะต"></div>
	<button id="b">ะžั‚ะฟั€ะฐะฒะธั‚ัŒ</button>

CSS

body {
	font: 1em/1.333333333 Helvetica, Arial, sans-serif;
}
img {
	width: 18px;
	height: 18px;
	vertical-align: middle;
}

#t {
	position: relative;
	margin: 20px 0;
	height: 200px;
	border: 1px solid #ccc;
	font-size: 18px;
	overflow-x: hidden;
	overflow-y: auto;
	white-space: pre-wrap;
	word-wrap: break-word;
}

#t:empty:before {
	display: block;
	position: absolute;
	top: 0;
	left: 0;
	margin-right: -4px;
	content: attr(data-placeholder);
	cursor: text;
	color: #bfbfbf;
	font: 1em/1.333333333 Helvetica, Arial, sans-serif;
}
#m {
	height: 200px; 
	border: 1px solid #ccc;
	margin-bottom: 30px;
}
#b {
  padding: 10px;
}

JavaScript

t.addEventListener('keyup', onKeyup);
t.addEventListener('paste', onPaste);
b.addEventListener('click', onSend);

function onKeyup() {
	cleanUp(t.innerHTML);
	var text = emojiToHtml(t.innerHTML);
	if (text != t.innerHTML) {
		t.innerHTML = text;
		restore();
	}
}

function onPaste(e) {
	e.preventDefault();
	var clp = e.clipboardData;

	if (clp !== undefined || window.clipboardData !== undefined) {
		var text;

		if (clp !== undefined) {
			text = clp.getData('text/html') || clp.getData('text/plain') || '';
		} else {
			text = window.clipboardData.getData('text') || '';
		}

		if (text) {
			text = cleanUp(text);
			text = emojiToHtml(text);
			var el = document.createElement('span');
			el.innerHTML = text;
			el.innerHTML = el.innerHTML.replace(/\n/g, '');
			t.appendChild(el);
			restore();
		}
	}
}

function onSend() {
	m.innerHTML = htmlToEmoji(t.innerHTML);
}

var emojiRanges = [
	'(?:\uD83C[\uDDE6-\uDDFF]){2}', // flags
	'[\u0023-\u0039]\u20E3', // numbers
	'(?:[\uD83D\uD83C\uD83E][\uDC00-\uDFFF]|[\u270A-\u270D\u261D\u26F9])\uD83C[\uDFFB-\uDFFF]', // skin color
	'\uD83D[\uDC68\uDC69][\u200D\u200C].+?\uD83D[\uDC66-\uDC69](?![\u200D\u200C])', // family
	'[\uD83D\uD83C\uD83E][\uDC00-\uDFFF]', // surrogate pair
	'[\u3297\u3299\u303D\u2B50\u2B55\u2B1B\u27BF\u27A1\u24C2\u25B6\u25C0\u2600\u2705\u21AA\u21A9]', // simple
	'[\u203C\u2049\u2122\u2328\u2601\u260E\u261d\u2620\u2626\u262A\u2638\u2639\u263a\u267B\u267F\u2702\u2708]',
	'[\u2194-\u2199]',
	'[\u2B05-\u2B07]',
	'[\u2934-\u2935]',
	'[\u2795-\u2797]',
	'[\u2709-\u2764]',
	'[\u2622-\u2623]',
	'[\u262E-\u262F]',
	'[\u231A-\u231B]',
	'[\u23E9-\u23EF]',
	'[\u23F0-\u23F4]',
	'[\u23F8-\u23FA]',
	'[\u25AA-\u25AB]',
	'[\u25FB-\u25FE]',
	'[\u2602-\u2618]',
	'[\u2648-\u2653]',
	'[\u2660-\u2668]',
	'[\u26A0-\u26FA]',
	'[\u2692-\u269C]'
];
var emojiRegex = new RegExp(emojiRanges.join('|'), 'g');

function emojiToHtml(str) {
  str = str.replace(/\uFE0F/g, '');
	return str.replace(emojiRegex, buildImgFromEmoji);
}

var tpl...