-1

I want to be able to select text click on a button and have the text color change e. The text color change should persist after the text is no longer selected.

I know that there are many solutions that do this already with CSS. However; I want to be able to have access to the nodes so that on another button click, I can revert the color change. I have tried looking into window.getSelection() and Ranges and DocumentFragment, but I am having trouble understanding how to select the nodes in a DocumentFragment, modify each node, insert it in the right position in the document and also create a reference so that I can, in a later click, change the color again back to black.

I also found this thread which essentially does what I"m trying to do, but it uses execCommand which is obsolete.

I don't want a CSS solution and I don't want a solution that uses jQuery.

Below is the js code and codepen with a similar html structure that I am working with.

I have 2 buttons, one that changes the selections color and one that will revert the color of the selection even after the text is no longer selected.

I am using window.getSelection() to get a Selection of the selected text. I check that the Selection is valid and then get a Range with getRangeAt(0) followed by a call to extractContents().

This is where the hard part comes in because:

  1. It extracts the DocumentFragment from the document so how can I re-insert the DocumentFragment in the same position it was extracted from?
  2. I am having trouble figuring out how to modify the nodes in the DocumentFragment styles
var changeColorButton = document.getElementById('xyz');
var revertColor = document.getElementById('zyx');

const changeSelectionColor = () => {
  let selection = window.getSelection()
  if (selection) {
    let range = selection.getRangeAt(0)
    if (range) {
      let frag = range.extractContents();
    }
    /*
      2 problems:
      1. accessing each node in the DocumentFragment and modifying the style then re-inserting into the correct spot
      2. Creating a reference to this fragment for revertColorChange() to use to change the color back to black
    */
  }
}

const revertColorChange = () => {
  // revert color
}

changeColorButton.addEventListener('click', changeSelectionColor);

Minimal Reproducible Example - https://codepen.io/NoobCodePenner/pen/GRoKNRd

c0de
  • 819
  • 2
  • 9
  • 21
  • You want the text color to change permanently or only while being selected? – D. Pardal Jun 01 '20 at 10:29
  • You want to change something's colour but don't want to use CSS? – Mitya Jun 01 '20 at 10:30
  • Please share what you already tried and provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) – Ishant Solanki Jun 01 '20 at 10:31
  • You can add 's. with classes for colors. If the whole selection is with on one node that's easy. It gets more complicated when several text nodes, parts of
    's etc are spanned.
    – QuentinUK Jun 01 '20 at 10:40
  • The task is quite complex, it's easy to get the nodes, but if you've a cross-element selection, you've to create new elements so that all the insertion and layout rules of the enclosed elements are fullfilled. As an example, you're selecting a couple of cells from a table, and additionally some text below the table, you can't just wrap that selection in a HTML element with the style of the wanted color, you'd need to add multiple elements within the table and after the table. – Teemu Jun 01 '20 at 10:41
  • Thanks for the feedback. I have updated the original topic with more details and an example. In short, I want to permanent change the Selection's color with one button click. In another button click, I want to revert the change even when I don't have anything selected – c0de Jun 01 '20 at 11:14
  • Just an idea, you could try to keep the selection alive (use CSS to color the characters). Store the selection in a range, and when ever the selection is going to be removed, rebuild it from the stored range. Then when you need to restore the color, just let the selection go. A lot depends on the page itself, if it's a simple page without a lot of (or any ...) interactivities, this might work ..? – Teemu Jun 01 '20 at 11:21
  • @Teemu could you please provide a small example? I think that sounds viable, but the colors of selections will vary depending on what is clicked after a selection. once a selection is colored, we should not be able to overwrite that color unless we revert first. – c0de Jun 01 '20 at 11:27
  • The point is, that you'd try to keep the selection alive, then the colors won't change. That means you can't select anything else before the selection is removed. You've just to capture all the events which would remove the current selection (pointer and keyboard events at least) and rebuild the selection, if it's going to be removed. If you need other selections on the page, then this won't solve your problem, but eg. button clicks would be possible. If you're going to wrap the selected nodes to extra elements, you'd almost need to implement your own HTML parser in JS. – Teemu Jun 01 '20 at 11:36
  • ok i understand now and i think you're right. i definitely don't want to keep the selection 'alive'. i tried going down the route of get the Selections parent, extractContents() modifying the DocumentFragment from extractContents() then append it to the Selections parent, but running into some troubles here since some of these methods are read-only.... – c0de Jun 01 '20 at 11:40

1 Answers1

-2
<!DOCTYPE html>
<html>
<body>

<button onClick="changeColor()">Change color</button><br/>
<button onClick="changeColorBack()">Change to previous color</button>
<p id="demo">Javascript</p>

<script>
changeColor=()=>{
document.getElementById("demo").style.color ="red"
}

changeColorBack=()=>{
document.getElementById("demo").style.color ="black"
}

</script>

</body>
</html>

Is this what you are looking for?

upender
  • 160
  • 1
  • 10
  • no. i am working on a minimal reproducible example. the flow is: 1. user selects some part of the dom. 2. user clicks on a button 3. the selected text should not be a different color even when the selection is deselected – c0de Jun 01 '20 at 10:56
  • ok got it now. The clarity of the question can be improved to understand more precisely. – upender Jun 01 '20 at 11:01
  • I added an example – c0de Jun 01 '20 at 11:07