В целом задача состоит в том, что бы сделать вывод реактивного оглавления для содержимого WYSIWYG редактора.
Я работаю с React и интегрирую ckeditor в качестве редактора. Задача - сделать так, что бы при заполнении редактора контентом, все заголовки парсились и реактивно выводились в виде оглавления рядом с окном редактора. При этом пункты в этом оглавлении должны быть кликабельны - по клику должно происходить прокручивание окна редактора до соответствующего якоря(заголовка). Имеющиеся плагины позволяют только выводить таблицу с оглавлением, но не делать ее элементы кликабельными.
Я решил "вручную" достать заголовки из содержимого редактора, вывести их, и навесить на них ссылки на якоря внутри редактора. Но это не сработало, переход по якорям внутри iframe или не возможен, или я не смог найти способа это сделать. Тогда я решил на эти выведенные заголовки навесить обработчики и методом scrollTo имитировать переход по якорям.
Здесь возникла проблема с получением координат заголовков в тексте редактора (внутри iframe). headerObj.offsetTop все время возвращается равным 0.
Буду рад за помощь в решении проблемы любым из путей)
import React, { useState } from 'react';
import CKEditor from 'ckeditor4-react';
const App = () => {
const [headers, setHeaders] = useState([]);
const handleChange = e => {
const content = e.editor.getData();
const contentObject = document.createElement('div');
contentObject.innerHTML = content;
const headersArray = [...contentObject.getElementsByTagName('h2')];
setHeaders(headersArray);
};
const goToAnchor = headerObj => {
const frame = document.getElementsByTagName('iframe')[0];
const top = headerObj.offsetTop + frame.contentWindow.scrollY;
frame.contentWindow.scrollTo({
top: top,
behavior: "smooth"
})
};
return (
<div className="App">
<h2>Using CKEditor 4 in React</h2>
<CKEditor
data="<h2>1. Заголовок 1</h2><h2>2. Заголовок 2</h2><h2>3. Заголовок 3</h2>"
onChange={e => handleChange(e)}
/>
<div>
<h2>Содержание</h2>
{headers.map((header, index) => {
return (
<h2
key={index}
dangerouslySetInnerHTML={{__html: header.innerHTML}}
onClick={() => goToAnchor(header)}
/>
);
})}
</div>
</div>
);
};
export default App;