(function ($, Drupal, displace) { "use strict"; /** * Attaches sticky table headers. */ Drupal.behaviors.tableHeader = { attach: function (context) { $(window).one('scroll.TableHeaderInit', {context: context}, tableHeaderInitHandler); } }; function scrollValue(position) { return document.documentElement[position] || document.body[position]; } // Select and initialize sticky table headers. function tableHeaderInitHandler(e) { var $tables = $(e.data.context).find('table.sticky-enabled').once('tableheader'); for (var i = 0, il = $tables.length; i < il; i++) { TableHeader.tables.push(new TableHeader($tables[i])); } } // Helper method to loop through tables and execute a method. function forTables(method, arg) { var tables = TableHeader.tables; for (var i = 0, il = tables.length; i < il; i++) { tables[i][method](arg); } } function tableHeaderResizeHandler(e) { forTables('recalculateSticky'); } function tableHeaderOnScrollHandler(e) { forTables('onScroll'); } function tableHeaderOffsetChangeHandler(e, offsets) { forTables('stickyPosition', offsets.top); } // Bind event that need to change all tables. $(window).on({ /** * When resizing table width can change, recalculate everything. */ 'resize.TableHeader': tableHeaderResizeHandler, /** * Bind only one event to take care of calling all scroll callbacks. */ 'scroll.TableHeader': tableHeaderOnScrollHandler }); // Bind to custom Drupal events. $(document).on({ /** * Recalculate columns width when window is resized and when show/hide * weight is triggered. */ 'columnschange.TableHeader': tableHeaderResizeHandler, /** * Recalculate TableHeader.topOffset when viewport is resized */ 'drupalViewportOffsetChange.TableHeader': tableHeaderOffsetChangeHandler }); /** * Constructor for the tableHeader object. Provides sticky table headers. * * TableHeader will make the current table header stick to the top of the page * if the table is very long. * * @param table * DOM object for the table to add a sticky header to. * * @constructor */ function TableHeader(table) { var $table = $(table); this.$originalTable = $table; this.$originalHeader = $table.children('thead'); this.$originalHeaderCells = this.$originalHeader.find('> tr > th'); this.displayWeight = null; this.$originalTable.addClass('sticky-table'); this.tableHeight = $table[0].clientHeight; this.tableOffset = this.$originalTable.offset(); // React to columns change to avoid making checks in the scroll callback. this.$originalTable.on('columnschange', {tableHeader: this}, function (e, display) { var tableHeader = e.data.tableHeader; if (tableHeader.displayWeight === null || tableHeader.displayWeight !== display) { tableHeader.recalculateSticky(); } tableHeader.displayWeight = display; }); // Create and display sticky header. this.createSticky(); } /** * Store the state of TableHeader. */ $.extend(TableHeader, { /** * This will store the state of all processed tables. * * @type {Array} */ tables: [] }); /** * Extend TableHeader prototype. */ $.extend(TableHeader.prototype, { /** * Minimum height in pixels for the table to have a sticky header. */ minHeight: 100, /** * Absolute position of the table on the page. */ tableOffset: null, /** * Absolute position of the table on the page. */ tableHeight: null, /** * Boolean storing the sticky header visibility state. */ stickyVisible: false, /** * Create the duplicate header. */ createSticky: function () { // Clone the table header so it inherits original jQuery properties. var $stickyHeader = this.$originalHeader.clone(true); // Hide the table to avoid a flash of the header clone upon page load. this.$stickyTable = $('