You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
6.8 KiB
195 lines
6.8 KiB
/** |
|
* @file |
|
* Responsive table functionality. |
|
*/ |
|
|
|
(function ($, Drupal, window) { |
|
/** |
|
* 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. |
|
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', this.eventhandlerToggleColumns.bind(this)); |
|
|
|
this.$table.before( |
|
$('<div class="tableresponsive-toggle-columns"></div>').append( |
|
this.$link, |
|
), |
|
); |
|
|
|
// Attach a resize handler to the window. |
|
$(window).on( |
|
'resize.tableresponsive', |
|
this.eventhandlerEvaluateColumnVisibility.bind(this), |
|
); |
|
} |
|
|
|
/** |
|
* Attach the tableResponsive function to {@link Drupal.behaviors}. |
|
* |
|
* @type {Drupal~behavior} |
|
* |
|
* @prop {Drupal~behaviorAttach} attach |
|
* Attaches tableResponsive functionality. |
|
*/ |
|
Drupal.behaviors.tableResponsive = { |
|
attach(context, settings) { |
|
once('tableresponsive', 'table.responsive-enabled', context).forEach( |
|
(table) => { |
|
TableResponsive.tables.push(new TableResponsive(table)); |
|
}, |
|
); |
|
if (TableResponsive.tables.length) { |
|
$(window).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 |
|
* 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(); |
|
this.$link[0].textContent = 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(); |
|
this.$link[0].textContent = 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 |
|
* 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); |
|
}); |
|
this.$link[0].textContent = this.hideText; |
|
this.$link.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); |
|
} |
|
// Return the rest of the style attribute values to the element. |
|
$cell.attr('style', newProps.join(';')); |
|
}); |
|
this.$link[0].textContent = this.showText; |
|
this.$link.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);
|
|
|