table shiftSelectable

by construct_pylons

HTML

<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<table>
  <tr>
    <td>Alice</td>
  </tr>
  <tr>
    <td>Bob</td>
  </tr>
  <tr>
    <td>Charlie</td>
  </tr>
  <tr>
    <td>Dave</td>
  </tr>
  <tr>
    <td>Eve</td>
  </tr>
</table>

CSS

.ui-selected {
    background-color: #CC0;
}
tr {
    border: solid 1px #CC0;
    cursor: pointer;
}

JavaScript

// attach 'shiftSelectable' to jquery
(function($, _) {
  var augmentedSelectedCallback, methods;
  augmentedSelectedCallback = function(selected, $element, event, ui) {
    if ($element.length) {
      $element.addClass('ui-selected');
      // honor original "ui.selectable" callback with new selected element passed
      ui = _.extend({}, ui, {selected: $element.get(0)});
      _.isFunction(selected) && selected(event, ui);
    }
  };
  methods = {
    init: function(options) {
      var settings = _.extend({}, options),
          selected = settings.selected,
          unselected = settings.unselected,
          $lastSelected;
      settings.selected = function(event, ui) {
        var $selected = $(ui.selected),
            isShiftSelect = false;
        // enable shift+click if the user has clicked on something already 
        // OR has not deselected the last item clicked.
        if (event.shiftKey && $lastSelected) {
          // currently only supports elements that are siblings of each 
          // other, so lists made of tables are out right now.
          $selected.siblings('.ui-selectee').andSelf().each(function(){
            var $element = $(this);
            // To support click, then shift+click both up a list and down a list; turn
            // selection on when encountering either actions and off on the other one.
            if ($element.is($selected) || $element.is($lastSelected)) {
              isShiftSelect = !isShiftSelect;
              augmentedSelectedCallback(selected, $element, event, ui);
            } else if (isShiftSelect) {
              augmentedSelectedCallback(selected, $element, event, ui);
            }
          });
        // otherwise just treat click like a normal click, which can include 
        // shift+click with no previous click.
        } else {
          $lastSelected = $selected;
          // honor original "ui.selectable" callback
          _.isFunction(selected) && selected(event, ui);
        }        
  ...