58

I've got this problem where I need to show and hide divs when clicking on a table cell. However, I also want people to be able to select text and copy it within the cell without hiding the information.

Totally open to changing the design if necessary. :)

Here's a fiddle which demonstrates the issue

http://jsfiddle.net/k61u66ek/1/

Here's the HTML code in the fiddle:

<table border=1>
    <tr>
        <td>
            Information
        </td>
        <td onClick="toggleInfo()">
            <div id="information" style="display:none">
                More information that I want to select without hiding
            </div>
            <div id="clicktoshow">
                Click to show info
            </div>

        </td>
    </tr>
</table>

Here's the javascript:

function toggleInfo() {
    $("#clicktoshow").toggle();
    $("#information").toggle();    
}

Any suggestion/advise is much appreciated!

/Patrik

PatrikJ
  • 2,327
  • 3
  • 24
  • 35

6 Answers6

70

One option is to check the type of the Selection object returned by window.getSelection:

function toggleInfo() {
    var selection = window.getSelection();
    if(selection.type != "Range") {
        $("#clicktoshow").toggle();
        $("#information").toggle();
    }
}

http://jsfiddle.net/k61u66ek/4/

Update

If the browser you're targeting doesn't expose a type property on the Selection object then you can test against the length of the selected value instead:

function toggleInfo() {
    var selection = window.getSelection();
    if(selection.toString().length === 0) {
        $("#clicktoshow").toggle();
        $("#information").toggle();
    }
}

http://jsfiddle.net/k61u66ek/9/

which can in turn be reduced down to a bool check on toString:

if(!selection.toString()) {

http://jsfiddle.net/k61u66ek/10/

Jamie Dixon
  • 53,019
  • 19
  • 125
  • 162
  • 1
    Thanks @t00thy, I've updated my answer to include a solution when `type` isn't available. – Jamie Dixon Aug 13 '15 at 08:08
  • 1
    Or there is my solution, with catching the time on mouseclick [http://jsfiddle.net/k61u66ek/15/](http://jsfiddle.net/k61u66ek/15/) I set 200 milliseconds as difference between click and copy situation. Maybe it will help. – t00thy Aug 13 '15 at 08:25
  • it seems toString() is a better option than type=="Range", at least on IE11 & Firefox – Sam Jason Braddock May 23 '17 at 07:57
  • The `toString()` method does not work for example when only images are selected. The `type` approach seems to have good browser support nowadays. – cdauth Apr 05 '22 at 15:23
12

You could check if there is a selection made in the click event handler:

window.getSelection().toString();
BobbyTables
  • 4,481
  • 1
  • 31
  • 39
12

TLDR JS solution

Demo: http://jsfiddle.net/5472ja38/

Code (cancels click event when text highlighted/selected):

document.getElementById('information').addEventListener('click', (e) => {
  const cellText = document.getSelection();
  if (cellText.type === 'Range') e.stopPropagation();
})

Explanation

document.getSelection().type checks on the document object level if any of the text has been highlighted. If so, the type property is equal to 'Range' stop the event propagation which will cancel the click toggle button change.

Taken from MDN

A DOMString describing the type of the current selection. Possible values are:

None: No selection has currently been made.

Caret: The selection is collapsed (i.e. the caret is placed on some text, but no range has been selected).

Range: A range has been selected.

EugenSunic
  • 13,162
  • 13
  • 64
  • 86
4

You can use mouseup, mousedown and mousemove events to achieve this:

DEMO

var isDragging = false;
$("#clickshow")
.mousedown(function() {
    isDragging = false;
})
.mousemove(function() {
    isDragging = true;
 })
.mouseup(function() {
    var wasDragging = isDragging;
    isDragging = false;
    if (!wasDragging) {
        $("#information").toggle();
        $("#clicktoshow").toggle();
    }
});

SOURCE

Community
  • 1
  • 1
Guruprasad J Rao
  • 29,410
  • 14
  • 101
  • 200
2

Another way to go is to use the isCollapsed property of the selection. As per MDN, it returns true if the start and end of a selection are the same (which is true of a click):

document.getElementById('information').addEventListener('click', (e) => {
    if (!window.getSelection().isCollapsed) {
        return;
    }

    // do something here
});
fij
  • 29
  • 2
0

You can check if the 'information' div is toggled :

function toggleInfo() {
    if(document.getElementById('information').style.display == 'none'){
         $("#clicktoshow").toggle();
         $("#information").toggle();
   } else { 
       // do nothing
   }
}

Check this Fiddle

wilson
  • 334
  • 1
  • 15