JS сгруппировать фрагменты текста

229
08 апреля 2022, 22:20

У меня есть текст такого вида:

<div class="content">
    <h3>Заголовок 1</h3>
    <h2>Подзаголовок 1</h2>
    <p>Параграф 1</p>
    <h3>Заголовок 2</h3>
    <h2>Подзаголовок 2</h2>
    <p>Параграф 2</p>
    <p>Параграф 2</p>
</div>

Как можно обернуть фрагменты текста дополнительным div? Чтобы получилось так:

<div class="content">
    <div class="wrap">
        <h3>Заголовок 1</h3>
        <h2>Подзаголовок 1</h2>
        <p>Параграф 1</p>
    </div>
    <div class="wrap">
        <h3>Заголовок 2</h3>
        <h2>Подзаголовок 2</h2>
        <p>Параграф 2</p>
        <p>Параграф 2</p>
    </div>
</div>

Ключевым элементом для разделения является заголовок h3. Сколько этих заголовков на странице, столько обёрток и должно быть. Обёртка должна включать сам заголовок h3, следующий за ним h2 и все параграфы до следующего h3.

Answer 1
type $contentList = NodeListOf<Element>
type $isTarget = (node: Node) => boolean
type $genEl = () => Element
type $a = (contentList: $contentList, isTarget: $isTarget, genEl: $genEl) => void
type $b = (element: Element, isTarget: $isTarget, genEl: $genEl) => void
const a: $a = (contentList, isTarget, genEl) => {
    contentList.forEach(el => b(el, isTarget, genEl))
}
const b: $b = (element, isTarget, genEl) => {
    const childNodeList = Array.from(element.childNodes) // !important `Array.from`
    let lastConteiner: Element | null = null
    childNodeList.forEach(childNode => {
        const _isTarget = isTarget(childNode)
        const _isNotTarget = !_isTarget
        if (lastConteiner && _isNotTarget) { // !important this first
            lastConteiner.appendChild(childNode)
        } else if (_isTarget) { // !important this second
            lastConteiner = genEl()
            childNode.replaceWith(lastConteiner)
            lastConteiner.appendChild(childNode)
        }
    })
}

const a=(a,c,l)=>{a.forEach(a=>b(a,c,l))},b=(a,c,l)=>{const o=Array.from(a.childNodes);let d=null;o.forEach(a=>{const o=c(a);d&&!o?d.appendChild(a):o&&(d=l(),a.replaceWith(d),d.appendChild(a))})}; 
 
void function MAIN() { 
    const { nodeName } = document.createElement('h3') 
    // -,- 
    a( 
        document.querySelectorAll('.content') 
        , node => nodeName === node.nodeName 
        , () => { 
            const div = document.createElement('div') 
            div.className = 'dd' 
            return div 
        } 
    ) 
}();
.dd { 
border: dashed 1px red; 
}
<div class="content"> 
    <p>Параграф 0</p> 
    <p>Параграф 0</p> 
    <p>Параграф 0</p> 
 
    <h3>Заголовок 1</h3> 
    <h2>Подзаголовок 1</h2> 
    <p>Параграф 1</p> 
 
    <h3>Заголовок 2</h3> 
    <h2>Подзаголовок 2</h2> 
    <p>Параграф 2</p> 
    <p>Параграф 2</p> 
</div> 
 
<div class="content"> 
    <p>Параграф 0</p> 
    <p>Параграф 0</p> 
    <p>Параграф 0</p> 
 
    <h3>Заголовок 1</h3> 
    <h2>Подзаголовок 1</h2> 
    <p>Параграф 1</p> 
 
    <h3>Заголовок 2</h3> 
    <h2>Подзаголовок 2</h2> 
    <p>Параграф 2</p> 
    <p>Параграф 2</p> 
</div>

READ ALSO
Автодополнение js в VS Code

Автодополнение js в VS Code

Как настроить автодополнение таким образом, чтобы добавлялось не только имя функции, но и скобки после него?

79
Возможна ли HTML и JS валидация одновременно?

Возможна ли HTML и JS валидация одновременно?

Стоит такая задачаНе спрашивайте ситуацию и зачем такой способ, просто в данном случае так надо

116