mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2025-08-09 07:45:01 +02:00
Add a utility function to create tabs with lazy loading functionality
This commit is contained in:
@ -683,7 +683,7 @@ class ServiceContainer {
|
||||
* @param {string} tag
|
||||
* @param {object} attributes
|
||||
* @param {string | Array<string>} classes
|
||||
* @param {string | HTMLElement | Array<string | HTMLElement>}
|
||||
* @param {string | Node | Array<string | Node>}
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
function createElement(tagName, attributes, classes, textOrElements) {
|
||||
@ -699,7 +699,7 @@ function createElement(tagName, attributes, classes, textOrElements) {
|
||||
if (textOrElements) {
|
||||
const children = Array.isArray(textOrElements) ? textOrElements : [textOrElements]
|
||||
children.forEach(textOrElem => {
|
||||
if (textOrElem instanceof HTMLElement) {
|
||||
if (textOrElem instanceof Node) {
|
||||
element.appendChild(textOrElem)
|
||||
} else {
|
||||
element.appendChild(document.createTextNode(textOrElem))
|
||||
@ -708,3 +708,135 @@ function createElement(tagName, attributes, classes, textOrElements) {
|
||||
}
|
||||
return element
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} TabOpenDetails
|
||||
* @property {HTMLElement} contentElement
|
||||
* @property {HTMLElement} labelElement
|
||||
* @property {number} timesOpened
|
||||
* @property {boolean} firstOpen
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} CreateTabRequest
|
||||
* @property {string} id
|
||||
* @property {string | Node | (() => (string | Node))} label
|
||||
* Label text or an HTML element
|
||||
* @property {string} icon
|
||||
* @property {string | Node | Promise<string | Node> | (() => (string | Node | Promise<string | Node>)) | undefined} content
|
||||
* HTML string or HTML element
|
||||
* @property {((TabOpenDetails, Event) => (undefined | string | Node | Promise<string | Node>)) | undefined} onOpen
|
||||
* If an HTML string or HTML element is returned, then that will replace the tab content
|
||||
* @property {string | undefined} css
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {CreateTabRequest} request
|
||||
*/
|
||||
function createTab(request) {
|
||||
if (!request?.id) {
|
||||
console.error('createTab() error - id is required', Error().stack)
|
||||
return
|
||||
}
|
||||
|
||||
if (!request.label) {
|
||||
console.error('createTab() error - label is required', Error().stack)
|
||||
return
|
||||
}
|
||||
|
||||
if (!request.icon) {
|
||||
console.error('createTab() error - icon is required', Error().stack)
|
||||
return
|
||||
}
|
||||
|
||||
if (!request.content && !request.onOpen) {
|
||||
console.error('createTab() error - content or onOpen required', Error().stack)
|
||||
return
|
||||
}
|
||||
|
||||
const tabsContainer = document.querySelector('.tab-container')
|
||||
if (!tabsContainer) {
|
||||
return
|
||||
}
|
||||
|
||||
const tabsContentWrapper = document.querySelector('#tab-content-wrapper')
|
||||
if (!tabsContentWrapper) {
|
||||
return
|
||||
}
|
||||
|
||||
console.debug('creating tab: ', request)
|
||||
|
||||
if (request.css) {
|
||||
document.querySelector('body').insertAdjacentElement(
|
||||
'beforeend',
|
||||
createElement('style', { id: `tab-${request.id}-css` }, undefined, request.css),
|
||||
)
|
||||
}
|
||||
|
||||
const label = typeof request.label === 'function' ? request.label() : request.label
|
||||
const labelElement = label instanceof Node ? label : createElement('span', undefined, undefined, label)
|
||||
|
||||
const tab = createElement(
|
||||
'span',
|
||||
{ id: `tab-${request.id}`, 'data-times-opened': 0 },
|
||||
['tab'],
|
||||
createElement(
|
||||
'span',
|
||||
undefined,
|
||||
undefined,
|
||||
[
|
||||
createElement(
|
||||
'i',
|
||||
{ style: 'margin-right: 0.25em' },
|
||||
['fa-solid', `${request.icon.startsWith('fa-') ? '' : 'fa-'}${request.icon}`, 'icon'],
|
||||
),
|
||||
labelElement,
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
tabsContainer.insertAdjacentElement('beforeend', tab)
|
||||
|
||||
const wrapper = createElement('div', { id: request.id }, ['tab-content-inner'], 'Loading..')
|
||||
|
||||
const tabContent = createElement('div', { id: `tab-content-${request.id}` }, ['tab-content'], wrapper)
|
||||
tabsContentWrapper.insertAdjacentElement('beforeend', tabContent)
|
||||
|
||||
linkTabContents(tab)
|
||||
|
||||
function replaceContent(resultFactory) {
|
||||
if (resultFactory === undefined || resultFactory === null) {
|
||||
return
|
||||
}
|
||||
const result = typeof resultFactory === 'function' ? resultFactory() : resultFactory
|
||||
if (result instanceof Promise) {
|
||||
result.then(replaceContent)
|
||||
} else if (result instanceof Node) {
|
||||
wrapper.replaceChildren(result)
|
||||
} else {
|
||||
wrapper.innerHTML = result
|
||||
}
|
||||
}
|
||||
|
||||
replaceContent(request.content)
|
||||
|
||||
tab.addEventListener('click', (e) => {
|
||||
const timesOpened = +(tab.dataset.timesOpened || 0) + 1
|
||||
tab.dataset.timesOpened = timesOpened
|
||||
|
||||
if (request.onOpen) {
|
||||
const result = request.onOpen(
|
||||
{
|
||||
contentElement: wrapper,
|
||||
labelElement,
|
||||
timesOpened,
|
||||
firstOpen: timesOpened === 1,
|
||||
},
|
||||
e,
|
||||
)
|
||||
|
||||
replaceContent(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user