Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
web/core/misc
329
web/core/misc/tableheader.es6.js
Normal file
329
web/core/misc/tableheader.es6.js
Normal file
|
@ -0,0 +1,329 @@
|
|||
/**
|
||||
* @file
|
||||
* Sticky table headers.
|
||||
*/
|
||||
|
||||
(function($, Drupal, displace) {
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @constructor Drupal.TableHeader
|
||||
*
|
||||
* @param {HTMLElement} table
|
||||
* DOM object for the table to add a sticky header to.
|
||||
*
|
||||
* @listens event:columnschange
|
||||
*/
|
||||
function TableHeader(table) {
|
||||
const $table = $(table);
|
||||
|
||||
/**
|
||||
* @name Drupal.TableHeader#$originalTable
|
||||
*
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
this.$originalTable = $table;
|
||||
|
||||
/**
|
||||
* @type {jQuery}
|
||||
*/
|
||||
this.$originalHeader = $table.children('thead');
|
||||
|
||||
/**
|
||||
* @type {jQuery}
|
||||
*/
|
||||
this.$originalHeaderCells = this.$originalHeader.find('> tr > th');
|
||||
|
||||
/**
|
||||
* @type {null|bool}
|
||||
*/
|
||||
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 },
|
||||
(e, display) => {
|
||||
const tableHeader = e.data.tableHeader;
|
||||
if (
|
||||
tableHeader.displayWeight === null ||
|
||||
tableHeader.displayWeight !== display
|
||||
) {
|
||||
tableHeader.recalculateSticky();
|
||||
}
|
||||
tableHeader.displayWeight = display;
|
||||
},
|
||||
);
|
||||
|
||||
// Create and display sticky header.
|
||||
this.createSticky();
|
||||
}
|
||||
|
||||
// Helper method to loop through tables and execute a method.
|
||||
function forTables(method, arg) {
|
||||
const tables = TableHeader.tables;
|
||||
const il = tables.length;
|
||||
for (let i = 0; i < il; i++) {
|
||||
tables[i][method](arg);
|
||||
}
|
||||
}
|
||||
|
||||
// Select and initialize sticky table headers.
|
||||
function tableHeaderInitHandler(e) {
|
||||
const $tables = $(e.data.context)
|
||||
.find('table.sticky-enabled')
|
||||
.once('tableheader');
|
||||
const il = $tables.length;
|
||||
for (let i = 0; i < il; i++) {
|
||||
TableHeader.tables.push(new TableHeader($tables[i]));
|
||||
}
|
||||
forTables('onScroll');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches sticky table headers.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the sticky table header behavior.
|
||||
*/
|
||||
Drupal.behaviors.tableHeader = {
|
||||
attach(context) {
|
||||
$(window).one(
|
||||
'scroll.TableHeaderInit',
|
||||
{ context },
|
||||
tableHeaderInitHandler,
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
function scrollValue(position) {
|
||||
return document.documentElement[position] || document.body[position];
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
'resize.TableHeader': tableHeaderResizeHandler,
|
||||
|
||||
/**
|
||||
* Bind only one event to take care of calling all scroll callbacks.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
'scroll.TableHeader': tableHeaderOnScrollHandler,
|
||||
});
|
||||
// Bind to custom Drupal events.
|
||||
$(document).on({
|
||||
/**
|
||||
* Recalculate columns width when window is resized and when show/hide
|
||||
* weight is triggered.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
'columnschange.TableHeader': tableHeaderResizeHandler,
|
||||
|
||||
/**
|
||||
* Recalculate TableHeader.topOffset when viewport is resized.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
'drupalViewportOffsetChange.TableHeader': tableHeaderOffsetChangeHandler,
|
||||
});
|
||||
|
||||
/**
|
||||
* Store the state of TableHeader.
|
||||
*/
|
||||
$.extend(
|
||||
TableHeader,
|
||||
/** @lends Drupal.TableHeader */ {
|
||||
/**
|
||||
* This will store the state of all processed tables.
|
||||
*
|
||||
* @type {Array.<Drupal.TableHeader>}
|
||||
*/
|
||||
tables: [],
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Extend TableHeader prototype.
|
||||
*/
|
||||
$.extend(
|
||||
TableHeader.prototype,
|
||||
/** @lends Drupal.TableHeader# */ {
|
||||
/**
|
||||
* Minimum height in pixels for the table to have a sticky header.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
minHeight: 100,
|
||||
|
||||
/**
|
||||
* Absolute position of the table on the page.
|
||||
*
|
||||
* @type {?Drupal~displaceOffset}
|
||||
*/
|
||||
tableOffset: null,
|
||||
|
||||
/**
|
||||
* Absolute position of the table on the page.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
tableHeight: null,
|
||||
|
||||
/**
|
||||
* Boolean storing the sticky header visibility state.
|
||||
*
|
||||
* @type {bool}
|
||||
*/
|
||||
stickyVisible: false,
|
||||
|
||||
/**
|
||||
* Create the duplicate header.
|
||||
*/
|
||||
createSticky() {
|
||||
// Clone the table header so it inherits original jQuery properties.
|
||||
const $stickyHeader = this.$originalHeader.clone(true);
|
||||
// Hide the table to avoid a flash of the header clone upon page load.
|
||||
this.$stickyTable = $('<table class="sticky-header"/>')
|
||||
.css({
|
||||
visibility: 'hidden',
|
||||
position: 'fixed',
|
||||
top: '0px',
|
||||
})
|
||||
.append($stickyHeader)
|
||||
.insertBefore(this.$originalTable);
|
||||
|
||||
this.$stickyHeaderCells = $stickyHeader.find('> tr > th');
|
||||
|
||||
// Initialize all computations.
|
||||
this.recalculateSticky();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set absolute position of sticky.
|
||||
*
|
||||
* @param {number} offsetTop
|
||||
* The top offset for the sticky header.
|
||||
* @param {number} offsetLeft
|
||||
* The left offset for the sticky header.
|
||||
*
|
||||
* @return {jQuery}
|
||||
* The sticky table as a jQuery collection.
|
||||
*/
|
||||
stickyPosition(offsetTop, offsetLeft) {
|
||||
const css = {};
|
||||
if (typeof offsetTop === 'number') {
|
||||
css.top = `${offsetTop}px`;
|
||||
}
|
||||
if (typeof offsetLeft === 'number') {
|
||||
css.left = `${this.tableOffset.left - offsetLeft}px`;
|
||||
}
|
||||
return this.$stickyTable.css(css);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if sticky is currently visible.
|
||||
*
|
||||
* @return {bool}
|
||||
* The visibility status.
|
||||
*/
|
||||
checkStickyVisible() {
|
||||
const scrollTop = scrollValue('scrollTop');
|
||||
const tableTop = this.tableOffset.top - displace.offsets.top;
|
||||
const tableBottom = tableTop + this.tableHeight;
|
||||
let visible = false;
|
||||
|
||||
if (tableTop < scrollTop && scrollTop < tableBottom - this.minHeight) {
|
||||
visible = true;
|
||||
}
|
||||
|
||||
this.stickyVisible = visible;
|
||||
return visible;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if sticky header should be displayed.
|
||||
*
|
||||
* This function is throttled to once every 250ms to avoid unnecessary
|
||||
* calls.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
* The scroll event.
|
||||
*/
|
||||
onScroll(e) {
|
||||
this.checkStickyVisible();
|
||||
// Track horizontal positioning relative to the viewport.
|
||||
this.stickyPosition(null, scrollValue('scrollLeft'));
|
||||
this.$stickyTable.css(
|
||||
'visibility',
|
||||
this.stickyVisible ? 'visible' : 'hidden',
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler: recalculates position of the sticky table header.
|
||||
*
|
||||
* @param {jQuery.Event} event
|
||||
* Event being triggered.
|
||||
*/
|
||||
recalculateSticky(event) {
|
||||
// Update table size.
|
||||
this.tableHeight = this.$originalTable[0].clientHeight;
|
||||
|
||||
// Update offset top.
|
||||
displace.offsets.top = displace.calculateOffset('top');
|
||||
this.tableOffset = this.$originalTable.offset();
|
||||
this.stickyPosition(displace.offsets.top, scrollValue('scrollLeft'));
|
||||
|
||||
// Update columns width.
|
||||
let $that = null;
|
||||
let $stickyCell = null;
|
||||
let display = null;
|
||||
// Resize header and its cell widths.
|
||||
// Only apply width to visible table cells. This prevents the header from
|
||||
// displaying incorrectly when the sticky header is no longer visible.
|
||||
const il = this.$originalHeaderCells.length;
|
||||
for (let i = 0; i < il; i++) {
|
||||
$that = $(this.$originalHeaderCells[i]);
|
||||
$stickyCell = this.$stickyHeaderCells.eq($that.index());
|
||||
display = $that.css('display');
|
||||
if (display !== 'none') {
|
||||
$stickyCell.css({ width: $that.css('width'), display });
|
||||
} else {
|
||||
$stickyCell.css('display', 'none');
|
||||
}
|
||||
}
|
||||
this.$stickyTable.css('width', this.$originalTable.outerWidth());
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Expose constructor in the public space.
|
||||
Drupal.TableHeader = TableHeader;
|
||||
})(jQuery, Drupal, window.parent.Drupal.displace);
|
Reference in a new issue