Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

260
Visualizações
Numbering h1,h2 headings, nested documents that reset counter

I'm looking to add numbers to headers like below. The problem is that there are documents that may be infinitely nested and need to be counted independently. In the original document, the headings are text only, with no numbered prefix.

<div id="text_output">
  <h1>Document 1</h1>
    <h2>1 Heading</h2>
      <h3>1.1 Subheading</h3>
      <h3>1.2 Subheading</h3>
        <div class="text_output_expansion">
          <h1>Document 2</h1>
            <h2>1 Heading</h2>
              <h3>1.1 Subheading</h3>
            <h2>2 Heading</h2>
              <h3>2.1 Subheading</h3>
        </div>
      <h3>1.3 Subheading</h3>
    <h2>2 Heading</h2>
      <h3>2.1 Subheading</h3>
      <h3>2.2 Subheading</h3>
        <div class="text_output_expansion">
          <h1>Document 3</h1>
            <h2>1 Heading</h2>
              <h3>1.1 Subheading</h3>
            <h2>2 Heading</h2>
              <h3>2.1 Subheading</h3>
                <div class="text_output_expansion">
                  <h1>Document 4</h1>
                    <h2>1 Heading</h2>
                      <h3>1.1 Subheading</h3>
                    <h2>2 Heading</h2>
                      <h3>2.1 Subheading</h3>
                </div>
              <h3>2.2 Subheading</h3>
        </div>
      <h3>2.3 Subheading</h3>
    <h2>3 Heading</h2>
      <h3>3.1 Subheading</h3>
      <h3>3.2 Subheading</h3>
</div>

I'll post a CSS solution, but I'm just struggling to get this working in javascript instead. The idea is so that I can copy and paste the document with the numbers intact (CSS solution won't allow that). Admittedly my javascript isn't great, but my struggle seems to be how js loops through the elements from top to bottom.

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

One solution is to use CSS counters to append text to the headers instead. Unfortunately, the weakness (or strength) of this approach is that it is visible to the user, but it cannot be copy pasted from the browser, nor is it easy to get the value if you need it elsewhere in your script.

#text_output {
  counter-reset: h2
}

#text_output h2 {
  counter-reset: h3
}

#text_output .text_output_expansion .card-body{
  counter-reset: h2
}

#text_output .text_output_expansion .card-body h2 {
  counter-reset: h3
}

#text_output h2:before {
  counter-increment: h2;
  content: counter(h2) ". "
}

#text_output h3:before,
h3.md-focus.md-heading:before {
  counter-increment: h3;
  content: counter(h2) "."counter(h3) ". "
}

about 4 years ago · Juan Pablo Isaza Relatório

0

You can recursively traverse the structure by grouping on h tag blocks:

var div = document.createElement("div");
div.innerHTML = `<div id="text_output">
  <h1>Document</h1>
    <h2>Heading</h2>
      <h3>Subheading</h3>
      <h3>Subheading</h3>
        <div class="text_output_expansion">
          <h1>Document</h1>
            <h2>Heading</h2>
              <h3>Subheading</h3>
            <h2>Heading</h2>
              <h3>Subheading</h3>
        </div>
      <h3>Subheading</h3>
    <h2>Heading</h2>
      <h3>Subheading</h3>
      <h3>Subheading</h3>
        <div class="text_output_expansion">
          <h1>Document</h1>
            <h2>Heading</h2>
              <h3>Subheading</h3>
            <h2>Heading</h2>
              <h3>Subheading</h3>
                <div class="text_output_expansion">
                  <h1>Document</h1>
                    <h2>Heading</h2>
                      <h3>Subheading</h3>
                    <h2>Heading</h2>
                      <h3>Subheading</h3>
                </div>
              <h3>Subheading</h3>
        </div>
      <h3>Subheading</h3>
    <h2>Heading</h2>
      <h3>Subheading</h3>
      <h3>Subheading</h3>
</div>`
document.querySelector('body').appendChild(div)

function number_headings(root){
    var h1 = 1;
    function label_headings(nodes, p){
       var [groups, group, h] = [[], [], null]
       for (var i of nodes){
          if (i.tagName[0].toLowerCase() != 'h' || (h != null && i.tagName != h.tagName)){
             group.push(i)
          }
          else if (h === null){
             h = i;
          }
          else{
             groups.push({node:h, block:group.slice()});
             group = [];
             h = i;
          }
       }
       if (h != null){
          groups.push({node:h, block:group.slice()});
       }
       var c = 1;
       for ({node:n, block:b} of groups){
           if (n.tagName === 'H1'){
              n.textContent = `${n.textContent} ${h1}`;
              h1++;
           }
           else{
              n.textContent = `${(p === null ? c.toString() : p+'.'+c.toString())} ${n.textContent}`;
           }
           label_headings(b, n.tagName === 'H1' ? null : (p === null ? '':p+'.')+c.toString());
           for (var k of b.filter(function(x){return x.nodeType === 1 && x.tagName[0] != "H"})){
              label_headings(Array.from(k.childNodes).filter(function(x){return x.nodeType === 1}), null);
           }
           c++;
       }
    }
    label_headings(Array.from(root.childNodes).filter(function(x){return x.nodeType === 1}))
}
number_headings(document.querySelector('#text_output'), null)
about 4 years ago · Juan Pablo Isaza Relatório

0

Did another recursive option. I think Ajax has the best answer tho!

function numberHeadings(element) {
var h1_counter = 0;
var h2_counter = 0;
var h3_counter = 0;
var h4_counter = 0;
var h5_counter = 0;
var h6_counter = 0;
element.find(".text_output_expansion").each(function () {
  numberHeadings($(this));
});

element.find("h1:not([numberHeadings=complete]),h2:not([numberHeadings=complete]),h3:not([numberHeadings=complete]),h4:not([numberHeadings=complete]),h5:not([numberHeadings=complete]),h6:not([numberHeadings=complete])").each(function () {
  switch ($(this).prop("tagName")) {
    case "H1":
      h1_counter += 1;
      h2_counter = 0;
      h3_counter = 0;
      h4_counter = 0;
      h5_counter = 0;
      h6_counter = 0;
      $(this).text(h1_counter.toString() + ". " + $(this).text());
      $(this).attr("numberHeadings", "complete");
      break;
    case "H2":
      h2_counter += 1;
      h3_counter = 0;
      h4_counter = 0;
      h5_counter = 0;
      h6_counter = 0;
      $(this).text(h1_counter.toString() + "." + h2_counter.toString() + ". " + $(this).text());
      $(this).attr("numberHeadings", "complete");
      break;
    case "H3":
      h3_counter += 1;
      h4_counter = 0;
      h5_counter = 0;
      h6_counter = 0;
      $(this).text(h1_counter.toString() + "." + h2_counter.toString() + "." + h3_counter.toString() + ". " + $(this).text());
      $(this).attr("numberHeadings", "complete");
      break;
    case "H4":
      h4_counter += 1;
      h5_counter = 0;
      h6_counter = 0;
      $(this).text(h1_counter.toString() + "." + h2_counter.toString() + "." + h3_counter.toString() + "." + h4_counter.toString() + ". " + $(this).text());
      $(this).attr("numberHeadings", "complete");
      break;
    case "H5":
      h5_counter += 1;
      h6_counter = 0;
      $(this).text(h1_counter.toString() + "." + h2_counter.toString() + "." + h3_counter.toString() + "." + h4_counter.toString() + "." + h5_counter.toString() + ". " + $(this).text());
      $(this).attr("numberHeadings", "complete");
      break;
    case "H6":
      h6_counter += 1;
      $(this).text(h1_counter.toString() + "." + h2_counter.toString() + "." + h3_counter.toString() + "." + h4_counter.toString() + "." + h5_counter.toString() + "." + h6_counter.toString() + ". " + $(this).text());
      $(this).attr("numberHeadings", "complete");
      break;
  }
})

};

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda