Use Javascript to Modify Selected Text in Multiple Nodes

Suppose I selected a group of text which lie in multiple nodes using getSelection(). For example some highlighted text are in a div, some in a paragraph element, and some in an i element as follows:

<div>Sample Text1</div> <p> Sample Text2</p><i>Sample Text3</i>

I would like to then surround the selected text with the h1 tags using surroundContents() method but I cannot as it will only work if the selected text are all in a single node. Also I want to modify the text inside of all the nodes at once (When I say all at once what I mean is I don’t have to modify the text in each node separately), how can I go about doing those things just mentioned?

Hi @liagapi555, do you mean you want to wrap all the selected nodes in a single element, or each of the contained text nodes separately? I suppose what would be closest to surroundContents() would be to extractContents() into a wrapper element, and then insert that wrapper into the range:

const selection = window.getSelection()
const range = selection.getRangeAt(0)
const wrapper = document.createElement('div')

wrapper.appendChild(range.extractContents())
range.insertNode(wrapper)

You mean like using replace() on the contents? I don’t think that’s possible… what’s wrong with just iterating over the text nodes though?

Hi, I guess I haven’t been clear on what I am trying to do so let me explain. Suppose I have a web page containing text and these text could be in any elements i.e. some could be in paragraph elements, some in divs, some in spans, some in forms etc.

The user does not know what element the text are in and all I want them to know is that they can highlight any text on the screen and modify them any way they want from changing their size to deleting the text and then writing new text. After they are done they can save the changes. If this is possible and you know of a tutorial on this please let me know. Thanks.

Hm isn’t that a lot like what you had asked here a couple of months ago? Here’s the gist of the code pen from that thread:

/**
 * Helper to conveniently iterate a tree walker
 *
 * @param {TreeWalker} walker
 * @returns {IterableIterator}
 */
function iterateWalker (walker) {
  return {
    [Symbol.iterator] () {
      return this
    },

    next () {
      const value = walker.nextNode()
      return { value, done: !value }
    }
  }
}

/**
 * Get the text nodes contained in a given range
 *
 * @param {Range} range
 * @returns {Text[]}
 */
function getSelectedNodes (range) {
  const walker = document.createTreeWalker(
    range.commonAncestorContainer.parentElement,
    NodeFilter.SHOW_TEXT,
    {
      acceptNode (node) {
        return range.intersectsNode(node)
          ? NodeFilter.FILTER_ACCEPT
          : NodeFilter.FILTER_REJECT
      }
    }
  )

  return [...iterateWalker(walker)]
}

/**
 * Test if a given node has some actual
 * text other than whitespace
 *
 * @param {Node} node
 * @returns {boolean}
 */
function hasText (node) {
  return /\S/.test(node.textContent)
}

document.addEventListener('mouseup', () => {
  const selection = window.getSelection()
  const range = selection.getRangeAt(0)
  const selectedNodes = getSelectedNodes(range).filter(hasText)

  // Do something with the selected nodes...
  console.log(selectedNodes)
})

Hi, thanks for your reply. I think that the code you’ve provided does not work very well and it doesn’t work the way I wanted. I think a better solution is to add or enable the ContentEditable property in the elements in which the highlighted text are in. Then when the user saves the changes or deselects the text without making any changes, the ContentEditable property is removed or disabled. I just need to grab all highlighted elements containing the highlighted text. Then I would iterate through them one by one adding or enabling the mentioned property. Finally the opposite will need to take place on save or deselect (if changes are not made).

Hi, The reason I mentioned that your code is not working very well is because when I change the markups your script stops working. The script works if the parent tag is main but that’s not what I’m talking about. What I meant when I said I changed the markups is changing the children of the main element. For some reason after changing the markups the selection will behave as follows depending on the markups used:

work intermittently
work all the time
does not work at all

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.