Как можно получить выделенный текст в редакторе Gutenberg?

Я пробовал реализовать следующий код: <br/> <br/> <pre><code class="javascript">const getSelectedText = () =&gt; {
	const { getSelectedBlock, getSelectionStart, getSelectionEnd } = select('core/block-editor');
	const block = getSelectedBlock();

	if (!block || block.name !== 'core/paragraph') return '';

	const content = block.attributes.content;
	const start = getSelectionStart()?.offset || 0;
	const end = getSelectionEnd()?.offset || content.length;

	return content.slice(start, end);
};</code></pre> <br/> <br/> Однако, если в выделенном тексте или перед ним присутствуют HTML-теги, функция возвращает неправильный фрагмент текста. Как можно решить эту проблему?
  • 18 апреля 2025 г. 9:25
Ответы на вопрос 2
Для корректного получения выделенного текста из редактора Gutenberg, особенно если ваш контент содержит HTML-теги, вы можете использовать разные подходы. Один из них — это использование метода `createRange` для работы с текстовым содержимым, что позволяет игнорировать HTML-теги.

Вот пример того, как можно получить выделенный текст, учитывая HTML-теги в контенте:

```javascript
import { select } from '@wordpress/data';
import { createRef } from '@wordpress/element';

// Функция для получения выделенного текста
const getSelectedText = () => {
    const { getSelectedBlock, getSelectionStart, getSelectionEnd } = select('core/block-editor');
    const block = getSelectedBlock();

    if (!block || block.name !== 'core/paragraph') return '';

    const content = block.attributes.content;

    // Создаем временный элемент для обработки HTML
    const tempDiv = document.createElement('div');
    tempDiv.innerHTML = content;

    // Флаг для хранения текста
    let selectedText = '';

    // Получаем выделение
    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    const rangeStart = range.startContainer;
    const rangeEnd = range.endContainer;

    // Если выделение внутри одного узла
    if (rangeStart === rangeEnd) {
        selectedText = range.toString();
    } else {
        // Обходим узлы между началом и концом выделения
        let node = rangeStart;

        while (node) {
            // Добавляем текст выделенных узлов
            if (node.nodeType === Node.TEXT_NODE) {
                selectedText += node.textContent.slice(rangeStart === node ? range.startOffset : 0, 
                                                       rangeEnd === node ? range.endOffset : node.length);
            }

            // Переходим к следующему узлу
            if (node === rangeEnd) break; // Если достигли конца выделения
            node = node.nextSibling || node.parentNode.nextSibling;
        }
    }

    return selectedText;
};
```

### Объяснение:

1. **Создание временного элемента**: Мы создаем временный элемент `div`, чтобы загрузить HTML-содержимое. Это позволяет нам работать с текстом, как с обычным текстом, а не с HTML.

2. **Получение выделенного текста**: Мы используем метод `getSelection()`, чтобы получить текущее выделение. `Range` помогает нам обработать выделение, даже если оно охватывает несколько узлов.

3. **Обработка текстовых узлов**: Мы обходим текущее выделение, извлекая текст из узлов, соответствующих началу и концу выделения, тем самым игнорируя HTML-теги.

Этот подход должен дать вам корректный выделенный текст, независимо от наличия HTML-тегов в контенте.
Вообщем, получилось вот так: 

const getSelectedText = () => {
	const { getSelectedBlock, getSelectionStart, getSelectionEnd } = select('core/block-editor');
	const block = getSelectedBlock();

	if (!block || block.name !== 'core/paragraph') return '';

	const start = getSelectionStart();
	const end = getSelectionEnd();

	if (!start || !end) return '';

	const value = create({ html: block.attributes.content });
	const sliced = slice(value, start.offset, end.offset);
	return getTextContent(sliced);
};


ИИ подсказал
Похожие вопросы