Базовый текстовый редактор

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

Модель данных

Контент редактора описан в виде формализованной модели данных. Модель данных представляет из себя JSON-объект со строго определенными полями. Модель никак не завязана на HTML и имеет четко определенные семантические элементы.

Каждый элемент модели имеет тип, данные и свое визуальное представление.

Модель может содержать блочные элементы (например, абзац или цитата), а внутри них текстовые форматированные элементы (например полужирный текст или ссылка).

Подробнее про формат модели можно почитать здесь.

Конфигурация

Чтобы добавить базовый редактор на страницу, необходимо выполнить следующие действия:

  1. Добавить контрол TextEditor/base:Editor в шаблон своего контрола;
  2. Определить опцию value, удовлетворяющую требованиям модели данных.
  3. Определить функцию-коллбэк onValueChanged для получения актуального значения.
  4. Использовать метод setValue для установки значения в редактор.
<!-- WML -->
<TextEditor.base:Editor
    name="editor"
    onValueChanged="{{_onValueChangedHandler}}"
    value="{{_value}}" />
// TypeScript
protected _value = [{
    type: 'paragraph',
    data: {
        content: [{
            type: 'text',
            data: {
                value: 'Разнообразный и богатый опыт говорит нам, что начало повседневной работы по формированию позиции предполагает независимые способы реализации кластеризации усилий. Господа, граница обучения кадров требует определения и уточнения новых принципов формирования материально-технической и кадровой базы. А ещё независимые государства могут быть функционально разнесены на независимые элементы.'
            }
        }]
    }
}];

// Получим актуальное значение.
protected _onValueChangedHandler = (value) => {
    this._value = value;
};

// Установим новое значение в редактор.
protected _setValue(): void {
    this._children.editor.setValue(this._value);
}

Прикладные форматы

Редактор можно расширить прикладными форматами с помощью опции formats.

Определение прикладного формата осуществляется через JS-объект, где:

  • поле type указывает тип прикладного формата;
  • поле template описывает шаблон формата.

В примере ниже определим прикладной формат, стилизованный под блок кода (серый фон, моноширинный шрифт).

Для начала опишем шаблон с редактором:

<!-- WML -->
<TextEditor.base:Editor
   name="editor"
   formats="{{_formats}}"
   value="{{_value}}" />

Затем опишем шаблон нового формата:

// TypeScript
import * as React from 'react';

export ({children, element, attributes}): React.ReactNode => {]
   return <code className="engine-demo-TextEditor_code" {...attributes}>{children}</code>;
};

В завершение укажем новый элемент в опцию value и опишем опцию formats с прикладным форматом:

//TypeScript
import Code from './Code';

protected _value = {
      type: 'code',
      data: {
         content: [{
            type: 'text',
            data: {
               value: 'Разнообразный и богатый текст.'
            }
         }]
      }
};
protected _formats: IFormatConfig[] = [{
      type: 'code',
      template: Code
}];

Прикладные стили

Контрол редактора предоставляет возможность определения прикладных стилей (инлайн-форматов) через опцию-массив styles.

Отличие стиля от формата в том, что стиль может сочетаться с другими стилями, и применяется он только к тексту.

Определение прикладного стиля осуществляется через JS-объект, где:

  • поле type указывает тип прикладного стиля;
  • поле template описывает шаблон стиля;
  • опциональное поле hotkeys определяет список хоткеев для применения стиля к текущему выделению редактора.

В примере ниже определим прикладной стиль, стилизованный градиентным фоном, и его шаблон отображения.

Для начала опишем шаблон с редактором:

<!-- WML -->
<TextEditor.base:Editor
   name="editor"
   styles="{{_styles}}"
   value="{{_value}}" />

Затем опишем шаблон нового стиля:

// TypeScript
import * as React from 'react';

export default ({children, leaf, attributes}): React.ReactNode => {]
   const gradientStyle = 'linear-gradient(90deg, rgba(252,0,255,1) 0%, rgba(254,190,255,1) 45%, rgba(255,255,255,1) 100%)';
   return <span style={{background: gradientStyle}}>{children}</span>;
};

В завершение укажем новый элемент в опцию value и опишем опцию styles с прикладным стилем:

//TypeScript
import ColoredText from './ColoredText';

protected _value = {
   type: 'paragraph',
   data: {
      content: [{
         type: 'text',
         data: {
            value: 'Разнообразный и богатый текст.',
            styles: {
               gradient: true
            }
         }
      }]
   }
};
protected _styles: IStyleConfig[] = [{
      type: 'gradient',
      hotkeys: ['mod+p'],
      template: ColoredText
}];

Плейсхолдер

Редактор позволяет задать подсказку, отображающуюся при пустом редакторе, с помощью опции placeholder. Подсказка может являться как простым текстом, так и иметь более сложную верстку.

В примере ниже сконфигурируем редактор с простой подсказкой:

<!-- WML -->
<TextEditor.base:Editor
   placeholder="Введите текст ниже..."
   value="{{ [] }}" />

А в этом примере отобразим подсказку с кнопкой:

<!-- WML -->
<TextEditor.base:Editor
   value="{{ [] }}">
   <ws:placeholder>
      Напишите сообщение или продолжите
      <Controls.buttons:Button
         viewMode="link"
         buttonStyle="secondary"
         fontColorStyle="label"
         fontSize="m"
         caption=" {[старый диалог]}" />
   </ws:placeholder>
</TextEditor.base:Editor>

Высота строки

В контроле есть возможность настроить высоту строки через опцию lineHeight.

В примере ниже установим высоту размера "s":

<!-- WML -->
<TextEditor.base:Editor
   name="editor"
   lineHeight="s"
   value="{{ _value }}" />

Вставка контента

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

В примере ниже опишем вставку смайлика в редактор:

<!-- WML -->
<TextEditor.base:Editor
   name="editor"
   value="{{ _value }}" />
// TypeScript
// ...

protected _insertEmoji(): void {
    this._children.editor.insertContent({
        type: 'emoji',
        data: {
            value: '🙂'
        }
    }
}

// ...

Изменение позиции курсора

В редакторе есть возможность устанавливать курсор в начало или конец редактора через метод setCursorPosition.

В примере ниже установим курсор в конец редактора:

<!-- WML -->
<TextEditor.base:Editor
   name="editor"
   value="{{ _value }}" />
// TypeScript
// ...

protected _setCursorToEnd(): void {
    this._children.editor.setCursorPosition('end');
}

// ...

Применение стилей

Стиль текста можно менять не только через горячие клавиши.

Может потребоваться применить к тексту стиль через пользовательский интерфейс.

Для этого необходимо использовать метод applyStyle. Также может потребоваться выделить элемент интерфейса относительно активного стиля, который определяется по текущему выделению редактора. Для этого необходимо определить функцию-коллбэк onActiveStylesChanged.

В примере ниже опишем кнопку применения полужирного начертания и отследим изменения активных стилей:

<!-- WML -->
<TextEditor.base:Editor
   name="editor"
   onActiveStylesChanged="{{_onActiveStylesChangedHandler}}"
   value="{{ _value }}" />

<Controls.buttons:Button
   caption="Применить/снять полужирный стиль"
   buttonStyle="{{ _isBoldActive ? 'danger' : 'secondary' }}"
   on:click="_applyBold()" />
// TypeScript
// ...

protected _isBoldActive: boolean = false;

// Обработаем изменения активного стиля.
protected _onActiveStylesChangedHandler = (activeStyles) => {
    this._isBoldActive = activeStyles['bold'];
}

// Применим стиль к тексту.
protected _applyBold(): void {
    this._children.editor.applyStyle({ bold: true });
}

// ...

Справочные материалы и ресурсы