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