|
| 1 | +(function($) { |
| 2 | + /** |
| 3 | + * A jQuery plugin that lets you easily enhance data tables with selectable rows. |
| 4 | + * |
| 5 | + * |
| 6 | + * @author Marco Kerwitz <[email protected]> |
| 7 | + * @see https://github.com/kerwitz/jquery.tableCheckbox.js |
| 8 | + */ |
| 9 | + $.fn.tableCheckbox = function(options) { |
| 10 | + var _private = { |
| 11 | + /** |
| 12 | + * The configuration of this plugin. |
| 13 | + * |
| 14 | + * Overload with custom values when calling the plugin: |
| 15 | + * $('table').tableCheckbox({selectedRowClass: 'selected-row'}); |
| 16 | + * |
| 17 | + * @var object |
| 18 | + */ |
| 19 | + config: $.extend({ |
| 20 | + // The class that will be applied to selected rows. |
| 21 | + selectedRowClass: 'warning', |
| 22 | + // The selector used to find the checkboxes on the table. You may customize this in |
| 23 | + // order to match your table layout if it differs from the assumed one. |
| 24 | + checkboxSelector: 'td:first-of-type input[type="checkbox"],th:first-of-type input[type="checkbox"]', |
| 25 | + // A callback that is used to determine wether a checkbox is selected or not. |
| 26 | + isChecked: function($checkbox) { |
| 27 | + return $checkbox.is(':checked'); |
| 28 | + } |
| 29 | + }, options), |
| 30 | + /** |
| 31 | + * Variables used across multiple tables. |
| 32 | + * |
| 33 | + * @var object |
| 34 | + */ |
| 35 | + registry: { |
| 36 | + shiftKeyIsPressed: false |
| 37 | + }, |
| 38 | + helpers: { |
| 39 | + /** |
| 40 | + * Returns the selection methods available in the current browser. |
| 41 | + * |
| 42 | + * @author Grinn, http://stackoverflow.com/users/152648/grinn |
| 43 | + * @author Gert Grenander, http://stackoverflow.com/users/339850/gert-grenander |
| 44 | + * @see http://stackoverflow.com/questions/3169786/clear-text-selection-with-javascript |
| 45 | + */ |
| 46 | + selection: window.getSelection ? window.getSelection() : document.selection ? document.selection : null, |
| 47 | + /** |
| 48 | + * Removes any text selection the user made. |
| 49 | + * |
| 50 | + * @author Marco Kerwitz <[email protected]> |
| 51 | + */ |
| 52 | + removeTextSelection: function() { |
| 53 | + if (!!_private.helpers.selection) { |
| 54 | + _private.helpers.selection.empty |
| 55 | + ? _private.helpers.selection.empty() |
| 56 | + : _private.helpers.selection.removeAllRanges(); |
| 57 | + } |
| 58 | + }, |
| 59 | + /** |
| 60 | + * Returns wether or not a text selection currently exists. |
| 61 | + * |
| 62 | + * @author Marco Kerwitz <[email protected]> |
| 63 | + * @todo This will return false positives when the user selected text outside of |
| 64 | + * the table and then tries to select rows. |
| 65 | + * @return {boolean} |
| 66 | + */ |
| 67 | + hasSelection: function() { |
| 68 | + return !!_private.helpers.selection && _private.helpers.selection.toString().length; |
| 69 | + } |
| 70 | + } |
| 71 | + }; |
| 72 | + // Initiate a event callback that we can use to tell wether the user is pressing the shift |
| 73 | + // key or not. |
| 74 | + $(document).on('keydown.tsc keyup.tsc', function(e) { |
| 75 | + _private.registry.shiftKeyIsPressed = e.shiftKey; |
| 76 | + }); |
| 77 | + return this.each(function() { |
| 78 | + var $table = $(this), |
| 79 | + $headCheckbox = $table.find('thead tr ' + _private.config.checkboxSelector), |
| 80 | + $checkboxes = $table.find('tr ' + _private.config.checkboxSelector).not($headCheckbox), |
| 81 | + $lastRow = []; |
| 82 | + // Listen for changes on the checkbox in the table header and apply its current state |
| 83 | + // to all checkboxe on the table. |
| 84 | + $headCheckbox.on('change', function(e) { |
| 85 | + $checkboxes |
| 86 | + .prop('checked', _private.config.isChecked($headCheckbox)) |
| 87 | + .trigger('change'); |
| 88 | + }); |
| 89 | + // Cycle through each checkbox found on the table. |
| 90 | + $checkboxes.each(function() { |
| 91 | + var $checkbox = $(this), |
| 92 | + $row = $checkbox.parents('tr'); |
| 93 | + $checkbox.on('change', function(e, isInternal) { |
| 94 | + // When the user clicks directly on the rows he will unwillingly select |
| 95 | + // the text of all rows inbetween. Remove that selection immediately. |
| 96 | + _private.helpers.removeTextSelection(); |
| 97 | + if (!isInternal && _private.registry.shiftKeyIsPressed && $lastRow.length) { |
| 98 | + // User held shift key while clicking on this checkbox and clicked another one |
| 99 | + // prior. Get all checkboxes inbetween the two and check or uncheck them. |
| 100 | + $inbetween = ($lastRow.index() < $row.index()) |
| 101 | + ? $row.prevUntil($lastRow) |
| 102 | + : $row.nextUntil($lastRow); |
| 103 | + $inbetween.find(_private.config.checkboxSelector) |
| 104 | + .prop('checked', _private.config.isChecked($checkbox)) |
| 105 | + .trigger('change', [true]); |
| 106 | + } |
| 107 | + $lastRow = $row; |
| 108 | + $row.toggleClass(_private.config.selectedRowClass, _private.config.isChecked($checkbox)); |
| 109 | + }); |
| 110 | + // Monitor the row and check the checkbox accordingly. |
| 111 | + $row.on('click', function(e) { |
| 112 | + if (_private.helpers.hasSelection()) { |
| 113 | + // There was a text slection prior to this click. Chances are that the user |
| 114 | + // simply wants to clear that instead of selecting this row - so do nothing. |
| 115 | + return; |
| 116 | + } |
| 117 | + if ($.data($row, 'tc-timeout')) { |
| 118 | + // There was a timeout running from a previous click event, this seems to be |
| 119 | + // a double click. Cancel the first timeout before we create a new one. |
| 120 | + window.clearTimeout($.data($row, 'tc-timeout')); |
| 121 | + } |
| 122 | + // We use a short timeout to wait for double-click selections that the user might |
| 123 | + // have intended to make. If any selection is created withing this timespan we |
| 124 | + // wont do anything to not interfere with the users intentions too much. |
| 125 | + $.data($row, 'tc-timeout', window.setTimeout(function() { |
| 126 | + // Do nothing if the user selected text on the row. |
| 127 | + if (_private.helpers.hasSelection()) return; |
| 128 | + // Make sure the user did not click on any clickable content in the row. |
| 129 | + if (!$(e.target).is('a,input,button') && !$(e.target).parents('a,input,button').length) { |
| 130 | + $checkbox |
| 131 | + .prop('checked', !_private.config.isChecked($checkbox)) |
| 132 | + .trigger('change'); |
| 133 | + } |
| 134 | + }, 50)); |
| 135 | + }) |
| 136 | + }); |
| 137 | + }); |
| 138 | + }; |
| 139 | +}(jQuery)); |
0 commit comments