openapi-explorer 0.10.419 → 0.10.421
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/dist/browser/openapi-explorer.min.js +5 -5
- package/dist/browser/openapi-explorer.min.js.map +1 -1
- package/dist/es/components/api-request.js +5 -5
- package/dist/es/components/api-response.js +3 -3
- package/dist/es/components/json-tree.js +2 -2
- package/dist/es/components/schema-table.js +3 -3
- package/dist/es/components/schema-tree.js +3 -3
- package/dist/es/components/tag-input.js +2 -2
- package/dist/es/openapi-explorer.js +2 -2
- package/dist/es/styles/advanced-search-styles.js +1 -1
- package/dist/es/styles/api-request-styles.js +1 -1
- package/dist/es/styles/border-styles.js +1 -1
- package/dist/es/styles/endpoint-styles.js +1 -1
- package/dist/es/styles/flex-styles.js +1 -1
- package/dist/es/styles/font-styles.js +1 -1
- package/dist/es/styles/info-styles.js +1 -1
- package/dist/es/styles/input-styles.js +1 -1
- package/dist/es/styles/nav-styles.js +1 -1
- package/dist/es/styles/prism-styles.js +1 -1
- package/dist/es/styles/schema-styles.js +1 -1
- package/dist/es/styles/tab-styles.js +1 -1
- package/dist/es/styles/table-styles.js +1 -1
- package/dist/es/templates/advance-search-template.js +1 -1
- package/dist/es/templates/callback-template.js +1 -1
- package/dist/es/templates/code-samples-template.js +2 -2
- package/dist/es/templates/components-template.js +2 -2
- package/dist/es/templates/endpoint-template.js +2 -2
- package/dist/es/templates/expanded-endpoint-template.js +2 -2
- package/dist/es/templates/focused-endpoint-template.js +1 -1
- package/dist/es/templates/navbar-template.js +1 -1
- package/dist/es/templates/overview-template.js +2 -2
- package/dist/es/templates/responsiveViewMainBodyTemplate.js +1 -1
- package/dist/es/templates/security-scheme-template.js +2 -2
- package/dist/es/templates/server-template.js +2 -2
- package/dist/es/utils/schema-utils.js +42 -21
- package/dist/es/utils/theme.js +1 -1
- package/dist/lib/components/api-request.js +22 -22
- package/dist/lib/components/api-response.js +18 -18
- package/dist/lib/components/json-tree.js +9 -9
- package/dist/lib/components/schema-table.js +10 -10
- package/dist/lib/components/schema-tree.js +20 -20
- package/dist/lib/components/tag-input.js +6 -6
- package/dist/lib/openapi-explorer.js +4 -4
- package/dist/lib/styles/advanced-search-styles.js +2 -2
- package/dist/lib/styles/api-request-styles.js +2 -2
- package/dist/lib/styles/border-styles.js +2 -2
- package/dist/lib/styles/endpoint-styles.js +2 -2
- package/dist/lib/styles/flex-styles.js +2 -2
- package/dist/lib/styles/font-styles.js +2 -2
- package/dist/lib/styles/info-styles.js +2 -2
- package/dist/lib/styles/input-styles.js +2 -2
- package/dist/lib/styles/nav-styles.js +2 -2
- package/dist/lib/styles/prism-styles.js +2 -2
- package/dist/lib/styles/schema-styles.js +2 -2
- package/dist/lib/styles/tab-styles.js +2 -2
- package/dist/lib/styles/table-styles.js +2 -2
- package/dist/lib/templates/advance-search-template.js +3 -3
- package/dist/lib/templates/callback-template.js +2 -2
- package/dist/lib/templates/code-samples-template.js +4 -4
- package/dist/lib/templates/components-template.js +4 -4
- package/dist/lib/templates/endpoint-template.js +6 -6
- package/dist/lib/templates/expanded-endpoint-template.js +4 -4
- package/dist/lib/templates/focused-endpoint-template.js +3 -3
- package/dist/lib/templates/navbar-template.js +8 -8
- package/dist/lib/templates/overview-template.js +3 -3
- package/dist/lib/templates/responsiveViewMainBodyTemplate.js +3 -3
- package/dist/lib/templates/security-scheme-template.js +10 -10
- package/dist/lib/templates/server-template.js +7 -7
- package/dist/lib/utils/schema-utils.js +42 -21
- package/dist/lib/utils/theme.js +2 -2
- package/package.json +2 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi-explorer.min.js","mappings":";;AA0BA;AAQA;AC+rBA","sources":["webpack://openapi-explorer/./src/templates/code-samples-template.js","webpack://openapi-explorer/./src/components/api-request.js"],"sourcesContent":["import { html } from 'lit-element';\nimport { unsafeHTML } from 'lit-html/directives/unsafe-html.js';\nimport Prism from 'prismjs';\nimport { copyToClipboard } from '../utils/common-utils';\nimport { getI18nText } from '../languages';\n\n/* eslint-disable indent */\nexport default function codeSamplesTemplate(xCodeSamples) {\n return html`\n <section class=\"table-title top-gap\"> CODE SAMPLES </div>\n <div class=\"tab-panel col\"\n @click=\"${\n (e) => {\n if (!e.target.classList.contains('tab-btn')) { return; }\n const clickedTab = e.target.dataset.tab;\n\n const tabButtons = [...e.currentTarget.querySelectorAll('.tab-btn')];\n const tabContents = [...e.currentTarget.querySelectorAll('.tab-content')];\n tabButtons.forEach((tabBtnEl) => tabBtnEl.classList[tabBtnEl.dataset.tab === clickedTab ? 'add' : 'remove']('active'));\n tabContents.forEach((tabBodyEl) => { tabBodyEl.style.display = (tabBodyEl.dataset.tab === clickedTab ? 'block' : 'none'); });\n }\n }\">\n <div class=\"tab-buttons row\" style=\"width:100; overflow\">\n ${xCodeSamples.map((v, i) => html`<button class=\"tab-btn ${i === 0 ? 'active' : ''}\" data-tab = '${v.lang}${i}'> ${v.label || v.lang} </button>`)}\n </div>\n ${xCodeSamples.map((v, i) => html`\n <div class=\"tab-content m-markdown code-sample-wrapper\" style= \"display:${i === 0 ? 'block' : 'none'}\" data-tab = '${v.lang}${i}'>\n <button class=\"toolbar-copy-btn\" @click='${(e) => { copyToClipboard(v.source, e); }}'>${getI18nText('operations.copy')}</button>\n <pre>\n <code>${Prism.languages[v.lang && v.lang.toLowerCase()] ? unsafeHTML(Prism.highlight(v.source, Prism.languages[v.lang && v.lang.toLowerCase()], v.lang && v.lang.toLowerCase())) : v.source}</code>\n </pre>\n </div>`)\n }\n </section>`;\n}\n/* eslint-enable indent */\n","import { LitElement, html } from 'lit-element';\nimport { marked } from 'marked';\nimport Prism from 'prismjs';\nimport mimeTypeResolver from './mime-types';\n\nimport { unsafeHTML } from 'lit-html/directives/unsafe-html.js';\nimport formatXml from 'xml-but-prettier';\n\nimport { copyToClipboard } from '../utils/common-utils';\nimport { getI18nText } from '../languages';\nimport { schemaInObjectNotation, getTypeInfo, generateExample } from '../utils/schema-utils';\nimport './json-tree';\nimport './schema-tree';\nimport './tag-input';\n\nconst textFileRegex = RegExp('^font/|tar$|zip$|7z$|rtf$|msword$|excel$|/pdf$|/octet-stream$|^application/vnd.');\nconst mediaFileRegex = RegExp('^audio/|^image/|^video/');\nconst truncateString = (str, length) => (str && str.length > length ? `${str.substring(0, length - 1)}…` : str);\n\nexport default class ApiRequest extends LitElement {\n createRenderRoot() { return this; }\n\n constructor() {\n super();\n this.responseMessage = '';\n this.responseStatus = '';\n this.responseHeaders = '';\n this.responseText = '';\n this.responseUrl = '';\n this.responseElapsedMs = 0;\n this.curlSyntax = '';\n this.activeResponseTab = 'response'; // allowed values: response, headers, curl\n this.selectedRequestBodyType = '';\n this.selectedRequestBodyExample = '';\n }\n\n static get properties() {\n return {\n serverUrl: { type: String, attribute: 'server-url' },\n servers: { type: Array },\n method: { type: String },\n path: { type: String },\n elementId: { type: String, attribute: 'element-id' },\n parameters: { type: Array },\n request_body: { type: Object },\n api_keys: { type: Array },\n parser: { type: Object },\n accept: { type: String },\n callback: { type: String },\n responseMessage: { type: String, attribute: false },\n responseText: { type: String, attribute: false },\n responseHeaders: { type: String, attribute: false },\n responseStatus: { type: String, attribute: false },\n responseUrl: { type: String, attribute: false },\n responseElapsedMs: { type: Number, attribute: false },\n fillRequestWithDefault: { type: String, attribute: 'fill-defaults' },\n includeNulls: { type: Boolean, attribute: 'display-nulls', converter(value) { return value === 'true'; } },\n allowTry: { type: String, attribute: 'enable-console' },\n renderStyle: { type: String, attribute: 'render-style' },\n schemaStyle: { type: String, attribute: 'schema-style' },\n activeSchemaTab: { type: String, attribute: 'active-schema-tab' },\n schemaExpandLevel: { type: Number, attribute: 'schema-expand-level' },\n schemaHideReadOnly: { type: String, attribute: 'schema-hide-read-only' },\n fetchCredentials: { type: String, attribute: 'fetch-credentials' },\n\n // properties for internal tracking\n activeResponseTab: { type: String }, // internal tracking of response-tab not exposed as a attribute\n selectedRequestBodyType: { type: String, attribute: 'selected-request-body-type' }, // internal tracking of selected request-body type\n selectedRequestBodyExample: { type: String, attribute: 'selected-request-body-example' }, // internal tracking of selected request-body example\n };\n }\n\n render() {\n return html`\n <div class=\"api-request col regular-font request-panel ${(this.renderStyle === 'focused' || this.callback === 'true') ? 'focused-mode' : 'view-mode'}\">\n <div class=\" ${this.callback === 'true' ? 'tiny-title' : 'req-res-title'} \"> \n ${this.callback === 'true' ? 'CALLBACK REQUEST' : getI18nText('operations.request')}\n </div>\n <div>\n ${this.inputParametersTemplate('path')}\n ${this.inputParametersTemplate('query')}\n ${this.requestBodyTemplate()}\n ${this.inputParametersTemplate('header')}\n ${this.inputParametersTemplate('cookie')}\n ${this.allowTry === 'false' ? '' : html`${this.apiCallTemplate()}`}\n </div> \n </div>\n `;\n }\n\n updated(changedProperties) {\n // In focused mode after rendering the request component, update the text-areas(which contains examples) using the original values from hidden textareas.\n // This is done coz, user may update the dom by editing the textarea's and once the DOM is updated externally change detection wont happen, therefore update the values manually\n if (this.renderStyle !== 'focused') {\n return;\n }\n\n // dont update example as only tabs is switched\n if (changedProperties.size === 1 && changedProperties.has('activeSchemaTab')) {\n return;\n }\n\n const exampleTextAreaEls = [...this.querySelectorAll('textarea[data-ptype=\"form-data\"]')];\n exampleTextAreaEls.forEach((el) => {\n const origExampleEl = this.querySelector(`textarea[data-pname='hidden-${el.dataset.pname}']`);\n if (origExampleEl) {\n el.value = origExampleEl.value;\n }\n });\n }\n\n /* eslint-disable indent */\n inputParametersTemplate(paramType) {\n const filteredParams = this.parameters ? this.parameters.filter((param) => param.in === paramType) : [];\n if (filteredParams.length === 0) {\n return '';\n }\n let title = '';\n if (paramType === 'path') {\n title = 'PATH PARAMETERS';\n } else if (paramType === 'query') {\n title = 'QUERY-STRING PARAMETERS';\n } else if (paramType === 'header') {\n title = 'REQUEST HEADERS';\n } else if (paramType === 'cookie') {\n title = 'COOKIES';\n }\n\n const tableRows = [];\n for (const param of filteredParams) {\n if (!param.schema) {\n continue;\n }\n const paramSchema = getTypeInfo(param.schema, { includeNulls: this.includeNulls });\n if (!paramSchema) {\n continue;\n }\n const defaultVal = Array.isArray(paramSchema.default) ? paramSchema.default : `${paramSchema.default}`;\n let paramStyle = 'form';\n let paramExplode = true;\n if (paramType === 'query') {\n if (param.style && 'form spaceDelimited pipeDelimited'.includes(param.style)) {\n paramStyle = param.style;\n }\n if (typeof param.explode === 'boolean') {\n paramExplode = param.explode;\n }\n }\n\n tableRows.push(html`\n <tr> \n <td style=\"width:160px; min-width:50px;\">\n <div class=\"param-name ${paramSchema.deprecated ? 'deprecated' : ''}\">\n ${param.name}${!paramSchema.deprecated && param.required ? html`<span style='color:var(--red);'>*</span>` : ''}\n </div>\n <div class=\"param-type\">\n ${paramSchema.type === 'array'\n ? `${paramSchema.arrayType}`\n : `${paramSchema.format ? paramSchema.format : paramSchema.type}`\n }${!paramSchema.deprecated && param.required ? html`<span style='opacity: 0;'>*</span>` : ''}\n </div>\n </td> \n ${this.allowTry === 'true'\n ? html`\n <td style=\"min-width:160px;\">\n ${paramSchema.type === 'array'\n ? html`\n <tag-input class=\"request-param\" \n style = \"width:100%;\" \n data-ptype = \"${paramType}\"\n data-pname = \"${param.name}\"\n data-default = \"${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}\"\n data-param-serialize-style = \"${paramStyle}\"\n data-param-serialize-explode = \"${paramExplode}\"\n data-array = \"true\"\n placeholder=\"${paramSchema.example || (Array.isArray(defaultVal) ? defaultVal[0] : defaultVal) || 'add-multiple ↩'}\"\n .value = \"${Array.isArray(defaultVal) ? defaultVal : defaultVal.split(',')}\"\n >\n </tag-input>`\n : paramSchema.type === 'object'\n ? html`\n <textarea \n class = \"textarea request-param\"\n part = \"textarea textarea-param\"\n data-ptype = \"${paramType}-object\"\n data-pname = \"${param.name}\"\n data-default = \"${defaultVal}\"\n data-param-serialize-style = \"${paramStyle}\"\n data-param-serialize-explode = \"${paramExplode}\"\n spellcheck = \"false\"\n placeholder=\"${paramSchema.example || defaultVal || ''}\"\n style = \"resize:vertical; width:100%; height: ${'read focused'.includes(this.renderStyle) ? '180px' : '120px'};\"\n >${this.fillRequestWithDefault === 'true' ? defaultVal : ''}</textarea>`\n : html`\n <input type=\"${paramSchema.format === 'password' ? 'password' : 'text'}\" spellcheck=\"false\" style=\"width:100%\" placeholder=\"${paramSchema.example || defaultVal || ''}\"\n class=\"request-param\"\n part=\"textbox textbox-param\"\n data-ptype=\"${paramType}\"\n data-pname=\"${param.name}\" \n data-default=\"${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}\"\n data-array=\"false\"\n @keyup=\"${this.requestParamFunction}\"\n .value=\"${this.fillRequestWithDefault === 'true' ? defaultVal : ''}\"\n />`\n }\n </td>`\n : ''\n }\n ${this.renderStyle === 'focused'\n ? html`\n <td>\n ${paramSchema.default || paramSchema.constraint || paramSchema.allowedValues || paramSchema.pattern\n ? html`\n <div class=\"param-constraint\">\n ${paramSchema.constraint ? html`<span style=\"font-weight:bold\">Constraints: </span>${paramSchema.constraint}<br>` : ''}\n ${paramSchema.pattern ? html`<span style=\"font-weight:bold\">Pattern: </span>${truncateString(paramSchema.pattern, 60)}<br>` : ''}\n ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => html`\n ${i > 0 ? '|' : html`<span style=\"font-weight:bold\">Allowed: </span>`}\n ${html`\n <a part=\"anchor anchor-param-constraint\" class = \"${this.allowTry === 'true' ? '' : 'inactive-link'}\"\n data-type=\"${paramSchema.type === 'array' ? 'array' : 'string'}\"\n data-enum=\"${v.trim()}\"\n @click=\"${(e) => {\n const inputEl = e.target.closest('table').querySelector(`[data-pname=\"${param.name}\"]`);\n if (inputEl) {\n if (e.target.dataset.type === 'array') {\n inputEl.value = [e.target.dataset.enum];\n } else {\n inputEl.value = e.target.dataset.enum;\n }\n }\n }}\"\n >\n ${v} \n </a>`\n }`)}\n </div>`\n : ''\n }\n </td> \n </tr>`\n : ''\n }\n `);\n }\n\n return html`\n <div class=\"table-title top-gap\">${title}${paramType === 'path' ? html`<span style='color:var(--red);'>*</span>` : ''}</div>\n <div style=\"display:block; overflow-x:auto; max-width:100%;\">\n <table role=\"presentation\" class=\"m-table\" style=\"width:100%; word-break:break-word;\">\n ${tableRows}\n </table>\n </div>`;\n }\n\n resetRequestBodySelection() {\n this.selectedRequestBodyType = '';\n this.selectedRequestBodyExample = '';\n this.clearResponseData();\n }\n\n // Request-Body Event Handlers\n onSelectExample(e) {\n this.selectedRequestBodyExample = e.target.value;\n const exampleDropdownEl = e.target;\n window.setTimeout((selectEl) => {\n const exampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param');\n const userInputExampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param-user-input');\n userInputExampleTextareaEl.value = exampleTextareaEl.value;\n }, 0, exampleDropdownEl);\n }\n\n onMimeTypeChange(e) {\n this.selectedRequestBodyType = e.target.value;\n const mimeDropdownEl = e.target;\n this.selectedRequestBodyExample = '';\n window.setTimeout((selectEl) => {\n const exampleTextareaEl = selectEl.closest('.request-body-container').querySelector('.request-body-param');\n if (exampleTextareaEl) {\n const userInputExampleTextareaEl = selectEl.closest('.request-body-container').querySelector('.request-body-param-user-input');\n userInputExampleTextareaEl.value = exampleTextareaEl.value;\n }\n }, 0, mimeDropdownEl);\n }\n\n requestBodyTemplate() {\n if (!this.request_body) {\n return '';\n }\n if (Object.keys(this.request_body).length === 0) {\n return '';\n }\n\n // Variable to store partial HTMLs\n let reqBodyTypeSelectorHtml = '';\n let reqBodyFileInputHtml = '';\n let reqBodyFormHtml = '';\n let reqBodySchemaHtml = '';\n let reqBodyDefaultHtml = '';\n\n const requestBodyTypes = [];\n const content = this.request_body.content;\n for (const mimeType in content) {\n requestBodyTypes.push({\n mimeType,\n schema: content[mimeType].schema,\n example: content[mimeType].example,\n examples: content[mimeType].examples,\n });\n if (!this.selectedRequestBodyType) {\n this.selectedRequestBodyType = mimeType;\n }\n }\n // MIME Type selector\n reqBodyTypeSelectorHtml = requestBodyTypes.length === 1\n ? ''\n : html`\n <select aria-label=\"mime type\" style=\"min-width:100px; max-width:100%; margin-bottom:-1px;\" @change = '${(e) => this.onMimeTypeChange(e)}'>\n ${requestBodyTypes.map((reqBody) => html`\n <option value = '${reqBody.mimeType}' ?selected = '${reqBody.mimeType === this.selectedRequestBodyType}'>\n ${reqBody.mimeType}\n </option> `)\n }\n </select>\n `;\n\n // For Loop - Main\n requestBodyTypes.forEach((reqBody) => {\n let reqBodyExamples = [];\n\n if (this.selectedRequestBodyType.includes('json') || this.selectedRequestBodyType.includes('xml') || this.selectedRequestBodyType.includes('text')) {\n // Generate Example\n if (reqBody.mimeType === this.selectedRequestBodyType) {\n reqBodyExamples = generateExample(\n reqBody.examples ? reqBody.examples : '',\n reqBody.example ? reqBody.example : '',\n reqBody.schema,\n reqBody.mimeType,\n false,\n true,\n 'text',\n true\n );\n\n if (!this.selectedRequestBodyExample) {\n this.selectedRequestBodyExample = (reqBodyExamples.length > 0 ? reqBodyExamples[0].exampleId : '');\n }\n reqBodyDefaultHtml = html`\n ${reqBodyDefaultHtml}\n <div class = 'example-panel border-top pad-top-8'>\n ${reqBodyExamples.length === 1\n ? ''\n : html`\n <select aria-label='request body example' style=\"min-width:100px; max-width:100%; margin-bottom:-1px;\" @change='${(e) => this.onSelectExample(e)}'>\n ${reqBodyExamples.map((v) => html`<option value=\"${v.exampleId}\" ?selected=${v.exampleId === this.selectedRequestBodyExample} > \n ${v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary ? v.exampleSummary : v.exampleId} \n </option>`)}\n </select>\n `\n }\n ${reqBodyExamples\n .filter((v) => v.exampleId === this.selectedRequestBodyExample)\n .map((v) => html`\n <div class=\"example ${v.exampleId === this.selectedRequestBodyExample ? 'example-selected' : ''}\" data-default = '${v.exampleId}'>\n ${v.exampleSummary && v.exampleSummary.length > 80 ? html`<div style=\"padding: 4px 0\"> ${v.exampleSummary} </div>` : ''}\n ${v.exampleDescription ? html`<div class=\"m-markdown-small\" style=\"padding: 4px 0\"> ${unsafeHTML(marked(v.exampleDescription || ''))} </div>` : ''}\n <!-- this textarea is for user to edit the example -->\n <slot name=\"${this.elementId}--request-body\">\n <textarea \n class = \"textarea request-body-param-user-input\"\n part = \"textarea textarea-param\"\n spellcheck = \"false\"\n data-ptype = \"${reqBody.mimeType}\" \n data-default = \"${v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8)}\"\n data-default-format = \"${v.exampleFormat}\"\n style=\"width:100%; resize:vertical;\"\n >${this.fillRequestWithDefault === 'true' ? (v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8)) : ''}</textarea>\n </slot>\n\n <!-- This textarea(hidden) is to store the original example value, this will remain unchanged when users switches from one example to another, its is used to populate the editable textarea -->\n <textarea \n class = \"textarea is-hidden request-body-param ${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)}\" \n spellcheck = \"false\"\n data-ptype = \"${reqBody.mimeType}\" \n style=\"width:100%; resize:vertical; display:none\"\n >${(v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8))}</textarea>\n </div> \n `)}\n\n </div>\n `;\n }\n } else if (this.selectedRequestBodyType.includes('form-urlencoded') || this.selectedRequestBodyType.includes('form-data')) {\n if (reqBody.mimeType === this.selectedRequestBodyType) {\n const ex = generateExample(\n reqBody.examples ? reqBody.examples : '',\n reqBody.example ? reqBody.example : '',\n reqBody.schema,\n reqBody.mimeType,\n false,\n true,\n 'text',\n true\n );\n if (reqBody.schema) {\n reqBodyFormHtml = this.formDataTemplate(reqBody.schema, reqBody.mimeType, (ex[0] ? ex[0].exampleValue : ''));\n }\n }\n } else if (mediaFileRegex.test(this.selectedRequestBodyType) || textFileRegex.test(this.selectedRequestBodyType)) {\n if (reqBody.mimeType === this.selectedRequestBodyType) {\n reqBodyFileInputHtml = html`\n <div class = \"small-font-size bold-text row\">\n <input type=\"file\" part=\"file-input\" style=\"max-width:100%\" class=\"request-body-param-file\" data-ptype=\"${reqBody.mimeType}\" spellcheck=\"false\" />\n </div> \n `;\n }\n }\n\n // Generate Schema\n if (reqBody.mimeType.includes('json') || reqBody.mimeType.includes('xml') || reqBody.mimeType.includes('text')) {\n const schemaAsObj = schemaInObjectNotation(reqBody.schema, { includeNulls: this.includeNulls });\n if (this.schemaStyle === 'table') {\n reqBodySchemaHtml = html`\n ${reqBodySchemaHtml}\n <schema-table\n class = '${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)} pad-top-8'\n style = 'display: ${this.selectedRequestBodyType === reqBody.mimeType ? 'block' : 'none'};'\n .data = '${schemaAsObj}'\n schema-expand-level = \"${this.schemaExpandLevel}\"\n schema-hide-read-only = \"${this.schemaHideReadOnly.includes(this.method)}\"\n schema-hide-write-only = false\n > </schema-table>\n `;\n } else {\n reqBodySchemaHtml = html`\n ${reqBodySchemaHtml}\n <schema-tree\n class = '${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)} pad-top-8'\n style = 'display: ${this.selectedRequestBodyType === reqBody.mimeType ? 'block' : 'none'};'\n .data = '${schemaAsObj}'\n schema-expand-level = \"${this.schemaExpandLevel}\"\n schema-hide-read-only = \"${this.schemaHideReadOnly.includes(this.method)}\"\n schema-hide-write-only = false\n > </schema-tree>\n `;\n }\n }\n });\n\n return html`\n <div class='request-body-container' data-selected-request-body-type=\"${this.selectedRequestBodyType}\">\n <div class=\"table-title top-gap row\">\n REQUEST BODY ${this.request_body.required ? html`<span class=\"mono-font\" style='color:var(--red)'>*</span>` : ''} \n <span style = \"font-weight:normal; margin-left:5px\"> ${this.selectedRequestBodyType}</span>\n <span style=\"flex:1\"></span>\n ${reqBodyTypeSelectorHtml}\n </div>\n ${this.request_body.description ? html`<div class=\"m-markdown\" style=\"margin-bottom:12px\">${unsafeHTML(marked(this.request_body.description))}</div>` : ''}\n \n ${(this.selectedRequestBodyType.includes('json') || this.selectedRequestBodyType.includes('xml') || this.selectedRequestBodyType.includes('text'))\n ? html`\n <div class=\"tab-panel col\" style=\"border-width:0 0 1px 0;\">\n <div class=\"tab-buttons row\" @click=\"${(e) => { if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; } }}\">\n <button class=\"tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}\" data-tab=\"model\" >${getI18nText('operations.model')}</button>\n <button class=\"tab-btn ${this.activeSchemaTab === 'body' ? 'active' : ''}\" data-tab=\"body\">${getI18nText('operations.body')}</button>\n </div>\n ${html`<div class=\"tab-content col\" style=\"display: ${this.activeSchemaTab === 'model' ? 'block' : 'none'}\"> ${reqBodySchemaHtml}</div>`}\n ${html`<div class=\"tab-content col\" style=\"display: ${this.activeSchemaTab === 'model' ? 'none' : 'block'}\"> ${reqBodyDefaultHtml}</div>`}\n </div>`\n : html` \n ${reqBodyFileInputHtml}\n ${reqBodyFormHtml}`\n }\n </div> \n `;\n }\n\n formDataTemplate(schema, mimeType, exampleValue = '') {\n const formDataTableRows = [];\n if (schema.properties) {\n for (const fieldName in schema.properties) {\n const fieldSchema = schema.properties[fieldName];\n if (fieldSchema.readOnly) {\n continue;\n }\n\n const fieldType = fieldSchema.type;\n const formdataPartSchema = schemaInObjectNotation(fieldSchema, { includeNulls: this.includeNulls });\n const paramSchema = getTypeInfo(fieldSchema, { includeNulls: this.includeNulls });\n const formdataPartExample = generateExample(\n '',\n fieldSchema.example ? fieldSchema.example : '',\n fieldSchema,\n 'json',\n false,\n true,\n 'text',\n true\n );\n\n formDataTableRows.push(html`\n <tr> \n <td style=\"width:160px; min-width:100px;\">\n <div class=\"param-name ${fieldSchema.deprecated ? 'deprecated' : ''}\">\n ${fieldName}${!fieldSchema.deprecated && (schema.required && schema.required.includes(fieldName) || fieldSchema.required) ? html`<span style='color:var(--red);'>*</span>` : ''}\n </div>\n <div class=\"param-type\">\n ${paramSchema.type === 'array' ? html`[<span>${paramSchema.format || paramSchema.type}</span>]` : `${paramSchema.format || paramSchema.type}`}\n </div>\n </td> \n <td \n style=\"${fieldType === 'object' ? 'width:100%; padding:0;' : this.allowTry === 'true' ? '' : 'display:none;'} min-width:100px;\" \n colspan=\"${fieldType === 'object' ? 2 : 1}\">\n ${fieldType === 'array'\n ? (fieldSchema.items && fieldSchema.items.format === 'binary')\n ? html`\n <div class=\"file-input-container col\" style='align-items:flex-end;' @click=\"${(e) => this.onAddRemoveFileInput(e, fieldName, mimeType)}\">\n <div class='input-set row'>\n <input \n type = \"file\"\n part = \"file-input\"\n style = \"width:100%\" \n data-pname = \"${fieldName}\" \n data-ptype = \"${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}\"\n data-array = \"false\" \n data-file-array = \"true\" \n />\n <button class=\"file-input-remove-btn\"> ✕ </button>\n </div> \n <button class=\"m-btn primary file-input-add-btn\" part=\"btn btn-fill\" style=\"margin:2px 25px 0 0; padding:2px 6px;\">ADD</button>\n </div> \n `\n : html`\n <tag-input\n style = \"width:100%;\" \n data-ptype = \"${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}\"\n data-pname = \"${fieldName}\"\n data-default = \"${paramSchema.default || ''}\"\n data-array = \"true\"\n placeholder=\"${(Array.isArray(paramSchema.example) ? paramSchema.example[0] : paramSchema.example) || 'add-multiple ↩'}\"\n .value = \"${paramSchema.default || ''}\"\n >\n </tag-input>\n `\n : html`\n ${fieldType === 'object'\n ? html`\n <div class=\"tab-panel row\" style=\"min-height:300px; border-left: 6px solid var(--light-border-color); align-items: stretch;\">\n <div style=\"width:24px; background-color:var(--light-border-color)\">\n <div class=\"row\" style=\"flex-direction:row-reverse; width:260px; height:24px; transform:rotate(270deg) translateX(-260px); transform-origin:top left; display:block;\" @click=\"${(e) => {\n if (e.target.classList.contains('v-tab-btn')) {\n const tab = e.target.dataset.tab;\n if (tab) {\n const tabPanelEl = e.target.closest('.tab-panel');\n const selectedTabBtnEl = tabPanelEl.querySelector(`.v-tab-btn[data-tab=\"${tab}\"]`);\n const otherTabBtnEl = [...tabPanelEl.querySelectorAll(`.v-tab-btn:not([data-tab=\"${tab}\"])`)];\n const selectedTabContentEl = tabPanelEl.querySelector(`.tab-content[data-tab=\"${tab}\"]`);\n const otherTabContentEl = [...tabPanelEl.querySelectorAll(`.tab-content:not([data-tab=\"${tab}\"])`)];\n selectedTabBtnEl.classList.add('active');\n selectedTabContentEl.style.display = 'block';\n otherTabBtnEl.forEach((el) => { el.classList.remove('active'); });\n otherTabContentEl.forEach((el) => { el.style.display = 'none'; });\n }\n }\n if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; }\n }}\">\n <button class=\"v-tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}\" data-tab = 'model'>${getI18nText('operations.model')}</button>\n <button class=\"v-tab-btn ${this.activeSchemaTab === 'body' ? 'active' : ''}\" data-tab = 'body'>${getI18nText('operations.request-body')}</button>\n </div>\n </div> \n ${html`\n <div class=\"tab-content col\" data-tab = 'model' style=\"display:${this.activeSchemaTab === 'model' ? 'block' : 'none'}; padding-left:5px; width:100%;\"> \n <schema-tree\n .data = '${formdataPartSchema}'\n schema-expand-level = \"${this.schemaExpandLevel}\"> </schema-tree>\n </div>`\n }\n ${html`\n <div class=\"tab-content col\" data-tab = 'body' style=\"display:${this.activeSchemaTab === 'body' ? 'block' : 'none'}; padding-left:5px; width:100%\"> \n <textarea \n class = \"textarea\" placeholder=\"${formdataPartExample[0] && formdataPartExample[0].exampleValue || paramSchema.default || ''}\"\n part = \"textarea textarea-param\"\n style = \"width:100%; border:none; resize:vertical;\" \n data-array = \"false\" \n data-ptype = \"${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}\"\n data-pname = \"${fieldName}\"\n data-default = \"${paramSchema.default || ''}\"\n spellcheck = \"false\"\n >${this.fillRequestWithDefault === 'true' ? paramSchema.default : ''}</textarea>\n <!-- This textarea(hidden) is to store the original example value, in focused mode on navbar change it is used to update the example text -->\n <textarea data-pname = \"hidden-${fieldName}\" data-ptype = \"${mimeType.includes('form-urlencode') ? 'hidden-form-urlencode' : 'hidden-form-data'}\" class=\"is-hidden\" style=\"display:none\">${paramSchema.default}</textarea>\n </div>`\n }\n </div>`\n : html`\n ${this.allowTry === 'true'\n ? html`<input placeholder=\"${paramSchema.example || paramSchema.default || ''}\"\n .value = \"${this.fillRequestWithDefault === 'true' ? (paramSchema.default || '') : ''}\"\n spellcheck = \"false\"\n type = \"${fieldSchema.format === 'binary' ? 'file' : fieldSchema.format === 'password' ? 'password' : 'text'}\"\n part = \"textbox textbox-param\"\n style = \"width:100%\"\n data-ptype = \"${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}\"\n data-pname = \"${fieldName}\"\n data-default = \"${paramSchema.default || ''}\"\n data-array = \"false\"\n />`\n : ''\n }\n `\n }`\n }\n </td>\n ${fieldType === 'object'\n ? ''\n : html`\n <td>\n ${paramSchema.default || paramSchema.constraint || paramSchema.allowedValues || paramSchema.pattern\n ? html`\n <div class=\"param-constraint\">\n ${paramSchema.pattern ? html`<span style=\"font-weight:bold\">Pattern: </span>${paramSchema.pattern}<br/>` : ''}\n ${paramSchema.constraint ? html`<span style=\"font-weight:bold\">Constraints: </span>${paramSchema.constraint}<br/>` : ''}\n ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => html`\n ${i > 0 ? '|' : html`<span style=\"font-weight:bold\">Allowed: </span>`}\n ${html`\n <a part=\"anchor anchor-param-constraint\" class = \"${this.allowTry === 'true' ? '' : 'inactive-link'}\"\n data-type=\"${paramSchema.type === 'array' ? paramSchema.type : 'string'}\"\n data-enum=\"${v.trim()}\"\n @click=\"${(e) => {\n const inputEl = e.target.closest('table').querySelector(`[data-pname=\"${fieldName}\"]`);\n if (inputEl) {\n if (e.target.dataset.type === 'array') {\n inputEl.value = [e.target.dataset.enum];\n } else {\n inputEl.value = e.target.dataset.enum;\n }\n }\n }}\"\n > \n ${v} \n </a>`\n }`)\n }\n </div>`\n : ''\n }\n </td>`\n }\n </tr>\n ${fieldType === 'object'\n ? ''\n : html`\n <tr>\n <td style=\"border:none\"> </td>\n <td colspan=\"2\" style=\"border:none; margin-top:0; padding:0 5px 8px 5px;\"> \n <span class=\"m-markdown-small\">${unsafeHTML(marked(fieldSchema.description || ''))}</span>\n ${paramSchema.example\n ? html`\n <span>\n <span style=\"font-weight:bold\"> Example: </span>\n ${paramSchema.type === 'array' ? '[ ' : ''}\n <a part=\"anchor anchor-param-example\" class = \"${this.allowTry === 'true' ? '' : 'inactive-link'}\"\n data-default-type=\"${paramSchema.type === 'array' ? paramSchema.type : 'string'}\"\n data-default = \"${Array.isArray(paramSchema.example) && paramSchema.example.join('~|~') || paramSchema.example || ''}\"\n @click=\"${(e) => {\n const inputEl = e.target.closest('table').querySelector(`[data-pname=\"${fieldName}\"]`);\n if (inputEl) {\n if (e.target.dataset.exampleType === 'array') {\n inputEl.value = e.target.dataset.example.split('~|~');\n } else {\n inputEl.value = e.target.dataset.example;\n }\n }\n }}\"\n >\n ${paramSchema.type === 'array' ? paramSchema.example.join(', ') : paramSchema.example}\n </a>\n ${paramSchema.type === 'array' ? '] ' : ''}\n </span>`\n : ''\n }\n </td>\n </tr>\n `\n }`);\n }\n return html`\n <table role=\"presentation\" style=\"width:100%;\" class=\"m-table\">\n ${formDataTableRows}\n </table>\n `;\n }\n\n return html`\n <textarea\n class = \"textarea dynamic-form-param ${mimeType}\"\n part = \"textarea textarea-param\"\n spellcheck = \"false\"\n data-pname=\"dynamic-form\" \n data-ptype=\"${mimeType}\" \n style=\"width:100%\"\n >${exampleValue}</textarea>\n ${schema.description ? html`<span class=\"m-markdown-small\">${unsafeHTML(marked(schema.description))}</span>` : ''}\n `;\n }\n\n apiResponseTabTemplate() {\n const responseFormat = this.responseHeaders.includes('json') ? 'json' : (this.responseHeaders.includes('html') || this.responseHeaders.includes('xml')) ? 'html' : '';\n return html`\n <div class=\"row\" style=\"font-size:var(--font-size-small); margin:5px 0\">\n ${this.responseMessage\n ? html`<div class=\"response-message ${this.responseStatus}\">Response Status: ${this.responseMessage}\n ${this.responseElapsedMs ? html`<span><br>Execution Time: ${this.responseElapsedMs}ms</span>` : ''}\n </div>` : ''\n }\n <div style=\"flex:1\"></div>\n <button class=\"m-btn\" part=\"btn btn-outline\" @click=\"${this.clearResponseData}\">CLEAR RESPONSE</button>\n </div>\n <div class=\"tab-panel col\" style=\"border-width:0 0 1px 0;\">\n <div id=\"tab_buttons\" class=\"tab-buttons row\" @click=\"${(e) => {\n if (e.target.classList.contains('tab-btn') === false) { return; }\n this.activeResponseTab = e.target.dataset.tab;\n }}\">\n <button class=\"tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}\" data-tab = 'response'>${getI18nText('operations.response')}</button>\n <button class=\"tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}\" data-tab = 'headers'>${getI18nText('operations.response-headers')}</button>\n <button class=\"tab-btn ${this.activeResponseTab === 'curl' ? 'active' : ''}\" data-tab = 'curl'>CURL</button>\n </div>\n ${this.responseIsBlob\n ? html`\n <div class=\"tab-content col\" style=\"flex:1; display:${this.activeResponseTab === 'response' ? 'flex' : 'none'};\">\n <button class=\"m-btn thin-border mar-top-8\" style=\"width:135px\" @click=\"${this.downloadResponseBlob}\" part=\"btn btn-outline\">DOWNLOAD</button>\n ${this.responseBlobType === 'view'\n ? html`<button class=\"m-btn thin-border mar-top-8\" style=\"width:135px\" @click=\"${this.viewResponseBlob}\" part=\"btn btn-outline\">VIEW (NEW TAB)</button>`\n : ''\n }\n </div>`\n : html`\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'};\" >\n <button class=\"toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.responseText, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre>${responseFormat\n ? html`<code>${unsafeHTML(Prism.highlight(this.responseText, Prism.languages[responseFormat], responseFormat))}</code>`\n : `${this.responseText}`\n }\n </pre>\n </div>`\n }\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'};\" >\n <button class=\"toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.responseHeaders, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre><code>${unsafeHTML(Prism.highlight(this.responseHeaders, Prism.languages.css, 'css'))}</code></pre>\n </div>\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'curl' ? 'flex' : 'none'};\">\n <button class=\"toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.curlSyntax.replace(/\\\\$/, ''), e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre><code>${unsafeHTML(Prism.highlight(this.curlSyntax.trim().replace(/\\\\$/, ''), Prism.languages.shell, 'shell'))}</code></pre>\n </div>\n </div>`;\n }\n\n apiCallTemplate() {\n return html`\n <div style=\"display:flex; align-items:flex-end; margin:16px 0; font-size:var(--font-size-small);\">\n ${\n this.parameters.length > 0 || this.request_body\n ? html`\n <button class=\"m-btn thin-border\" part=\"btn btn-outline\" style=\"margin-right:5px;\" @click=\"${this.onClearRequestData}\">\n ${getI18nText('operations.clear')}\n </button>`\n : ''\n }\n <button class=\"m-btn primary btn-execute thin-border\" part=\"btn btn-fill btn-try\" @click=\"${this.onTryClick}\">${getI18nText('operations.execute')}</button>\n </div>\n ${this.responseMessage === '' ? '' : this.apiResponseTabTemplate()}\n `;\n }\n /* eslint-enable indent */\n\n onClearRequestData(e) {\n const requestPanelEl = e.target.closest('.request-panel');\n const requestPanelInputEls = [...requestPanelEl.querySelectorAll('input, tag-input, textarea:not(.is-hidden)')];\n requestPanelInputEls.forEach((el) => { el.value = ''; });\n\n const event = { bubbles: true, composed: true, detail: { explorerLocation: this.elementId, type: 'RequestCleared' } };\n this.dispatchEvent(new CustomEvent('event', event));\n }\n\n async onTryClick() {\n const tryBtnEl = this.querySelectorAll('.btn-execute')[0];\n let fetchUrl;\n let curlUrl;\n let curl = '';\n let curlHeaders = '';\n let curlData = '';\n let curlForm = '';\n const closestRespContainer = this.closest('.expanded-req-resp-container, .req-resp-container');\n const respEl = closestRespContainer && closestRespContainer.getElementsByTagName('api-response')[0];\n const acceptHeader = respEl && respEl.selectedMimeType;\n const requestPanelEl = this.closest('.request-panel');\n const pathParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='path']\")];\n const queryParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='query']\")];\n const queryParamObjTypeEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='query-object']\")];\n const headerParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='header']\")];\n const requestBodyContainerEl = requestPanelEl.querySelector('.request-body-container');\n\n fetchUrl = this.path.replaceAll(' ', '');\n const fetchOptions = {\n method: this.method.toUpperCase(),\n headers: new Headers()\n };\n // Generate URL using Path Params\n pathParamEls.map((el) => {\n fetchUrl = fetchUrl.replace(`{${el.dataset.pname}}`, encodeURIComponent(el.value));\n });\n\n // Query Params\n const urlQueryParam = new URLSearchParams();\n if (queryParamEls.length > 0) {\n queryParamEls.forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.value !== '') {\n urlQueryParam.append(el.dataset.pname, el.value);\n }\n } else {\n const paramSerializeStyle = el.dataset.paramSerializeStyle;\n const paramSerializeExplode = el.dataset.paramSerializeExplode;\n let vals = ((el.value && Array.isArray(el.value)) ? el.value : []);\n vals = Array.isArray(vals) ? vals.filter((v) => v !== '') : [];\n if (vals.length > 0) {\n if (paramSerializeStyle === 'spaceDelimited') {\n urlQueryParam.append(el.dataset.pname, vals.join(' ').replace(/^\\s|\\s$/g, ''));\n } else if (paramSerializeStyle === 'pipeDelimited') {\n urlQueryParam.append(el.dataset.pname, vals.join('|').replace(/^\\||\\|$/g, ''));\n } else {\n if (paramSerializeExplode === 'true') { // eslint-disable-line no-lonely-if\n vals.forEach((v) => { urlQueryParam.append(el.dataset.pname, v); });\n } else {\n urlQueryParam.append(el.dataset.pname, vals.join(',').replace(/^,|,$/g, ''));\n }\n }\n }\n }\n });\n }\n\n // Query Params (Dynamic - create from JSON)\n if (queryParamObjTypeEls.length > 0) {\n queryParamObjTypeEls.map((el) => {\n try {\n let queryParamObj = {};\n const paramSerializeStyle = el.dataset.paramSerializeStyle;\n const paramSerializeExplode = el.dataset.paramSerializeExplode;\n queryParamObj = Object.assign(queryParamObj, JSON.parse(el.value.replace(/\\s+/g, ' ')));\n for (const key in queryParamObj) {\n if (typeof queryParamObj[key] === 'object') {\n if (Array.isArray(queryParamObj[key])) {\n if (paramSerializeStyle === 'spaceDelimited') {\n urlQueryParam.append(key, queryParamObj[key].join(' '));\n } else if (paramSerializeStyle === 'pipeDelimited') {\n urlQueryParam.append(key, queryParamObj[key].join('|'));\n } else {\n if (paramSerializeExplode === 'true') { // eslint-disable-line no-lonely-if\n queryParamObj[key].forEach((v) => {\n urlQueryParam.append(key, v);\n });\n } else {\n urlQueryParam.append(key, queryParamObj[key]);\n }\n }\n }\n } else {\n urlQueryParam.append(key, queryParamObj[key]);\n }\n }\n } catch (err) {\n console.log('OpenAPI Explorer: unable to parse %s into object', el.value); // eslint-disable-line no-console\n }\n });\n }\n\n // Add Authentication api keys if provided\n this.api_keys.filter((v) => v.finalKeyValue).forEach((v) => {\n if (v.in === 'query') {\n urlQueryParam.append(v.name, v.finalKeyValue);\n return;\n }\n\n // Otherwise put it in the header\n fetchOptions.headers.append(v.name, v.finalKeyValue);\n curlHeaders += ` -H \"${v.name}: ${v.finalKeyValue}\" \\\\\\n`;\n });\n\n fetchUrl = `${fetchUrl}${urlQueryParam.toString() ? '?' : ''}${urlQueryParam.toString()}`;\n\n // Final URL for API call\n fetchUrl = `${this.serverUrl.replace(/\\/$/, '')}${fetchUrl}`;\n if (fetchUrl.startsWith('http') === false) {\n const url = new URL(fetchUrl, window.location.href);\n curlUrl = url.href;\n } else {\n curlUrl = fetchUrl;\n }\n curl = `curl -X ${this.method.toUpperCase()} \"${curlUrl}\" \\\\\\n`;\n\n if (acceptHeader) {\n // Uses the acceptHeader from Response panel\n fetchOptions.headers.append('Accept', acceptHeader);\n curlHeaders += ` -H \"Accept: ${acceptHeader}\" \\\\\\n`;\n } else if (this.accept) {\n fetchOptions.headers.append('Accept', this.accept);\n curlHeaders += ` -H \"Accept: ${this.accept}\" \\\\\\n`;\n }\n\n // Add Header Params\n headerParamEls.map((el) => {\n if (el.value) {\n fetchOptions.headers.append(el.dataset.pname, el.value);\n curlHeaders += ` -H \"${el.dataset.pname}: ${el.value}\" \\\\\\n`;\n }\n });\n\n // Request Body Params\n if (requestBodyContainerEl) {\n const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;\n if (requestBodyType.includes('form-urlencoded')) {\n // url-encoded Form Params (dynamic) - Parse JSON and generate Params\n const formUrlDynamicTextAreaEl = requestPanelEl.querySelector(\"[data-ptype='dynamic-form']\");\n if (formUrlDynamicTextAreaEl) {\n const val = formUrlDynamicTextAreaEl.value;\n const formUrlDynParams = new URLSearchParams();\n let proceed = true;\n let tmpObj;\n if (val) {\n try {\n tmpObj = JSON.parse(val);\n } catch (err) {\n proceed = false;\n console.warn('OpenAPI Explorer: Invalid JSON provided', err); // eslint-disable-line no-console\n }\n } else {\n proceed = false;\n }\n if (proceed) {\n for (const prop in tmpObj) {\n formUrlDynParams.append(prop, JSON.stringify(tmpObj[prop]));\n }\n fetchOptions.body = formUrlDynParams;\n curlData = ` -d ${formUrlDynParams.toString()} \\\\\\n`;\n }\n } else {\n // url-encoded Form Params (regular)\n const formUrlEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='form-urlencode']\")];\n const formUrlParams = new URLSearchParams();\n formUrlEls\n .filter((v) => (v.type !== 'file'))\n .forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.value) {\n formUrlParams.append(el.dataset.pname, el.value);\n }\n } else {\n const vals = (el.value && Array.isArray(el.value)) ? el.value.join(',') : '';\n formUrlParams.append(el.dataset.pname, vals);\n }\n });\n fetchOptions.body = formUrlParams;\n curlData = ` -d ${formUrlParams.toString()} \\\\\\n`;\n }\n } else if (requestBodyType.includes('form-data')) {\n const formDataParams = new FormData();\n const formDataEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='form-data']\")];\n formDataEls.forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.type === 'file' && el.files[0]) {\n formDataParams.append(el.dataset.pname, el.files[0], el.files[0].name);\n curlForm += ` -F \"${el.dataset.pname}=@${el.files[0].name}\" \\\\\\n`;\n } else if (el.value) {\n formDataParams.append(el.dataset.pname, el.value);\n curlForm += ` -F \"${el.dataset.pname}=${el.value}\" \\\\\\n`;\n }\n } else if (el.value && Array.isArray(el.value)) {\n el.value.forEach((v) => {\n curlForm = `${curlForm} -F \"${el.dataset.pname}[]=${v}\" \\\\\\n`;\n });\n formDataParams.append(el.dataset.pname, el.value.join(','));\n }\n });\n fetchOptions.body = formDataParams;\n } else if (mediaFileRegex.test(requestBodyType) || textFileRegex.test(requestBodyType)) {\n const bodyParamFileEl = requestPanelEl.querySelector('.request-body-param-file');\n if (bodyParamFileEl && bodyParamFileEl.files[0]) {\n fetchOptions.body = bodyParamFileEl.files[0];\n curlData = ` --data-binary @${bodyParamFileEl.files[0].name} \\\\\\n`;\n }\n } else if (requestBodyType.includes('json') || requestBodyType.includes('xml') || requestBodyType.includes('text')) {\n const exampleTextAreaEl = requestPanelEl.querySelector('.request-body-param-user-input');\n if (exampleTextAreaEl && exampleTextAreaEl.value) {\n fetchOptions.body = exampleTextAreaEl.value;\n if (requestBodyType.includes('json')) {\n try {\n curlData = ` -d '${JSON.stringify(JSON.parse(exampleTextAreaEl.value))}' \\\\\\n`;\n } catch (err) { /* Ignore unparseable JSON */ }\n }\n\n if (!curlData) {\n // Save single quotes wrapped => 'text' => `\"'\"text\"'\"`\n curlData = ` -d '${exampleTextAreaEl.value.replace(/'/g, '\\'\"\\'\"\\'')}' \\\\\\n`;\n }\n }\n }\n // Common for all request-body\n if (!requestBodyType.includes('form-data')) {\n // For multipart/form-data don't set the content-type to allow creation of browser generated part boundaries\n fetchOptions.headers.append('Content-Type', requestBodyType);\n }\n curlHeaders += ` -H \"Content-Type: ${requestBodyType}\" \\\\\\n`;\n }\n this.curlSyntax = '';\n this.responseIsBlob = false;\n\n this.respContentDisposition = '';\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n this.curlSyntax = `${curl}${curlHeaders}${curlData}${curlForm}`;\n if (this.fetchCredentials) {\n fetchOptions.credentials = this.fetchCredentials;\n }\n\n // Options is legacy usage, documentation has been updated to reference properties of the fetch option directly, but older usages may still be using options\n const fetchRequest = { explorerLocation: this.elementId, url: fetchUrl, options: fetchOptions, ...fetchOptions };\n const event = {\n bubbles: true,\n composed: true,\n detail: {\n request: fetchRequest,\n },\n };\n this.dispatchEvent(new CustomEvent('before-try', event));\n this.dispatchEvent(new CustomEvent('request', event));\n const newFetchOptions = {\n method: fetchRequest.method || fetchOptions.method,\n headers: fetchRequest.headers || fetchOptions.headers,\n credentials: fetchRequest.credentials || fetchOptions.credentials,\n body: fetchRequest.body || fetchOptions.body\n };\n const fetchRequestObject = new Request(fetchRequest.url, newFetchOptions);\n\n let fetchResponse;\n try {\n let respBlob;\n let respJson;\n let respText;\n tryBtnEl.disabled = true;\n const fetchStart = new Date();\n\n this.responseStatus = '';\n this.responseMessage = '';\n this.responseUrl = '';\n this.responseHeaders = '';\n this.responseText = '⌛';\n\n this.requestUpdate();\n const awaiter = new Promise(resolve => setTimeout(resolve, 200));\n fetchResponse = await fetch(fetchRequestObject);\n this.responseElapsedMs = new Date() - fetchStart;\n await awaiter;\n\n tryBtnEl.disabled = false;\n this.responseStatus = fetchResponse.ok ? 'success' : 'error';\n this.responseMessage = fetchResponse.statusText ? `${fetchResponse.statusText} (${fetchResponse.status})` : fetchResponse.status;\n this.responseUrl = fetchResponse.url;\n this.responseHeaders = '';\n const headers = {};\n fetchResponse.headers.forEach((hdrVal, hdr) => {\n this.responseHeaders = `${this.responseHeaders}${hdr.trim()}: ${hdrVal}\\n`;\n headers[hdr.trim()] = hdrVal && hdrVal.trim();\n });\n const contentType = fetchResponse.headers.get('content-type');\n const respEmpty = (await fetchResponse.clone().text()).length === 0;\n if (respEmpty) {\n this.responseText = '';\n } else if (contentType) {\n if (contentType.includes('json')) {\n if ((/charset=[^\"']+/).test(contentType)) {\n const encoding = contentType.split('charset=')[1];\n const buffer = await fetchResponse.arrayBuffer();\n try {\n respText = new TextDecoder(encoding).decode(buffer);\n } catch {\n respText = new TextDecoder('utf-8').decode(buffer);\n }\n try {\n this.responseText = JSON.stringify(JSON.parse(respText), null, 8);\n } catch {\n this.responseText = respText;\n }\n } else {\n respJson = await fetchResponse.json();\n this.responseText = JSON.stringify(respJson, null, 8);\n }\n } else if (textFileRegex.test(contentType)) {\n this.responseIsBlob = true;\n this.responseBlobType = 'download';\n } else if (mediaFileRegex.test(contentType)) {\n this.responseIsBlob = true;\n this.responseBlobType = 'view';\n } else {\n respText = await fetchResponse.text();\n if (contentType.includes('xml')) {\n this.responseText = formatXml(respText, { textNodesOnSameLine: true, indentor: ' ' });\n } else {\n this.responseText = respText;\n }\n }\n if (this.responseIsBlob) {\n const contentDisposition = fetchResponse.headers.get('content-disposition');\n const filenameRegex = /filename[^;=\\n]*=((['\"]).*?\\2|[^;\\n]*)/;\n const filename = filenameRegex.exec(contentDisposition);\n this.respContentDisposition = filename && filename[1] && filename[1].replace(/['\"]/g, '') || `download.${mimeTypeResolver.extension(contentType) || 'file'}`;\n respBlob = await fetchResponse.blob();\n this.responseBlobUrl = URL.createObjectURL(respBlob);\n }\n } else {\n respText = await fetchResponse.text();\n this.responseText = respText;\n }\n const responseEvent = {\n bubbles: true,\n composed: true,\n detail: {\n explorerLocation: this.elementId,\n request: fetchRequest,\n response: {\n headers,\n body: respJson || respText || respBlob || fetchResponse.body,\n status: fetchResponse.status,\n },\n },\n };\n this.dispatchEvent(new CustomEvent('after-try', responseEvent));\n this.dispatchEvent(new CustomEvent('response', responseEvent));\n } catch (error) {\n tryBtnEl.disabled = false;\n this.responseMessage = `${error.message} (Check the browser network tab for more information.)`;\n this.responseStatus = 'error';\n const responseEvent = {\n bubbles: true,\n composed: true,\n detail: {\n explorerLocation: this.elementId,\n error,\n request: fetchRequest,\n },\n };\n document.dispatchEvent(new CustomEvent('after-try', responseEvent));\n document.dispatchEvent(new CustomEvent('response', responseEvent));\n }\n }\n\n onAddRemoveFileInput(e, pname, ptype) {\n if (e.target.tagName.toLowerCase() !== 'button') {\n return;\n }\n\n if (e.target.classList.contains('file-input-remove-btn')) {\n // Remove File Input Set\n const el = e.target.closest('.input-set');\n el.remove();\n return;\n }\n const el = e.target.closest('.file-input-container');\n\n // Add File Input Set\n\n // Container\n const newInputContainerEl = document.createElement('div');\n newInputContainerEl.setAttribute('class', 'input-set row');\n\n // File Input\n const newInputEl = document.createElement('input');\n newInputEl.type = 'file';\n newInputEl.style = 'width:200px; margin-top:2px;';\n newInputEl.setAttribute('data-pname', pname);\n newInputEl.setAttribute('data-ptype', ptype.includes('form-urlencode') ? 'form-urlencode' : 'form-data');\n newInputEl.setAttribute('data-array', 'false');\n newInputEl.setAttribute('data-file-array', 'true');\n\n // Remover Button\n const newRemoveBtnEl = document.createElement('button');\n newRemoveBtnEl.setAttribute('class', 'file-input-remove-btn');\n newRemoveBtnEl.innerHTML = '✕';\n\n newInputContainerEl.appendChild(newInputEl);\n newInputContainerEl.appendChild(newRemoveBtnEl);\n el.insertBefore(newInputContainerEl, e.target);\n // el.appendChild(newInputContainerEl);\n }\n\n downloadResponseBlob() {\n if (this.responseBlobUrl) {\n const a = document.createElement('a');\n document.body.appendChild(a);\n a.style = 'display: none';\n a.href = this.responseBlobUrl;\n a.download = this.respContentDisposition;\n a.click();\n a.remove();\n }\n }\n\n viewResponseBlob() {\n if (this.responseBlobUrl) {\n const a = document.createElement('a');\n document.body.appendChild(a);\n a.style = 'display: none';\n a.href = this.responseBlobUrl;\n a.target = '_blank';\n a.click();\n a.remove();\n }\n }\n\n clearResponseData() {\n this.responseUrl = '';\n this.responseHeaders = '';\n this.responseText = '';\n this.responseStatus = '';\n this.responseMessage = '';\n this.responseElapsedMs = 0;\n this.responseIsBlob = false;\n this.responseBlobType = '';\n this.respContentDisposition = '';\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n }\n\n requestParamFunction(event) {\n if (event.key === 'Enter') {\n this.onTryClick();\n event.preventDefault();\n }\n }\n\n disconnectedCallback() {\n // Cleanup ObjectURL forthe blob data if this component created one\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n super.disconnectedCallback();\n }\n}\n\n// Register the element with the browser\nif (!customElements.get('openapi-explorer')) {\n customElements.define('api-request', ApiRequest);\n}\n"],"names":[],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"openapi-explorer.min.js","mappings":";;AA0BA;AAQA;ACmsBA","sources":["webpack://openapi-explorer/./src/templates/code-samples-template.js","webpack://openapi-explorer/./src/components/api-request.js"],"sourcesContent":["import { html } from 'lit';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport Prism from 'prismjs';\nimport { copyToClipboard } from '../utils/common-utils';\nimport { getI18nText } from '../languages';\n\n/* eslint-disable indent */\nexport default function codeSamplesTemplate(xCodeSamples) {\n return html`\n <section class=\"table-title top-gap\"> CODE SAMPLES </div>\n <div class=\"tab-panel col\"\n @click=\"${\n (e) => {\n if (!e.target.classList.contains('tab-btn')) { return; }\n const clickedTab = e.target.dataset.tab;\n\n const tabButtons = [...e.currentTarget.querySelectorAll('.tab-btn')];\n const tabContents = [...e.currentTarget.querySelectorAll('.tab-content')];\n tabButtons.forEach((tabBtnEl) => tabBtnEl.classList[tabBtnEl.dataset.tab === clickedTab ? 'add' : 'remove']('active'));\n tabContents.forEach((tabBodyEl) => { tabBodyEl.style.display = (tabBodyEl.dataset.tab === clickedTab ? 'block' : 'none'); });\n }\n }\">\n <div class=\"tab-buttons row\" style=\"width:100; overflow\">\n ${xCodeSamples.map((v, i) => html`<button class=\"tab-btn ${i === 0 ? 'active' : ''}\" data-tab = '${v.lang}${i}'> ${v.label || v.lang} </button>`)}\n </div>\n ${xCodeSamples.map((v, i) => html`\n <div class=\"tab-content m-markdown code-sample-wrapper\" style= \"display:${i === 0 ? 'block' : 'none'}\" data-tab = '${v.lang}${i}'>\n <button class=\"toolbar-copy-btn\" @click='${(e) => { copyToClipboard(v.source, e); }}'>${getI18nText('operations.copy')}</button>\n <pre>\n <code>${Prism.languages[v.lang && v.lang.toLowerCase()] ? unsafeHTML(Prism.highlight(v.source, Prism.languages[v.lang && v.lang.toLowerCase()], v.lang && v.lang.toLowerCase())) : v.source}</code>\n </pre>\n </div>`)\n }\n </section>`;\n}\n/* eslint-enable indent */\n","import { LitElement, html } from 'lit';\nimport { marked } from 'marked';\nimport Prism from 'prismjs';\nimport mimeTypeResolver from './mime-types';\n\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport formatXml from 'xml-but-prettier';\n\nimport { copyToClipboard } from '../utils/common-utils';\nimport { getI18nText } from '../languages';\nimport { schemaInObjectNotation, getTypeInfo, generateExample } from '../utils/schema-utils';\nimport './json-tree';\nimport './schema-tree';\nimport './tag-input';\n\nconst textFileRegex = RegExp('^font/|tar$|zip$|7z$|rtf$|msword$|excel$|/pdf$|/octet-stream$|^application/vnd.');\nconst mediaFileRegex = RegExp('^audio/|^image/|^video/');\nconst truncateString = (str, length) => (str && str.length > length ? `${str.substring(0, length - 1)}…` : str);\n\nexport default class ApiRequest extends LitElement {\n createRenderRoot() { return this; }\n\n constructor() {\n super();\n this.responseMessage = '';\n this.responseStatus = '';\n this.responseHeaders = '';\n this.responseText = '';\n this.responseUrl = '';\n this.responseElapsedMs = 0;\n this.curlSyntax = '';\n this.activeResponseTab = 'response'; // allowed values: response, headers, curl\n this.selectedRequestBodyType = '';\n this.selectedRequestBodyExample = '';\n }\n\n static get properties() {\n return {\n serverUrl: { type: String, attribute: 'server-url' },\n servers: { type: Array },\n method: { type: String },\n path: { type: String },\n elementId: { type: String, attribute: 'element-id' },\n parameters: { type: Array },\n request_body: { type: Object },\n api_keys: { type: Array },\n parser: { type: Object },\n accept: { type: String },\n callback: { type: String },\n responseMessage: { type: String, attribute: false },\n responseText: { type: String, attribute: false },\n responseHeaders: { type: String, attribute: false },\n responseStatus: { type: String, attribute: false },\n responseUrl: { type: String, attribute: false },\n responseElapsedMs: { type: Number, attribute: false },\n fillRequestWithDefault: { type: String, attribute: 'fill-defaults' },\n includeNulls: { type: Boolean, attribute: 'display-nulls', converter(value) { return value === 'true'; } },\n allowTry: { type: String, attribute: 'enable-console' },\n renderStyle: { type: String, attribute: 'render-style' },\n schemaStyle: { type: String, attribute: 'schema-style' },\n activeSchemaTab: { type: String, attribute: 'active-schema-tab' },\n schemaExpandLevel: { type: Number, attribute: 'schema-expand-level' },\n schemaHideReadOnly: { type: String, attribute: 'schema-hide-read-only' },\n fetchCredentials: { type: String, attribute: 'fetch-credentials' },\n\n // properties for internal tracking\n activeResponseTab: { type: String }, // internal tracking of response-tab not exposed as a attribute\n selectedRequestBodyType: { type: String, attribute: 'selected-request-body-type' }, // internal tracking of selected request-body type\n selectedRequestBodyExample: { type: String, attribute: 'selected-request-body-example' }, // internal tracking of selected request-body example\n };\n }\n\n render() {\n return html`\n <div class=\"api-request col regular-font request-panel ${(this.renderStyle === 'focused' || this.callback === 'true') ? 'focused-mode' : 'view-mode'}\">\n <div class=\" ${this.callback === 'true' ? 'tiny-title' : 'req-res-title'} \"> \n ${this.callback === 'true' ? 'CALLBACK REQUEST' : getI18nText('operations.request')}\n </div>\n <div>\n ${this.inputParametersTemplate('path')}\n ${this.inputParametersTemplate('query')}\n ${this.requestBodyTemplate()}\n ${this.inputParametersTemplate('header')}\n ${this.inputParametersTemplate('cookie')}\n ${this.allowTry === 'false' ? '' : html`${this.apiCallTemplate()}`}\n </div> \n </div>\n `;\n }\n\n updated(changedProperties) {\n // In focused mode after rendering the request component, update the text-areas(which contains examples) using the original values from hidden textareas.\n // This is done coz, user may update the dom by editing the textarea's and once the DOM is updated externally change detection wont happen, therefore update the values manually\n if (this.renderStyle !== 'focused') {\n return;\n }\n\n // dont update example as only tabs is switched\n if (changedProperties.size === 1 && changedProperties.has('activeSchemaTab')) {\n return;\n }\n\n const exampleTextAreaEls = [...this.querySelectorAll('textarea[data-ptype=\"form-data\"]')];\n exampleTextAreaEls.forEach((el) => {\n const origExampleEl = this.querySelector(`textarea[data-pname='hidden-${el.dataset.pname}']`);\n if (origExampleEl) {\n el.value = origExampleEl.value;\n }\n });\n }\n\n /* eslint-disable indent */\n inputParametersTemplate(paramType) {\n const filteredParams = this.parameters ? this.parameters.filter((param) => param.in === paramType) : [];\n if (filteredParams.length === 0) {\n return '';\n }\n let title = '';\n if (paramType === 'path') {\n title = 'PATH PARAMETERS';\n } else if (paramType === 'query') {\n title = 'QUERY-STRING PARAMETERS';\n } else if (paramType === 'header') {\n title = 'REQUEST HEADERS';\n } else if (paramType === 'cookie') {\n title = 'COOKIES';\n }\n\n const tableRows = [];\n for (const param of filteredParams) {\n if (!param.schema) {\n continue;\n }\n const paramSchema = getTypeInfo(param.schema, { includeNulls: this.includeNulls });\n if (!paramSchema) {\n continue;\n }\n const defaultVal = Array.isArray(paramSchema.default) ? paramSchema.default : `${paramSchema.default}`;\n let paramStyle = 'form';\n let paramExplode = true;\n if (paramType === 'query') {\n if (param.style && 'form spaceDelimited pipeDelimited'.includes(param.style)) {\n paramStyle = param.style;\n }\n if (typeof param.explode === 'boolean') {\n paramExplode = param.explode;\n }\n }\n\n tableRows.push(html`\n <tr> \n <td style=\"width:160px; min-width:50px;\">\n <div class=\"param-name ${paramSchema.deprecated ? 'deprecated' : ''}\">\n ${param.name}${!paramSchema.deprecated && param.required ? html`<span style='color:var(--red);'>*</span>` : ''}\n </div>\n <div class=\"param-type\">\n ${paramSchema.type === 'array'\n ? `${paramSchema.arrayType}`\n : `${paramSchema.format ? paramSchema.format : paramSchema.type}`\n }${!paramSchema.deprecated && param.required ? html`<span style='opacity: 0;'>*</span>` : ''}\n </div>\n </td> \n ${this.allowTry === 'true'\n ? html`\n <td style=\"min-width:160px;\">\n ${paramSchema.type === 'array'\n ? html`\n <tag-input class=\"request-param\" \n style = \"width:100%;\" \n data-ptype = \"${paramType}\"\n data-pname = \"${param.name}\"\n data-default = \"${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}\"\n data-param-serialize-style = \"${paramStyle}\"\n data-param-serialize-explode = \"${paramExplode}\"\n data-array = \"true\"\n placeholder=\"${paramSchema.example || (Array.isArray(defaultVal) ? defaultVal[0] : defaultVal) || 'add-multiple ↩'}\"\n .value = \"${Array.isArray(defaultVal) ? defaultVal : defaultVal.split(',')}\"\n >\n </tag-input>`\n : paramSchema.type === 'object'\n ? html`\n <textarea \n class = \"textarea request-param\"\n part = \"textarea textarea-param\"\n data-ptype = \"${paramType}-object\"\n data-pname = \"${param.name}\"\n data-default = \"${defaultVal}\"\n data-param-serialize-style = \"${paramStyle}\"\n data-param-serialize-explode = \"${paramExplode}\"\n spellcheck = \"false\"\n placeholder=\"${paramSchema.example || defaultVal || ''}\"\n style = \"resize:vertical; width:100%; height: ${'read focused'.includes(this.renderStyle) ? '180px' : '120px'};\"\n .value=\"${this.fillRequestWithDefault === 'true' ? defaultVal : ''}\"\n ></textarea>`\n : html`\n <input type=\"${paramSchema.format === 'password' ? 'password' : 'text'}\" spellcheck=\"false\" style=\"width:100%\" placeholder=\"${paramSchema.example || defaultVal || ''}\"\n class=\"request-param\"\n part=\"textbox textbox-param\"\n data-ptype=\"${paramType}\"\n data-pname=\"${param.name}\" \n data-default=\"${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}\"\n data-array=\"false\"\n @keyup=\"${this.requestParamFunction}\"\n .value=\"${this.fillRequestWithDefault === 'true' ? defaultVal : ''}\"\n />`\n }\n </td>`\n : ''\n }\n ${this.renderStyle === 'focused'\n ? html`\n <td>\n ${paramSchema.default || paramSchema.constraint || paramSchema.allowedValues || paramSchema.pattern\n ? html`\n <div class=\"param-constraint\">\n ${paramSchema.constraint ? html`<span style=\"font-weight:bold\">Constraints: </span>${paramSchema.constraint}<br>` : ''}\n ${paramSchema.pattern ? html`<span style=\"font-weight:bold\">Pattern: </span>${truncateString(paramSchema.pattern, 60)}<br>` : ''}\n ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => html`\n ${i > 0 ? '|' : html`<span style=\"font-weight:bold\">Allowed: </span>`}\n ${html`\n <a part=\"anchor anchor-param-constraint\" class = \"${this.allowTry === 'true' ? '' : 'inactive-link'}\"\n data-type=\"${paramSchema.type === 'array' ? 'array' : 'string'}\"\n data-enum=\"${v.trim()}\"\n @click=\"${(e) => {\n const inputEl = e.target.closest('table').querySelector(`[data-pname=\"${param.name}\"]`);\n if (inputEl) {\n if (e.target.dataset.type === 'array') {\n inputEl.value = [e.target.dataset.enum];\n } else {\n inputEl.value = e.target.dataset.enum;\n }\n }\n }}\"\n >\n ${v} \n </a>`\n }`)}\n </div>`\n : ''\n }\n </td> \n </tr>`\n : ''\n }\n `);\n }\n\n return html`\n <div class=\"table-title top-gap\">${title}${paramType === 'path' ? html`<span style='color:var(--red);'>*</span>` : ''}</div>\n <div style=\"display:block; overflow-x:auto; max-width:100%;\">\n <table role=\"presentation\" class=\"m-table\" style=\"width:100%; word-break:break-word;\">\n ${tableRows}\n </table>\n </div>`;\n }\n\n resetRequestBodySelection() {\n this.selectedRequestBodyType = '';\n this.selectedRequestBodyExample = '';\n this.clearResponseData();\n }\n\n // Request-Body Event Handlers\n onSelectExample(e) {\n this.selectedRequestBodyExample = e.target.value;\n const exampleDropdownEl = e.target;\n window.setTimeout((selectEl) => {\n const exampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param');\n const userInputExampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param-user-input');\n userInputExampleTextareaEl.value = exampleTextareaEl.value;\n }, 0, exampleDropdownEl);\n }\n\n onMimeTypeChange(e) {\n this.selectedRequestBodyType = e.target.value;\n const mimeDropdownEl = e.target;\n this.selectedRequestBodyExample = '';\n window.setTimeout((selectEl) => {\n const exampleTextareaEl = selectEl.closest('.request-body-container').querySelector('.request-body-param');\n if (exampleTextareaEl) {\n const userInputExampleTextareaEl = selectEl.closest('.request-body-container').querySelector('.request-body-param-user-input');\n userInputExampleTextareaEl.value = exampleTextareaEl.value;\n }\n }, 0, mimeDropdownEl);\n }\n\n requestBodyTemplate() {\n if (!this.request_body) {\n return '';\n }\n if (Object.keys(this.request_body).length === 0) {\n return '';\n }\n\n // Variable to store partial HTMLs\n let reqBodyTypeSelectorHtml = '';\n let reqBodyFileInputHtml = '';\n let reqBodyFormHtml = '';\n let reqBodySchemaHtml = '';\n let reqBodyDefaultHtml = '';\n\n const requestBodyTypes = [];\n const content = this.request_body.content;\n for (const mimeType in content) {\n requestBodyTypes.push({\n mimeType,\n schema: content[mimeType].schema,\n example: content[mimeType].example,\n examples: content[mimeType].examples,\n });\n if (!this.selectedRequestBodyType) {\n this.selectedRequestBodyType = mimeType;\n }\n }\n // MIME Type selector\n reqBodyTypeSelectorHtml = requestBodyTypes.length === 1\n ? ''\n : html`\n <select aria-label=\"mime type\" style=\"min-width:100px; max-width:100%; margin-bottom:-1px;\" @change = '${(e) => this.onMimeTypeChange(e)}'>\n ${requestBodyTypes.map((reqBody) => html`\n <option value = '${reqBody.mimeType}' ?selected = '${reqBody.mimeType === this.selectedRequestBodyType}'>\n ${reqBody.mimeType}\n </option> `)\n }\n </select>\n `;\n\n // For Loop - Main\n requestBodyTypes.forEach((reqBody) => {\n let reqBodyExamples = [];\n\n if (this.selectedRequestBodyType.includes('json') || this.selectedRequestBodyType.includes('xml') || this.selectedRequestBodyType.includes('text')) {\n // Generate Example\n if (reqBody.mimeType === this.selectedRequestBodyType) {\n reqBodyExamples = generateExample(\n reqBody.examples ? reqBody.examples : '',\n reqBody.example ? reqBody.example : '',\n reqBody.schema,\n reqBody.mimeType,\n false,\n true,\n 'text',\n true\n );\n\n if (!this.selectedRequestBodyExample) {\n this.selectedRequestBodyExample = (reqBodyExamples.length > 0 ? reqBodyExamples[0].exampleId : '');\n }\n reqBodyDefaultHtml = html`\n ${reqBodyDefaultHtml}\n <div class = 'example-panel border-top pad-top-8'>\n ${reqBodyExamples.length === 1\n ? ''\n : html`\n <select aria-label='request body example' style=\"min-width:100px; max-width:100%; margin-bottom:-1px;\" @change='${(e) => this.onSelectExample(e)}'>\n ${reqBodyExamples.map((v) => html`<option value=\"${v.exampleId}\" ?selected=${v.exampleId === this.selectedRequestBodyExample} > \n ${v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary ? v.exampleSummary : v.exampleId} \n </option>`)}\n </select>\n `\n }\n ${reqBodyExamples\n .filter((v) => v.exampleId === this.selectedRequestBodyExample)\n .map((v) => html`\n <div class=\"example ${v.exampleId === this.selectedRequestBodyExample ? 'example-selected' : ''}\" data-default = '${v.exampleId}'>\n ${v.exampleSummary && v.exampleSummary.length > 80 ? html`<div style=\"padding: 4px 0\"> ${v.exampleSummary} </div>` : ''}\n ${v.exampleDescription ? html`<div class=\"m-markdown-small\" style=\"padding: 4px 0\"> ${unsafeHTML(marked(v.exampleDescription || ''))} </div>` : ''}\n <!-- this textarea is for user to edit the example -->\n <slot name=\"${this.elementId}--request-body\">\n <textarea \n class = \"textarea request-body-param-user-input\"\n part = \"textarea textarea-param\"\n spellcheck = \"false\"\n data-ptype = \"${reqBody.mimeType}\" \n data-default = \"${v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8)}\"\n data-default-format = \"${v.exampleFormat}\"\n style=\"width:100%; resize:vertical;\"\n .value=\"${this.fillRequestWithDefault === 'true' ? (v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8)) : ''}\"\n ></textarea>\n </slot>\n\n <!-- This textarea(hidden) is to store the original example value, this will remain unchanged when users switches from one example to another, its is used to populate the editable textarea -->\n <textarea \n class = \"textarea is-hidden request-body-param ${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)}\" \n spellcheck = \"false\"\n data-ptype = \"${reqBody.mimeType}\" \n style=\"width:100%; resize:vertical; display:none\"\n .value=\"${(v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8))}\"\n ></textarea>\n </div> \n `)}\n\n </div>\n `;\n }\n } else if (this.selectedRequestBodyType.includes('form-urlencoded') || this.selectedRequestBodyType.includes('form-data')) {\n if (reqBody.mimeType === this.selectedRequestBodyType) {\n const ex = generateExample(\n reqBody.examples ? reqBody.examples : '',\n reqBody.example ? reqBody.example : '',\n reqBody.schema,\n reqBody.mimeType,\n false,\n true,\n 'text',\n true\n );\n if (reqBody.schema) {\n reqBodyFormHtml = this.formDataTemplate(reqBody.schema, reqBody.mimeType, (ex[0] ? ex[0].exampleValue : ''));\n }\n }\n } else if (mediaFileRegex.test(this.selectedRequestBodyType) || textFileRegex.test(this.selectedRequestBodyType)) {\n if (reqBody.mimeType === this.selectedRequestBodyType) {\n reqBodyFileInputHtml = html`\n <div class = \"small-font-size bold-text row\">\n <input type=\"file\" part=\"file-input\" style=\"max-width:100%\" class=\"request-body-param-file\" data-ptype=\"${reqBody.mimeType}\" spellcheck=\"false\" />\n </div> \n `;\n }\n }\n\n // Generate Schema\n if (reqBody.mimeType.includes('json') || reqBody.mimeType.includes('xml') || reqBody.mimeType.includes('text')) {\n const schemaAsObj = schemaInObjectNotation(reqBody.schema, { includeNulls: this.includeNulls });\n if (this.schemaStyle === 'table') {\n reqBodySchemaHtml = html`\n ${reqBodySchemaHtml}\n <schema-table\n class = '${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)} pad-top-8'\n style = 'display: ${this.selectedRequestBodyType === reqBody.mimeType ? 'block' : 'none'};'\n .data = '${schemaAsObj}'\n schema-expand-level = \"${this.schemaExpandLevel}\"\n schema-hide-read-only = \"${this.schemaHideReadOnly.includes(this.method)}\"\n schema-hide-write-only = false\n > </schema-table>\n `;\n } else {\n reqBodySchemaHtml = html`\n ${reqBodySchemaHtml}\n <schema-tree\n class = '${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)} pad-top-8'\n style = 'display: ${this.selectedRequestBodyType === reqBody.mimeType ? 'block' : 'none'};'\n .data = '${schemaAsObj}'\n schema-expand-level = \"${this.schemaExpandLevel}\"\n schema-hide-read-only = \"${this.schemaHideReadOnly.includes(this.method)}\"\n schema-hide-write-only = false\n > </schema-tree>\n `;\n }\n }\n });\n\n return html`\n <div class='request-body-container' data-selected-request-body-type=\"${this.selectedRequestBodyType}\">\n <div class=\"table-title top-gap row\">\n REQUEST BODY ${this.request_body.required ? html`<span class=\"mono-font\" style='color:var(--red)'>*</span>` : ''} \n <span style = \"font-weight:normal; margin-left:5px\"> ${this.selectedRequestBodyType}</span>\n <span style=\"flex:1\"></span>\n ${reqBodyTypeSelectorHtml}\n </div>\n ${this.request_body.description ? html`<div class=\"m-markdown\" style=\"margin-bottom:12px\">${unsafeHTML(marked(this.request_body.description))}</div>` : ''}\n \n ${(this.selectedRequestBodyType.includes('json') || this.selectedRequestBodyType.includes('xml') || this.selectedRequestBodyType.includes('text'))\n ? html`\n <div class=\"tab-panel col\" style=\"border-width:0 0 1px 0;\">\n <div class=\"tab-buttons row\" @click=\"${(e) => { if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; } }}\">\n <button class=\"tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}\" data-tab=\"model\" >${getI18nText('operations.model')}</button>\n <button class=\"tab-btn ${this.activeSchemaTab === 'body' ? 'active' : ''}\" data-tab=\"body\">${getI18nText('operations.body')}</button>\n </div>\n ${html`<div class=\"tab-content col\" style=\"display: ${this.activeSchemaTab === 'model' ? 'block' : 'none'}\"> ${reqBodySchemaHtml}</div>`}\n ${html`<div class=\"tab-content col\" style=\"display: ${this.activeSchemaTab === 'model' ? 'none' : 'block'}\"> ${reqBodyDefaultHtml}</div>`}\n </div>`\n : html` \n ${reqBodyFileInputHtml}\n ${reqBodyFormHtml}`\n }\n </div> \n `;\n }\n\n formDataTemplate(schema, mimeType, exampleValue = '') {\n const formDataTableRows = [];\n if (schema.properties) {\n for (const fieldName in schema.properties) {\n const fieldSchema = schema.properties[fieldName];\n if (fieldSchema.readOnly) {\n continue;\n }\n\n const fieldType = fieldSchema.type;\n const formdataPartSchema = schemaInObjectNotation(fieldSchema, { includeNulls: this.includeNulls });\n const paramSchema = getTypeInfo(fieldSchema, { includeNulls: this.includeNulls });\n const formdataPartExample = generateExample(\n '',\n fieldSchema.example ? fieldSchema.example : '',\n fieldSchema,\n 'json',\n false,\n true,\n 'text',\n true\n );\n\n formDataTableRows.push(html`\n <tr> \n <td style=\"width:160px; min-width:100px;\">\n <div class=\"param-name ${fieldSchema.deprecated ? 'deprecated' : ''}\">\n ${fieldName}${!fieldSchema.deprecated && (schema.required && schema.required.includes(fieldName) || fieldSchema.required) ? html`<span style='color:var(--red);'>*</span>` : ''}\n </div>\n <div class=\"param-type\">\n ${paramSchema.type === 'array' ? html`[<span>${paramSchema.format || paramSchema.type}</span>]` : `${paramSchema.format || paramSchema.type}`}\n </div>\n </td> \n <td \n style=\"${fieldType === 'object' ? 'width:100%; padding:0;' : this.allowTry === 'true' ? '' : 'display:none;'} min-width:100px;\" \n colspan=\"${fieldType === 'object' ? 2 : 1}\">\n ${fieldType === 'array'\n ? (fieldSchema.items && fieldSchema.items.format === 'binary')\n ? html`\n <div class=\"file-input-container col\" style='align-items:flex-end;' @click=\"${(e) => this.onAddRemoveFileInput(e, fieldName, mimeType)}\">\n <div class='input-set row'>\n <input \n type = \"file\"\n part = \"file-input\"\n style = \"width:100%\" \n data-pname = \"${fieldName}\" \n data-ptype = \"${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}\"\n data-array = \"false\" \n data-file-array = \"true\" \n />\n <button class=\"file-input-remove-btn\"> ✕ </button>\n </div> \n <button class=\"m-btn primary file-input-add-btn\" part=\"btn btn-fill\" style=\"margin:2px 25px 0 0; padding:2px 6px;\">ADD</button>\n </div> \n `\n : html`\n <tag-input\n style = \"width:100%;\" \n data-ptype = \"${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}\"\n data-pname = \"${fieldName}\"\n data-default = \"${paramSchema.default || ''}\"\n data-array = \"true\"\n placeholder=\"${(Array.isArray(paramSchema.example) ? paramSchema.example[0] : paramSchema.example) || 'add-multiple ↩'}\"\n .value = \"${paramSchema.default || ''}\"\n >\n </tag-input>\n `\n : html`\n ${fieldType === 'object'\n ? html`\n <div class=\"tab-panel row\" style=\"min-height:300px; border-left: 6px solid var(--light-border-color); align-items: stretch;\">\n <div style=\"width:24px; background-color:var(--light-border-color)\">\n <div class=\"row\" style=\"flex-direction:row-reverse; width:260px; height:24px; transform:rotate(270deg) translateX(-260px); transform-origin:top left; display:block;\" @click=\"${(e) => {\n if (e.target.classList.contains('v-tab-btn')) {\n const tab = e.target.dataset.tab;\n if (tab) {\n const tabPanelEl = e.target.closest('.tab-panel');\n const selectedTabBtnEl = tabPanelEl.querySelector(`.v-tab-btn[data-tab=\"${tab}\"]`);\n const otherTabBtnEl = [...tabPanelEl.querySelectorAll(`.v-tab-btn:not([data-tab=\"${tab}\"])`)];\n const selectedTabContentEl = tabPanelEl.querySelector(`.tab-content[data-tab=\"${tab}\"]`);\n const otherTabContentEl = [...tabPanelEl.querySelectorAll(`.tab-content:not([data-tab=\"${tab}\"])`)];\n selectedTabBtnEl.classList.add('active');\n selectedTabContentEl.style.display = 'block';\n otherTabBtnEl.forEach((el) => { el.classList.remove('active'); });\n otherTabContentEl.forEach((el) => { el.style.display = 'none'; });\n }\n }\n if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; }\n }}\">\n <button class=\"v-tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}\" data-tab = 'model'>${getI18nText('operations.model')}</button>\n <button class=\"v-tab-btn ${this.activeSchemaTab === 'body' ? 'active' : ''}\" data-tab = 'body'>${getI18nText('operations.request-body')}</button>\n </div>\n </div> \n ${html`\n <div class=\"tab-content col\" data-tab = 'model' style=\"display:${this.activeSchemaTab === 'model' ? 'block' : 'none'}; padding-left:5px; width:100%;\"> \n <schema-tree\n .data = '${formdataPartSchema}'\n schema-expand-level = \"${this.schemaExpandLevel}\"> </schema-tree>\n </div>`\n }\n ${html`\n <div class=\"tab-content col\" data-tab = 'body' style=\"display:${this.activeSchemaTab === 'body' ? 'block' : 'none'}; padding-left:5px; width:100%\"> \n <textarea \n class = \"textarea\" placeholder=\"${formdataPartExample[0] && formdataPartExample[0].exampleValue || paramSchema.default || ''}\"\n part = \"textarea textarea-param\"\n style = \"width:100%; border:none; resize:vertical;\" \n data-array = \"false\" \n data-ptype = \"${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}\"\n data-pname = \"${fieldName}\"\n data-default = \"${paramSchema.default || ''}\"\n spellcheck = \"false\"\n .value=\"${this.fillRequestWithDefault === 'true' ? paramSchema.default : ''}\"\n ></textarea>\n <!-- This textarea(hidden) is to store the original example value, in focused mode on navbar change it is used to update the example text -->\n <textarea data-pname = \"hidden-${fieldName}\" data-ptype = \"${mimeType.includes('form-urlencode') ? 'hidden-form-urlencode' : 'hidden-form-data'}\" class=\"is-hidden\" style=\"display:none\" .value=\"${paramSchema.default}\"></textarea>\n </div>`\n }\n </div>`\n : html`\n ${this.allowTry === 'true'\n ? html`<input placeholder=\"${paramSchema.example || paramSchema.default || ''}\"\n .value = \"${this.fillRequestWithDefault === 'true' ? (paramSchema.default || '') : ''}\"\n spellcheck = \"false\"\n type = \"${fieldSchema.format === 'binary' ? 'file' : fieldSchema.format === 'password' ? 'password' : 'text'}\"\n part = \"textbox textbox-param\"\n style = \"width:100%\"\n data-ptype = \"${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}\"\n data-pname = \"${fieldName}\"\n data-default = \"${paramSchema.default || ''}\"\n data-array = \"false\"\n />`\n : ''\n }\n `\n }`\n }\n </td>\n ${fieldType === 'object'\n ? ''\n : html`\n <td>\n ${paramSchema.default || paramSchema.constraint || paramSchema.allowedValues || paramSchema.pattern\n ? html`\n <div class=\"param-constraint\">\n ${paramSchema.pattern ? html`<span style=\"font-weight:bold\">Pattern: </span>${paramSchema.pattern}<br/>` : ''}\n ${paramSchema.constraint ? html`<span style=\"font-weight:bold\">Constraints: </span>${paramSchema.constraint}<br/>` : ''}\n ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => html`\n ${i > 0 ? '|' : html`<span style=\"font-weight:bold\">Allowed: </span>`}\n ${html`\n <a part=\"anchor anchor-param-constraint\" class = \"${this.allowTry === 'true' ? '' : 'inactive-link'}\"\n data-type=\"${paramSchema.type === 'array' ? paramSchema.type : 'string'}\"\n data-enum=\"${v.trim()}\"\n @click=\"${(e) => {\n const inputEl = e.target.closest('table').querySelector(`[data-pname=\"${fieldName}\"]`);\n if (inputEl) {\n if (e.target.dataset.type === 'array') {\n inputEl.value = [e.target.dataset.enum];\n } else {\n inputEl.value = e.target.dataset.enum;\n }\n }\n }}\"\n > \n ${v} \n </a>`\n }`)\n }\n </div>`\n : ''\n }\n </td>`\n }\n </tr>\n ${fieldType === 'object'\n ? ''\n : html`\n <tr>\n <td style=\"border:none\"> </td>\n <td colspan=\"2\" style=\"border:none; margin-top:0; padding:0 5px 8px 5px;\"> \n <span class=\"m-markdown-small\">${unsafeHTML(marked(fieldSchema.description || ''))}</span>\n ${paramSchema.example\n ? html`\n <span>\n <span style=\"font-weight:bold\"> Example: </span>\n ${paramSchema.type === 'array' ? '[ ' : ''}\n <a part=\"anchor anchor-param-example\" class = \"${this.allowTry === 'true' ? '' : 'inactive-link'}\"\n data-default-type=\"${paramSchema.type === 'array' ? paramSchema.type : 'string'}\"\n data-default = \"${Array.isArray(paramSchema.example) && paramSchema.example.join('~|~') || paramSchema.example || ''}\"\n @click=\"${(e) => {\n const inputEl = e.target.closest('table').querySelector(`[data-pname=\"${fieldName}\"]`);\n if (inputEl) {\n if (e.target.dataset.exampleType === 'array') {\n inputEl.value = e.target.dataset.example.split('~|~');\n } else {\n inputEl.value = e.target.dataset.example;\n }\n }\n }}\"\n >\n ${paramSchema.type === 'array' ? paramSchema.example.join(', ') : paramSchema.example}\n </a>\n ${paramSchema.type === 'array' ? '] ' : ''}\n </span>`\n : ''\n }\n </td>\n </tr>\n `\n }`);\n }\n return html`\n <table role=\"presentation\" style=\"width:100%;\" class=\"m-table\">\n ${formDataTableRows}\n </table>\n `;\n }\n\n return html`\n <textarea\n class = \"textarea dynamic-form-param ${mimeType}\"\n part = \"textarea textarea-param\"\n spellcheck = \"false\"\n data-pname=\"dynamic-form\" \n data-ptype=\"${mimeType}\" \n style=\"width:100%\"\n >${exampleValue}</textarea>\n ${schema.description ? html`<span class=\"m-markdown-small\">${unsafeHTML(marked(schema.description))}</span>` : ''}\n `;\n }\n\n apiResponseTabTemplate() {\n const responseFormat = this.responseHeaders.includes('json') ? 'json' : (this.responseHeaders.includes('html') || this.responseHeaders.includes('xml')) ? 'html' : '';\n return html`\n <div class=\"row\" style=\"font-size:var(--font-size-small); margin:5px 0\">\n ${this.responseMessage\n ? html`<div class=\"response-message ${this.responseStatus}\">Response Status: ${this.responseMessage}\n ${this.responseElapsedMs ? html`<span><br>Execution Time: ${this.responseElapsedMs}ms</span>` : ''}\n </div>` : ''\n }\n <div style=\"flex:1\"></div>\n <button class=\"m-btn\" part=\"btn btn-outline\" @click=\"${this.clearResponseData}\">CLEAR RESPONSE</button>\n </div>\n <div class=\"tab-panel col\" style=\"border-width:0 0 1px 0;\">\n <div id=\"tab_buttons\" class=\"tab-buttons row\" @click=\"${(e) => {\n if (e.target.classList.contains('tab-btn') === false) { return; }\n this.activeResponseTab = e.target.dataset.tab;\n }}\">\n <button class=\"tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}\" data-tab = 'response'>${getI18nText('operations.response')}</button>\n <button class=\"tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}\" data-tab = 'headers'>${getI18nText('operations.response-headers')}</button>\n <button class=\"tab-btn ${this.activeResponseTab === 'curl' ? 'active' : ''}\" data-tab = 'curl'>CURL</button>\n </div>\n ${this.responseIsBlob\n ? html`\n <div class=\"tab-content col\" style=\"flex:1; display:${this.activeResponseTab === 'response' ? 'flex' : 'none'};\">\n <button class=\"m-btn thin-border mar-top-8\" style=\"width:135px\" @click=\"${this.downloadResponseBlob}\" part=\"btn btn-outline\">DOWNLOAD</button>\n ${this.responseBlobType === 'view'\n ? html`<button class=\"m-btn thin-border mar-top-8\" style=\"width:135px\" @click=\"${this.viewResponseBlob}\" part=\"btn btn-outline\">VIEW (NEW TAB)</button>`\n : ''\n }\n </div>`\n : html`\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'};\" >\n <button class=\"toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.responseText, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre>${responseFormat\n ? html`<code>${unsafeHTML(Prism.highlight(this.responseText, Prism.languages[responseFormat], responseFormat))}</code>`\n : `${this.responseText}`\n }\n </pre>\n </div>`\n }\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'};\" >\n <button class=\"toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.responseHeaders, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre><code>${unsafeHTML(Prism.highlight(this.responseHeaders, Prism.languages.css, 'css'))}</code></pre>\n </div>\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'curl' ? 'flex' : 'none'};\">\n <button class=\"toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.curlSyntax.replace(/\\\\$/, ''), e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre><code>${unsafeHTML(Prism.highlight(this.curlSyntax.trim().replace(/\\\\$/, ''), Prism.languages.shell, 'shell'))}</code></pre>\n </div>\n </div>`;\n }\n\n apiCallTemplate() {\n return html`\n <div style=\"display:flex; align-items:flex-end; margin:16px 0; font-size:var(--font-size-small);\">\n ${\n this.parameters.length > 0 || this.request_body\n ? html`\n <button class=\"m-btn thin-border\" part=\"btn btn-outline\" style=\"margin-right:5px;\" @click=\"${this.onClearRequestData}\">\n ${getI18nText('operations.clear')}\n </button>`\n : ''\n }\n <button class=\"m-btn primary btn-execute thin-border\" part=\"btn btn-fill btn-try\" @click=\"${this.onTryClick}\">${getI18nText('operations.execute')}</button>\n </div>\n ${this.responseMessage === '' ? '' : this.apiResponseTabTemplate()}\n `;\n }\n /* eslint-enable indent */\n\n onClearRequestData(e) {\n const requestPanelEl = e.target.closest('.request-panel');\n const requestPanelInputEls = [...requestPanelEl.querySelectorAll('input, tag-input, textarea:not(.is-hidden)')];\n requestPanelInputEls.forEach((el) => { el.value = ''; });\n\n const event = { bubbles: true, composed: true, detail: { explorerLocation: this.elementId, type: 'RequestCleared' } };\n this.dispatchEvent(new CustomEvent('event', event));\n }\n\n async onTryClick() {\n const tryBtnEl = this.querySelectorAll('.btn-execute')[0];\n let fetchUrl;\n let curlUrl;\n let curl = '';\n let curlHeaders = '';\n let curlData = '';\n let curlForm = '';\n const closestRespContainer = this.closest('.expanded-req-resp-container, .req-resp-container');\n const respEl = closestRespContainer && closestRespContainer.getElementsByTagName('api-response')[0];\n const acceptHeader = respEl && respEl.selectedMimeType;\n const requestPanelEl = this.closest('.request-panel');\n const pathParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='path']\")];\n const queryParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='query']\")];\n const queryParamObjTypeEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='query-object']\")];\n const headerParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='header']\")];\n const requestBodyContainerEl = requestPanelEl.querySelector('.request-body-container');\n\n fetchUrl = this.path.replaceAll(' ', '');\n const fetchOptions = {\n method: this.method.toUpperCase(),\n headers: new Headers()\n };\n // Generate URL using Path Params\n pathParamEls.map((el) => {\n fetchUrl = fetchUrl.replace(`{${el.dataset.pname}}`, encodeURIComponent(el.value));\n });\n\n // Query Params\n const urlQueryParam = new URLSearchParams();\n if (queryParamEls.length > 0) {\n queryParamEls.forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.value !== '') {\n urlQueryParam.append(el.dataset.pname, el.value);\n }\n } else {\n const paramSerializeStyle = el.dataset.paramSerializeStyle;\n const paramSerializeExplode = el.dataset.paramSerializeExplode;\n let vals = ((el.value && Array.isArray(el.value)) ? el.value : []);\n vals = Array.isArray(vals) ? vals.filter((v) => v !== '') : [];\n if (vals.length > 0) {\n if (paramSerializeStyle === 'spaceDelimited') {\n urlQueryParam.append(el.dataset.pname, vals.join(' ').replace(/^\\s|\\s$/g, ''));\n } else if (paramSerializeStyle === 'pipeDelimited') {\n urlQueryParam.append(el.dataset.pname, vals.join('|').replace(/^\\||\\|$/g, ''));\n } else {\n if (paramSerializeExplode === 'true') { // eslint-disable-line no-lonely-if\n vals.forEach((v) => { urlQueryParam.append(el.dataset.pname, v); });\n } else {\n urlQueryParam.append(el.dataset.pname, vals.join(',').replace(/^,|,$/g, ''));\n }\n }\n }\n }\n });\n }\n\n // Query Params (Dynamic - create from JSON)\n if (queryParamObjTypeEls.length > 0) {\n queryParamObjTypeEls.map((el) => {\n try {\n let queryParamObj = {};\n const paramSerializeStyle = el.dataset.paramSerializeStyle;\n const paramSerializeExplode = el.dataset.paramSerializeExplode;\n queryParamObj = Object.assign(queryParamObj, JSON.parse(el.value.replace(/\\s+/g, ' ')));\n for (const key in queryParamObj) {\n if (typeof queryParamObj[key] === 'object') {\n if (Array.isArray(queryParamObj[key])) {\n if (paramSerializeStyle === 'spaceDelimited') {\n urlQueryParam.append(key, queryParamObj[key].join(' '));\n } else if (paramSerializeStyle === 'pipeDelimited') {\n urlQueryParam.append(key, queryParamObj[key].join('|'));\n } else {\n if (paramSerializeExplode === 'true') { // eslint-disable-line no-lonely-if\n queryParamObj[key].forEach((v) => {\n urlQueryParam.append(key, v);\n });\n } else {\n urlQueryParam.append(key, queryParamObj[key]);\n }\n }\n }\n } else {\n urlQueryParam.append(key, queryParamObj[key]);\n }\n }\n } catch (err) {\n console.log('OpenAPI Explorer: unable to parse %s into object', el.value); // eslint-disable-line no-console\n }\n });\n }\n\n // Add Authentication api keys if provided\n this.api_keys.filter((v) => v.finalKeyValue).forEach((v) => {\n if (v.in === 'query') {\n urlQueryParam.append(v.name, v.finalKeyValue);\n return;\n }\n\n // Otherwise put it in the header\n fetchOptions.headers.append(v.name, v.finalKeyValue);\n curlHeaders += ` -H \"${v.name}: ${v.finalKeyValue}\" \\\\\\n`;\n });\n\n fetchUrl = `${fetchUrl}${urlQueryParam.toString() ? '?' : ''}${urlQueryParam.toString()}`;\n\n // Final URL for API call\n fetchUrl = `${this.serverUrl.replace(/\\/$/, '')}${fetchUrl}`;\n if (fetchUrl.startsWith('http') === false) {\n const url = new URL(fetchUrl, window.location.href);\n curlUrl = url.href;\n } else {\n curlUrl = fetchUrl;\n }\n curl = `curl -X ${this.method.toUpperCase()} \"${curlUrl}\" \\\\\\n`;\n\n if (acceptHeader) {\n // Uses the acceptHeader from Response panel\n fetchOptions.headers.append('Accept', acceptHeader);\n curlHeaders += ` -H \"Accept: ${acceptHeader}\" \\\\\\n`;\n } else if (this.accept) {\n fetchOptions.headers.append('Accept', this.accept);\n curlHeaders += ` -H \"Accept: ${this.accept}\" \\\\\\n`;\n }\n\n // Add Header Params\n headerParamEls.map((el) => {\n if (el.value) {\n fetchOptions.headers.append(el.dataset.pname, el.value);\n curlHeaders += ` -H \"${el.dataset.pname}: ${el.value}\" \\\\\\n`;\n }\n });\n\n // Request Body Params\n if (requestBodyContainerEl) {\n const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;\n if (requestBodyType.includes('form-urlencoded')) {\n // url-encoded Form Params (dynamic) - Parse JSON and generate Params\n const formUrlDynamicTextAreaEl = requestPanelEl.querySelector(\"[data-ptype='dynamic-form']\");\n if (formUrlDynamicTextAreaEl) {\n const val = formUrlDynamicTextAreaEl.value;\n const formUrlDynParams = new URLSearchParams();\n let proceed = true;\n let tmpObj;\n if (val) {\n try {\n tmpObj = JSON.parse(val);\n } catch (err) {\n proceed = false;\n console.warn('OpenAPI Explorer: Invalid JSON provided', err); // eslint-disable-line no-console\n }\n } else {\n proceed = false;\n }\n if (proceed) {\n for (const prop in tmpObj) {\n formUrlDynParams.append(prop, JSON.stringify(tmpObj[prop]));\n }\n fetchOptions.body = formUrlDynParams;\n curlData = ` -d ${formUrlDynParams.toString()} \\\\\\n`;\n }\n } else {\n // url-encoded Form Params (regular)\n const formUrlEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='form-urlencode']\")];\n const formUrlParams = new URLSearchParams();\n formUrlEls\n .filter((v) => (v.type !== 'file'))\n .forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.value) {\n formUrlParams.append(el.dataset.pname, el.value);\n }\n } else {\n const vals = (el.value && Array.isArray(el.value)) ? el.value.join(',') : '';\n formUrlParams.append(el.dataset.pname, vals);\n }\n });\n fetchOptions.body = formUrlParams;\n curlData = ` -d ${formUrlParams.toString()} \\\\\\n`;\n }\n } else if (requestBodyType.includes('form-data')) {\n const formDataParams = new FormData();\n const formDataEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='form-data']\")];\n formDataEls.forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.type === 'file' && el.files[0]) {\n formDataParams.append(el.dataset.pname, el.files[0], el.files[0].name);\n curlForm += ` -F \"${el.dataset.pname}=@${el.files[0].name}\" \\\\\\n`;\n } else if (el.value) {\n formDataParams.append(el.dataset.pname, el.value);\n curlForm += ` -F \"${el.dataset.pname}=${el.value}\" \\\\\\n`;\n }\n } else if (el.value && Array.isArray(el.value)) {\n el.value.forEach((v) => {\n curlForm = `${curlForm} -F \"${el.dataset.pname}[]=${v}\" \\\\\\n`;\n });\n formDataParams.append(el.dataset.pname, el.value.join(','));\n }\n });\n fetchOptions.body = formDataParams;\n } else if (mediaFileRegex.test(requestBodyType) || textFileRegex.test(requestBodyType)) {\n const bodyParamFileEl = requestPanelEl.querySelector('.request-body-param-file');\n if (bodyParamFileEl && bodyParamFileEl.files[0]) {\n fetchOptions.body = bodyParamFileEl.files[0];\n curlData = ` --data-binary @${bodyParamFileEl.files[0].name} \\\\\\n`;\n }\n } else if (requestBodyType.includes('json') || requestBodyType.includes('xml') || requestBodyType.includes('text')) {\n const exampleTextAreaEl = requestPanelEl.querySelector('.request-body-param-user-input');\n if (exampleTextAreaEl && exampleTextAreaEl.value) {\n fetchOptions.body = exampleTextAreaEl.value;\n if (requestBodyType.includes('json')) {\n try {\n curlData = ` -d '${JSON.stringify(JSON.parse(exampleTextAreaEl.value))}' \\\\\\n`;\n } catch (err) { /* Ignore unparseable JSON */ }\n }\n\n if (!curlData) {\n // Save single quotes wrapped => 'text' => `\"'\"text\"'\"`\n curlData = ` -d '${exampleTextAreaEl.value.replace(/'/g, '\\'\"\\'\"\\'')}' \\\\\\n`;\n }\n }\n }\n // Common for all request-body\n if (!requestBodyType.includes('form-data')) {\n // For multipart/form-data don't set the content-type to allow creation of browser generated part boundaries\n fetchOptions.headers.append('Content-Type', requestBodyType);\n }\n curlHeaders += ` -H \"Content-Type: ${requestBodyType}\" \\\\\\n`;\n }\n this.curlSyntax = '';\n this.responseIsBlob = false;\n\n this.respContentDisposition = '';\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n this.curlSyntax = `${curl}${curlHeaders}${curlData}${curlForm}`;\n if (this.fetchCredentials) {\n fetchOptions.credentials = this.fetchCredentials;\n }\n\n // Options is legacy usage, documentation has been updated to reference properties of the fetch option directly, but older usages may still be using options\n const fetchRequest = { explorerLocation: this.elementId, url: fetchUrl, options: fetchOptions, ...fetchOptions };\n const event = {\n bubbles: true,\n composed: true,\n detail: {\n request: fetchRequest,\n },\n };\n this.dispatchEvent(new CustomEvent('before-try', event));\n this.dispatchEvent(new CustomEvent('request', event));\n const newFetchOptions = {\n method: fetchRequest.method || fetchOptions.method,\n headers: fetchRequest.headers || fetchOptions.headers,\n credentials: fetchRequest.credentials || fetchOptions.credentials,\n body: fetchRequest.body || fetchOptions.body\n };\n const fetchRequestObject = new Request(fetchRequest.url, newFetchOptions);\n\n let fetchResponse;\n try {\n let respBlob;\n let respJson;\n let respText;\n tryBtnEl.disabled = true;\n const fetchStart = new Date();\n\n this.responseStatus = '';\n this.responseMessage = '';\n this.responseUrl = '';\n this.responseHeaders = '';\n this.responseText = '⌛';\n\n this.requestUpdate();\n const awaiter = new Promise(resolve => setTimeout(resolve, 200));\n fetchResponse = await fetch(fetchRequestObject);\n this.responseElapsedMs = new Date() - fetchStart;\n await awaiter;\n\n tryBtnEl.disabled = false;\n this.responseStatus = fetchResponse.ok ? 'success' : 'error';\n this.responseMessage = fetchResponse.statusText ? `${fetchResponse.statusText} (${fetchResponse.status})` : fetchResponse.status;\n this.responseUrl = fetchResponse.url;\n this.responseHeaders = '';\n const headers = {};\n fetchResponse.headers.forEach((hdrVal, hdr) => {\n this.responseHeaders = `${this.responseHeaders}${hdr.trim()}: ${hdrVal}\\n`;\n headers[hdr.trim()] = hdrVal && hdrVal.trim();\n });\n const contentType = fetchResponse.headers.get('content-type');\n const respEmpty = (await fetchResponse.clone().text()).length === 0;\n if (respEmpty) {\n this.responseText = '';\n } else if (contentType) {\n if (contentType.includes('json')) {\n if ((/charset=[^\"']+/).test(contentType)) {\n const encoding = contentType.split('charset=')[1];\n const buffer = await fetchResponse.arrayBuffer();\n try {\n respText = new TextDecoder(encoding).decode(buffer);\n } catch {\n respText = new TextDecoder('utf-8').decode(buffer);\n }\n try {\n this.responseText = JSON.stringify(JSON.parse(respText), null, 8);\n } catch {\n this.responseText = respText;\n }\n } else {\n respJson = await fetchResponse.json();\n this.responseText = JSON.stringify(respJson, null, 8);\n }\n } else if (textFileRegex.test(contentType)) {\n this.responseIsBlob = true;\n this.responseBlobType = 'download';\n } else if (mediaFileRegex.test(contentType)) {\n this.responseIsBlob = true;\n this.responseBlobType = 'view';\n } else {\n respText = await fetchResponse.text();\n if (contentType.includes('xml')) {\n this.responseText = formatXml(respText, { textNodesOnSameLine: true, indentor: ' ' });\n } else {\n this.responseText = respText;\n }\n }\n if (this.responseIsBlob) {\n const contentDisposition = fetchResponse.headers.get('content-disposition');\n const filenameRegex = /filename[^;=\\n]*=((['\"]).*?\\2|[^;\\n]*)/;\n const filename = filenameRegex.exec(contentDisposition);\n this.respContentDisposition = filename && filename[1] && filename[1].replace(/['\"]/g, '') || `download.${mimeTypeResolver.extension(contentType) || 'file'}`;\n respBlob = await fetchResponse.blob();\n this.responseBlobUrl = URL.createObjectURL(respBlob);\n }\n } else {\n respText = await fetchResponse.text();\n this.responseText = respText;\n }\n const responseEvent = {\n bubbles: true,\n composed: true,\n detail: {\n explorerLocation: this.elementId,\n request: fetchRequest,\n response: {\n headers,\n body: respJson || respText || respBlob || fetchResponse.body,\n status: fetchResponse.status,\n },\n },\n };\n this.dispatchEvent(new CustomEvent('after-try', responseEvent));\n this.dispatchEvent(new CustomEvent('response', responseEvent));\n } catch (error) {\n tryBtnEl.disabled = false;\n this.responseMessage = `${error.message} (Check the browser network tab for more information.)`;\n this.responseStatus = 'error';\n const responseEvent = {\n bubbles: true,\n composed: true,\n detail: {\n explorerLocation: this.elementId,\n error,\n request: fetchRequest,\n },\n };\n document.dispatchEvent(new CustomEvent('after-try', responseEvent));\n document.dispatchEvent(new CustomEvent('response', responseEvent));\n }\n }\n\n onAddRemoveFileInput(e, pname, ptype) {\n if (e.target.tagName.toLowerCase() !== 'button') {\n return;\n }\n\n if (e.target.classList.contains('file-input-remove-btn')) {\n // Remove File Input Set\n const el = e.target.closest('.input-set');\n el.remove();\n return;\n }\n const el = e.target.closest('.file-input-container');\n\n // Add File Input Set\n\n // Container\n const newInputContainerEl = document.createElement('div');\n newInputContainerEl.setAttribute('class', 'input-set row');\n\n // File Input\n const newInputEl = document.createElement('input');\n newInputEl.type = 'file';\n newInputEl.style = 'width:200px; margin-top:2px;';\n newInputEl.setAttribute('data-pname', pname);\n newInputEl.setAttribute('data-ptype', ptype.includes('form-urlencode') ? 'form-urlencode' : 'form-data');\n newInputEl.setAttribute('data-array', 'false');\n newInputEl.setAttribute('data-file-array', 'true');\n\n // Remover Button\n const newRemoveBtnEl = document.createElement('button');\n newRemoveBtnEl.setAttribute('class', 'file-input-remove-btn');\n newRemoveBtnEl.innerHTML = '✕';\n\n newInputContainerEl.appendChild(newInputEl);\n newInputContainerEl.appendChild(newRemoveBtnEl);\n el.insertBefore(newInputContainerEl, e.target);\n // el.appendChild(newInputContainerEl);\n }\n\n downloadResponseBlob() {\n if (this.responseBlobUrl) {\n const a = document.createElement('a');\n document.body.appendChild(a);\n a.style = 'display: none';\n a.href = this.responseBlobUrl;\n a.download = this.respContentDisposition;\n a.click();\n a.remove();\n }\n }\n\n viewResponseBlob() {\n if (this.responseBlobUrl) {\n const a = document.createElement('a');\n document.body.appendChild(a);\n a.style = 'display: none';\n a.href = this.responseBlobUrl;\n a.target = '_blank';\n a.click();\n a.remove();\n }\n }\n\n clearResponseData() {\n this.responseUrl = '';\n this.responseHeaders = '';\n this.responseText = '';\n this.responseStatus = '';\n this.responseMessage = '';\n this.responseElapsedMs = 0;\n this.responseIsBlob = false;\n this.responseBlobType = '';\n this.respContentDisposition = '';\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n }\n\n requestParamFunction(event) {\n if (event.key === 'Enter') {\n this.onTryClick();\n event.preventDefault();\n }\n }\n\n disconnectedCallback() {\n // Cleanup ObjectURL forthe blob data if this component created one\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n super.disconnectedCallback();\n }\n}\n\n// Register the element with the browser\nif (!customElements.get('openapi-explorer')) {\n customElements.define('api-request', ApiRequest);\n}\n"],"names":[],"sourceRoot":""}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { LitElement, html } from 'lit
|
|
1
|
+
import { LitElement, html } from 'lit';
|
|
2
2
|
import { marked } from 'marked';
|
|
3
3
|
import Prism from 'prismjs';
|
|
4
4
|
import mimeTypeResolver from './mime-types';
|
|
5
|
-
import { unsafeHTML } from 'lit
|
|
5
|
+
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
6
6
|
import formatXml from 'xml-but-prettier';
|
|
7
7
|
import { copyToClipboard } from '../utils/common-utils';
|
|
8
8
|
import { getI18nText } from '../languages';
|
|
@@ -231,7 +231,7 @@ export default class ApiRequest extends LitElement {
|
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
tableRows.push(html` <tr> <td style="width:160px;min-width:50px"> <div class="param-name ${paramSchema.deprecated ? 'deprecated' : ''}"> ${param.name}${!paramSchema.deprecated && param.required ? html`<span style="color:var(--red)">*</span>` : ''} </div> <div class="param-type"> ${paramSchema.type === 'array' ? `${paramSchema.arrayType}` : `${paramSchema.format ? paramSchema.format : paramSchema.type}`}${!paramSchema.deprecated && param.required ? html`<span style="opacity:0">*</span>` : ''} </div> </td> ${this.allowTry === 'true' ? html` <td style="min-width:160px"> ${paramSchema.type === 'array' ? html` <tag-input class="request-param" style="width:100%" data-ptype="${paramType}" data-pname="${param.name}" data-default="${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" data-array="true" placeholder="${paramSchema.example || (Array.isArray(defaultVal) ? defaultVal[0] : defaultVal) || 'add-multiple ↩'}" .value="${Array.isArray(defaultVal) ? defaultVal : defaultVal.split(',')}"> </tag-input>` : paramSchema.type === 'object' ? html` <textarea class="textarea request-param" part="textarea textarea-param" data-ptype="${paramType}-object" data-pname="${param.name}" data-default="${defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" spellcheck="false" placeholder="${paramSchema.example || defaultVal || ''}" style="resize:vertical;width:100%;height:${'read focused'.includes(this.renderStyle) ? '180px' : '120px'}"
|
|
234
|
+
tableRows.push(html` <tr> <td style="width:160px;min-width:50px"> <div class="param-name ${paramSchema.deprecated ? 'deprecated' : ''}"> ${param.name}${!paramSchema.deprecated && param.required ? html`<span style="color:var(--red)">*</span>` : ''} </div> <div class="param-type"> ${paramSchema.type === 'array' ? `${paramSchema.arrayType}` : `${paramSchema.format ? paramSchema.format : paramSchema.type}`}${!paramSchema.deprecated && param.required ? html`<span style="opacity:0">*</span>` : ''} </div> </td> ${this.allowTry === 'true' ? html` <td style="min-width:160px"> ${paramSchema.type === 'array' ? html` <tag-input class="request-param" style="width:100%" data-ptype="${paramType}" data-pname="${param.name}" data-default="${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" data-array="true" placeholder="${paramSchema.example || (Array.isArray(defaultVal) ? defaultVal[0] : defaultVal) || 'add-multiple ↩'}" .value="${Array.isArray(defaultVal) ? defaultVal : defaultVal.split(',')}"> </tag-input>` : paramSchema.type === 'object' ? html` <textarea class="textarea request-param" part="textarea textarea-param" data-ptype="${paramType}-object" data-pname="${param.name}" data-default="${defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" spellcheck="false" placeholder="${paramSchema.example || defaultVal || ''}" style="resize:vertical;width:100%;height:${'read focused'.includes(this.renderStyle) ? '180px' : '120px'}" .value="${this.fillRequestWithDefault === 'true' ? defaultVal : ''}"></textarea>` : html` <input type="${paramSchema.format === 'password' ? 'password' : 'text'}" spellcheck="false" style="width:100%" placeholder="${paramSchema.example || defaultVal || ''}" class="request-param" part="textbox textbox-param" data-ptype="${paramType}" data-pname="${param.name}" data-default="${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}" data-array="false" @keyup="${this.requestParamFunction}" .value="${this.fillRequestWithDefault === 'true' ? defaultVal : ''}">`} </td>` : ''} ${this.renderStyle === 'focused' ? html` <td> ${paramSchema.default || paramSchema.constraint || paramSchema.allowedValues || paramSchema.pattern ? html` <div class="param-constraint"> ${paramSchema.constraint ? html`<span style="font-weight:700">Constraints: </span>${paramSchema.constraint}<br>` : ''} ${paramSchema.pattern ? html`<span style="font-weight:700">Pattern: </span>${truncateString(paramSchema.pattern, 60)}<br>` : ''} ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => html` ${i > 0 ? '|' : html`<span style="font-weight:700">Allowed: </span>`} ${html` <a part="anchor anchor-param-constraint" class="${this.allowTry === 'true' ? '' : 'inactive-link'}" data-type="${paramSchema.type === 'array' ? 'array' : 'string'}" data-enum="${v.trim()}" @click="${e => {
|
|
235
235
|
const inputEl = e.target.closest('table').querySelector(`[data-pname="${param.name}"]`);
|
|
236
236
|
|
|
237
237
|
if (inputEl) {
|
|
@@ -324,7 +324,7 @@ export default class ApiRequest extends LitElement {
|
|
|
324
324
|
this.selectedRequestBodyExample = reqBodyExamples.length > 0 ? reqBodyExamples[0].exampleId : '';
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
-
reqBodyDefaultHtml = html` ${reqBodyDefaultHtml} <div class="example-panel border-top pad-top-8"> ${reqBodyExamples.length === 1 ? '' : html` <select aria-label="request body example" style="min-width:100px;max-width:100%;margin-bottom:-1px" @change="${e => this.onSelectExample(e)}"> ${reqBodyExamples.map(v => html`<option value="${v.exampleId}" ?selected="${v.exampleId === this.selectedRequestBodyExample}"> ${v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary ? v.exampleSummary : v.exampleId} </option>`)} </select> `} ${reqBodyExamples.filter(v => v.exampleId === this.selectedRequestBodyExample).map(v => html` <div class="example ${v.exampleId === this.selectedRequestBodyExample ? 'example-selected' : ''}" data-default="${v.exampleId}"> ${v.exampleSummary && v.exampleSummary.length > 80 ? html`<div style="padding:4px 0"> ${v.exampleSummary} </div>` : ''} ${v.exampleDescription ? html`<div class="m-markdown-small" style="padding:4px 0"> ${unsafeHTML(marked(v.exampleDescription || ''))} </div>` : ''} <slot name="${this.elementId}--request-body"> <textarea class="textarea request-body-param-user-input" part="textarea textarea-param" spellcheck="false" data-ptype="${reqBody.mimeType}" data-default="${v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8)}" data-default-format="${v.exampleFormat}" style="width:100%;resize:vertical"
|
|
327
|
+
reqBodyDefaultHtml = html` ${reqBodyDefaultHtml} <div class="example-panel border-top pad-top-8"> ${reqBodyExamples.length === 1 ? '' : html` <select aria-label="request body example" style="min-width:100px;max-width:100%;margin-bottom:-1px" @change="${e => this.onSelectExample(e)}"> ${reqBodyExamples.map(v => html`<option value="${v.exampleId}" ?selected="${v.exampleId === this.selectedRequestBodyExample}"> ${v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary ? v.exampleSummary : v.exampleId} </option>`)} </select> `} ${reqBodyExamples.filter(v => v.exampleId === this.selectedRequestBodyExample).map(v => html` <div class="example ${v.exampleId === this.selectedRequestBodyExample ? 'example-selected' : ''}" data-default="${v.exampleId}"> ${v.exampleSummary && v.exampleSummary.length > 80 ? html`<div style="padding:4px 0"> ${v.exampleSummary} </div>` : ''} ${v.exampleDescription ? html`<div class="m-markdown-small" style="padding:4px 0"> ${unsafeHTML(marked(v.exampleDescription || ''))} </div>` : ''} <slot name="${this.elementId}--request-body"> <textarea class="textarea request-body-param-user-input" part="textarea textarea-param" spellcheck="false" data-ptype="${reqBody.mimeType}" data-default="${v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8)}" data-default-format="${v.exampleFormat}" style="width:100%;resize:vertical" .value="${this.fillRequestWithDefault === 'true' ? v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8) : ''}"></textarea> </slot> <textarea class="textarea is-hidden request-body-param ${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)}" spellcheck="false" data-ptype="${reqBody.mimeType}" style="width:100%;resize:vertical;display:none" .value="${v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 8)}"></textarea> </div> `)} </div> `;
|
|
328
328
|
}
|
|
329
329
|
} else if (this.selectedRequestBodyType.includes('form-urlencoded') || this.selectedRequestBodyType.includes('form-data')) {
|
|
330
330
|
if (reqBody.mimeType === this.selectedRequestBodyType) {
|
|
@@ -403,7 +403,7 @@ export default class ApiRequest extends LitElement {
|
|
|
403
403
|
if (e.target.tagName.toLowerCase() === 'button') {
|
|
404
404
|
this.activeSchemaTab = e.target.dataset.tab;
|
|
405
405
|
}
|
|
406
|
-
}}"> <button class="v-tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}" data-tab="model">${getI18nText('operations.model')}</button> <button class="v-tab-btn ${this.activeSchemaTab === 'body' ? 'active' : ''}" data-tab="body">${getI18nText('operations.request-body')}</button> </div> </div> ${html` <div class="tab-content col" data-tab="model" style="display:${this.activeSchemaTab === 'model' ? 'block' : 'none'};padding-left:5px;width:100%"> <schema-tree .data="${formdataPartSchema}" schema-expand-level="${this.schemaExpandLevel}"> </schema-tree> </div>`} ${html` <div class="tab-content col" data-tab="body" style="display:${this.activeSchemaTab === 'body' ? 'block' : 'none'};padding-left:5px;width:100%"> <textarea class="textarea" placeholder="${formdataPartExample[0] && formdataPartExample[0].exampleValue || paramSchema.default || ''}" part="textarea textarea-param" style="width:100%;border:none;resize:vertical" data-array="false" data-ptype="${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}" data-pname="${fieldName}" data-default="${paramSchema.default || ''}" spellcheck="false"
|
|
406
|
+
}}"> <button class="v-tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}" data-tab="model">${getI18nText('operations.model')}</button> <button class="v-tab-btn ${this.activeSchemaTab === 'body' ? 'active' : ''}" data-tab="body">${getI18nText('operations.request-body')}</button> </div> </div> ${html` <div class="tab-content col" data-tab="model" style="display:${this.activeSchemaTab === 'model' ? 'block' : 'none'};padding-left:5px;width:100%"> <schema-tree .data="${formdataPartSchema}" schema-expand-level="${this.schemaExpandLevel}"> </schema-tree> </div>`} ${html` <div class="tab-content col" data-tab="body" style="display:${this.activeSchemaTab === 'body' ? 'block' : 'none'};padding-left:5px;width:100%"> <textarea class="textarea" placeholder="${formdataPartExample[0] && formdataPartExample[0].exampleValue || paramSchema.default || ''}" part="textarea textarea-param" style="width:100%;border:none;resize:vertical" data-array="false" data-ptype="${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}" data-pname="${fieldName}" data-default="${paramSchema.default || ''}" spellcheck="false" .value="${this.fillRequestWithDefault === 'true' ? paramSchema.default : ''}"></textarea> <textarea data-pname="hidden-${fieldName}" data-ptype="${mimeType.includes('form-urlencode') ? 'hidden-form-urlencode' : 'hidden-form-data'}" class="is-hidden" style="display:none" .value="${paramSchema.default}"></textarea> </div>`} </div>` : html` ${this.allowTry === 'true' ? html`<input placeholder="${paramSchema.example || paramSchema.default || ''}" .value="${this.fillRequestWithDefault === 'true' ? paramSchema.default || '' : ''}" spellcheck="false" type="${fieldSchema.format === 'binary' ? 'file' : fieldSchema.format === 'password' ? 'password' : 'text'}" part="textbox textbox-param" style="width:100%" data-ptype="${mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}" data-pname="${fieldName}" data-default="${paramSchema.default || ''}" data-array="false">` : ''} `}`} </td> ${fieldType === 'object' ? '' : html` <td> ${paramSchema.default || paramSchema.constraint || paramSchema.allowedValues || paramSchema.pattern ? html` <div class="param-constraint"> ${paramSchema.pattern ? html`<span style="font-weight:700">Pattern: </span>${paramSchema.pattern}<br>` : ''} ${paramSchema.constraint ? html`<span style="font-weight:700">Constraints: </span>${paramSchema.constraint}<br>` : ''} ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => html` ${i > 0 ? '|' : html`<span style="font-weight:700">Allowed: </span>`} ${html` <a part="anchor anchor-param-constraint" class="${this.allowTry === 'true' ? '' : 'inactive-link'}" data-type="${paramSchema.type === 'array' ? paramSchema.type : 'string'}" data-enum="${v.trim()}" @click="${e => {
|
|
407
407
|
const inputEl = e.target.closest('table').querySelector(`[data-pname="${fieldName}"]`);
|
|
408
408
|
|
|
409
409
|
if (inputEl) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
2
|
import { marked } from 'marked';
|
|
3
|
-
import { unsafeHTML } from 'lit
|
|
3
|
+
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
4
4
|
import { schemaInObjectNotation, generateExample } from '../utils/schema-utils';
|
|
5
5
|
import { getI18nText } from '../languages';
|
|
6
6
|
import FontStyles from '../styles/font-styles.js';
|
|
@@ -71,7 +71,7 @@ export default class ApiResponse extends LitElement {
|
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
static
|
|
74
|
+
static finalizeStyles() {
|
|
75
75
|
return [FontStyles, FlexStyles, TabStyles, TableStyles, InputStyles, BorderStyles, css`.resp-head{vertical-align:middle;padding:16px 0 8px}.resp-head.divider{border-top:1px solid var(--border-color);margin-top:10px}.resp-status{font-weight:700;font-size:calc(var(--font-size-small) + 1px)}.resp-descr{font-size:calc(var(--font-size-small) + 1px)}.top-gap{margin-top:16px}.example-panel{font-size:var(--font-size-small);margin:0}.generic-tree{background:#333;color:#fff}.example-panel.generic-tree{margin-top:8px}pre.generic-tree{border:none;padding:8px 10px 10px}.example-panel select{margin-left:8px;padding-top:8px;min-width:100px;max-width:100%}.example-panel .example{padding:0 12px}.focused-mode,.read-mode{padding-top:24px;margin-top:12px;border-top:1px dashed var(--border-color)}`];
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
2
|
import { copyToClipboard } from '../utils/common-utils';
|
|
3
3
|
import { getI18nText } from '../languages';
|
|
4
4
|
import FontStyles from '../styles/font-styles.js';
|
|
@@ -17,7 +17,7 @@ export default class JsonTree extends LitElement {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
static
|
|
20
|
+
static finalizeStyles() {
|
|
21
21
|
return [FontStyles, BorderStyles, InputStyles, css`:host{display:flex}.json-tree{background:#333;color:#fff;padding:12px;min-height:30px;font-family:var(--font-mono);font-size:var(--font-size-small);overflow:hidden;word-break:break-all;flex:1;line-height:calc(var(--font-size-small) + 6px)}.open-bracket{display:inline-block;padding:0 20px 0 0;cursor:pointer;border:1px solid transparent;border-radius:3px}.collapsed.open-bracket{padding-right:0}.tree>.open-bracket{margin-left:-2px}.open-bracket:hover{color:var(--primary-color);background-color:var(--hover-color);border:1px solid var(--border-color)}.inside-bracket-wrapper{max-height:10000px;transition:max-height 1.2s ease-in-out;overflow:hidden}.open-bracket.collapsed+.inside-bracket-wrapper{transition:max-height 1.2s ease-in-out -1.1s;max-height:0}.inside-bracket{padding-left:16px;border-left:1px dotted var(--border-color)}.string{color:var(--green)}.number{color:var(--blue)}.null{color:var(--red)}.boolean{color:var(--orange)}.object{color:#fff}.toolbar{display:none}.tree .toolbar{display:flex;justify-content:space-between;width:100%}.tree .item{border-bottom:1px dotted transparent}.toolbar-item{cursor:pointer;padding:5px 0 5px 1rem;margin:0 1rem!important;color:#38b3f9;flex-shrink:0}.tree .toolbar .toolbar-item{display:none}.inside-bracket.xxx-of{padding:5px 0;border-style:dotted;border-width:0 0 1px 0;border-color:var(--primary-color)}.schema-root-type.xxx-of{display:none}.toolbar-item:first-of-type{margin:0 2px 0 0}@media only screen and (min-width:576px){.key-descr{display:block}.tree .toolbar .toolbar-item{display:block}.toolbar{display:flex}}.toolbar-backup{position:absolute;right:6px;display:flex;align-items:center}`];
|
|
22
22
|
}
|
|
23
23
|
/* eslint-disable indent */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
2
|
import { marked } from 'marked';
|
|
3
|
-
import { unsafeHTML } from 'lit
|
|
3
|
+
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
4
4
|
import FontStyles from '../styles/font-styles.js';
|
|
5
5
|
import SchemaStyles from '../styles/schema-styles';
|
|
6
6
|
export default class SchemaTable extends LitElement {
|
|
@@ -45,7 +45,7 @@ export default class SchemaTable extends LitElement {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
static
|
|
48
|
+
static finalizeStyles() {
|
|
49
49
|
return [FontStyles, SchemaStyles, css`.table{font-size:var(--font-size-small);text-align:left;line-height:calc(var(--font-size-small) + 6px)}.table .tr{width:calc(100% - 5px);padding:0 0 0 5px;border-bottom:1px dotted var(--light-border-color)}.table .td{padding:4px 0}.table .key{width:240px}.key.deprecated .key-label{text-decoration:line-through}.table .key-type{white-space:normal;width:150px}.obj-toggle{padding:0 2px;border-radius:2px;border:1px solid transparent;display:inline-block;margin-left:-16px;color:var(--primary-color);cursor:pointer;font-size:calc(var(--font-size-small) + 4px);font-family:var(--font-mono);background-clip:border-box}.obj-toggle:hover{border-color:var(--primary-color)}.tr.expanded+.object-body{display:block}.tr.collapsed+.object-body{display:none}`];
|
|
50
50
|
}
|
|
51
51
|
/* eslint-disable indent */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
2
|
import { marked } from 'marked';
|
|
3
|
-
import { unsafeHTML } from 'lit
|
|
3
|
+
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
4
4
|
import { getI18nText } from '../languages';
|
|
5
5
|
import FontStyles from '../styles/font-styles.js';
|
|
6
6
|
import SchemaStyles from '../styles/schema-styles';
|
|
@@ -47,7 +47,7 @@ export default class SchemaTree extends LitElement {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
static
|
|
50
|
+
static finalizeStyles() {
|
|
51
51
|
return [FontStyles, SchemaStyles, BorderStyles, css`.tree{min-height:30px;background:#333;padding:12px;color:#fff;font-size:var(--font-size-small);text-align:left;line-height:calc(var(--font-size-small) + 6px)}.tree .key{max-width:300px}.key.deprecated .key-label{text-decoration:line-through}.open-bracket{display:inline-block;padding:0 20px 0 0;cursor:pointer;border:1px solid transparent;border-radius:3px}.collapsed .open-bracket{padding-right:0}.td.key>.open-bracket:first-child{margin-left:-2px}.open-bracket:hover{color:var(--primary-color);background-color:var(--hover-color);border:1px solid var(--border-color)}.close-bracket{display:inline-block;font-family:var(--font-mono)}.inside-bracket-wrapper{max-height:10000px;transition:max-height 1.2s ease-in-out;overflow:hidden}.tr.collapsed+.inside-bracket-wrapper{transition:max-height 1.2s ease-in-out -1.1s;max-height:0}.inside-bracket.array,.inside-bracket.object{border-left:1px dotted var(--border-color)}.inside-bracket.xxx-of.option{border-left:1px solid transparent}`];
|
|
52
52
|
}
|
|
53
53
|
/* eslint-disable indent */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
2
|
export default class TagInput extends LitElement {
|
|
3
3
|
render() {
|
|
4
4
|
const tagItemTemplate = html`${(this.value || []).filter(v => v.trim()).map(v => html`<span class="tag">${v}</span>`)}`;
|
|
@@ -56,7 +56,7 @@ export default class TagInput extends LitElement {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
static
|
|
59
|
+
static finalizeStyles() {
|
|
60
60
|
return [css`.tags{display:flex;flex-wrap:wrap;outline:0;padding:0;border-radius:var(--border-radius);border:1px solid var(--border-color);cursor:text;overflow:hidden;background:var(--input-bg)}.editor,.tag{padding:3px;margin:2px}.tag{border:1px solid var(--border-color);background-color:var(--bg3);color:var(--fg3);border-radius:var(--border-radius);word-break:break-all;font-size:var(--font-size-small)}.tag:hover~#cursor{display:block}.editor{flex:1;border:1px solid transparent;color:var(--fg);min-width:60px;outline:0;line-height:inherit;font-family:inherit;background:0 0;font-size:calc(var(--font-size-small) + 1px)}.editor::placeholder{color:var(--placeholder-color);opacity:1}`];
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LitElement, css, unsafeCSS } from 'lit';
|
|
2
2
|
import { marked } from 'marked';
|
|
3
3
|
import Prism from 'prismjs'; // It's possible none of these imports are actually necessary and should just be removed
|
|
4
4
|
|
|
@@ -219,7 +219,7 @@ export default class OpenApiExplorer extends LitElement {
|
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
static
|
|
222
|
+
static finalizeStyles() {
|
|
223
223
|
return [FontStyles, InputStyles, FlexStyles, TableStyles, EndpointStyles, PrismStyles, TabStyles, NavStyles, InfoStyles, advancedSearchStyles, apiRequestStyles, css`:not(:defined){display:none}:host{display:flex;flex-direction:column;width:100%;height:100%;margin:0;padding:0;overflow:hidden;letter-spacing:normal;color:var(--fg);background-color:var(--bg);font-family:var(--font-regular)}.body{display:flex;height:100%;width:100%;overflow:hidden}.main-content{margin:0;padding:0;display:block;flex:1;height:100%;overflow-y:overlay;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:var(--border-color) transparent}.main-content::-webkit-scrollbar{width:8px;height:8px}.main-content::-webkit-scrollbar-track{background:0 0}.main-content::-webkit-scrollbar-thumb{background-color:var(--border-color)}.section-gap.section-tag{border-bottom:1px solid var(--border-color)}.method-section-gap{padding:24px 8px 0 4px}.section-gap{padding:24px 0 0}.section-tag-header{position:relative;cursor:n-resize;padding:12px 0}.collapsed .section-tag-header:hover{cursor:s-resize}.section-tag-header:hover{background-image:linear-gradient(to right,rgba(0,0,0,0),var(--border-color),rgba(0,0,0,0))}.collapsed .section-tag-header:hover::after{color:var(--primary-color)}.collapsed .section-tag-body{display:none}.logo{height:36px;width:36px;margin-left:5px}.only-large-screen,.only-large-screen-flex{display:none}.header-title{font-size:calc(var(--font-size-regular) + 8px);padding:0 8px}.tag.title{text-transform:uppercase}.header{background-color:var(--header-bg);color:var(--header-fg);width:100%}input.header-input{background:var(--header-color-darker);color:var(--header-fg);border:1px solid var(--header-color-border);flex:1;padding-right:24px;border-radius:3px}input.header-input::placeholder{opacity:.4}input:disabled{cursor:not-allowed}.loader{margin:16px auto 16px auto;border:4px solid var(--bg3);border-radius:50%;border-top:4px solid var(--primary-color);width:36px;height:36px;animation:spin 2s linear infinite}.expanded-endpoint-body{position:relative;padding:6px 0}.divider{border-top:2px solid var(--border-color);margin:24px 0;width:100%}.tooltip{border:1px solid var(--border-color);border-left-width:4px;margin-left:2px}.tooltip a{color:var(--fg2);text-decoration:none}.tooltip-text{color:var(--fg2);background-color:var(--bg2);visibility:hidden;overflow-wrap:break-word}.tooltip:hover{color:var(--primary-color);border-color:var(--primary-color)}.tooltip:hover a:hover{color:var(--primary-color)}.tooltip:hover .tooltip-text{visibility:visible;opacity:1}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@media only screen and (max-width:767.98px){.section-padding{margin:1rem}.sub-title.tag{margin-left:1rem}.section-tag-body .description{margin-left:1rem;margin-right:1rem}}@media only screen and (min-width:768px){.nav-bar{width:260px;display:flex}.only-large-screen{display:block}.only-large-screen-flex{display:flex}.section-gap{padding:24px 24px}.section-gap--read-mode{padding:24px 8px}.section-gap--focused-mode{padding:1.5rem}.endpoint-body{position:relative;padding:36px 0 48px 0}}@media only screen and (min-width:1024px){.nav-bar{width:${unsafeCSS(this.fontSize === 'default' ? '300px' : this.fontSize === 'large' ? '315px' : '330px')};display:flex}.section-gap--read-mode{padding:24px 24px 12px}.main-content-inner{padding:24px}}`];
|
|
224
224
|
} // Startup
|
|
225
225
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { css } from 'lit
|
|
1
|
+
import { css } from 'lit';
|
|
2
2
|
export default css`*,:after,:before{box-sizing:border-box}.dialog-box-overlay{background-color:var(--overlay-bg);position:fixed;left:0;top:0;width:100vw;height:100vh;overflow:hidden;z-index:var(--dialog-z-index)}.dialog-box{position:fixed;top:100px;left:50%;transform:translate(-50%,0);display:flex;flex-direction:column;width:50vw;background-color:var(--bg2);color:var(--fg2);border-radius:4px;overflow:hidden;border:1px solid var(--border-color);box-shadow:0 14px 28px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.22)}.dialog-box-header{position:sticky;top:0;align-self:stretch;display:flex;align-items:center;padding:0 16px;min-height:60px;max-height:60px;border-bottom:1px solid var(--light-border-color);overflow:hidden}.dialog-box .m-btn{padding:1px 6px}.dialog-box-content{padding:16px;display:block}.dialog-box-title{flex-grow:1;font-size:20px}.advanced-search-dialog-input{width:100%}#advanced-search-dialog-input{width:100%}.advanced-search-locations{display:flex;flex-direction:column;margin:8px 0 24px}.advanced-search-locations label{font-size:var(--font-size-small)}.advanced-search-results{max-height:400px;overflow:auto}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { css } from 'lit
|
|
1
|
+
import { css } from 'lit';
|
|
2
2
|
export default css`.api-request,.api-request *,.api-request :after,.api-request :before,.api-request:after,.api-request:before{box-sizing:border-box}.api-request.focused-mode,.api-request.read-mode{padding-top:24px;margin-top:12px;border-top:1px dashed var(--border-color)}.api-request .param-name,.api-request .param-type{margin:1px 0;text-align:right;line-height:var(--font-size-small)}.api-request .param-name{color:var(--fg);font-family:var(--font-mono)}.api-request .param-name.deprecated{text-decoration:line-through}.api-request .param-type{color:var(--light-fg);font-family:var(--font-regular)}.api-request .param-constraint{min-width:100px}.api-request .param-constraint:empty{display:none}.api-request .top-gap{margin-top:24px}.api-request .textarea{min-height:220px;padding:5px;resize:vertical}.api-request .response-message{font-weight:700;text-overflow:ellipsis}.api-request .response-message.error{color:var(--red)}.api-request .response-message.success{color:var(--blue)}.api-request .file-input-container{align-items:flex-end}.api-request .file-input-container .input-set:first-child .file-input-remove-btn{visibility:hidden}.api-request .file-input-remove-btn{font-size:16px;color:var(--red);outline:0;border:none;background:0 0;cursor:pointer}.api-request .v-tab-btn{font-size:var(--smal-font-size);height:24px;border:none;background:0 0;opacity:.3;cursor:pointer;padding:4px 8px}.api-request .v-tab-btn.active{font-weight:700;background:var(--bg);opacity:1}.api-request .border-top{border-top:1px solid var(--border-color)}.api-request .border{border:1px solid var(--border-color);border-radius:var(--border-radius)}.api-request .light-border{border:1px solid var(--light-border-color);border-radius:var(--border-radius)}.api-request .pad-8-16{padding:8px 16px}.api-request .pad-top-8{padding-top:8px}.api-request .mar-top-8{margin-top:8px}@media only screen and (min-width:768px){.api-request .textarea{padding:8px}}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { css } from 'lit
|
|
1
|
+
import { css } from 'lit';
|
|
2
2
|
export default css`.border-top{border-top:1px solid var(--border-color)}.border{border:1px solid var(--border-color);border-radius:var(--border-radius)}.light-border{border:1px solid var(--light-border-color);border-radius:var(--border-radius)}.pad-8-16{padding:8px 16px}.pad-top-8{padding-top:8px}.mar-top-8{margin-top:8px}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { css } from 'lit
|
|
1
|
+
import { css } from 'lit';
|
|
2
2
|
export default css`.only-large-screen{display:none}.endpoint-head .path{display:flex;font-family:var(--font-mono);font-size:var(--font-size-small);align-items:center;overflow-wrap:break-word;word-break:break-all}.endpoint-head .descr{font-size:var(--font-size-small);color:var(--light-fg);font-weight:400;align-items:center;overflow-wrap:break-word;word-break:break-all;display:none}.m-endpoint.expanded{margin-bottom:16px}.m-endpoint>.endpoint-head{border-width:1px 1px 1px 5px;border-style:solid;border-color:transparent;border-top-color:var(--light-border-color);display:flex;padding:6px 16px;align-items:center;cursor:pointer}.m-endpoint>.endpoint-head.put.expanded,.m-endpoint>.endpoint-head.put:hover{border-color:var(--orange);background-color:var(--light-orange)}.m-endpoint>.endpoint-head.post.expanded,.m-endpoint>.endpoint-head.post:hover{border-color:var(--green);background-color:var(--light-green)}.m-endpoint>.endpoint-head.get.expanded,.m-endpoint>.endpoint-head.get:hover,.m-endpoint>.endpoint-head.head.expanded,.m-endpoint>.endpoint-head.head:hover{border-color:var(--blue);background-color:var(--light-blue)}.m-endpoint>.endpoint-head.delete.expanded,.m-endpoint>.endpoint-head.delete:hover{border-color:var(--red);background-color:var(--light-red)}.m-endpoint>.endpoint-head.patch.expanded,.m-endpoint>.endpoint-head.patch:hover{border-color:var(--yellow);background-color:var(--light-yellow)}.m-endpoint>.endpoint-head.query.expanded,.m-endpoint>.endpoint-head.query:hover{border-color:var(--purple);background-color:var(--light-purple)}.m-endpoint>.endpoint-head.options.expanded,.m-endpoint>.endpoint-head.options:hover{border-color:var(--gray);background-color:var(--light-gray)}.m-endpoint .endpoint-body{word-break:break-word;flex-wrap:wrap;padding:16px 0 0 0;border-width:0 1px 1px 5px;border-style:solid;box-shadow:0 4px 3px -3px rgba(0,0,0,.15)}.m-endpoint .endpoint-body.delete{border-color:var(--red)}.m-endpoint .endpoint-body.put{border-color:var(--orange)}.m-endpoint .endpoint-body.post{border-color:var(--green)}.m-endpoint .endpoint-body.get,.m-endpoint .endpoint-body.head{border-color:var(--blue)}.m-endpoint .endpoint-body.patch{border-color:var(--yellow)}.m-endpoint .endpoint-body.query{border-color:var(--purple)}.m-endpoint .endpoint-body.options{border-color:var(--gray)}.summary{padding:8px 8px}.summary .title{font-size:calc(var(--font-size-regular) + 2px);margin-bottom:6px;word-break:break-word}.method{padding:2px 5px;vertical-align:middle;font-size:var(--font-size-small);height:calc(var(--font-size-small) + 16px);line-height:calc(var(--font-size-small) + 8px);width:68px;flex-shrink:0;border-radius:2px;display:inline-block;text-align:center;font-weight:700;text-transform:uppercase;margin-right:5px}.method.delete{border:2px solid var(--red)}.method.put{border:2px solid var(--orange)}.method.post{border:2px solid var(--green)}.method.get,.method.head{border:2px solid var(--blue)}.method.patch{border:2px solid var(--yellow)}.method.query{border:2px solid var(--purple)}.method.options{border:2px solid var(--gray)}.req-resp-container{display:flex;margin-top:16px;align-items:stretch;flex-wrap:wrap;flex-direction:column}.view-request{flex:1;min-height:100px;max-width:100%;padding:16px 8px;overflow:hidden;border-width:0;border-style:dashed}.request,.response{flex:1;min-height:100px;max-width:100%;padding:16px 8px;overflow:hidden}.request{border-width:0 0 1px 0;border-style:dashed}.patch .request{border-top:1px dashed var(--yellow);border-color:var(--yellow)}.query .request{border-top:1px dashed var(--purple);border-color:var(--purple)}.options .request{border-top:1px dashed var(--gray);border-color:var(--gray)}.put .request{border-top:1px dashed var(--orange);border-color:var(--orange)}.post .request{border-top:1px dashed var(--green);border-color:var(--green)}.get .request,.head .request{border-top:1px dashed var(--blue);border-color:var(--blue)}.delete .request{border-top:1px dashed var(--red);border-color:var(--red)}@media only screen and (min-width:1024px){.only-large-screen{display:block}.endpoint-head .path{font-size:var(--font-size-regular);min-width:400px}.endpoint-head .descr{display:flex}.descr .m-markdown-small,.endpoint-head .m-markdown-small{display:block}.req-resp-container{flex-direction:var(--layout,row)}.request{border-width:0 1px 0 0;padding:16px}.response{padding:16px}.summary{padding:8px 16px}}.security-info-button{position:absolute;top:3px;right:2px;font-size:var(--font-size-small);line-height:1.5}@media only screen and (max-width:768px){.security-info-button{display:none}}pre.code-sample{padding:8px;min-height:30px;font-family:var(--font-mono);font-size:var(--font-size-small)}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { css } from 'lit
|
|
1
|
+
import { css } from 'lit';
|
|
2
2
|
export default css`.col,.row{display:flex}.row{align-items:center;flex-direction:row}.col{align-items:stretch;flex-direction:column}`;
|