Upgraded drupal core with security updates
[yaffs-website] / web / core / misc / tableselect.js
1 /**
2  * @file
3  * Table select functionality.
4  */
5
6 (function ($, Drupal) {
7
8   'use strict';
9
10   /**
11    * Initialize tableSelects.
12    *
13    * @type {Drupal~behavior}
14    *
15    * @prop {Drupal~behaviorAttach} attach
16    *   Attaches tableSelect functionality.
17    */
18   Drupal.behaviors.tableSelect = {
19     attach: function (context, settings) {
20       // Select the inner-most table in case of nested tables.
21       $(context).find('th.select-all').closest('table').once('table-select').each(Drupal.tableSelect);
22     }
23   };
24
25   /**
26    * Callback used in {@link Drupal.behaviors.tableSelect}.
27    */
28   Drupal.tableSelect = function () {
29     // Do not add a "Select all" checkbox if there are no rows with checkboxes
30     // in the table.
31     if ($(this).find('td input[type="checkbox"]').length === 0) {
32       return;
33     }
34
35     // Keep track of the table, which checkbox is checked and alias the
36     // settings.
37     var table = this;
38     var checkboxes;
39     var lastChecked;
40     var $table = $(table);
41     var strings = {
42       selectAll: Drupal.t('Select all rows in this table'),
43       selectNone: Drupal.t('Deselect all rows in this table')
44     };
45     var updateSelectAll = function (state) {
46       // Update table's select-all checkbox (and sticky header's if available).
47       $table.prev('table.sticky-header').addBack().find('th.select-all input[type="checkbox"]').each(function () {
48         var $checkbox = $(this);
49         var stateChanged = $checkbox.prop('checked') !== state;
50
51         $checkbox.attr('title', state ? strings.selectNone : strings.selectAll);
52
53         /**
54          * @checkbox {HTMLElement}
55          */
56         if (stateChanged) {
57           $checkbox.prop('checked', state).trigger('change');
58         }
59       });
60     };
61
62     // Find all <th> with class select-all, and insert the check all checkbox.
63     $table.find('th.select-all').prepend($('<input type="checkbox" class="form-checkbox" />').attr('title', strings.selectAll)).on('click', function (event) {
64       if ($(event.target).is('input[type="checkbox"]')) {
65         // Loop through all checkboxes and set their state to the select all
66         // checkbox' state.
67         checkboxes.each(function () {
68           var $checkbox = $(this);
69           var stateChanged = $checkbox.prop('checked') !== event.target.checked;
70
71           /**
72            * @checkbox {HTMLElement}
73            */
74           if (stateChanged) {
75             $checkbox.prop('checked', event.target.checked).trigger('change');
76           }
77           // Either add or remove the selected class based on the state of the
78           // check all checkbox.
79
80           /**
81            * @checkbox {HTMLElement}
82            */
83           $checkbox.closest('tr').toggleClass('selected', this.checked);
84         });
85         // Update the title and the state of the check all box.
86         updateSelectAll(event.target.checked);
87       }
88     });
89
90     // For each of the checkboxes within the table that are not disabled.
91     checkboxes = $table.find('td input[type="checkbox"]:enabled').on('click', function (e) {
92       // Either add or remove the selected class based on the state of the
93       // check all checkbox.
94
95       /**
96        * @this {HTMLElement}
97        */
98       $(this).closest('tr').toggleClass('selected', this.checked);
99
100       // If this is a shift click, we need to highlight everything in the
101       // range. Also make sure that we are actually checking checkboxes
102       // over a range and that a checkbox has been checked or unchecked before.
103       if (e.shiftKey && lastChecked && lastChecked !== e.target) {
104         // We use the checkbox's parent <tr> to do our range searching.
105         Drupal.tableSelectRange($(e.target).closest('tr')[0], $(lastChecked).closest('tr')[0], e.target.checked);
106       }
107
108       // If all checkboxes are checked, make sure the select-all one is checked
109       // too, otherwise keep unchecked.
110       updateSelectAll((checkboxes.length === checkboxes.filter(':checked').length));
111
112       // Keep track of the last checked checkbox.
113       lastChecked = e.target;
114     });
115
116     // If all checkboxes are checked on page load, make sure the select-all one
117     // is checked too, otherwise keep unchecked.
118     updateSelectAll((checkboxes.length === checkboxes.filter(':checked').length));
119   };
120
121   /**
122    * @param {HTMLElement} from
123    *   The HTML element representing the "from" part of the range.
124    * @param {HTMLElement} to
125    *   The HTML element representing the "to" part of the range.
126    * @param {bool} state
127    *   The state to set on the range.
128    */
129   Drupal.tableSelectRange = function (from, to, state) {
130     // We determine the looping mode based on the order of from and to.
131     var mode = from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
132
133     // Traverse through the sibling nodes.
134     for (var i = from[mode]; i; i = i[mode]) {
135       var $i;
136       // Make sure that we're only dealing with elements.
137       if (i.nodeType !== 1) {
138         continue;
139       }
140       $i = $(i);
141       // Either add or remove the selected class based on the state of the
142       // target checkbox.
143       $i.toggleClass('selected', state);
144       $i.find('input[type="checkbox"]').prop('checked', state);
145
146       if (to.nodeType) {
147         // If we are at the end of the range, stop.
148         if (i === to) {
149           break;
150         }
151       }
152       // A faster alternative to doing $(i).filter(to).length.
153       else if ($.filter(to, [i]).r.length) {
154         break;
155       }
156     }
157   };
158
159 })(jQuery, Drupal);