Перейти к основному содержимому

HTML

Поле типа HTML предназначено для хранения форматированного текста с поддержкой Rich Text Editor.

Основные характеристики

  • Тип данных: HTML-разметка
  • Редактор: WYSIWYG (What You See Is What You Get)
  • Максимальный размер: До 1 МБ
  • Санитизация: Автоматическая очистка от опасного кода
  • Форматирование: Поддержка стилей, списков, таблиц, изображений

Возможности редактора

Форматирование текста

  • Жирный, курсив, подчеркнутый, зачеркнутый
  • Заголовки (H1-H6)
  • Цвет текста и фона
  • Размер шрифта
  • Выравнивание (по левому краю, по центру, по правому краю, по ширине)

Списки

  • Маркированные списки
  • Нумерованные списки
  • Вложенные списки
  • Чек-листы

Вставка элементов

  • Изображения
  • Ссылки
  • Таблицы
  • Видео (YouTube, Vimeo)
  • Блоки кода
  • Цитаты
  • Горизонтальные линии

Настройки поля

При создании поля типа "HTML" доступны следующие настройки:

  • Название поля: Отображаемое имя поля
  • Системное имя: Уникальный идентификатор для API
  • Описание: Подсказка для пользователей
  • Обязательное поле: Требовать заполнения
  • Максимальная длина: Ограничение размера контента
  • Разрешенные теги: Список допустимых HTML-тегов
  • Разрешенные атрибуты: Список допустимых атрибутов
  • Автосанитизация: Автоматическая очистка от опасного кода

Примеры использования

Описание товара

{
"name": "description",
"type": "html",
"required": true
}

Контент статьи

{
"name": "content",
"type": "html",
"required": true,
"maxLength": 1000000
}

Комментарий

{
"name": "comment",
"type": "html",
"allowedTags": ["p", "br", "strong", "em", "a", "ul", "ol", "li"]
}

Работа через API

Создание записи

const record = await emd.database.collection('articles').create({
title: 'Моя статья',
content: `
<h1>Заголовок статьи</h1>
<p>Это первый абзац с <strong>жирным текстом</strong> и <em>курсивом</em>.</p>
<ul>
<li>Первый пункт</li>
<li>Второй пункт</li>
</ul>
<p>Ссылка на <a href="https://example.com">сайт</a>.</p>
`
});

Получение HTML

const record = await emd.database.collection('articles').get(recordId);

console.log(record.content);
// {
// html: "<h1>Заголовок</h1><p>Текст...</p>",
// text: "Заголовок\nТекст...",
// length: 1234,
// wordCount: 156
// }

Отображение HTML

const record = await emd.database.collection('articles').get(recordId);

// Безопасное отображение (уже санитизировано)
document.getElementById('content').innerHTML = record.content.html;

Обновление HTML

await emd.database.collection('articles').update(recordId, {
content: `
<h1>Обновленный заголовок</h1>
<p>Новый контент статьи.</p>
`
});

Санитизация HTML

Автоматическая очистка

HTML автоматически очищается от потенциально опасного кода:

// Ввод
const dangerousHtml = `
<p>Безопасный текст</p>
<script>alert('XSS')</script>
<img src="x" onerror="alert('XSS')">
`;

// После санитизации
const sanitized = `
<p>Безопасный текст</p>
`;

Настройка разрешенных тегов

{
"name": "content",
"type": "html",
"allowedTags": [
"p", "br", "strong", "em", "u", "s",
"h1", "h2", "h3", "h4", "h5", "h6",
"ul", "ol", "li",
"a", "img",
"blockquote", "code", "pre",
"table", "thead", "tbody", "tr", "th", "td"
],
"allowedAttributes": {
"a": ["href", "title", "target"],
"img": ["src", "alt", "width", "height"]
}
}

Извлечение текста

Получение plain text

const record = await emd.database.collection('articles').get(recordId);

// Текст без HTML-тегов
const plainText = record.content.text;

// Или вручную
function stripHtml(html) {
return html.replace(/<[^>]*>/g, '');
}

Получение краткого описания

const record = await emd.database.collection('articles').get(recordId);

// Первые 200 символов текста
const excerpt = record.content.text.substring(0, 200) + '...';

Подсчет слов

const record = await emd.database.collection('articles').get(recordId);

console.log(`Количество слов: ${record.content.wordCount}`);

Поиск по HTML контенту

Полнотекстовый поиск

const articles = await emd.database.collection('articles').find({
content: { $search: 'ключевое слово' }
});

Поиск по тексту (без тегов)

const articles = await emd.database.collection('articles').find({
'content.text': { $contains: 'поисковый запрос' }
});

Вставка изображений

Загрузка изображения

// Загрузить изображение
const formData = new FormData();
formData.append('file', imageFile);
const uploadedImage = await emd.storage.upload(formData);

// Вставить в HTML
const html = `
<p>Текст перед изображением</p>
<img src="${uploadedImage.url}" alt="Описание изображения" />
<p>Текст после изображения</p>
`;

await emd.database.collection('articles').update(recordId, {
content: html
});

Base64 изображения

// Конвертировать изображение в Base64
function imageToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}

const base64 = await imageToBase64(imageFile);
const html = `<img src="${base64}" alt="Изображение" />`;

Вставка видео

YouTube

const youtubeUrl = 'https://www.youtube.com/watch?v=VIDEO_ID';
const videoId = 'VIDEO_ID';

const html = `
<div class="video-container">
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/${videoId}"
frameborder="0"
allowfullscreen>
</iframe>
</div>
`;

Vimeo

const vimeoId = 'VIDEO_ID';

const html = `
<div class="video-container">
<iframe
src="https://player.vimeo.com/video/${vimeoId}"
width="640"
height="360"
frameborder="0"
allowfullscreen>
</iframe>
</div>
`;

Таблицы

Создание таблицы

const html = `
<table>
<thead>
<tr>
<th>Название</th>
<th>Цена</th>
<th>Количество</th>
</tr>
</thead>
<tbody>
<tr>
<td>Товар 1</td>
<td>1000 ₽</td>
<td>5</td>
</tr>
<tr>
<td>Товар 2</td>
<td>2000 ₽</td>
<td>3</td>
</tr>
</tbody>
</table>
`;

Блоки кода

Вставка кода

const html = `
<p>Пример кода на JavaScript:</p>
<pre><code class="language-javascript">
function hello() {
console.log('Hello, World!');
}
</code></pre>
`;

Подсветка синтаксиса

Используйте библиотеки типа Prism.js или Highlight.js для подсветки кода при отображении.

Шаблоны

Шаблон письма

const emailTemplate = `
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h1 style="color: #333;">Добро пожаловать!</h1>
<p>Спасибо за регистрацию на нашем сайте.</p>
<a href="{{confirmUrl}}" style="display: inline-block; padding: 10px 20px; background: #007bff; color: white; text-decoration: none; border-radius: 5px;">
Подтвердить email
</a>
</div>
`;

Шаблон статьи

const articleTemplate = `
<article>
<header>
<h1>{{title}}</h1>
<p class="meta">
<time>{{date}}</time> |
<span>{{author}}</span>
</p>
</header>
<div class="content">
{{content}}
</div>
</article>
`;

Экспорт в другие форматы

HTML в Markdown

import TurndownService from 'turndown';

const turndownService = new TurndownService();
const markdown = turndownService.turndown(record.content.html);

HTML в PDF

import html2pdf from 'html2pdf.js';

const element = document.getElementById('content');
element.innerHTML = record.content.html;

html2pdf()
.from(element)
.save('article.pdf');

Рекомендации

  • Используйте HTML для форматированного контента (статьи, описания)
  • Для простого текста используйте тип String
  • Всегда включайте санитизацию для безопасности
  • Ограничивайте разрешенные теги в зависимости от контекста
  • Используйте CDN для изображений вместо Base64
  • Оптимизируйте изображения перед вставкой
  • Добавляйте alt-текст для изображений (SEO и доступность)
  • Используйте семантические теги (h1-h6, p, ul, ol)
  • Тестируйте отображение на разных устройствах

Безопасность

Защита от XSS

  • Автоматическая санитизация включена по умолчанию
  • Удаление опасных тегов (<script>, <iframe>, <object>)
  • Удаление опасных атрибутов (onclick, onerror)
  • Валидация URL в ссылках и изображениях

Content Security Policy

// Настройка CSP для безопасного отображения HTML
const cspMeta = `
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
img-src 'self' https://cdn.emd.one;
script-src 'none';">
`;

Отличие от других типов

  • HTML vs String: HTML для форматированного текста, String для простого
  • HTML vs JSON: HTML для контента, JSON для структурированных данных
  • HTML vs Markdown: HTML для WYSIWYG редактора, Markdown для разметки