Newer
Older
Alex Pott
committed
/**
* @file
* Responsive table functionality.
*/
Lauri Eskola
committed
(function($, Drupal, window) {
Alex Pott
committed
/**
* 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
* The table element to initialize the responsive table on.
*/
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.
Lauri Eskola
committed
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.',
),
)
Alex Pott
committed
.on('click', $.proxy(this, 'eventhandlerToggleColumns'));
Lauri Eskola
committed
this.$table.before(
$('<div class="tableresponsive-toggle-columns"></div>').append(
this.$link,
),
);
Alex Pott
committed
// Attach a resize handler to the window.
$(window)
Lauri Eskola
committed
.on(
'resize.tableresponsive',
$.proxy(this, 'eventhandlerEvaluateColumnVisibility'),
)
Alex Pott
committed
.trigger('resize.tableresponsive');
}
/**
* Attach the tableResponsive function to {@link Drupal.behaviors}.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches tableResponsive functionality.
*/
Drupal.behaviors.tableResponsive = {
attach(context, settings) {
Lauri Eskola
committed
const $tables = $(context)
.find('table.responsive-enabled')
.once('tableresponsive');
if ($tables.length) {
const il = $tables.length;
for (let i = 0; i < il; i++) {
TableResponsive.tables.push(new TableResponsive($tables[i]));
}
}
},
};
Alex Pott
committed
/**
* Extend the TableResponsive function with a list of managed tables.
*/
Lauri Eskola
committed
$.extend(
TableResponsive,
/** @lends Drupal.TableResponsive */ {
/**
* Store all created instances.
*
* @type {Array.<Drupal.TableResponsive>}
*/
tables: [],
},
);
Alex Pott
committed
/**
* 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.
*/
Lauri Eskola
committed
$.extend(
TableResponsive.prototype,
/** @lends Drupal.TableResponsive# */ {
/**
* @param {jQuery.Event} e
* The event triggered.
*/
eventhandlerEvaluateColumnVisibility(e) {
const pegged = parseInt(this.$link.data('pegged'), 10);
const 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);
}
},
Alex Pott
committed
Lauri Eskola
committed
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
/**
* Toggle the visibility of columns based on their priority.
*
* Columns are classed with either 'priority-low' or 'priority-medium'.
*
* @param {jQuery.Event} e
* The event triggered.
*/
eventhandlerToggleColumns(e) {
e.preventDefault();
const self = this;
const $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) {
const $header = $(this);
const position = $header.prevAll('th').length;
self.$table.find('tbody tr').each(function() {
const $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);
Alex Pott
committed
});
Lauri Eskola
committed
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) {
const $cell = $(this);
const properties = $cell.attr('style').split(';');
const 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.
const match = /^display\s*:\s*none$/;
for (let i = 0; i < properties.length; i++) {
const prop = properties[i];
prop.trim();
// Find the display:none property and remove it.
const isDisplayNone = match.exec(prop);
if (isDisplayNone) {
continue;
}
newProps.push(prop);
Alex Pott
committed
}
Lauri Eskola
committed
// 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');
}
},
},
Lauri Eskola
committed
);
Alex Pott
committed
// Make the TableResponsive object available in the Drupal namespace.
Drupal.TableResponsive = TableResponsive;
Lauri Eskola
committed
})(jQuery, Drupal, window);