cssgoogle-chromequill

Force refresh of CSS counter calculation


I am integrating the Quill editor into our application, and have been asked to implement line-numbering in code blocks. Following from this discussion, I used

.ql-code-block-container {
    counter-reset: line;
    padding-left: 0;
}

.ql-code-block:before {
    counter-increment: line;
    content: counter(line);
    display: inline-block;
    border-right: 1px solid #ddd;
    padding: 0 .5em;
    margin-right: .5em;
    color: #EEE;
}

This works well but for one issue in Chrome. I can add some text, which appears in Dev-tools as:

<div class="ql-code-block-container" spellcheck="false">
    <div class="ql-code-block">Here</div>
    <div class="ql-code-block">is</div>
    <div class="ql-code-block">some</div>
    <div class="ql-code-block">text</div>
</div>

and Crome renders as

Four lines of text, numbered 1–4

But if I highlight and delete the middle two lines, Dev-tools shows

<div class="ql-code-block-container" spellcheck="false">
    <div class="ql-code-block">Here</div>
    <div class="ql-code-block">text</div>
</div>

while Chrome renders it as

Two lines of text, numbered 1 and 4

If I add a new line of text, it seems to recalculate the counters correctly. I suspect this is a Chrome bug (it refreshes fine in FireFox), but is there any general way to force a browser to refresh its CSS counter calculations when content changes?


Solution

  • You can try to toggle counterReset in javascript to force chrome to refresh. Take a look a this example :

    function remove() {
      console.log("remove")
      var els = document.getElementsByClassName("ql-code-block");
      removeCodeBlocElement(els[1])
    }
    
    
    function removeCodeBlocElement(element) {
      var elementContainer = element.closest(".ql-code-block-container");
      element.remove();
      elementContainer.style.counterReset = "none"
      //using setTimeout to disable browser property optimisation
      setTimeout(() => { 
      elementContainer.style.counterReset = "";
      }, 0);
    }
    .ql-code-block-container {
      counter-reset: line;
      padding-left: 0;
    }
    
    .ql-code-block:before {
      counter-increment: line;
      content: counter(line);
      display: inline-block;
      border-right: 1px solid #ddd;
      padding: 0 .5em;
      margin-right: .5em;
    }
    <div class="ql-code-block-container" spellcheck="false">
      <div class="ql-code-block">Here</div>
      <div class="ql-code-block" id="remove">is</div>
      <div class="ql-code-block">some</div>
      <div class="ql-code-block">text</div>
    </div>
    
    <button onclick="remove()">Remove</button>


    Edit : If you have any events on your ql-code-block, you can also use innerHTML and avoid a possible flickering counter number

    function remove() {
      var elements = document.getElementsByClassName("ql-code-block");
      var element = elements[1];
      var elementContainer = element.closest(".ql-code-block-container"); 
      element.remove();
      //using innerHTML removes all events from child elements
      elementContainer.innerHTML = elementContainer.innerHTML;
    }
    .ql-code-block-container {
      counter-reset: line;
      padding-left: 0;
    }
    
    .ql-code-block:before {
      counter-increment: line;
      content: counter(line);
      display: inline-block;
      border-right: 1px solid #ddd;
      padding: 0 .5em;
      margin-right: .5em;
    }
    <div class="ql-code-block-container" spellcheck="false">
      <div class="ql-code-block">Here</div>
      <div class="ql-code-block" id="remove">is</div>
      <div class="ql-code-block">some</div>
      <div class="ql-code-block">text</div>
    </div>
    
    <button onclick="remove()">Remove using InnerHTML</button>