2

Let's say I have a random string (span) of characters, each in their own span. A user can select these. I want to know which ones they select. The window.GetSelection API is useful here. It returns a Selection. However, I can't seem to figure out how I can get which characters the user selected, i.e. a NodeList of character spans. I do not mean simply which string it is (which you can get with .toString()) but also which character spans the selection belongs to.

I know there is Selection.anchorNode and Selection.focusNode as the respective start and end nodes but I want to get all of the selected nodes.

In the snippet below you can have a look.

function getSelectionNodes() {
  const selection = window.getSelection();
  let anchor = selection.anchorNode,
    focus = selection.focusNode;
  anchor = anchor.nodeType === Node.TEXT_NODE ? anchor.parentNode : anchor
  focus = focus.nodeType === Node.TEXT_NODE ? focus.parentNode : focus

  const anchorIdx = getIndex(anchor),
    focusIdx = getIndex(focus);

  console.log(anchor);
  console.log(focus);
};

function getIndex(el) {
  return Array.from(el.parentNode.children).indexOf(el)
}
<span onmouseup="getSelectionNodes()">
<span>d</span>
<span>d</span>
<span>s</span>
<span>r</span>
<span>e</span>
<span>g</span>
<span>p</span>
<span>j</span>
<span>l</span>
<span>u</span>
</span>

Note a particular difficulty: If you select a couple of letters and a seeming "space" after them, you'll notice that the anchor will not be a character span, but the parent span because we selected the "space between" the character spans, which is a text node with the wrapper span. This seems problematic. If I could get the starting and ending character span, I could use an while loop with nextSibling or previousSibling to get what I want, I think.

Bram Vanroy
  • 24,991
  • 21
  • 120
  • 214
  • 1
    This question is (sort of) being discussed on [meta](https://meta.stackoverflow.com/q/415017/17242583). – richardec Dec 30 '21 at 17:36
  • As said on Meta, avoid `onmouseup` attributes. In this scope, `getSelection` has nothing to do with your function `getSelection`, but refers to `document.getSelection`. Related: [JS function named `animate` doesn't work in Chrome, but works in IE](/q/28173800/4642212). – Sebastian Simon Dec 30 '21 at 18:37
  • (1/2) I think this will help you by visualizing the html that the browser copies when you select and copy text: (1) Copy and paste this script into your JS console (but don't execute it yet): `setTimeout(async () => console.log(await (await (await navigator.clipboard.read())[0].getType('text/html')).text()), 3000);` (2) Select a range of text in the page across multiple elements and cmd/ctrl+c to copy (3) Focus the console again and execute what you pasted from step 1 (4) Within 3 seconds, click in the document again to focus it (5) Look at the console to see the html – jsejcksn Dec 31 '21 at 09:14
  • (2/2) [`Clipboard.read()`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/read) – jsejcksn Dec 31 '21 at 09:15

0 Answers0