1

I have two simple JavaScript functions: getSelectedText() and doSomethingWithSelectedText() that I found in a different example.

Now I've adjusted it more to my needs: http://jsfiddle.net/83T7U/.

The example currently works but not the way it should. Currently, when text is selected, there is an alert(), but instead the text on button should change from Reply to Quote.

So, instead:

alert("Text selected - it should change "Reply" to "Quote" text button ONLY if text was selected within one of these DIVs and text should change only in the div within which the text was selected.");

It should be like document.getElementsByTagName("button") or similar.

My goal is to:

  1. Change the value of the button from Reply to Quote as soon as text from a particular div is selected. When the text is de-selected, then button should change back to Reply.

  2. Make sure the Reply<>Quote change applies only when text is selected within one of these DIVS (and not in other parts of the page).

  3. Minimize the functions - I think instead of the two functions one is enough because I don't want to know the value of selection - I just want to check if there is something (ie. at least one character) selected/highlighted.

  4. The JavaScript should work correctly with all the major browsers.

Please note I cannot use jQuery here. Thank you!

HTML:

<div id="first" style="background:yellow">DIV1: First some test text for you to select
<br>
<button>Reply</button>
</div>
<br>
<div id="second" style="background:green">DIV2: Second some test text for you to select
<br>
<button>Reply</button>
</div>
<br>
<div id="third" style="background:lightblue">DIV3: Third some test text for you to select
<br>
<button>Reply</button>
</div>
<br>
    <i>(there could be more similar divs on a page)</i>

JavaScript:

function getSelectedText() {
    var text = "";
    if (typeof window.getSelection != "undefined") {
        text = window.getSelection().toString();
    } else if (typeof document.selection != "undefined" && document.selection.type == "Text") {
        text = document.selection.createRange().text;
    }
    return text;
}

function doSomethingWithSelectedText() {
    var selectedText = getSelectedText();
    if (selectedText) {
        alert("Text selected - it should change Reply to Quote text button ONLY if text was selected within one of these DIVs and text should change only in the div within which the text was selected.");
    }
}

document.onmouseup = doSomethingWithSelectedText;
document.onkeyup = doSomethingWithSelectedText;
AstroCB
  • 12,337
  • 20
  • 57
  • 73

2 Answers2

0

Look at this fiddle

with following html (yours with additional class for divs):

<div id="first" class="specialDiv" style="background:yellow">DIV1: First some test text for you to select
<br>
<button>Reply</button>
</div>
<br>
<div id="second"  class="specialDiv" style="background:green">DIV2: Second some test text for you to select
<br>
<button>Reply</button>
</div>
<br>
<div id="third"  class="specialDiv" style="background:lightblue">DIV3: Third some test text for you to select
<br>
<button>Reply</button>
</div>
<br>
    <i>(there could be more similar divs on a page)</i>

and the javascript:

 function doSomethingWithSelectedText() {
       //relabel quoteButton to standard-label
          var buttons = document.getElementsByClassName('quoteButton');
            if(buttons.length){
                var button = buttons[0];
                button.innerHTML = 'Reply';
                var classArr = button.className.split(' ');
                classArr.splice(classArr.indexOf('quoteButton'), 1);
                button.className = classArr.join(' ');
           }

        //check if new quoteButton should be labeled
        if (window.getSelection && window.getSelection().toString()) {
            if(window.getSelection().anchorNode.parentNode && window.getSelection().anchorNode.parentNode.className && window.getSelection().anchorNode.parentNode.className.split(' ').indexOf('specialDiv') > -1){
               var button = window.getSelection().anchorNode.parentNode.getElementsByTagName('button')[0];
               button.innerHTML = 'Quote';
               button.className += ' quoteButton';
            }
        }
    }    
    document.onmouseup = doSomethingWithSelectedText;
    document.onkeyup = doSomethingWithSelectedText;

In this article is mentioned to get the element that is selected by window.getSelection().anchorNode.parentNode. So I simply let check if the selected element has the newly added class 'specialDiv'. If it has search for the button and relabel it. Additonaly add a class to the button to be able to find relabeled buttons again. At any selection let the button be reset to the standard label, before maybe relabeling other buttons.

EDIT :
It's a little sad but there's one way the solution above wont work: Selecting text and then clicking into it. Thats the only way that at the timepoint of mouseup-event the old selectedText is still set (and will be unset immediatly after mouseup-event).

To fix this use onclick instead of onmouseup
Look at this fiddle... it uses onclick instead of of keyup since click will be triggered at a timepoint at that the new selection has been set in any case

Community
  • 1
  • 1
L. Monty
  • 872
  • 9
  • 17
  • At first look it looks great! I'll play with it and will confirm. Just a question - are the 'if(buttons.length){' parts needed? In other words, is this function optimized enough so that it doesn't include unnecessary code (the goal is to make it optimized and fast as it can be). Thanks again... –  Jul 05 '14 at 15:46
  • Also, your JavaScript contains the following: document.onclick = doSomethingWithSelectedText; document.onkeyup = doSomethingWithSelectedText; Is "document.onkeyup = doSomethingWithSelectedText;" needed? Maybe only "document.onclick = doSomethingWithSelectedText;" would be enough? –  Jul 05 '14 at 15:59
  • I overtook it from your code. For divs the keyup is not needed. But when you would like to use also inputs/textareas the keyup should be also used, since the user can also select text with shift + arrow. To buttons.length: yes its needed since buttons[0] will be undefined (in case of !buttons.length / buttons.length == 0) and calling and setting properties on it will cause an exception – L. Monty Jul 05 '14 at 16:26
  • I still have an issue though.. - what if text inside of 'specialDiv' class contains some HTML, like or -- then the code won't work..? Could you make it work in such cases too? I updated the fiddle to show the problem: http://jsfiddle.net/83T7U/9/ –  Jul 05 '14 at 19:22
  • 1
    Look at http://jsfiddle.net/83T7U/29/. This works for seperatly selecting nodes. For selection more then one node at once seems like you will have to put design-mode on. Look for that at this article http://stackoverflow.com/questions/2582831/how-can-i-highlight-the-text-of-the-dom-range-object. – L. Monty Jul 06 '14 at 02:12
  • Thanks, I realized it was not the best way to go (as I described here: http://stackoverflow.com/questions/24590454/selecting-text-within-a-div-changing-button-when-text-is-highlighted-deselect/24590895) –  Jul 06 '14 at 02:19
  • funny...seems like *@Tim Down* and I had a similiar idea of 'getAncestorOrSelfByClass'/'getSelfOrAncestorWithClass'-function *(while the decision of iterative and recursive differed .. to me both seem equal)*. Those functions seem to be a reasonable approach. – L. Monty Jul 06 '14 at 02:24
0

Try following example. I hope it will help you. To try following example just copy following code and pest it in blank notepad and save it with .html extension and run it in any browser.

<html>
<head>
<style>
.head {
    border:1px solid #666;
    background-color:#f0f0f0;
    padding:3px;
    cursor:pointer;
}
.content {
    border:1px solid #666;
    background-color:#fff;
    height:100px;
    padding:3px;
}
</style>
<script type="text/javascript">
function getSelectedText(i) {
    var pi = document.getElementById("pi").value;
    var str = window.getSelection();
    if(str!="") {
        if(pi=="") {
            document.getElementById("btn"+i).value="Quote";
        }
        else {
            document.getElementById("btn"+i).value="Quote";
            document.getElementById("btn"+pi).value="Reply";
        }
    }
    else {
        document.getElementById("btn"+i).value="Reply";
        document.getElementById("btn"+pi).value="Reply";
    }
    document.getElementById("pi").value = i;
}
</script>
</head>
<body>
    <div>
        <div id="head1" class="head">Head 1</div>
        <div id="content1" class="content" onMouseUp="getSelectedText('1')">Content 1 Div. Select text in this div.</div>
        <input type="button" id="btn1" value="Reply" />
        <div id="content2" class="content" onMouseUp="getSelectedText('2')">Content 2 Div. Select text in this div.</div>
        <input type="button" id="btn2" value="Reply" />
    </div>
    <input type="hidden" id="pi" name="pi" value="" />
</body>
</html>
Swapnil
  • 14
  • you should try to avoid inline-javascript...also your code has the flaw i mentioned in my answer of onmousedown. If you select some text and click directly in it the button wont be relabeled correct – L. Monty Jul 05 '14 at 06:49