Расширенная панель отправки смайлов

Панель является универсальным и расширенным аналогом панели смайликов распространенных мессенджеров. Она предназначена для отправки в сообщениях различных графических элементов (смайликов, гифок, стикеров).

С помощью панели можно производить поиск элементов, просматривать и отправлять последние использованные смайлики и гифки.

Элементы вкладки "Смайлики" разделены на группы, по которым можно производить навигацию с помощью меню в нижней части панели.

В боковой панели вкладки "Гифки" содержится набор кнопок, которые позволяют получить гифки различных категорий (например, гифки, которые сейчас находится в тренде).

Функционал панели может быть расширен добавлением новых категорий (например, бейджей и стикеров).

Подключение

Панель представляет собой всплывающее окно, которое открывается при наведении на кнопку открытия панели Emotions/picker:Button.

<!-- WML -->
<Emotions.picker:Button 
    categories="{{_categories}}" 
    on:choose="_chooseHandler()" />

Контрол принимает опцию categories — массив категорий. В библиотеке Emotions/picker определены конфигурации категорий, отображающих смайлики и гифки в модуле Emotions/picker:defaultCategories.

Для отображения смайликов и гифок в панели необходимо импортировать defaultCategories из библиотеки Emotions/picker и добавить конфиги emoji и gifs в опцию панели categories.

// TypeScript
import {ICategoryItem} from 'Emotions/_picker/ISmilePicker';
import {defaultCategories} from 'Emotions/picker';
 
protected _categories: ICategoryItem[] = [
    defaultCategories.emoji,
    defaultCategories.gifs
];

Добавление собственной категории

В опцию categories можно передать свою собственную категорию. Объект категории должен содержать следующие поля:

  1. id — идентификатор категории.
  2. title — название категории.
  3. icon — иконка категории.
  4. template — шаблон элемента категории.
// TypeScript
protected _categories: ICategoryItem[] = [
    {
       id: 'stickers',
       title: 'Стикеры',
       icon: 'icon-Stickers',
       template: 'Path/to/StickerTemplate'
    }
];

Контрол должен поддерживать API: запускать событие sendResult при выборе элемента категории и поддерживать работу со строкой поиска, приходящей в опцию searchValue.

В событие sendResult необходимо передавать объект с полями category и item: название категории и объект, соответствующий выбранному элементу.

<!-- WML -->
<div class="list">
   <ws:for data="item in list">
      <span on:click="_itemClickHandler(item)" class="item">
         {{item.title}}
      </span>
   </ws:for>
</div> 
// TypeScript
protected _itemClickHandler(e: Event, item: IEmoji): void {
    this._notify('sendResult', [{category: 'emoji', item}], {bubbling: true});
}

Для обработки результата в контроле необходимо подписаться на событие choose, в обработчик которого будут переданы категория и выбранный элемент.

<!-- WML -->
<Emotions.picker:Button categories="{{_categories}}" on:choose="_chooseHandler()" />
// TypeScript
protected _chooseHandler(event: Event, {category, item}: {category: string, item: object}): void {
    this._notify('callMethod', ['paste', item.title], {bubbling: true});
}

Задание раскладки содержимого панели

Для задания стандартной раскладки содержимого панели, состоящей из основного контента и тулбара, необходимо использовать Emotions.dialog:ContentContainer, в который необходимо передать шаблон для основного контента, массив элементов для тулбара, callback-функцию, которая будет срабатывать при нажатии на элемент тулбара, а также id активного элемента тублара. В опции toolbarVisible необходимо задать условие, при котором элементы тулбара будут отображаться и скрываться. Каждый элемент тулбара должен содержать следующие поля: id, title, а также icon или emoji.

<!-- WML -->
<ws:partial template="Emotions.dialog:ContentContainer"
            toolbarItems="{{_items}}"
            activeItem="{{_activeItem}}"
            toolbarItemSelectedHandler="{{_toolbarItemSelectedHandler}}"
            toolbarVisible="{{!_options.searchValue.length}}">
   <ws:contentTemplate>
      <div>Содержимое панели</div>
   </ws:contentTemplate>
</ws:partial>
// TypeScript
protected _items: object[] = [
    {
      id: 'emotions',
      title: 'Эмоции',
      icon: 'icon-EmoiconSmile'
   }, {
      id: 'people',
      title: 'Люди',
      icon: 'icon-Workers'
   }
];
protected _activeItem: string = 'emotions';
protected _toolbarItemSelectedHandler = (selectedKey: string) => {
        ...
}

Поиск

В шаблон template в качестве опции searchValue передается значение поля поиска.

Для реализации поиска можно использовать контрол Controls/browser:Browser, в который необходимо передать источник данных в опцию source и строку поиска в опцию searchValue.

Источник данных должен содержать метод filter для фильтрации записей, который будет использоваться при вызове метода query. Отфильтрованные значение можно отобразить, используя, например, Controls.columns:View.

<!-- WML -->
<Controls.browser:Browser 
    source="{{_source}}" 
    searchValue="{{_options.searchValue}}">
   <Controls.columns:View
       name="columnsView"
       keyProperty="id"
       useNewModel="{{true}}"
       markerVisibility="visible">
      <ws:itemTemplate>
         <div>
            {{itemTemplate.item.getContents().get('name')}}
         </div>
      </ws:itemTemplate>
      <ws:emptyTemplate>
         <div>
            Ничего не найдено
         </div>
      </ws:emptyTemplate>
   </Controls.columns:View>
</Controls.browser:Browser>
// TypeScript
protected _source = new Memory({
    data: [
        {id: 1, name: 'Sun', kind: 'Star'},
        {id: 2, name: 'Mercury', kind: 'Planet'},
        {id: 3, name: 'Venus', kind: 'Planet'},
        {id: 4, name: 'Earth', kind: 'Planet'},
        {id: 5, name: 'Mars', kind: 'Planet'},
        {id: 6, name: 'Jupiter', kind: 'Planet'},
        {id: 7, name: 'Saturn', kind: 'Planet'},
    ],
    filter: (item) => item.get('name') !== 'Earth',
    keyProperty: 'id'
});