UNPKG

openapi-explorer

Version:

OpenAPI Explorer - API viewer with dynamically generated components, documentation, and interaction console

774 lines (750 loc) 29.8 kB
"use strict"; exports.__esModule = true; exports.default = void 0; var _lit = require("lit"); var _fontStyles = _interopRequireDefault(require("./styles/font-styles.js")); var _inputStyles = _interopRequireDefault(require("./styles/input-styles.js")); var _schemaStyles = _interopRequireDefault(require("./styles/schema-styles.js")); var _flexStyles = _interopRequireDefault(require("./styles/flex-styles.js")); var _tableStyles = _interopRequireDefault(require("./styles/table-styles.js")); var _keyFrameStyles = _interopRequireDefault(require("./styles/key-frame-styles.js")); var _endpointStyles = _interopRequireDefault(require("./styles/endpoint-styles.js")); var _prismStyles = _interopRequireDefault(require("./styles/prism-styles.js")); var _tagInputStyles = _interopRequireDefault(require("./styles/tag-input-styles.js")); var _tabStyles = _interopRequireDefault(require("./styles/tab-styles.js")); var _navStyles = _interopRequireDefault(require("./styles/nav-styles.js")); var _infoStyles = _interopRequireDefault(require("./styles/info-styles.js")); var _advancedSearchStyles = _interopRequireDefault(require("./styles/advanced-search-styles.js")); var _mainBodyStyles = _interopRequireDefault(require("./styles/main-body-styles.js")); var _commonUtils = require("./utils/common-utils.js"); var _index = require("./languages/index.js"); var _specParser = _interopRequireDefault(require("./utils/spec-parser.js")); var _mainBodyTemplate = _interopRequireDefault(require("./templates/mainBodyTemplate.js")); var _apiRequestStyles = _interopRequireDefault(require("./styles/api-request-styles.js")); var _securitySchemeTemplate = require("./templates/security-scheme-template.js"); require("./components/syntax-highlighter.js"); require("./openapi-explorer-oauth-handler.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } // Styles class OpenApiExplorer extends _lit.LitElement { constructor() { super(); this.loading = true; const intersectionObserverOptions = { root: this.getRootNode().host, rootMargin: '-50px 0px -50px 0px', // when the element is visible 100px from bottom threshold: 0 }; this.isIntersectionObserverActive = true; if (typeof IntersectionObserver !== 'undefined') { this.intersectionObserver = new IntersectionObserver(entries => { this.onIntersect(entries); }, intersectionObserverOptions); } else { this.intersectionObserver = { disconnect() {}, observe() {} }; } } static get properties() { return { // Heading headingText: { type: String, attribute: 'heading-text' }, explorerLocation: { type: String, attribute: 'explorer-location' }, // Spec specUrl: { type: String, attribute: 'spec-url' }, // UI Layouts layout: { type: String }, collapsed: { type: Boolean, attribute: 'collapse', converter(value) { return value !== 'false' && value !== false; } }, operationsCollapsed: { type: Boolean }, componentsCollapsed: { type: Boolean }, defaultSchemaTab: { type: String, attribute: 'default-schema-tab' }, responseAreaHeight: { type: String, attribute: 'response-area-height' }, hideDefaults: { type: Boolean, attribute: 'hide-defaults', converter(value) { return value !== 'false' && value !== false; } }, // Schema Styles displaySchemaAsTree: { type: Boolean, attribute: 'tree', converter(value) { return value !== 'false' && value !== false; } }, schemaExpandLevel: { type: Number, attribute: 'schema-expand-level' }, // API Server serverUrl: { type: String, attribute: 'server-url' }, // Hide/Show Sections & Enable Disable actions hideInfo: { type: Boolean, attribute: 'hide-info', converter(value) { return value !== 'false' && value !== false; } }, hideAuthentication: { type: Boolean, attribute: 'hide-authentication', converter(value) { return value !== 'false' && value !== false; } }, hideExecution: { type: Boolean, attribute: 'hide-console', converter(value) { return value !== 'false' && value !== false; } }, includeNulls: { type: Boolean, attribute: 'display-nulls', converter(value) { return value !== 'false' && value !== false; } }, hideSearch: { type: Boolean, attribute: 'hide-search', converter(value) { return value !== 'false' && value !== false; } }, hideServerSelection: { type: Boolean, attribute: 'hide-server-selection', converter(value) { return value !== 'false' && value !== false; } }, hideComponents: { type: Boolean, attribute: 'hide-components', converter(value) { return value !== 'false' && value !== false; } }, // Main Colors and Font primaryColor: { type: String, attribute: 'primary-color' }, secondaryColor: { type: String, attribute: 'secondary-color' }, bgColor: { type: String, attribute: 'bg-color' }, bgHeaderColor: { type: String, attribute: 'header-bg-color' }, textColor: { type: String, attribute: 'text-color' }, headerColor: { type: String, attribute: 'header-color' }, // Nav Bar Colors navBgColor: { type: String, attribute: 'nav-bg-color' }, navTextColor: { type: String, attribute: 'nav-text-color' }, navHoverBgColor: { type: String, attribute: 'nav-hover-bg-color' }, navHoverTextColor: { type: String, attribute: 'nav-hover-text-color' }, usePathInNavBar: { type: Boolean, attribute: 'use-path-in-nav-bar', converter(value) { return value !== 'false' && value !== false; } }, // Fetch Options fetchCredentials: { type: String, attribute: 'fetch-credentials' }, // Filters matchPaths: { type: String, attribute: 'match-paths' }, // Internal Properties loading: { type: Boolean }, // indicates spec is being loaded showAdvancedSearchDialog: { type: Boolean }, advancedSearchMatches: { type: Object } }; } static finalizeStyles() { return [_fontStyles.default, _schemaStyles.default, _inputStyles.default, _flexStyles.default, _tableStyles.default, _keyFrameStyles.default, _endpointStyles.default, _prismStyles.default, _tabStyles.default, _navStyles.default, _infoStyles.default, _tagInputStyles.default, _advancedSearchStyles.default, _apiRequestStyles.default, _mainBodyStyles.default]; } // Startup connectedCallback() { super.connectedCallback(); this.handleResize = this.handleResize.bind(this); window.addEventListener('resize', this.handleResize); this.loading = true; const parent = this.parentElement; if (parent) { if (parent.offsetWidth === 0 && parent.style.width === '') { parent.style.width = '100vw'; } if (parent.offsetHeight === 0 && parent.style.height === '') { parent.style.height = '100vh'; } if (parent.tagName === 'BODY') { if (!parent.style.marginTop) { parent.style.marginTop = '0'; } if (!parent.style.marginRight) { parent.style.marginRight = '0'; } if (!parent.style.marginBottom) { parent.style.marginBottom = '0'; } if (!parent.style.marginLeft) { parent.style.marginLeft = '0'; } } } this.renderStyle = 'focused'; this.operationsCollapsed = this.collapsed; this.componentsCollapsed = this.collapsed; this.explorerLocation = this.explorerLocation || (0, _commonUtils.getCurrentElement)(); if (!this.defaultSchemaTab || !'body, model, form,'.includes(`${this.defaultSchemaTab},`)) { this.defaultSchemaTab = 'model'; } if (!this.schemaExpandLevel || this.schemaExpandLevel < 1) { this.schemaExpandLevel = 99999; } this.schemaHideReadOnly = ['post', 'put', 'patch', 'query'].join(','); this.schemaHideWriteOnly = true; if (!this.responseAreaHeight) { this.responseAreaHeight = '300px'; } if (!this.fetchCredentials || !'omit, same-origin, include,'.includes(`${this.fetchCredentials},`)) { this.fetchCredentials = ''; } if (!this.showAdvancedSearchDialog) { this.showAdvancedSearchDialog = false; } window.addEventListener('hashchange', () => { this.scrollTo((0, _commonUtils.getCurrentElement)()); }, true); this.handleResize(); } // Cleanup disconnectedCallback() { this.intersectionObserver.disconnect(); window.removeEventListener('resize', this.handleResize); super.disconnectedCallback(); } render() { return _mainBodyTemplate.default.call(this); } observeExpandedContent() { // Main Container const observeOverviewEls = this.shadowRoot.querySelectorAll('.observe-me'); observeOverviewEls.forEach(targetEl => { this.intersectionObserver.observe(targetEl); }); } handleResize() { const mediaQueryResult = window.matchMedia('(min-width: 768px)'); const newDisplay = mediaQueryResult.matches ? 'focused' : 'view'; if (this.renderStyle !== newDisplay) { this.renderStyle = newDisplay; this.requestUpdate(); } } attributeChangedCallback(name, oldVal, newVal) { if (name === 'spec-url') { if (oldVal !== newVal) { window.setTimeout(async () => { await this.loadSpec(newVal); // If the initial location is set, then attempt to scroll there if (this.explorerLocation) { this.scrollTo(this.explorerLocation); } }, 0); } } if (name === 'server-url' && newVal) { var _this$resolvedSpec; this.selectedServer = ((_this$resolvedSpec = this.resolvedSpec) === null || _this$resolvedSpec === void 0 ? void 0 : _this$resolvedSpec.servers.find(s => s.url === newVal || !newVal)) || { url: newVal, computedUrl: newVal }; } if (name === 'render-style') { if (newVal === 'read') { window.setTimeout(() => { this.observeExpandedContent(); }, 100); } else { this.intersectionObserver.disconnect(); } } if (name === 'explorer-location') { window.setTimeout(() => { this.scrollTo(newVal); }, 0); } if (name === 'collapsed') { this.operationsCollapsed = newVal; this.componentsCollapsed = newVal; } super.attributeChangedCallback(name, oldVal, newVal); } onSearchChange(e) { var _this$matchPaths; this.matchPaths = e.target.value; const expand = !!((_this$matchPaths = this.matchPaths) !== null && _this$matchPaths !== void 0 && _this$matchPaths.trim()); this.operationsCollapsed = !expand; this.componentsCollapsed = !expand; this.resolvedSpec.tags.forEach(tag => { tag.expanded = expand; }); this.resolvedSpec.components.forEach(component => { component.expanded = expand; }); this.requestUpdate(); } onClearSearch() { const searchEl = this.shadowRoot.getElementById('nav-bar-search'); searchEl.value = ''; this.matchPaths = ''; } async onShowSearchModalClicked() { this.showAdvancedSearchDialog = true; // wait for the dialog to render await (0, _commonUtils.sleep)(10); const inputEl = this.shadowRoot.getElementById('advanced-search-dialog-input'); if (inputEl) { inputEl.focus(); } } // Public Method async loadSpec(specUrlOrObject) { if (!specUrlOrObject) { return; } this.matchPaths = ''; try { var _spec$info; this.resolvedSpec = null; this.loading = true; this.loadingFailedError = null; const spec = await (0, _specParser.default)(specUrlOrObject, this.serverUrl); this.loading = false; if (spec === undefined || spec === null) { console.error('Unable to resolve the API spec. '); // eslint-disable-line no-console return; } (0, _index.initI18n)((_spec$info = spec.info) === null || _spec$info === void 0 ? void 0 : _spec$info['x-locale']); if (!this.serverUrl) { var _spec$servers$, _spec$servers$2; this.serverUrl = ((_spec$servers$ = spec.servers[0]) === null || _spec$servers$ === void 0 ? void 0 : _spec$servers$.computedUrl) || ((_spec$servers$2 = spec.servers[0]) === null || _spec$servers$2 === void 0 ? void 0 : _spec$servers$2.url); } this.selectedServer = spec.servers.find(s => s.url === this.serverUrl || !this.serverUrl) || spec.servers[0]; this.afterSpecParsedAndValidated(spec); } catch (err) { this.loading = false; this.loadingFailedError = err.message; this.resolvedSpec = null; console.error('OpenAPI Explorer: Unable to resolve the API spec..', err); // eslint-disable-line no-console } try { await _securitySchemeTemplate.checkForAuthToken.call(this); } catch (error) { // eslint-disable-next-line no-console console.error('Failed to check for authentication token', error); } } // Public Method async setAuthenticationConfiguration(apiKeyId, { token, clientId, clientSecret, redirectUri }) { const securityObj = this.resolvedSpec && this.resolvedSpec.securitySchemes.find(v => v.apiKeyId === apiKeyId); if (!securityObj) { throw Error('SecuritySchemeNotFound'); } let authorizationToken = token && token.replace(/^(Bearer|Basic)\s+/i, '').trim(); if (authorizationToken && securityObj.type && securityObj.type === 'http' && securityObj.scheme && securityObj.scheme.toLowerCase() === 'basic') { authorizationToken = `Basic ${btoa(authorizationToken)}`; } else if (authorizationToken && securityObj.scheme && securityObj.scheme.toLowerCase() === 'bearer') { authorizationToken = `Bearer ${authorizationToken}`; } securityObj.clientId = clientId && clientId.trim(); securityObj.clientSecret = clientSecret && clientSecret.trim(); securityObj.redirectUri = new URL(redirectUri && redirectUri.trim() || '', window.location.href).toString(); securityObj.finalKeyValue = authorizationToken; await _securitySchemeTemplate.checkForAuthToken.call(this); this.requestUpdate(); } afterSpecParsedAndValidated(spec) { this.resolvedSpec = spec; if (this.operationsCollapsed) { this.resolvedSpec.tags.forEach(t => t.expanded = false); } if (this.componentsCollapsed) { this.resolvedSpec.components.forEach(c => c.expanded = false); } this.dispatchEvent(new CustomEvent('spec-loaded', { bubbles: true, detail: spec })); this.requestUpdate(); // Initiate IntersectionObserver and put it at the end of event loop, to allow loading all the child elements (must for larger specs) this.intersectionObserver.disconnect(); if (this.renderStyle === 'focused') { const defaultElementId = !this.hideInfo ? 'overview' : this.resolvedSpec.tags && this.resolvedSpec.tags[0] && this.resolvedSpec.tags[0].paths[0]; this.scrollTo(this.explorerLocation || defaultElementId); } if (this.renderStyle === 'view' && this.explorerLocation) { this.expandAndGotoOperation(this.explorerLocation); } } expandAndGotoOperation(elementId) { var _tag$paths; // Expand full operation and tag let isExpandingNeeded = false; const tag = this.resolvedSpec.tags.find(t => t.paths && t.paths.find(p => p.elementId === elementId)); const path = tag === null || tag === void 0 ? void 0 : (_tag$paths = tag.paths) === null || _tag$paths === void 0 ? void 0 : _tag$paths.find(p => p.elementId === elementId); if (path && (!path.expanded || !tag.expanded)) { isExpandingNeeded = true; path.expanded = true; tag.expanded = true; this.requestUpdate(); } // requestUpdate() and delay required, else we cant find element because it won't exist immediately const tmpElementId = elementId.indexOf('#') === -1 ? elementId : elementId.substring(1); window.setTimeout(() => { const gotoEl = this.shadowRoot.getElementById(tmpElementId); if (gotoEl) { gotoEl.scrollIntoView({ behavior: 'auto', block: 'start' }); (0, _commonUtils.replaceState)(tmpElementId); } }, isExpandingNeeded ? 150 : 0); } onIntersect(entries) { if (this.isIntersectionObserverActive === false) { return; } entries.forEach(entry => { if (entry.isIntersecting && entry.intersectionRatio > 0) { const oldNavEl = this.shadowRoot.querySelector('.nav-bar-tag.active, .nav-bar-path.active, .nav-bar-info.active, .nav-bar-h1.active, .nav-bar-h2.active'); const newNavEl = this.shadowRoot.getElementById(`link-${entry.target.id}`); // Add active class in the new element if (newNavEl) { (0, _commonUtils.replaceState)(entry.target.id); newNavEl.scrollIntoView({ behavior: 'auto', block: 'center' }); newNavEl.classList.add('active'); } // Remove active class from previous element if (oldNavEl) { oldNavEl.classList.remove('active'); } } }); } // Called by anchor tags created using markdown handleHref(e) { if (e.target.tagName.toLowerCase() === 'a') { const anchor = e.target.getAttribute('href'); if (anchor && anchor.startsWith('#')) { const gotoEl = this.shadowRoot.getElementById(anchor.replace('#', '')); if (gotoEl) { gotoEl.scrollIntoView({ behavior: 'auto', block: 'start' }); } } } } /** * Called by * - onClick of Navigation Bar * - onClick of Advanced Search items * * Functionality: * 1. First deactivate IntersectionObserver * 2. Scroll to the element * 3. Activate IntersectionObserver (after little delay) * */ scrollToEventTarget(event, scrollNavItemToView = true) { const navEl = event.currentTarget; if (!navEl.dataset.contentId) { return; } this.isIntersectionObserverActive = false; this.scrollTo(navEl.dataset.contentId, scrollNavItemToView); setTimeout(() => { this.isIntersectionObserverActive = true; }, 300); } scrollToCustomNavSectionTarget(event, scrollNavItemToView = true) { const navEl = event.currentTarget; if (!navEl.dataset.contentId) { return; } const navSectionSlot = this.shadowRoot.querySelector('slot.custom-nav-section'); const assignedNodes = navSectionSlot === null || navSectionSlot === void 0 ? void 0 : navSectionSlot.assignedNodes(); // clicked child node could be multiple levels deep in a custom nav const hasChildNode = node => { return node === event.target || node.children && [...node.children].some(c => hasChildNode(c)); }; let repeatedElementIndex = assignedNodes && [].findIndex.call(assignedNodes, slot => hasChildNode(slot)); if (repeatedElementIndex === -1 && navEl.dataset.contentId.match(/^section--\d+/)) { repeatedElementIndex = Number(navEl.dataset.contentId.split('--')[1]) - 1; } this.isIntersectionObserverActive = false; this.scrollTo(navEl.dataset.contentId, scrollNavItemToView, repeatedElementIndex); setTimeout(() => { this.isIntersectionObserverActive = true; }, 300); } async scrollToSchemaComponentByName(schemaComponentNameEvent) { var _this$resolvedSpec2, _this$resolvedSpec2$c, _this$resolvedSpec2$c2, _this$resolvedSpec2$c3; const schemaComponentName = schemaComponentNameEvent.detail; const schemaComponent = (_this$resolvedSpec2 = this.resolvedSpec) === null || _this$resolvedSpec2 === void 0 ? void 0 : (_this$resolvedSpec2$c = _this$resolvedSpec2.components) === null || _this$resolvedSpec2$c === void 0 ? void 0 : (_this$resolvedSpec2$c2 = _this$resolvedSpec2$c.find(c => c.componentKeyId === 'schemas')) === null || _this$resolvedSpec2$c2 === void 0 ? void 0 : (_this$resolvedSpec2$c3 = _this$resolvedSpec2$c2.subComponents) === null || _this$resolvedSpec2$c3 === void 0 ? void 0 : _this$resolvedSpec2$c3.find(s => s.name === schemaComponentName); if (schemaComponent) { await this.scrollTo(`cmp--${schemaComponent.id}`, true); } } // Public Method (scrolls to a given path and highlights the left-nav selection) async scrollTo(elementId, scrollNavItemToView = true, repeatedElementIndex) { try { await this.scrollToOrThrowException(elementId, scrollNavItemToView, repeatedElementIndex); } catch (error) { // There's an issue for lit elements for some browsers which are causing this issue we'll log here and still throw console.error('Failed to scroll to target', elementId, scrollNavItemToView, repeatedElementIndex, error); // eslint-disable-line no-console throw error; } } async scrollToOrThrowException(elementId, scrollNavItemToView = true, forcedRepeatedElementIndex) { if (!this.resolvedSpec) { return; } this.emitOperationChangedEvent(elementId); if (this.renderStyle === 'view') { this.expandAndGotoOperation(elementId); return; } // explorerLocation will get validated in the focused-endpoint-template this.explorerLocation = elementId; const tagFoundByPath = this.resolvedSpec.tags.find(t => t.paths.some(p => p.elementId === elementId)); if (tagFoundByPath) { tagFoundByPath.expanded = true; } // Convert to Async and to the background, so that we can be sure that the operation has been expanded and put into view before trying to directly scroll to it (or it won't be found in the next line and even if it is, it might not be able to be scrolled into view) await (0, _commonUtils.sleep)(0); // In the case of section scrolling, these are hard swaps, so just load "section". In the case of `tags` the headers have the element html Id in the last `--id`, so split that off and check for it // NOTE: Really this whole nonsense is because Marked, inserts -- between the prefix and the type and we cannot control it at all. When upgrading to Node 20, marked 16+, we will have to change this and we might even be able to make it work correctly. The biggest problem is that both the separator `--` and invalid character replacement `-`, can stack up. const contentEl = this.shadowRoot.getElementById(elementId !== null && elementId !== void 0 && elementId.startsWith('section') ? 'section' : elementId) // Remove the prefix of the section as headers in sub sections are not prefixed with the type. || elementId.split('--').length > 1 && this.shadowRoot.getElementById(elementId.split('--').slice(1).join('--')) // Remove the prefix of the operation (tag--) and the tag name (tag--NAME--) from header, as headers in sub sections are not prefixed with the type. || elementId.split('--').length > 2 && this.shadowRoot.getElementById(elementId.split('--').slice(2).join('--')) || this.shadowRoot.getElementById(elementId.split('--').slice(-1)[0]); if (!contentEl) { return; } // For focused APIs, always scroll to the top of the component let newNavEl; let waitForComponentToExpand = false; const elementIndex = forcedRepeatedElementIndex || forcedRepeatedElementIndex === 0 ? forcedRepeatedElementIndex : Number(elementId.split('--')[1]) - 1; if (elementId.match(/^section/)) { const customSections = this.shadowRoot.querySelector('slot.custom-section'); const assignedNodesToCustomSections = customSections === null || customSections === void 0 ? void 0 : customSections.assignedNodes(); if (assignedNodesToCustomSections) { try { assignedNodesToCustomSections.map(customSection => { customSection.classList.remove('active'); }); const newActiveCustomSection = assignedNodesToCustomSections[elementIndex]; if (newActiveCustomSection && !newActiveCustomSection.classList.contains('active')) { newActiveCustomSection.classList.add('active'); } } catch (error) { // eslint-disable-next-line no-console console.error('Failed to switch between custom sections, usually happens because the DOM is not ready and has not loaded these sections yet.', error); } } const navSectionSlot = this.shadowRoot.querySelector('slot.custom-nav-section'); const assignedNodes = navSectionSlot === null || navSectionSlot === void 0 ? void 0 : navSectionSlot.assignedNodes(); newNavEl = assignedNodes === null || assignedNodes === void 0 ? void 0 : assignedNodes[elementIndex]; // Update Location Hash (0, _commonUtils.replaceState)(`section--${elementIndex + 1}`); } else if (elementId.match('cmp--')) { const component = this.resolvedSpec.components.find(c => c.subComponents.find(sub => elementId.includes(sub.id))); if (component && !component.expanded) { waitForComponentToExpand = true; component.expanded = true; } contentEl.scrollIntoView({ behavior: 'auto', block: 'start' }); // Update Location Hash (0, _commonUtils.replaceState)(elementId); newNavEl = this.shadowRoot.getElementById(`link-${elementId}`); } else if (elementId.match('cmp--') || elementId.match('tag--') || elementId.match('overview--') || elementId.match('auth--') || elementId.match('servers--')) { contentEl.scrollIntoView({ behavior: 'auto', block: 'start' }); // Update Location Hash (0, _commonUtils.replaceState)(elementId); newNavEl = this.shadowRoot.getElementById(`link-${elementId}`); } else { this.shadowRoot.getElementById('operations-root').scrollIntoView({ behavior: 'auto', block: 'start' }); // Update Location Hash (0, _commonUtils.replaceState)(elementId); newNavEl = this.shadowRoot.getElementById(`link-${elementId}`); } // for focused style it is important to reset request-body-selection and response selection which maintains the state for in case of multiple req-body or multiple response mime-type const requestEl = this.shadowRoot.querySelector('api-request'); if (requestEl) { requestEl.resetRequestBodySelection(); } const responseEl = this.shadowRoot.querySelector('api-response'); if (responseEl) { responseEl.resetSelection(); } // Update NavBar View and Styles if (!newNavEl) { return; } if (scrollNavItemToView) { newNavEl.scrollIntoView({ behavior: 'auto', block: 'center' }); // Also force it into view again if for some reason it isn't there if (waitForComponentToExpand) { setTimeout(() => newNavEl.scrollIntoView({ behavior: 'auto', block: 'center' }), 600); } } await (0, _commonUtils.sleep)(0); const oldNavEl = this.shadowRoot.querySelector('.nav-bar-tag.active, .nav-bar-path.active, .nav-bar-info.active, .nav-bar-h1.active, .nav-bar-h2.active'); if (oldNavEl) { oldNavEl.classList.remove('active'); } const navSectionSlot = this.shadowRoot.querySelector('slot.custom-nav-section'); const assignedNodes = navSectionSlot === null || navSectionSlot === void 0 ? void 0 : navSectionSlot.assignedNodes(); (assignedNodes || []).filter((n, nodeIndex) => isNaN(elementIndex) || nodeIndex !== elementIndex).forEach(node => { node.classList.remove('active'); }); newNavEl.classList.add('active'); // must add the class after scrolling this.requestUpdate(); } // Event handler for Advanced Search text-inputs and checkboxes onAdvancedSearch(ev) { const eventTargetEl = ev.target; clearTimeout(this.timeoutId); this.timeoutId = setTimeout(() => { let searchInputEl; if (eventTargetEl.type === 'text') { searchInputEl = eventTargetEl; } else { searchInputEl = eventTargetEl.closest('.advanced-search-options').querySelector('input[type=text]'); } const searchOptions = [...eventTargetEl.closest('.advanced-search-options').querySelectorAll('input:checked')].map(v => v.id); this.advancedSearchMatches = (0, _commonUtils.advancedSearch)(searchInputEl.value, this.resolvedSpec.tags, searchOptions); }, 0); } emitOperationChangedEvent(elementId) { const operation = this.resolvedSpec.tags.map(t => t.paths).flat(1).find(p => p.elementId === elementId); const event = { bubbles: true, composed: true, detail: { explorerLocation: elementId, operation, type: 'OperationChanged' } }; this.dispatchEvent(new CustomEvent('event', event)); } } exports.default = OpenApiExplorer; if (!customElements.get('openapi-explorer')) { customElements.define('openapi-explorer', OpenApiExplorer); }