initTabGroup(panes) {
			if (typeof(panes) != 'object' || !('length' in panes) || panes.length === 0)
				return;

			const menu = E('ul', { 'class': 'cbi-tabmenu' });
			const group = panes[0].parentNode;
			const groupId = +group.getAttribute('data-tab-group');
			let selected = null;

			if (group.getAttribute('data-initialized') === 'true')
				return;

			for (let i = 0, pane; pane = panes[i]; i++) {
				const name = pane.getAttribute('data-tab');
				const title = pane.getAttribute('data-tab-title');
				const active = pane.getAttribute('data-tab-active') === 'true';

				menu.appendChild(E('li', {
					'style': this.isEmptyPane(pane) ? 'display:none' : null,
					'class': active ? 'cbi-tab' : 'cbi-tab-disabled',
					'data-tab': name
				}, E('a', {
					'href': '#',
					'click': this.switchTab.bind(this)
				}, title)));

				if (active)
					selected = i;
			}

			group.parentNode.insertBefore(menu, group);
			group.setAttribute('data-initialized', true);

			if (selected === null) {
				selected = this.getActiveTabId(panes[0]);

				if (selected < 0 || selected >= panes.length || this.isEmptyPane(panes[selected])) {
					for (let i = 0; i < panes.length; i++) {
						if (!this.isEmptyPane(panes[i])) {
							selected = i;
							break;
						}
					}
				}

				menu.childNodes[selected].classList.add('cbi-tab');
				menu.childNodes[selected].classList.remove('cbi-tab-disabled');
				panes[selected].setAttribute('data-tab-active', 'true');

				this.setActiveTabId(panes[selected], selected);
			}

			requestAnimationFrame(L.bind(pane => {
				pane.dispatchEvent(new CustomEvent('cbi-tab-active', {
					detail: { tab: pane.getAttribute('data-tab') }
				}));
			}, this, panes[selected]));

			this.updateTabs(group);
		}
Initializes a new tab group from the given tab pane collection.

This function cycles through the given tab pane DOM nodes, extracts
their tab IDs, titles and active states, renders a corresponding
tab menu and prepends it to the tab panes common parent DOM node.

The tab menu labels will be set to the value of the `data-tab-title`
attribute of each corresponding pane. The last pane with the
`data-tab-active` attribute set to `true` will be selected by default.

If no pane is marked as active, the first one will be preselected.

@instance
@memberof LuCI.ui.tabs
@param {Array<Node>|NodeList} panes
A collection of tab panes to build a tab group menu for. May be a
plain array of DOM nodes or a NodeList collection, such as the result
of a `querySelectorAll()` call or the `.childNodes` property of a
DOM node.