Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make table column non-copyable? (HTML/CSS)

I have a simple table:

Column A | Column B
--------------------
    A    |  Item1 
    B    |  Item2    
    C    |  Item3   

I want to make the first column non-copyable. When user selects table rows and presses Ctrl+C, he should get just

Item1
Item2
Item3

but not

A  Item1 
B  Item2    
C  Item3  

I tried -moz-user-select: none; -webkit-user-select: none; user-select: none; but it doesn't work. Text is not being selected but still copied. It is working in Firefox but not in Chrome and Opera.

SOLUTION which works for me: It's still flickering and slightly modifing row height because of height() being not accurate but it is OK for me.

$(document).on('copy', function(e) {
    if (navigator.userAgent.indexOf("Firefox")==-1) {
        var nonCopyable = $('.nonCopyable:not(.empty)');
        nonCopyable.each(function(index,el) {
            var $el = $(el);
            if ( $el.hasClass('empty') )  {
                return;
            }
            var width = $(el).width();
            var height = $(el).height();
            $el.data('content', $el.html()).css({"width" : width+'px', "height": height + 'px'} ).html('');
        }).addClass('empty');
        setTimeout(function() { 
            nonCopyable.each(function(index,el) {
            $(el).html($(el).data('content')).removeClass('empty').css({"width":'auto', height:'auto'}).data('content',null);
        }); });
    }
} );
.nonCopyable {
    -moz-user-select: none; 
    -webkit-user-select: none; 
    user-select: none;
}

Off course if you have more than just text and images in non-copyable cell such as event handlers, your need another workaround.

like image 998
zenden2k Avatar asked Oct 19 '22 15:10

zenden2k


2 Answers

I'm not sure if this fits your needs (because of incompatibility with Internet Explorer) but one option is to use ::before/::after pseudo-elements to generate the first column content and prevent it from being selected/copied.

Also to follow DRY principle, we can use data-* attributes to define the contents and then use attr() expression to assign that to the pseudo-elements.

table > tbody td:first-child::before {
  content: attr(data-content);
}
table > thead th:first-child::before {
  content: attr(data-content);
}
<table>
  <thead>
    <tr>
      <th data-content="Column A"></th>
      <th>Column B</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td data-content="This"></td>
      <td>
        Item #1
      </td>
    </tr>
    <tr>
      <td data-content="is"></td>
      <td>
        Item #2
      </td>
    </tr>
    <tr>
      <td data-content="a"></td>
      <td>
        Item #3
      </td>
    </tr>
    <tr>
      <td data-content="demo"></td>
      <td>
        Item #4
      </td>
    </tr>
  </tbody>
</table>
like image 184
Hashem Qolami Avatar answered Oct 27 '22 10:10

Hashem Qolami


I've figured out a rather crazy solution to this problem. When you detect a Ctrl+C keydown event, you can completely hide the left column, which removes it from the selection (at least it does that in Firefox 36.0.1, IE11, Safari 5.1.7, and Chrome 41), and set a timeout to re-show the column immediately. The end result is the copy operation gets just the text in the right column. The user might see a weird little flicker as the left column disappears and then reappears, but I'm finding that it's not noticeable most of the time.

$(document).keydown(function(e) {
    if (e.ctrlKey && e.keyCode == 67) {
        $('.cellNumber').hide();
        setTimeout(function() { $('.cellNumber').show(); });
    } // end if
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
        <tr><td class="cellNumber">Column A</td><td>Column B</td></tr>
        <tr><td class="cellNumber">A</td><td>Item1</td></tr>
        <tr><td class="cellNumber">B</td><td>Item2</td></tr>
        <tr><td class="cellNumber">C</td><td>Item3</td></tr>
</table>

It should also be noted that this only works for a Ctrl+C keypress. You could extend it to also work for the Cmd+C keypress for Mac users, but that still wouldn't cover other means of copying, such as mouse right-click-Copy, and menubar Edit-Copy.

Edit: Awesome! I just discovered that you can actually use the copy event to get all of the above methods of copying:

$(document).on('copy', function(e) {
    $('.cellNumber').hide();
    setTimeout(function() { $('.cellNumber').show(); });
} );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
        <tr><td class="cellNumber">Column A</td><td>Column B</td></tr>
        <tr><td class="cellNumber">A</td><td>Item1</td></tr>
        <tr><td class="cellNumber">B</td><td>Item2</td></tr>
        <tr><td class="cellNumber">C</td><td>Item3</td></tr>
</table>

This works on every browser/system I've tested (Firefox, Chrome, and Safari on Mac, and Firefox, Chrome, Safari, and IE on Windows) and every method of copying (mouse, menubar, and Ctrl+C/Cmd+C).

like image 29
bgoldst Avatar answered Oct 27 '22 11:10

bgoldst