annotate core/misc/tableresponsive.es6.js @ 2:5311817fb629

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