3 горизонтальные линии, бургер
3 горизонтальные линии, бургер
3 горизонтальные линии, бургер
3 горизонтальные линии, бургер

3 горизонтальные линии, бургер
Удалить все
ЗАГРУЗКА ...

Содержание



    Как сделать собственный(custom) QuillJS модуль оглавления статьи

    Часы
    29.10.2024
    /
    Часы
    02.10.2025
    /
    Часы
    4 минуты
    Глазик
    342
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0

    Вступление

    В этой статье я рассмотрю вопрос о том как создать и добавить собственный модуль в редактор quill. Мы будем делать всё это на примере создания такого полезного модуля как, генератора оглавления статьи по использованным заголовкам.
    На официальном сайте уже есть что-то подобное, но там не раскрыты все те проблемы с которыми я столкнулся при создании данного модуля. Например, как отключить модуль. В официальной документации я этого не нашёл. Да и организация подключения модуля, честно говоря, тоже не может быть такой, какой её показали. А так, очень интересная и познавательная статья. ☜(゚ヮ゚☜) Рекомендую.

    Регистрация модуля и создание для него переключателя

    Пожалуй начну с того, как мы этот модуль подключим (или зарегистрируем). Для этого, первой переменной мы присвоим значение "modules/table_of_contents", а во вторая переменная будет у нас именем инициализирующей функции. Вот так:
    Quill.register('modules/table_of_contents', InitTableOfContents);
    Теперь к реализации самой инициализирующей функции. Дабы оглавление генерировалось динамически, мы подключим к quill-у функцию. Которая будет вызываться каждый раз при изменении текста.
    function InitTableOfContents(quill, options) { quill.on(Quill.events.TEXT_CHANGE, RunTableOfContents); }
    Подключим наш кастомный модуль к редактору.
    const quill = new Quill('#editor', { modules: { table_of_contents: true, toolbar: { container: '#toolbar-container', } }, placeholder: '', theme: 'snow', });
    Хорошо, мы подключили его, но как его отключать? (⊙_⊙)?А ни как. По крайней мере я не разобрался как. Вернее, я разобрался, но правильный ли это метод я не уверен. Quill имеет методы getModule, addModule, но не имеет deleteModule или removeModule. Что конечно странно.
    Как вариант удаления модуля, можно использовать delete на ассоциативном массиве (где, собственно говоря, и содержатся все модули). И это не сработает. Ведь мы ещё добавляем, собственный обработчик на событие изменения текста. И при удалении модуля обработчик останется ¯\(°_o)/¯
    Поэтому, моё решение данного вопроса, это не удаление модуля, а удаление непосредственно обработчика событий. В моём случае это RunTableOfContents. На странице html-редактора ты сможешь найти чекбокс для включения и выключения данного модуля. (Как ты уже понял, он удаляет не модуль, но обработчик RunTableOfContents.)
    Ниже я представлю код самого обработчика. В чём суть. Все обработчики храняться в _events переменной emmiter. Чтобы добавить и(или) удалить обработчк используй метод(ы) addListenerremoveListener), который (которые) принимает(принимают) 3(4) агрумента, это:
    1. Тип обработчика (Для меня это TEXT_CHANGE)
    2. Имя функции
    3. Контекст (Всегда передавай quill.emmiter)
    4. Булевое значение, которое используется, для того чтобы запустить передаваемую функцию, единожды.
    document.querySelector('#toc_module').addEventListener('click', (event)=>{   if (event.target.checked){     quill.emitter.addListener(Quill.events.TEXT_CHANGE, RunTableOfContents, quill.emitter)   }else{     quill.emitter.removeListener(Quill.events.TEXT_CHANGE, RunTableOfContents, quill.emitter, false)   } })
    С подключением и настройкой переключателя мы закончили. Давай непосредственно взглянем на реализацию.

    Реализация, генерации оглавления.

    Сразу хочу пояснить, я не добавлял тег H1, ибо в первую очередь создавал инструмент для себя. И данный тег в генерации оглавления не участвует. Ты в свою очередь волен поменять, повернуть и разобрать код на столько кусочков, на сколько сможешь. Никто тебя не остановит (~ ̄▽ ̄)~.
    Вот код обработчика RunTableOfContents.
    function RunTableOfContents(){ let range = quill.getSelection() let blot = Quill.find(quill.getLeaf(range.index)[0].domNode).parent let DOMnode = blot.domNode switch (DOMnode.tagName){ case 'H2': case 'H3': case 'H4': case 'H5': case 'H6': document.querySelectorAll('.table_of_contents').forEach((el) => { let prev = quill.scroll.find(el) if (prev){ prev.remove() } }) var container = quill.scroll.create(TableOfContents.blotName) var ref = quill.scroll.children.head quill.scroll.insertBefore(container, ref) break } }
    Данный обработчик находит blot на котором сейчас находится курсор и проверяет его тип по тегу. Если курсор на тегах оглавлений, то есть от h2 до h6, он обновляет оглавление предварительно удалив предыдущее.
    Для оглавления, я использую кастомный форматер. Вот как я его реализовал и зарегистрировал.
    class TableOfContents extends Quill.import('blots/block'){ static create(value){ let node = super.create(value); return node } constructor(scroll, domNode){ super(scroll, domNode) var header = document.createElement('h2') header.innerText = document.querySelector('#table_of_content_text').innerText header.style.marginTop = '0' header.style.borderBottom = '2px solid gray' header.style.marginBottom = '0' domNode.insertAdjacentElement('beforeend', header) document.querySelectorAll('h2,h3,h4,h5,h6').forEach( (heading) => { if (!heading.classList.contains('table_of_contents')){ var container_headers_element = document.createElement('div') let tag_name = heading.nodeName.toLowerCase() let padding = "padder-5" if( tag_name == 'h2') padding = "padder-5" else if (tag_name == 'h3') padding = "padder-10" else if (tag_name == 'h4') padding = "padder-15" else if (tag_name == 'h5') padding = "padder-20" else if (tag_name == 'h6') padding = "padder-25" container_headers_element.classList.add(padding) container_headers_element.style.display = 'flex' container_headers_element.style.gap = '8px' container_headers_element.style.alignItems = 'center' container_headers_element.style.marginTop = '10px' var container_headers_sign = document.createElement('p') container_headers_sign.innerText = tag_name container_headers_sign.style.border = '1px solid grey' container_headers_sign.style.borderRadius = '50%' container_headers_sign.style.padding = '5px' container_headers_sign.style.color = 'grey' container_headers_sign.style.fontSize = '10px' var container_headers_text = document.createElement('p') container_headers_text.innerText = heading.innerText container_headers_element.insertAdjacentElement('beforeend', container_headers_sign) container_headers_element.insertAdjacentElement('beforeend', container_headers_text) this.domNode.insertAdjacentElement('beforeend', container_headers_element) } }) } } TableOfContents.tagName = 'div' TableOfContents.blotName = 'table_of_contents' TableOfContents.className = 'table_of_contents' Quill.register({'formats/table_of_contents': TableOfContents})
    В моменте, я хотел реализовать его как контейнер (то есть расширить его от blots/container). Но подумал, что это слишком, для данного модуля, и не стоит его усложнять.
    И ещё. Я мог использовать CSS селекторы для стилизации, но подумал, что наверное для читателя будет проще воспринять именно такую форму, без необходимости ещё и учитывать каскадные стили.

    Заключение и заметки

    На самом деле, для корректной работы данного модуля необходимо ещё проводить дополнительную очистку редактора. Так как мой кастомный форматер не реализован в полной своей мере. Я провожу очистку в функции loadQuill. Сразу после того, как загрузил содержимое на страницу.
    function loadQuill( content ){ var scope = document.querySelector('.ql-editor') scope.innerHTML = content var table_of_content = scope.querySelector('.table_of_contents') if (table_of_content){ table_of_content.remove() } }
    Ещё, я не сделал оглавление динамическим, то есть не добавлял внутренних ссылок на соответствующие заголовки. Простите, поленился. (ಥ _ ಥ)
    А так, работоспособность данного модуля можно оценить на странице моего rich quill редактора. Так же, если ты вдруг не заметил, в самом начале этой статьи есть соответствующий блок с оглавлением. Посмотри, полюбуйся (⓿_⓿)

    Не забудь поделиться, лайкнуть и оставить комментарий)

    Комментарии

    (0)

    captcha
    Отправить
    ЗАГРУЗКА ...
    Сейчас тут пусто. Буть первым (o゚v゚)ノ

    Другое

    Похожие статьи


    Всё о quill blots (кляксах)

    Часы
    24.10.2024
    /
    Часы
    02.10.2025
    Глазик
    432
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье я расскажу о том, какие виды blot-ов бывают, чем каждый из них отличается, как используется ( в том числе и примеры реализации данных quill blot-ов). А так …

    Quill formats (ql-formats), как их расширить и существующие виды

    Часы
    24.10.2024
    /
    Часы
    02.10.2025
    Глазик
    701
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье я разберу типы форматеров (formats) quilljs, и объясню некоторые нюансы работы с таблицами, шрифтами, изображениями и видео. Так же покажу как переопределить форматер(ql-formats) на примере ссылки

    Как сделать собственный quill link tooltip(тултип для ссылок)

    Часы
    25.10.2024
    /
    Часы
    02.10.2025
    Глазик
    447
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье ты найдёшь пример того как реализовать свой quill tooltip/тултип для вставки ссылок и поймёшь как это вообще работает

    Как сделать/добавить кастомную(custom) ql-toolbar кнопку для quill редактора

    Часы
    25.10.2024
    /
    Часы
    02.10.2025
    Глазик
    404
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье я покажу как создавать кастомные кнопки для твоего quill редактора, custom toolbar buttons. Так же узнаешь как добавить выпадающий список для всё того же quill редактора.

    Использованные термины


    Релевантные вопросы