From cd8d633985c2520f136a0e46bb0763e29c5be38a Mon Sep 17 00:00:00 2001 From: Andreas Haller Date: Thu, 19 Dec 2024 16:12:20 +0100 Subject: [PATCH] move swagger ui navigation to separate block --- blocks/swaggerui/swaggerui.css | 19 ----- blocks/swaggerui/swaggerui.js | 81 ++---------------- .../swaggeruinavigation.css | 14 ++++ .../swaggeruinavigation.js | 82 +++++++++++++++++++ scripts/component-list/component-list.js | 8 ++ 5 files changed, 112 insertions(+), 92 deletions(-) create mode 100644 blocks/swaggeruinavigation/swaggeruinavigation.css create mode 100644 blocks/swaggeruinavigation/swaggeruinavigation.js diff --git a/blocks/swaggerui/swaggerui.css b/blocks/swaggerui/swaggerui.css index eabe522..6972971 100755 --- a/blocks/swaggerui/swaggerui.css +++ b/blocks/swaggerui/swaggerui.css @@ -1,22 +1,3 @@ raqn-swaggerui .topbar { display: none; } - -raqn-swaggerui .swagger-ui-selection ul input { - transition: opacity 0.5s ease; - margin: auto 10px; -} - -raqn-swaggerui .swagger-ui-selection ul li.closed input { - opacity: 0; -} - -raqn-swaggerui .swagger-ui-selection ul ul { - max-height: 300px; - overflow-y: scroll; - transition: max-height 0.5s ease-out, opacity 0.5s ease-out; -} - -raqn-swaggerui .swagger-ui-selection ul li.closed ul { - height: 0; -} diff --git a/blocks/swaggerui/swaggerui.js b/blocks/swaggerui/swaggerui.js index 23136e0..ef2aedd 100755 --- a/blocks/swaggerui/swaggerui.js +++ b/blocks/swaggerui/swaggerui.js @@ -1,18 +1,12 @@ import ComponentBase from '../../scripts/component-base.js'; -const prefixPath = '/api-definitions'; +export const prefixPath = '/api-definitions'; +export const apiSwitchEvent = 'swaggerUI:apiSwitch'; export default class SwaggerUI extends ComponentBase { switchAPI(hash) { const currentEnvironment = hash.length > 0 ? hash.substring(1).replace(/--.+$/, '') : false; - this.querySelectorAll('.swagger-ui-selection > ul > li').forEach((item) => { - if(item.dataset.environment === currentEnvironment) { - item.classList.remove('closed'); - } else { - item.classList.add('closed'); - } - }); const currentAPI = currentEnvironment && (() => { const index = hash.indexOf('--'); return index !== -1 ? hash.substring(index + 2) : false; @@ -30,71 +24,12 @@ export default class SwaggerUI extends ComponentBase { } } - navigationClick(e, hash) { - e.preventDefault(); - if(!window.location.hash.startsWith(hash)) { - window.location.hash = hash; - this.switchAPI(hash); - } - } - - async generateAPISelection(selectionElement) { - const response = await fetch(`${prefixPath}/environments.json`); - const environments = await response.json(); - const environmentElements = await Promise.all(environments.map(async (environment) => { - const item = document.createElement('li'); - item.dataset.environment = environment.folder; - const anchor = document.createElement('a'); - const url = new URL(window.location.href); - url.hash = environment.folder; - anchor.addEventListener('click', (e) => this.navigationClick(e, url.hash)); - anchor.href = url.toString(); - anchor.textContent = environment.label; - item.appendChild(anchor); - const filter = document.createElement('input'); - filter.placeholder = 'Search'; - item.appendChild(filter); - const apiResponse = await fetch(`${prefixPath}/${environment.folder}/index.json`); - const apis = await apiResponse.json(); - const definitionsElement = document.createElement('ul'); - apis.sort((a, b) => a.label.localeCompare(b.label)).forEach((api) => { - const apiItem = document.createElement('li'); - const apiAnchor = document.createElement('a'); - const apiUrl = new URL(window.location.href); - apiUrl.hash = `${environment.folder}--${api.id}`; - apiAnchor.addEventListener('click', (e) => this.navigationClick(e, apiUrl.hash)); - apiAnchor.href = apiUrl.toString(); - apiAnchor.textContent = `${api.label}${api.version ? ` (${api.version})` : ''}`; - apiItem.appendChild(apiAnchor); - definitionsElement.appendChild(apiItem); - }); - item.appendChild(definitionsElement); - filter.addEventListener('input', () => { - definitionsElement.querySelectorAll('li').forEach((apiItem) => { - if (apiItem.textContent.toLowerCase().includes(filter.value.toLowerCase())) { - apiItem.style.display = 'block'; - } else { - apiItem.style.display = 'none'; - } - }); - }); - return item; - })); - const environmentsElement = selectionElement.querySelector(':scope > ul'); - environmentElements.forEach((option) => environmentsElement.appendChild(option)); - } - async loadAPIs(apiFilter) { - const selectionElement = this.querySelector('.swagger-ui-selection'); - if(apiFilter.length === 0) { - await this.generateAPISelection(selectionElement); - } - const hashes = apiFilter.length > 0 ? apiFilter : [window.location.hash]; hashes.forEach((hash) => { const wrapper = document.createElement('div'); wrapper.classList.add('swagger-ui-wrapper'); - this.insertBefore(wrapper, selectionElement.nextSibling); + this.append(wrapper); this.switchAPI(hash); }); @@ -103,15 +38,15 @@ export default class SwaggerUI extends ComponentBase { async init() { super.init(); + + document.addEventListener(apiSwitchEvent, (e) => this.switchAPI(e.detail.hash)); + const apiFilter = [...this.querySelectorAll('a')] .map((a) => new URL(a.href).hash) .filter((hash) => hash.length > 0 && hash.indexOf('--') > 0); - this.innerHTML = ` -
- -
`; - + this.innerHTML = ''; + const loadCSS = async (href) => new Promise((resolve, reject) => { const link = document.createElement('link'); link.rel = 'stylesheet'; diff --git a/blocks/swaggeruinavigation/swaggeruinavigation.css b/blocks/swaggeruinavigation/swaggeruinavigation.css new file mode 100644 index 0000000..994f23f --- /dev/null +++ b/blocks/swaggeruinavigation/swaggeruinavigation.css @@ -0,0 +1,14 @@ +raqn-swaggerui-navigation > input { + margin: auto 10px; +} + +raqn-swaggerui-navigation > ul { + height: calc(100vh - var(--header-height, 110px) - 250px); + overflow-y: auto; +} + +raqn-swaggerui-navigation > ul.closed { + height: 0; + padding: 0; + margin: 0; +} diff --git a/blocks/swaggeruinavigation/swaggeruinavigation.js b/blocks/swaggeruinavigation/swaggeruinavigation.js new file mode 100644 index 0000000..61a98eb --- /dev/null +++ b/blocks/swaggeruinavigation/swaggeruinavigation.js @@ -0,0 +1,82 @@ +import ComponentBase from '../../scripts/component-base.js'; +import { prefixPath, apiSwitchEvent } from '../swaggerui/swaggerui.js'; + +export default class SwaggerUINavigation extends ComponentBase { + + navigationClick(e, hash) { + e?.preventDefault(); + this.querySelectorAll(':scope > ul[data-environment]').forEach((item) => { + if(hash.startsWith(`#${item.dataset.environment}`)) { + item.classList.remove('closed'); + } else if(!item.classList.contains('closed')) { + item.classList.add('closed'); + } + }); + if(!window.location.hash.startsWith(hash)) { + window.location.hash = hash; + document.dispatchEvent(new CustomEvent(apiSwitchEvent, { detail: { hash } })); + } + } + + async generateAPISelection() { + const response = await fetch(`${prefixPath}/environments.json`); + const environments = await response.json(); + const environmentOptions = await Promise.all(environments.map(async (environment) => { + const item = document.createElement('option'); + item.textContent = environment.label; + item.value = environment.folder; + if(window.location.hash.startsWith(`#${environment.folder}`)) { + item.selected = true; + } + + const apiResponse = await fetch(`${prefixPath}/${environment.folder}/index.json`); + const apis = await apiResponse.json(); + const definitionsElement = document.createElement('ul'); + definitionsElement.dataset.environment = environment.folder; + apis.sort((a, b) => a.label.localeCompare(b.label)).forEach((api) => { + const apiItem = document.createElement('li'); + const apiAnchor = document.createElement('a'); + const apiUrl = new URL(window.location.href); + apiUrl.hash = `${environment.folder}--${api.id}`; + apiAnchor.addEventListener('click', (e) => this.navigationClick(e, apiUrl.hash)); + apiAnchor.href = apiUrl.toString(); + apiAnchor.textContent = `${api.label}${api.version ? ` (${api.version})` : ''}`; + apiItem.appendChild(apiAnchor); + definitionsElement.appendChild(apiItem); + }); + this.appendChild(definitionsElement); + return item; + })); + const environmentsSelect = this.querySelector(':scope > select[name="environment-selection"]'); + environmentOptions.forEach((option) => environmentsSelect.appendChild(option)); + + environmentsSelect.addEventListener('change', (event) => this.navigationClick(event, `#${event.target.value}`)); + this.navigationClick(null, `#${environmentsSelect.selectedOptions[0].value}`); + } + + async init() { + super.init(); + + this.innerHTML = ` + + + + + `; + + await this.generateAPISelection(); + const filter = this.querySelector(':scope > input'); + const allApis = this.querySelectorAll(':scope > ul[data-environment] > li'); + filter.addEventListener('input', () => { + allApis.forEach((apiItem) => { + if (apiItem.textContent.toLowerCase().includes(filter.value.toLowerCase())) { + apiItem.style.display = 'block'; + } else { + apiItem.style.display = 'none'; + } + }); + }); + + } + +} diff --git a/scripts/component-list/component-list.js b/scripts/component-list/component-list.js index 4223f99..dce3f33 100644 --- a/scripts/component-list/component-list.js +++ b/scripts/component-list/component-list.js @@ -317,6 +317,14 @@ export const componentList = { priority: 4, }, }, + swaggeruinavigation: { + tag: 'raqn-swaggerui-navigation', + method: 'replace', + module: { + path: '/blocks/swaggeruinavigation/swaggeruinavigation', + priority: 2, + }, + }, swaggerui: { tag: 'raqn-swaggerui', method: 'replace',