1

I'm attempting to write a JavaScript tool to let my users compare ranges of characters in slightly varied text strings. It's critical that the users still be able to select that text.

# || is a section my tool highlights. The number of characters the highlight covers starts at one, but can be varied by text selection. 

Foo |Bar Baz Quux|
Foo |Bra Biz Quix|

At present, a div contains a table. A secondary div is inside the first, and a third div is inside the second.

The second div overlies the text in the table, while the third is the div that actually appears semi-opaque over the text that the user wants to examine.

<div>
    <div class="text-cell-area">
        <div class="highlighter"></div>
    </div>
    <table>
        <tr><td>text</td></tr>
        <tr><td>text</td></tr>
    </table>
</div>

On page load, I use JavaScript to modify .text-cell-area such that its offsets and dimensions completely cover all the text whose alignment I need to check; it's basically a box floating over several table rows.

Mouseover events and window.onmousemove track the user's cursor, setting the location of .highlighter to match the location of the user's cursor and snap to each monospaced character.

This functionality is fine - Alignment checking works perfectly. The problem is that I now have two divs overlying the text in my table so that I can't select it. I can't use pointer-events: none; to allow my users to the select the text because that prevents the mouseover event from tracking the user's cursor to set the location of the highlighting div.

What I need is a different way to allow my users to select the text underneath both divs. How might I do that?

Vardarac
  • 563
  • 2
  • 17
  • possible duplicate of [find elements that are stacked under (visually) an element in jquery](http://stackoverflow.com/questions/5598953/find-elements-that-are-stacked-under-visually-an-element-in-jquery) – Brian Dillingham Sep 26 '14 at 20:41
  • That answer may be similar to what I need, but I have to take it a step further and find how to send the underlying TDs my click event so that they know the user is selecting text. – Vardarac Sep 26 '14 at 20:47
  • I took a similar approach to that in the linked question and can now send `mousedown` and `mouseup` events to the `td`s underneath my secondary `div`s. The problem is that these events don't trigger any selection at all. I need to know how to invoke selection that corresponds to the where the user starts and ends their click on the `td`s. – Vardarac Sep 29 '14 at 14:19

1 Answers1

0

I solved my problem by wrapping my td contents in spans with a labeling class, then adding position:relative and z-index:50 to my span CSS attributes (position attributes must be included for z-index to take effect). I added z-indexes lower than that of the spans to my highlighting-related divs. This allowed my users to select the text in the spans.

$(document).ready(function() {
  window.onresize = function() {
    $(".text-area").css({
      left: $(".alignment-text").first().offset().left,
      top: $(".alignment-text").first().offset().top,
      width: (function() {
        var widest = 0;
        $(".alignment-text").each(function(index, element) {
          if($(element).width() > widest) widest = $(element).width();
        });
        return widest;
      })(),
      height: (function() {
        return ($(".alignment-text").last().offset().top + $(".alignment-text").last().height()) - $(".alignment-text").first().offset().top
      })()
    });
  };
                        
  $(window).trigger("resize");
  
  $(".text-area").mouseenter(function() {
    $(".highlighter").css("opacity", ".5");
  });
  
  $(".text-area").mouseleave(function() {
    $(".highlighter").css("opacity", "0");
  });
  
  $(".alignment-text").mouseenter(function() {
    $(".text-area").trigger("mouseenter");
  });
  
  $(".alignment-text").mouseleave(function() {
    $(".text-area").trigger("mouseleave");
  });
  
  window.onmousemove = function(e) {
    $(".highlighter").css({
      left: function() {
        return e.pageX - $(".text-area").offset().left - $(".highlighter").width()/2
      }
    });
  };
});
                  
.alignment-text {
  position: relative;
  z-index: 2;
}

.alignment-text, .highlighter-spacer {
  font-family: Fixed, monospace;
}

.highlighter-spacer {
  opacity: 0;
}

.highlighter {
  height: 100%;
  position: absolute;
  background-color: blue;
  opacity: 0;
  transition: opacity .25s ease-in-out;
  -moz-transition: opacity .25s ease-in-out;
  -webkit-transition: opacity .25s ease-in-out;
  z-index: 3;
}

.text-area {
  z-index: 0;
  position: absolute;
  overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="text-area">
  <span class="highlighter">
    <span class="highlighter-spacer">A</span>
  </div>
</div>
<table>
  <tr>
    <th>Row name</th>
    <th>Text we need to see aligned!</th>
  </tr>
  <tr>
    <td>First row!</td>
    <td class="alignment-text">This is some text. It should line up at some point with the text beneath it.</td>
  </tr>
  <tr>
    <td>Second row!</td>
    <td class="alignment-text">Here's some more text. I hope it lines up okay.</td>
  </tr>
</table>

However, it also blocked mouse events on the divs since they were now positioned beneath the text. To solve this, I set event handlers for mouseenter and mouseleave on .td-contents to trigger their respective counterparts in the wrapper div .text-cell-area. Users can now both select text and see the alignment of the text between rows.

Vardarac
  • 563
  • 2
  • 17