3 * Responsive table functionality.
6 (function ($, Drupal, window) {
11 * Attach the tableResponsive function to {@link Drupal.behaviors}.
13 * @type {Drupal~behavior}
15 * @prop {Drupal~behaviorAttach} attach
16 * Attaches tableResponsive functionality.
18 Drupal.behaviors.tableResponsive = {
19 attach: function (context, settings) {
20 var $tables = $(context).find('table.responsive-enabled').once('tableresponsive');
22 var il = $tables.length;
23 for (var i = 0; i < il; i++) {
24 TableResponsive.tables.push(new TableResponsive($tables[i]));
31 * The TableResponsive object optimizes table presentation for screen size.
33 * A responsive table hides columns at small screen sizes, leaving the most
34 * important columns visible to the end user. Users should not be prevented
35 * from accessing all columns, however. This class adds a toggle to a table
36 * with hidden columns that exposes the columns. Exposing the columns will
37 * likely break layouts, but it provides the user with a means to access
38 * data, which is a guiding principle of responsive design.
40 * @constructor Drupal.TableResponsive
42 * @param {HTMLElement} table
43 * The table element to initialize the responsive table on.
45 function TableResponsive(table) {
47 this.$table = $(table);
48 this.showText = Drupal.t('Show all columns');
49 this.hideText = Drupal.t('Hide lower priority columns');
50 // Store a reference to the header elements of the table so that the DOM is
51 // traversed only once to find them.
52 this.$headers = this.$table.find('th');
53 // Add a link before the table for users to show or hide weight columns.
54 this.$link = $('<button type="button" class="link tableresponsive-toggle"></button>')
55 .attr('title', Drupal.t('Show table cells that were hidden to make the table fit within a small screen.'))
56 .on('click', $.proxy(this, 'eventhandlerToggleColumns'));
58 this.$table.before($('<div class="tableresponsive-toggle-columns"></div>').append(this.$link));
60 // Attach a resize handler to the window.
62 .on('resize.tableresponsive', $.proxy(this, 'eventhandlerEvaluateColumnVisibility'))
63 .trigger('resize.tableresponsive');
67 * Extend the TableResponsive function with a list of managed tables.
69 $.extend(TableResponsive, /** @lends Drupal.TableResponsive */{
72 * Store all created instances.
74 * @type {Array.<Drupal.TableResponsive>}
80 * Associates an action link with the table that will show hidden columns.
82 * Columns are assumed to be hidden if their header has the class priority-low
85 $.extend(TableResponsive.prototype, /** @lends Drupal.TableResponsive# */{
88 * @param {jQuery.Event} e
89 * The event triggered.
91 eventhandlerEvaluateColumnVisibility: function (e) {
92 var pegged = parseInt(this.$link.data('pegged'), 10);
93 var hiddenLength = this.$headers.filter('.priority-medium:hidden, .priority-low:hidden').length;
94 // If the table has hidden columns, associate an action link with the
95 // table to show the columns.
96 if (hiddenLength > 0) {
97 this.$link.show().text(this.showText);
99 // When the toggle is pegged, its presence is maintained because the user
100 // has interacted with it. This is necessary to keep the link visible if
101 // the user adjusts screen size and changes the visibility of columns.
102 if (!pegged && hiddenLength === 0) {
103 this.$link.hide().text(this.hideText);
108 * Toggle the visibility of columns based on their priority.
110 * Columns are classed with either 'priority-low' or 'priority-medium'.
112 * @param {jQuery.Event} e
113 * The event triggered.
115 eventhandlerToggleColumns: function (e) {
118 var $hiddenHeaders = this.$headers.filter('.priority-medium:hidden, .priority-low:hidden');
119 this.$revealedCells = this.$revealedCells || $();
120 // Reveal hidden columns.
121 if ($hiddenHeaders.length > 0) {
122 $hiddenHeaders.each(function (index, element) {
123 var $header = $(this);
124 var position = $header.prevAll('th').length;
125 self.$table.find('tbody tr').each(function () {
126 var $cells = $(this).find('td').eq(position);
128 // Keep track of the revealed cells, so they can be hidden later.
129 self.$revealedCells = $().add(self.$revealedCells).add($cells);
132 // Keep track of the revealed headers, so they can be hidden later.
133 self.$revealedCells = $().add(self.$revealedCells).add($header);
135 this.$link.text(this.hideText).data('pegged', 1);
137 // Hide revealed columns.
139 this.$revealedCells.hide();
140 // Strip the 'display:none' declaration from the style attributes of
141 // the table cells that .hide() added.
142 this.$revealedCells.each(function (index, element) {
144 var properties = $cell.attr('style').split(';');
146 // The hide method adds display none to the element. The element
147 // should be returned to the same state it was in before the columns
148 // were revealed, so it is necessary to remove the display none value
149 // from the style attribute.
150 var match = /^display\s*\:\s*none$/;
151 for (var i = 0; i < properties.length; i++) {
152 var prop = properties[i];
154 // Find the display:none property and remove it.
155 var isDisplayNone = match.exec(prop);
161 // Return the rest of the style attribute values to the element.
162 $cell.attr('style', newProps.join(';'));
164 this.$link.text(this.showText).data('pegged', 0);
165 // Refresh the toggle link.
166 $(window).trigger('resize.tableresponsive');
171 // Make the TableResponsive object available in the Drupal namespace.
172 Drupal.TableResponsive = TableResponsive;
174 })(jQuery, Drupal, window);