Emoji Input
Кроссбраузерное поле со вставкой смайлов на чистом JS.
by Yuri Moskvin
HTML
<link rel="stylesheet" href="https://web3r.ru/css/embed/fiddle.min.css">
<script src="https://web3r.ru/js/embed/fiddle.min.js"></script>
<main>
<h3>
Использование
</h3>
<p>
По умолчанию смайлы добавляются в поле сразу после текста, но могут вставляться в зависимости от положения каретки.
</p>
<p>
Для получения введённых данных нажмите <kbd>Enter</kbd>, при этом смайлы заменятся на символы, указанные в регулярном выражении метода <code>einput.get()</code>. Результат будет отображен в консоли браузера.
</p>
<form action="#">
<!-- кнопка открытия панели смайлов -->
<button type="button" id="btn">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z"
/>
</svg>
</button>
<!-- блок для панели ввода -->
<div id="input-box"></div>
<!-- блок для панели смайлов-->
<div id="emoji-box"></div>
</form>
</main>
SCSS
// background-color для панели смайлов
$main-color: #f9f9f9;
p:last-of-type {
margin-bottom: 2.5rem;
}
form {
display: block;
position: relative;
min-height: 7.5rem;
}
// кнопока открытия панели смайлов
#btn {
float: left;
width: 1.5rem;
height: 1.5rem;
background: transparent;
color: darken($main-color,15%);
cursor: pointer;
// иконка
svg {
fill: currentColor;
display: inherit;
width: 1rem;
height: 1rem;
margin-left: .2rem;
transition: color .5s ease-in, transform .5s linear;
-webkit-transition: color .5s ease-in, transform .5s linear;
transform: rotate(0) translateZ(0);
backface-visibility: hidden;
will-change: transform;
}
&:hover { color: darken($main-color,25%); }
&.active {
svg {
color: #6f6fd1;
transform: rotate(720deg) translateZ(0);
}
}
}
// обертка для строки
#input-box {
max-height: 1.5rem;
height: 1.5rem;
cursor: text;
position: relative;
overflow: hidden;
padding: 0 .5rem;
line-height: 1.5rem;
background-color: $main-color;
font-weight: 400;
// поле ввода
#input-box-field {
display: inline-block; // см. https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
&:focus { outline: 0; }
position: absolute;
top: 0;
left: .5rem;
right: .5rem;
white-space: nowrap;
overflow-x: scroll; // скрытие скроллбара
min-height: 2.5rem;
resize: none;
text-overflow: ellipsis;
// вывод placeholder
&:not(:empty) ~ #input-box-placeholder { display: none; }
&:empty { caret-color: darken($main-color,15%); }
user-select: text;
-webkit-touch-callout: text;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
-o-user-select: text;
// скрытие лишних тегов
br, p, div { display: none; }
// смайлики
.emoji {
cursor: text;
vertical-align:...
JavaScript
/**
* Анонимная самовызывающаяся функция-обертка
* @param {document} d - получает документ
*/
!function(d) {
"use strict";
/**
* Полифилл для Object.assign()
*/
Object.assign||Object.defineProperty(Object,"assign",{enumerable:!1,configurable:!0,writable:!0,value:function(e,r){"use strict";if(null==e)throw new TypeError("Cannot convert first argument to object");for(var t=Object(e),n=1;n<arguments.length;n++){var o=arguments[n];if(null!=o)for(var a=Object.keys(Object(o)),c=0,b=a.length;c<b;c++){var i=a[c],l=Object.getOwnPropertyDescriptor(o,i);void 0!==l&&l.enumerable&&(t[i]=o[i])}}return t}});
/**
* Переменная необходима для правильной работы форматирования в IE
* @type {boolean}
*/
var _onPaste_Strip = false;
/**
* Главный объект
* @type {Object}
*/
var einput = {};
/**
* Shortcut для preventDefault()
* @param {Event} e - получает событие
*/
var prevent = function(e) {
e.preventDefault();
};
/**
* Функция форматирования контента при вставке в поле
* @param {Event} e - событие
* @param {Number} maxlength - максимальная длина контента
*/
einput.format = function(e, maxlength) {
if (e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.getData) {
e.preventDefault();
var text = e.originalEvent.originalEvent.clipboardData.getData("text/plain");
if (text.length > maxlength) text = text.substring(0, maxlength);
d.execCommand("insertText", false, text);
} else if (e.clipboardData && e.clipboardData.getData) {
e.preventDefault();
var text = e.clipboardData.getData("text/plain");
if (text.length > maxlength) text = text.substring(0, maxlength);
d.execCommand("insertText", false, text);
} else if (window.clipboardData && window.clipboardData.getData) {
if (!_onPaste_Strip) {
_onPaste_Strip = true;
e.preventDefault();
d.execCommand("ms-pasteTextOnly", false);
}
...