2023-04-30 23:54:31 +00:00
|
|
|
/**
|
|
|
|
* 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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-30 21:01:29 +00:00
|
|
|
/**
|
|
|
|
* Wrap table in div container to make it scrollable without breaking layout
|
2023-04-30 21:02:42 +00:00
|
|
|
*
|
2023-04-30 21:01:29 +00:00
|
|
|
* @param {HTMLTableElement} table
|
|
|
|
* @return {void}
|
|
|
|
*/
|
|
|
|
function wrapTable( table ) {
|
2023-05-01 07:08:08 +00:00
|
|
|
// TODO: Make this a config flag
|
2023-05-01 06:37:32 +00:00
|
|
|
const ignoredClasses = [
|
|
|
|
'citizen-table-nowrap',
|
|
|
|
'infobox'
|
|
|
|
];
|
|
|
|
|
|
|
|
const hasIgnoredClass = ( ignoreClass ) => table.classList.contains( ignoreClass );
|
|
|
|
|
|
|
|
// Return if table has one of the ignored classes
|
2023-05-01 06:38:27 +00:00
|
|
|
if ( ignoredClasses.some( hasIgnoredClass ) ) { return; }
|
2023-05-01 06:24:37 +00:00
|
|
|
|
|
|
|
const wrapper = document.createElement( 'div' );
|
|
|
|
|
|
|
|
// Some classes should be inherited from the table
|
|
|
|
// For example, float helper classes like floatleft and floatright
|
|
|
|
const inheritTableClass = () => {
|
2023-05-01 07:08:08 +00:00
|
|
|
// TODO: Make this a config flag
|
|
|
|
const inheritedClasses = [
|
2023-05-01 06:24:37 +00:00
|
|
|
'floatleft',
|
|
|
|
'floatright'
|
|
|
|
];
|
|
|
|
|
2023-05-01 07:08:08 +00:00
|
|
|
inheritedClasses.forEach( ( inheritedClass ) => {
|
|
|
|
if ( table.classList.contains( inheritedClass ) ) {
|
|
|
|
wrapper.classList.add( inheritedClass );
|
|
|
|
table.classList.remove( inheritedClass );
|
2023-05-01 06:24:37 +00:00
|
|
|
}
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
wrapper.classList.add( 'citizen-table-wrapper' );
|
|
|
|
inheritTableClass();
|
2023-04-30 21:01:29 +00:00
|
|
|
table.parentNode.insertBefore( wrapper, table );
|
|
|
|
wrapper.appendChild( table );
|
2023-04-30 23:54:31 +00:00
|
|
|
|
|
|
|
setupOverflowState( table );
|
2023-04-30 21:01:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {HTMLElement} bodyContent
|
|
|
|
* @return {void}
|
|
|
|
*/
|
|
|
|
function init( bodyContent ) {
|
|
|
|
if ( !bodyContent.querySelector( 'table' ) ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-04-30 23:54:31 +00:00
|
|
|
const tables = bodyContent.querySelectorAll( 'table' );
|
2023-04-30 21:01:29 +00:00
|
|
|
|
|
|
|
tables.forEach( ( table ) => {
|
|
|
|
wrapTable( table );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
init: init
|
|
|
|
};
|