UNPKG

swagger-theme

Version:

Convert any API Specification into an awesome HTML documentation website

594 lines (505 loc) 18.5 kB
class ZamaPopup { constructor () { this._basicAuthToken = null; this._apiKeyToken = null; this._oAuthToken = null; this._authType = null; this._pathId = null; } generateTextField({ label, name, required, disabled, value }) { return ` <div class="form-group"> <label for="field-${name}" class="col-form-label">${label || name}${required ? '&nbsp;<i style="color: red;font-size: 8px;vertical-align: super;" class="fas fa-asterisk"></i>' : ''}</label> <input type="text" placeholder="Enter ${name}" class="form-control" name="field-${name}" id="field-${name}"${required ? ' required' : ''}${disabled ? ' disabled' : ''}${value ? ` value="${value}"` : ''}> </div> `; } generatePasswordField({ label, name, required, disabled, value }) { return ` <div class="form-group"> <label for="field-${name}" class="col-form-label">${label || name}${required ? '&nbsp;<i style="color: red;font-size: 8px;vertical-align: super;" class="fas fa-asterisk"></i>' : ''}</label> <input type="password" placeholder="Enter ${name}" class="form-control" name="field-${name}" id="field-${name}"${required ? ' required' : ''}${disabled ? ' disabled' : ''}${value ? ` value="${value}"` : ''}> </div> `; } generateFileField({ label, name, required, disabled, value }) { return ` <div class="form-group"> <label style="display: flex;justify-content: center;align-items: center;" class="col-form-label"> ${name} <input type="file" style="border: none;" placeholder="${name}" class="form-control" name="field-${name}" id="field-${name}"${required ? ' required' : ''}${disabled ? ' disabled' : ''}> </label> </div> `; } generateTextArea({ label, name, required, disabled, modelExample, example, value }) { return ` <div class="form-group"> <label for="field-${name}" class="col-form-label">${label || name}${required ? '&nbsp;<i style="color: red;font-size: 8px;vertical-align: super;" class="fas fa-asterisk"></i>' : ''}</label> <textarea ${modelExample ? `rows="${(modelExample.match(/\n/g) || []).length < 15 ? (modelExample.match(/\n/g) || []).length : 15}"` : ''} placeholder="${name}" name="field-${name}" id="field-${name}" class="form-control"${required ? ' required' : ''}${disabled ? ' disabled' : ''}>${value || modelExample || example || ''}</textarea> </div> `; } generateSelect({ label, name, options = [], required, disabled, value }) { return ` <div class="form-group"> <label for="field-${name}" class="col-form-label">${label || name}${required ? '&nbsp;<i style="color: red;font-size: 8px;vertical-align: super;" class="fas fa-asterisk"></i>' : ''}</label> <select class="form-control" placeholder="${name}" name="field-${name}" id="field-${name}"${required ? ' required' : ''}${disabled ? ' disabled' : ''}${value ? ` value="${value}"` : ''}> ${options.map(({ name, value }) => `<option value="${value}">${name}</option>`).join('')} </select> </div> `; } injectFieldHtml(fieldHtml) { if ($('#zamaModal').length) { $('#zamaModal .modal-body').append(fieldHtml); } } injectBreak() { this.injectFieldHtml("<hr />"); } injectButton({ onClick, name = '', label = 'Submit'}) { if ($('#zamaModal').length) { this.injectFieldHtml(` <div class="form-group" style="height: 40px;"> <button type="button" style="float: right;" class="zama-internal-${name}-btn btn btn-primary">${label}</button> </div> `); $(`.zama-internal-${name}-btn`).off("click"); $(`.zama-internal-${name}-btn`).click(onClick); } } resetFields() { if ($('#zamaModal').length) { $('#zamaModal .modal-body').html(''); } } setTitle(title) { if ($('#zamaModal').length) { $('#zamaModal .modal-header .modal-title').html(title); } } injectTitle(title) { this.injectFieldHtml(`<h5>${title}</h5>`); } createField({ type, ...props }) { let fieldHtml = ''; type = type && type.toLowerCase(); if (type === 'array') { const {items = {}} = props; const {enum: enums = []} = items; if (enums.length) { props.options = enums.map(e => ({name: e, value: e})); type = 'select' } else { type = 'text'; } } if (type === 'boolean') { props.options = [true, false].map(e => ({name: e, value: e})); type = 'select' } if (['string'].includes(type)) type = 'text'; else if (['int', 'integer'].includes(type)) type = 'number'; else if (['boolean'].includes(type)) type = 'select'; else if (['object', '', undefined, null].includes(type)) type = 'textarea'; // type = 'string', format: 'byte' => https://swagger.io/docs/specification/data-models/data-types/#file // else if (['', '', ''].includes(type)) type = 'file'; if (type === 'text') { fieldHtml = this.generateTextField(props); } else if (type === 'number') { fieldHtml = this.generateTextField(props); } else if (type === 'password') { fieldHtml = this.generatePasswordField(props); } else if (type === 'select') { fieldHtml = this.generateSelect(props); } else if (type === 'textarea') { fieldHtml = this.generateTextArea(props); } else if (type === 'file') { fieldHtml = this.generateFileField(props); } if (fieldHtml) { this.injectFieldHtml(fieldHtml); } } attachOnSubmit(cb) { $('#zamaModal form').off('submit'); $('#zamaModal form').submit((e) => { e.preventDefault(); this.requestSubmitHandler(); }); } hide() { $('#zamaModal').modal('hide'); } show() { $('#zamaModal').modal({ backdrop: 'static', show: true, }) } showSubmitButton() { $('#zamaModal .modal-footer').show(); } hideSubmitButton() { $('#zamaModal .modal-footer').hide(); } getFieldValue(name) { return $(`*[name="field-${name}"]`).val(); } createRequestHeaders(headers = []) { this.injectTitle('Headers'); headers.forEach((header) => { this.createField(header); }); } createRequestPath(paths = []) { this.injectTitle('Paths'); paths.forEach((path) => { this.createField(path); }); } createRequestQuery(queries = []) { this.injectTitle('Query'); queries.forEach((query) => { this.createField(query); }); } createRequestBody(bodies = []) { this.injectTitle('Body'); bodies.forEach((body) => { this.createField(body); }); } createRequestFormData(formData = []) { this.injectTitle('Form Data'); formData.forEach((form) => { this.createField(form); }); } createRequest(pathId) { this._pathId = pathId; const {paths = [], auths = []} = pathsObject; const path = paths.find(({id}) => id === pathId); if (!path) return; if (!this.getAuthToken().type && auths.length) { this.createAuthenticationForm(); return this.show(); } let { summary = '', requests = [], methodName = '', pathName = '' } = path; requests = requests.reduce((acc, { title, items }) => { acc[title] = [...items]; return acc; }, {}); if (this.getAuthToken().type === 'basic') { const { value = '' } = this.getAuthToken(); if (requests['header'] && requests['header'].length) { requests['header'].unshift({ name: 'Authorization', value: `Basic ${value}`, disabled: true, type: 'text' }); } else { requests['header'] = [{ name: 'Authorization', value: `Basic ${value}`, disabled: true, type: 'text' }]; } } if (this.getAuthToken().type === 'apiKey') { const { value = '' } = this.getAuthToken(); const {in: inPlace, name} = auths.find(e => e.type === 'apiKey'); if (inPlace === 'header') { if (requests['header'] && requests['header'].length) { requests['header'].unshift({ name, value, disabled: true, type: 'text' }); } else { requests['header'] = [{ name, value, disabled: true, type: 'text' }]; } } else { if (requests['query'] && requests['query'].length) { requests['query'].unshift({ name, value, disabled: true, type: 'text' }); } else { requests['query'] = [{ name, value, disabled: true, type: 'text' }]; } } } this.setTitle(summary); this.showSubmitButton(); this.resetFields(); this.injectPathUrl({methodName, pathName}); if (!!requests['header']) { this.createRequestHeaders(requests['header']); } if (requests['query']) { this.createRequestQuery(requests['query']); } if (requests['path']) { this.createRequestPath(requests['path']); } if (requests['body']) { this.createRequestBody(requests['body']); } if (requests['formData']) { this.createRequestFormData(requests['formData']); } this.attachOnSubmit(this.requestSubmitHandler); this.show(); } getAuthToken() { const {_apiKeyToken, _basicAuthToken, _oAuthToken} = this; return {type: this._authType, value: _apiKeyToken || _basicAuthToken || _oAuthToken} } createAuthenticationForm() { const {auths = []} = pathsObject; this.setTitle('Authentication'); this.hideSubmitButton(); this.resetFields(); auths.forEach(({type = '', ...restProps}, i) => { if (type === 'basic') { this.createBasicAuth(); } if (type === 'apiKey') { this.createApiKeyAuth(restProps); } if (type === 'oauth2') { this.createOauth(restProps); } if (auths.length > i + 1) { this.injectBreak(); } }); } createBasicAuth() { this.injectTitle('Basic Authentication'); this.createField({ type: 'text', name: 'Username', placeholder: 'Enter username' }); this.createField({ type: 'password', name: 'Password', placeholder: 'Enter password' }); this.injectButton({ name: 'basic-auth', label: 'Authenticate', onClick: () => { const user = this.getFieldValue('Username'); const pass = this.getFieldValue('Password'); this._basicAuthToken = btoa(`${user}:${pass}`); this._authType = 'basic'; this._apiKeyToken = null; this._oAuthToken = null; this.resetFields(); this.showSubmitButton(); if (this._pathId) { return this.createRequest(this._pathId); } return this.hide(); } }); } createApiKeyAuth(props) { const { in: inPlace = 'header', name = '', } = props; this.injectTitle('API Key'); this.injectFieldHtml(`<p>An API key with the name of <code>${name}</code>, will be send in <code>${inPlace}</code></p>`); this.createField({ type: 'text', name }); this.injectButton({ name: 'api-key', label: 'Authenticate', onClick: () => { const token = this.getFieldValue(name); this._authType = 'apiKey'; this._apiKeyToken = token; this._basicAuthToken = null; this._oAuthToken = null; this.resetFields(); this.showSubmitButton(); if (this._pathId) { return this.createRequest(this._pathId); } return this.hide(); } }); } createOauth(props) { const {authorizationUrl = '', flow = '', scopes, tokenUrl = ''} = props; this.injectTitle('Oauth 2.0'); this.injectFieldHtml(` <p>Oauth Server Details</p> <table class="table basic_table_info"> <tr> <td>Authorization URL</td> <td>${authorizationUrl}<td/> </tr> <tr> <td>Token URL</td> <td>${tokenUrl}<td/> </tr> <tr> <td>Flow</td> <td>${flow}<td/> </tr> </table> <p>Scopes</p> <table class="table basic_table_info"> ${Object.keys(scopes).map(name => ` <tr> <td>${name}</td> <td>${scopes[name]}<td/> </tr> `).join('')} </table> `); } createResponseBody(body) { let viewCode = ''; try { viewCode = JSON.stringify(JSON.parse(body), null, 4); } catch (e) { viewCode = body; } this.injectFieldHtml(` <p>Response Body</p> <div class="highlight javascript"> <pre><code class="language-javascript" data-lang="javascript"><div class="zama-response-code">${viewCode}</div></code></pre> </div> `); Prism.highlightElement($('.zama-response-code')[0]) } createResponseHeaders(headers) { this.injectFieldHtml(` <p>Response Headers</p> <table class="table basic_table_info"> ${headers.map(({name, value}) => ` <tr> <td>${name}</td> <td>${value}<td/> </tr> `).join('')} </table> `); } createResponse({body, headers}) { this.resetFields(); this.hideSubmitButton(); this.createResponseBody(body); this.injectBreak(); this.createResponseHeaders(headers); } requestSubmitHandler(e) { const {auths, paths, rootUrl = '' } = pathsObject; const path = paths.find(({id}) => id === this._pathId); let { requests = [], methodName = '', pathName = '' } = path; requests = requests.reduce((acc, { title, items }) => { acc[title] = [...items]; return acc; }, {}); if (this.getAuthToken().type === 'basic') { const { value = '' } = this.getAuthToken(); if (requests['header'] && requests['header'].length) { requests['header'].unshift({ name: 'Authorization', value: `Basic ${value}`, disabled: true, type: 'text' }); } else { requests['header'] = [{ name: 'Authorization', value: `Basic ${value}`, disabled: true, type: 'text' }]; } } if (this.getAuthToken().type === 'apiKey') { const { value = '' } = this.getAuthToken(); const {in: inPlace, name} = auths.find(e => e.type === 'apiKey'); if (inPlace === 'header') { if (requests['header'] && requests['header'].length) { requests['header'].unshift({ name, value, disabled: true, type: 'text' }); } else { requests['header'] = [{ name, value, disabled: true, type: 'text' }]; } } else { if (requests['query'] && requests['query'].length) { requests['query'].unshift({ name, value, disabled: true, type: 'text' }); } else { requests['query'] = [{ name, value, disabled: true, type: 'text' }]; } } } let url = `${rootUrl}${pathName}`; const options = { method: methodName, }; if (requests['header'] && requests['header'].length) { options.headers = requests['header'].reduce((acc, cur) => { const _value = cur.value || this.getFieldValue(cur.name); if (_value) { acc[cur.name] = _value; } return acc; }, {}); } if (requests['query'] && requests['query'].length) { url += encodeURI(`?${requests['query'].map(({ name, value }) => { const _value = value || this.getFieldValue(name); if (!_value) return ''; return `${name}=${_value}`; }).filter(e => e).join('&')}`); } if (requests['path'] && requests['path'].length) { requests['path'].forEach(({name, value}) => { const _value = value || this.getFieldValue(name); if (_value) { url = url.replace(`{${name}}`, _value); } }); } if (requests['body'] && requests['body'].length) { options.body = requests['body'].reduce((acc, cur) => { const value = cur.value || this.getFieldValue(cur.name); if (value) { acc[cur.name] = value; } return acc; }, {}); } if (requests['formData'] && requests['formData'].length) { options.body = encodeURI(`?${requests['formData'].map(({ name, value }) => { const _value = value || this.getFieldValue(name); return _value ? `${name}=${_value}` : ''; }).filter(e => e).join('&')}`) } let responseHeaders = []; this.resetFields(); this.startLoading(); fetch(url, options) .then(e => { responseHeaders = Array.from(e.headers.entries()).map(e => ({name: e[0], value: e[1]})); return e.text(); }) .then(e => this.createResponse({body: e, headers: responseHeaders})); } injectPathUrl({ methodName = '', pathName = 'get' }) { const { rootUrl = '' } = pathsObject; const _html = ` <p class="api-path mb-30" style="justify-content: flex-start; margin-bottom: 20px !important; overflow: scroll;"> <span class="api-method api-method-${methodName.toLowerCase()}">${methodName}</span> <span class="api-path-root">${rootUrl}</span> <span class="api-path-name">${pathName}</span> </p> `; $('#zamaModal .modal-body').prepend(_html); } startLoading() { this.injectFieldHtml(` <div style="display: flex;justify-content: center;"> <img src="${window.ASSETS_ROOT}assets/img/loading.svg" /> </div> `); } injectPopup() { const { auths = [] } = pathsObject; const _temp = ` <div class="modal fade" id="zamaModal" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal-dialog modal-lg" role="document"> <form class="modal-content"> <div class="modal-header"> <h5 class="modal-title"></h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">&times;</span> </button> </div> <div class="modal-body"></div> <div class="modal-footer"> ${auths.length ? `<span class="btn-re-auth" style="color: #10b3d6; cursor: pointer;">Authenticate</span>` : ''} <button type="submit" class="btn btn-primary send-request-btn">Send Request</button> </div> </form> </div> </div> `; $(document.body).append(_temp); $('.btn-re-auth').off('click'); $('.btn-re-auth').click(() => this.createAuthenticationForm()); } }