Как заставить подсветку текста работать на нескольких элементах? - PullRequest
0 голосов
/ 02 мая 2020

Исходя из этого предыдущего ответа SO , я пытаюсь заставить подсветку текста работать для нескольких элементов. По какой-то причине средний элемент не выделяется, и я не могу понять, почему.

Вот код:

function getSafeRanges(dangerous) {
  // a for ancestor
  const a = dangerous.commonAncestorContainer;
  // Starts -- Work inward from the start, selecting the largest safe range
  const s = [];
  const rs = [];
  // if highlight doesn't start and end in the same container…
  if (dangerous.startContainer != a) {
    for (let i = dangerous.startContainer; i != a; i = i.parentNode) {
      // put the starting text and all its parents (except
      // common ancestor of start and end) into array `s`
      /*       debugger */
      s.push(i);
    }
  }
  // if highlight didn't start and end in the same container,
  // then create a new range for each item in `s`
  if (s.length > 0) {
    for (let i = 0; i < s.length; i++) {
      const xs = document.createRange();
      console.log(i, xs)
      /* debugger */
      // if at the parents of starting node
      if (i) {
        xs.setStartAfter(s[i - 1]);
        xs.setEndAfter(s[i].lastChild);
      }
      // if at the starting node (text node)
      else {
        xs.setStart(s[i], dangerous.startOffset);
        /* if (s[i].nodeType != Node.TEXT_NODE) debugger */
        xs.setEndAfter(
          (s[i].nodeType == Node.TEXT_NODE) ?
          s[i] :
          s[i].lastChild
        );
      }
      console.log(i)
      rs.push(xs);
      console.log("rs", rs)
      /* debugger */
    }
  }

  // Ends -- basically the same code reversed
  const e = [];
  const re = [];
  // if highlight doesn't start and end in the same container…
  if (dangerous.endContainer != a) {
    for (let i = dangerous.endContainer; i != a; i = i.parentNode) {
      // put the ending text and all its parents (except
      // common ancestor of start and end) into array `e`
      e.push(i);
    }
  }
  // if highlight didn't start and end in the same container,
  // then create a new range for each item in `e`
  if (e.length > 0) {
    for (let i = 0; i < e.length; i++) {
      const xe = document.createRange();
      // if at the parents of ending node
      if (i) {
        xe.setStartBefore(e[i].firstChild);
        xe.setEndBefore(e[i - 1]);
      }
      // if at the ending node (text node)
      else {
        xe.setEnd(e[i], dangerous.endOffset);
        /* if (e[i].nodeType != Node.TEXT_NODE) debugger */
        xe.setStartBefore(
          (e[i].nodeType == Node.TEXT_NODE) ?
          e[i] :
          e[i].firstChild
        );
      }
      re.unshift(xe);
    }
  }

  // Middle -- the uncaptured middle
  if ((s.length > 0) && (e.length > 0)) {
    /* debugger */
    const xm = document.createRange();
    xm.setStartAfter(s[s.length - 1]);
    xm.setEndBefore(e[e.length - 1]);
    // Concat
    rs.push(xm);
  } else {
    console.log("no middle?")
    return [dangerous];
  }


  response = rs.concat(re);
  /* debugger */
  // Send to Console
  console.log(response)
  return response;
}


function highlightSelection() {
  const userSelection = window.getSelection().getRangeAt(0);
  if (userSelection.collapsed) return;
  const safeRanges = getSafeRanges(userSelection);
  for (let i = 0; i < safeRanges.length; i++) {
    highlightRange(safeRanges[i]);
  }
  document.getSelection().removeAllRanges();
}

function highlightRange(range) {
  const newNode = document.createElement("span");
  newNode.setAttribute(
    "style",
    "background-color: yellow; display: inline;"
  );
  newNode.addEventListener("click", function(el) {
    /* debugger */
    el.target.outerHTML = el.target.innerHTML;
  })
  range.surroundContents(newNode);
}


window.addEventListener("mouseup", highlightSelection);
<div>
  <p>
    line1
  </p>
  <p>
    line2
  </p>
  <span>line3</span>
  <p>
    line4
  </p>
  <span>line5</span>
  <p>
    line6
  </p>
  <span>line7</span>
  <table style="width:100%">
    <tr>
      <th>Firstname</th>
      <th>Lastname</th>
      <th>Age</th>
    </tr>
    <tr>
      <td>Jill</td>
      <td>Smith</td>
      <td>50</td>
    </tr>
    <tr>
      <td>Eve</td>
      <td>Jackson</td>
      <td>94</td>
    </tr>
  </table>
</div>
<span>awoifja woiefj awf</span>

Если вы выделите весь текст, начиная с " line1 " вплоть до " line7 ", можете кто-нибудь, пожалуйста, скажите мне, почему средний элемент не выделяется? Кроме того, здесь - рабочая скрипка , поскольку кажется, что демонстрационная версия фрагмента SO содержит кучу странных ошибок (ничего общего с моим сценарием).

...