2022-04-21 19:14:52 +00:00
|
|
|
/**
|
|
|
|
* ContentEditable MediaWiki Tabber node.
|
|
|
|
*
|
|
|
|
* @class
|
|
|
|
* @extends ve.ce.MWBlockExtensionNode
|
|
|
|
*
|
|
|
|
* @constructor
|
|
|
|
* @param {ve.dm.MWTabberNode} model Model to observe
|
|
|
|
* @param {Object} [config] Configuration options
|
|
|
|
*/
|
|
|
|
ve.ce.MWTabberNode = function VeCeMWTabberNode() {
|
|
|
|
// Parent constructor
|
|
|
|
ve.ce.MWTabberNode.super.apply( this, arguments );
|
|
|
|
|
2022-04-23 00:00:32 +00:00
|
|
|
this.renderHeader = OO.ui.debounce( this.renderHeader.bind( this ), 300 );
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2022-04-21 19:14:52 +00:00
|
|
|
// DOM changes
|
|
|
|
this.$element.addClass( 've-ce-mwTabberNode' );
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Inheritance */
|
|
|
|
|
|
|
|
OO.inheritClass( ve.ce.MWTabberNode, ve.ce.MWBlockExtensionNode );
|
|
|
|
|
|
|
|
/* Static Properties */
|
|
|
|
|
|
|
|
ve.ce.MWTabberNode.static.name = 'mwTabber';
|
|
|
|
|
|
|
|
ve.ce.MWTabberNode.static.tagName = 'div';
|
|
|
|
|
|
|
|
ve.ce.MWTabberNode.static.primaryCommandName = 'mwTabber';
|
|
|
|
|
2022-04-22 04:38:16 +00:00
|
|
|
/* Methods */
|
2023-07-05 21:51:24 +00:00
|
|
|
// eslint-disable-next-line no-var
|
|
|
|
var lastHeader;
|
2022-04-22 04:38:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ce.MWTabberNode.prototype.onSetup = function () {
|
2022-04-23 00:00:32 +00:00
|
|
|
// Parent method
|
|
|
|
ve.ce.MWTabberNode.super.prototype.onSetup.call( this );
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2023-07-05 21:43:41 +00:00
|
|
|
const tabber = this.$element[ 0 ];
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2022-04-23 00:00:32 +00:00
|
|
|
// Do not render header if it is already rendered
|
|
|
|
if (
|
|
|
|
tabber.firstElementChild &&
|
2022-04-22 04:38:16 +00:00
|
|
|
tabber.firstElementChild !== lastHeader &&
|
|
|
|
!tabber.classList.contains( 'tabber--live' ) &&
|
2022-04-23 00:00:32 +00:00
|
|
|
tabber.classList.contains( 'tabber' )
|
|
|
|
) {
|
|
|
|
this.renderHeader( tabber );
|
|
|
|
}
|
2022-04-22 04:38:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* HACK: Render a simple static tab header for preview
|
2022-04-23 00:00:32 +00:00
|
|
|
*
|
2022-04-22 04:38:16 +00:00
|
|
|
* Since it is only for preview it does not have to be fancy,
|
|
|
|
* just having the right HTML and CSS will be sufficient
|
2022-04-23 00:00:32 +00:00
|
|
|
*
|
|
|
|
* @param {HTMLElement} tabber
|
2022-04-22 04:38:16 +00:00
|
|
|
*/
|
|
|
|
ve.ce.MWTabberNode.prototype.renderHeader = function ( tabber ) {
|
2023-07-06 02:57:05 +00:00
|
|
|
const nestedTabbers = tabber.querySelectorAll( '.tabber__panel:first-child .tabber' );
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2023-07-06 02:57:05 +00:00
|
|
|
const renderSingleHeader = function ( element ) {
|
|
|
|
const
|
|
|
|
tabPanels = element.querySelectorAll( ':scope > .tabber__section > .tabber__panel' ),
|
|
|
|
header = element.querySelector( ':scope > .tabber__header' ),
|
|
|
|
tabList = document.createElement( 'nav' ),
|
|
|
|
indicator = document.createElement( 'div' ),
|
|
|
|
fragment = new DocumentFragment();
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2023-07-06 02:57:05 +00:00
|
|
|
Array.prototype.forEach.call( tabPanels, function ( tabPanel, index ) {
|
|
|
|
const tab = document.createElement( 'a' );
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2024-05-24 02:05:28 +00:00
|
|
|
tab.innerText = tabPanel.getAttribute( 'data-mw-tabber-title' );
|
2023-07-06 02:57:05 +00:00
|
|
|
tab.classList.add( 'tabber__tab' );
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2023-07-06 02:57:05 +00:00
|
|
|
// Make first tab active
|
|
|
|
if ( index === 0 ) {
|
|
|
|
tab.setAttribute( 'aria-selected', true );
|
|
|
|
}
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2023-07-06 02:57:05 +00:00
|
|
|
fragment.append( tab );
|
|
|
|
} );
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2023-07-06 02:57:05 +00:00
|
|
|
tabList.append( fragment );
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2023-07-06 02:57:05 +00:00
|
|
|
tabList.classList.add( 'tabber__tabs' );
|
|
|
|
indicator.classList.add( 'tabber__indicator' );
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2023-07-06 02:57:05 +00:00
|
|
|
header.append( tabList, indicator );
|
|
|
|
|
|
|
|
indicator.style.width = tabList.firstElementChild.offsetWidth + 'px';
|
|
|
|
|
|
|
|
element.classList.add( 'tabber--live' );
|
|
|
|
};
|
|
|
|
|
|
|
|
if ( nestedTabbers.length > 0 ) {
|
|
|
|
Array.prototype.forEach.call( nestedTabbers, function ( nestedTabber ) {
|
|
|
|
renderSingleHeader( nestedTabber );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
renderSingleHeader( tabber );
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2022-04-23 00:00:32 +00:00
|
|
|
lastHeader = tabber.firstElementChild;
|
|
|
|
};
|
2022-04-22 04:38:16 +00:00
|
|
|
|
2022-04-21 19:14:52 +00:00
|
|
|
/* Registration */
|
|
|
|
|
|
|
|
ve.ce.nodeFactory.register( ve.ce.MWTabberNode );
|