mediawiki-skins-Citizen/resources/skins.citizen.scripts/tables.js

118 lines
3 KiB
JavaScript
Raw Normal View History

/**
* Set up scroll affordance for an overflowed element
* TODO: Move this out of tables when this is used by more stuff
*
* @param {HTMLElement} element
* @return {void}
*/
function setupOverflowState( element ) {
const initState = () => {
const updateState = () => {
const
containerWidth = element.parentNode.offsetWidth,
contentWidth = element.scrollWidth;
// Break if no horizontal overflow
if ( contentWidth <= containerWidth ) {
element.parentNode.classList.remove( 'citizen-overflow--left' );
element.parentNode.classList.remove( 'citizen-overflow--right' );
return;
}
const currentPosition = element.parentNode.scrollLeft;
if ( currentPosition <= 0 ) {
// At the start
element.parentNode.classList.remove( 'citizen-overflow--left' );
element.parentNode.classList.add( 'citizen-overflow--right' );
} else if ( currentPosition + containerWidth >= contentWidth ) {
// At the end
element.parentNode.classList.remove( 'citizen-overflow--right' );
element.parentNode.classList.add( 'citizen-overflow--left' );
} else {
// At the middle
element.parentNode.classList.add( 'citizen-overflow--left' );
element.parentNode.classList.add( 'citizen-overflow--right' );
}
};
updateState();
// Update state on element scroll
element.parentNode.addEventListener( 'scroll', () => {
window.requestAnimationFrame( updateState );
} );
};
initState();
// Listen for window resize
if ( window.ResizeObserver ) {
const overflowResizeObserver = new ResizeObserver( mw.util.debounce( 250, initState ) );
overflowResizeObserver.observe( element );
}
}
/**
* Wrap table in div container to make it scrollable without breaking layout
*
* @param {HTMLTableElement} table
* @return {void}
*/
function wrapTable( table ) {
const ignoredClasses = [
'citizen-table-nowrap',
'infobox'
];
const hasIgnoredClass = ( ignoreClass ) => table.classList.contains( ignoreClass );
// Return if table has one of the ignored classes
if ( ignoredClasses.some( hasIgnoredClass ) ) { return; }
const wrapper = document.createElement( 'div' );
// Some classes should be inherited from the table
// For example, float helper classes like floatleft and floatright
const inheritTableClass = () => {
const tableClasses = [
'floatleft',
'floatright'
];
tableClasses.forEach( ( tableClass ) => {
if ( table.classList.contains( tableClass ) ) {
wrapper.classList.add( tableClass );
table.classList.remove( tableClass );
}
} );
};
wrapper.classList.add( 'citizen-table-wrapper' );
inheritTableClass();
table.parentNode.insertBefore( wrapper, table );
wrapper.appendChild( table );
setupOverflowState( table );
}
/**
* @param {HTMLElement} bodyContent
* @return {void}
*/
function init( bodyContent ) {
if ( !bodyContent.querySelector( 'table' ) ) {
return;
}
const tables = bodyContent.querySelectorAll( 'table' );
tables.forEach( ( table ) => {
wrapTable( table );
} );
}
module.exports = {
init: init
};