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