Swagger Tool DAWN

内部使用swagger-ui增强脚本,方便复制url为函数

// ==UserScript==
// @name         Swagger Tool DAWN
// @version      1.0.3
// @description  内部使用swagger-ui增强脚本,方便复制url为函数
// @author      lixiang
// @match        http://*/swagger-ui.html*
// @require     https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.4/clipboard.min.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.11.0/beautify.js

// @grant        GM_addStyle
// @run-at       document-end
// @license     MIT
// @namespace https://greasyfork.org/users/559637
// ==/UserScript==
// https://developer.chrome.com/extensions/match_patterns
(async function (open) {
  let totalRes = null
  const opts = {
    indent_size: 2
}

  function splitLast (str) {
    const lastIndex = str.lastIndexOf('/')
    return str.slice(lastIndex + 1)
  }
  function highlight () {
    for (const codeblock of document.getElementsByTagName('code')) {
      hljs.highlightBlock(codeblock)
    }
  }
  function addOutCss (href) {
    var head = document.querySelector('head')
    var link = document.createElement('link')
    link.href = href + ''
    link.rel = 'stylesheet'
    link.type = 'text/css'
    head.appendChild(link)
  }
  function firstUpperCase (str) {
    return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
  }
  function splitLastSecond (str) {
    const arr = str.split('/')
    return arr[arr.length - 2]
  }
  function toHump (str) {
    if (!str) { return }
    let newStr = ''
    let big = false
    for (const i in str) {
      let s = str[i]
      if (big) {
        s = s.toLocaleUpperCase()
        big = false
      }
      if (s === '_') { big = true } else newStr += s
    }
    return newStr
  }
  function getSelectValue () {
    const selectUrl = document.querySelector('#selectUrl')
    const index = selectUrl.selectedIndex // 序号,取当前选中选项的序号
    const select = selectUrl.options[index].value
    return select
  }
  function getUrlName (url) {
    const type = getSelectValue()
    let urlName = ''
    if (type === 'first') {
      urlName = toHump(splitLast(url))
    } else if (type === 'second') {
      const urlName2 = firstUpperCase(toHump(splitLast(url)))
      const urlName1 = toHump(splitLastSecond(url))
      urlName = urlName1 + urlName2
    }
    return urlName
  }
  function getPrefix () {
    return document.querySelector('#urlPrefix').value ? '/' + document.querySelector('#urlPrefix').value : ''
  }
  function setClipboardDisplay (e) {
    const text = e.text
    document.querySelector('#cliDisplaySpan').textContent = text
    highlight()
    e.clearSelection()
  }
  function addSheet (params) {
    GM_addStyle(
      `
      #cliDisplay .hljs {
  display: block !important;
  overflow-x: auto !important;
  padding: 0.5em !important;
  color: #abb2bf !important;
  background: #282c34 !important;
}

#cliDisplay .hljs-comment,
#cliDisplay .hljs-quote {
  color: #5c6370 !important;
  font-style: italic !important;
}

#cliDisplay .hljs-doctag,
#cliDisplay .hljs-keyword,
#cliDisplay .hljs-formula {
  color: #c678dd !important;
}

#cliDisplay .hljs-section,
#cliDisplay .hljs-name,
#cliDisplay .hljs-selector-tag,
#cliDisplay .hljs-deletion,
#cliDisplay .hljs-subst {
  color: #e06c75 !important;
}

#cliDisplay .hljs-literal {
  color: #56b6c2 !important;
}

#cliDisplay .hljs-string,
#cliDisplay .hljs-regexp,
#cliDisplay .hljs-addition,
#cliDisplay .hljs-attribute,
#cliDisplay .hljs-meta-string {
  color: #98c379 !important;
}

#cliDisplay .hljs-built_in,
#cliDisplay .hljs-class .hljs-title {
  color: #e6c07b !important;
}

#cliDisplay .hljs-attr,
#cliDisplay .hljs-variable,
#cliDisplay .hljs-template-variable,
#cliDisplay .hljs-type,
#cliDisplay .hljs-selector-class,
#cliDisplay .hljs-selector-attr,
#cliDisplay .hljs-selector-pseudo,
#cliDisplay .hljs-number {
  color: #d19a66 !important;
}

#cliDisplay .hljs-symbol,
#cliDisplay .hljs-bullet,
#cliDisplay .hljs-link,
#cliDisplay .hljs-meta,
#cliDisplay .hljs-selector-id,
#cliDisplay .hljs-title {
  color: #61aeee !important;
}

#cliDisplay .hljs-emphasis {
  font-style: italic !important;
}

#cliDisplay .hljs-strong {
  font-weight: bold !important;
}

#cliDisplay .hljs-link {
  text-decoration: underline !important;
}

      `
    )
    GM_addStyle(
      `
::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}
::-webkit-scrollbar-track {
    border-radius: 3px;
    background: #c678dd57;
    -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.08);
}
::-webkit-scrollbar-thumb {
    border-radius: 3px;
    background: rgba(0,0,0,0.12);
    -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.2);
}
.swagger-section #header {
  position:relative;
}
.search_wrapper {
 
}
.setting_card {
       position: absolute;
    background: #fff;
    border: 1px solid rgba(0,0,0,0.2);
    border-radius: 8px;
    box-shadow: 0 1px 2px 0 rgba(60,64,67,.30), 0 2px 6px 2px rgba(60,64,67,.15);
    overflow-x: hidden;
    padding-top: 0;
    height: 120px;
    width: 320px;
    right: 10px;
    top: 60px;
    padding: 10px 10px;
    visibility:hidden;
    z-index:1
}
.setting_item {
      padding: 5px 0;
    margin-bottom: 5px;
    border-bottom: 1px solid #f2f2f2;
}
.setting_icon {
  position:absolute;
  right:10px;
  top:10px;
   cursor: pointer;
}
.setting_icon:hover {
   animation: myRotate 3s linear infinite;
}
@keyframes myRotate{
    0%{ -webkit-transform: rotate(0deg);}
    50%{ -webkit-transform: rotate(180deg);}
    100%{ -webkit-transform: rotate(360deg);}
}
        .card {
          position: relative;
          background: #282c34 !important;

          margin: 1rem 0;
          padding: 1em 1em;
          border-radius: 0.2rem;
          border:none !important;
        max-height: 150px;
    overflow: auto;
        }
        .card:hover {
          box-shadow:2px 2px 9px 0px #1e3b50;
        }
        .header-label {
          color:#666;
              width: 120px;
    display: inline-block;
        }
        select {
          border: 1px solid #ccc;
          padding: 7px 0px;
          border-radius: 3px;
          padding-left: 5px;
          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
          box-shadow: inset 0 1px 1px rgba(80, 69, 69, 0.075);
          -webkit-transition: border-color ease-in-out 0.15s,
            -webkit-box-shadow ease-in-out 0.15s;
          -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
          transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
        }
        option {
          height: 30px;
          padding: 5px 4px;
        }
        input {
          border: 1px solid #ccc;
          padding: 7px 0px;
          border-radius: 3px;
          padding-left: 5px;
          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
          -webkit-transition: border-color ease-in-out 0.15s,
            -webkit-box-shadow ease-in-out 0.15s;
          -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
          transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
        }
        input:focus {
          border-color: #66afe9;
          outline: 0;
          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
            0 0 8px rgba(102, 175, 233, 0.6);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
            0 0 8px rgba(102, 175, 233, 0.6);
        }
        button {
          display: inline-block;
          position: relative;
          cursor: pointer;
          padding: 7px 4px;
          color: white;
          font-size: 0.7em;
          text-align: center;
          text-decoration: none;
          text-transform: uppercase;
          vertical-align: middle;
          white-space: nowrap;
          outline: none;
          border: none;
          -webkit-user-select: none;
          -moz-user-select: none;
          -ms-user-select: none;
          user-select: none;
          border-radius: 2px;
          background-color: #89bf04;
        }
        button + button {
          margin-left: 5px;
        }
        button:hover {
          background-color: #aee032;
          text-decoration: none;
          box-shadow: 0 4px 10px 0px rgba(0, 0, 0, 0.225);
        }
    `)
  }
  function readyAsync () {
    return new Promise((resolve, reject) => {
      XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
        this.addEventListener('readystatechange', () => {
        }, false)
        let timer = null
        let inited = false
        let myUrl = null
        if (url.includes('api-docs')) {
          myUrl = url
          timer = setInterval(() => {
            if (inited) {
              clearInterval(timer)
              inited = false
            } else {
              const elementArr = document.querySelectorAll('.http_method')
              if (elementArr.length !== 0) {
                if (myUrl.includes('api-docs')) {
                  inited = true
                  resolve(myUrl)
                }
              }
            }
          }, 1000)
        }
        open.call(this, method, url, async, user, pass)
      }
    })
  }
  function readyAndWatch (func) {
    XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
      this.addEventListener('readystatechange', () => {
      }, false)
      let timer = null
      let inited = false
      let myUrl = null
      if (url.includes('api-docs')) {
        myUrl = url
        timer = setInterval(() => {
          if (inited) {
            clearInterval(timer)
            inited = false
          } else {
            const elementArr = document.querySelectorAll('.http_method')
            if (elementArr.length !== 0) {
              if (myUrl.includes('api-docs')) {
                inited = true
                func(myUrl)
              }
            }
          }
        }, 1000)
      }
      open.call(this, method, url, async, user, pass)
    }
  }
  function getJsonAsync (url) {
    return new Promise((resolve, reject) => {
      const res = fetch(url)
        .then(res => {
          return res.json()
        })
        .catch(e => {
          reject(e)
        })
      res.then(res => {
        const totalRes = res
        resolve(totalRes)
      })
    })
  }

  function createExpand () {
    document.querySelector('#message-bar').insertAdjacentHTML('afterbegin', `
      <button id='collapse'>合起全部</button>
      <button id='expandAll'>展开全部</button>
    `)
    document.querySelector('#collapse').onclick = collapse
    document.querySelector('#expandAll').onclick = expandAll
    function expandAll () {
      const list = document.querySelector('#resources')
      const items = list.children;
      [...items].forEach(li => {
        li.classList.add('active')
        li.querySelector('ul.endpoints').style.display = 'block'
      })
    }
    function collapse () {
      const list = document.querySelector('#resources')
      const items = list.children;
      [...items].forEach(li => {
        li.classList.remove('active')
        li.querySelector('ul.endpoints').style.display = 'none'
      })
    }
  }

  function createCliDisplay () {
    document.querySelector('#message-bar').insertAdjacentHTML('afterbegin',
        `
          <pre class='card' id='cliDisplay'><code class='code javascript' id='cliDisplaySpan'>剪贴板展示</code></pre>   
        `
    )
  }
  function createCopyUrlAll () {
    const blockArr = document.querySelectorAll('#resources > .resource')

    blockArr.forEach(ele => {
      const button = document.createElement('button')
      button.innerHTML = '复制所有url'
      button.classList.add('copy_url_all')

      ele.querySelector('.heading').children[0].prepend(button)

      const paths = new Set();

      [...ele.querySelector('.endpoints').children].forEach(li => {
        const url = li.querySelector('.path').children[0].innerHTML
        const method = li
          .querySelector('.http_method')
          .children[2].innerHTML.toUpperCase()
        const note = li.querySelector('.markdown').children[0].innerHTML
        const obj = {
          url,
          method,
          note
        }
        const objStr = JSON.stringify(obj)
        paths.add(objStr)
      })
      button.dataset.clipboardText = Array.from(paths).join(';')
    })
  }
  function createCopyUrl () {
    const elementArr = document.querySelectorAll('.endpoint')
    elementArr.forEach(ele => {
      const button = document.createElement('button')
      button.innerHTML = '复制url'
      button.classList.add('copy_url')
      ele.querySelector('.http_method').prepend(button)
      const url = ele.querySelector('.path').children[0].innerHTML
      const method = ele.querySelector('.http_method').children[2].innerHTML.toUpperCase()
      const note = ele.querySelector('.markdown').children[0].innerHTML
      const obj = {
        url,
        method,
        note
      }
      const objStr = JSON.stringify(obj)
      button.dataset.clipboardText = objStr
    })
  }
  function createCopyFunc () {
    const elementArr = document.querySelectorAll('.endpoint')
    elementArr.forEach(ele => {
      const button = document.createElement('button')
      button.innerHTML = '复制为async函数'
      button.classList.add('copy_func')
      ele.querySelector('.http_method').prepend(button)
      const url = ele.querySelector('.path').children[0].innerHTML

      const pathRes = totalRes.paths[url].get || totalRes.paths[url].post
      const parameters = pathRes.parameters
      if (!parameters) {
        return
      }
      const parameterLast = parameters[parameters.length - 1]

      let ref
      let comment
      if (parameterLast.in === 'body') {
        if (parameterLast.schema.$ref) {
          ref = splitLast(parameterLast.schema.$ref)

          const definition = totalRes.definitions[ref]
          if (definition) {
            const properties = definition.properties

            const parameters = Object.keys(properties).map(key => {
              const property = properties[key]
              const obj = {}
              obj.name = key
              obj.description = property.description
              obj.type = property.type

              return obj
            })

            comment = parameters.reduce((acc, cur) => {
              if (cur.name == 'token') {
                return acc
              }
              acc = `${acc}
                    ${cur.name}:'',//${cur.description} ${cur.type}`
              return acc
            }, '')
          }
        }
      } else {
        comment = parameters.reduce((acc, cur) => {
          if (cur.name == 'token') {
            return acc
          }
          acc = `${acc}
                ${cur.name}:'', //${cur.description} ${cur.type}`
          return acc
        }, '')
      }

      if (!comment) {
        comment = '//无需参数'
      }
      const obj = {
        url,
        comment
      }
      button.dataset.clipboardText = JSON.stringify(obj)
    })
  }
  function createMock() {
     const elementArr = document.querySelectorAll('.endpoint')
    elementArr.forEach(ele => {
      const button = document.createElement('button')
      button.innerHTML = '复制mock'
      button.classList.add('copy_mock')
      ele.querySelector('.http_method').prepend(button)
      const url = ele.querySelector('.path').children[0].innerHTML
      const method = ele.querySelector('.http_method').children[2].innerHTML.toUpperCase()
      const note = ele.querySelector('.markdown').children[0].innerHTML
      const obj = {
        url,
        method,
        note
      }
      const objStr = JSON.stringify(obj)
      button.dataset.clipboardText = objStr
    })
  }


  function createButtonTable () {
    const elementArr = document.querySelectorAll('.endpoint')
    elementArr.forEach(ele => {
      const button = document.createElement('button')
      button.innerHTML = '复制为列表项'
      button.classList.add('copy_table')
      if (ele.querySelector('.description')) {
        ele.querySelector('.description').prepend(button)
        const description = ele.querySelector('.description')
        const div = description.querySelectorAll('div')
        const list = [...div]
        const table = list.reduce((acc, cur) => {
          if (cur.querySelector('.propDesc')) {
            const propName = cur.querySelector('.propName').innerHTML
            const noPropNameList = ['code', 'data', 'message', 'list', 'pageNum', 'pageSize', 'total ']
            if (noPropNameList.includes(propName)) {
              return acc
            }
            const propDesc = cur.querySelector('.propDesc').querySelector('p').innerHTML
            acc = `
            ${acc}
              {
                prop:"${propName}",
                label:"${propDesc}"
              },
              `
            return acc
          } else {
            return acc
          }
        }, '')
        button.dataset.clipboardText = table
      }
    })
  }
  function getResponse(url,totalRes) {
    const paths = totalRes.paths
    const path = paths[url]
    const responseDes = path['get'] || path['post']
    const response = responseDes.responses['200']
    const schemaUrl = response.schema['$ref']
    if (!schemaUrl) {
      return
    }
    const schema = splitLast(schemaUrl)
   
    const value = generateMockRef(schema)
    return value
 
  }
  function generateMockRef(schema) {
    const definitions = totalRes.definitions
    const definition = definitions[schema]
    const value = generateMock('',definition)
 
    return value
  }
  function generateMock(key,data) {
    if (key==='code') {
      return "code:'200',"
    }
    if (key==='message') {
      return "message:'成功',"
    }
    const schemaUrl = data['$ref'] ||null
    const type = data['type']  ||null
    const format = data['format']  ||null
    const description = data['description'] || '无注释'
    const items = data['items']  ||null
    let dataType = null
    if (schemaUrl) {
      dataType = 'ref'
    } else if (type==='object') {
      dataType = 'object'
    }else if (type && (type === 'integer'||type==='number')) {
      dataType = 'number'
    }else if (type&&type === 'string' && !format) {
      dataType = 'string'
    } else if (type&&type === 'string' && (format && format === 'date-time')) {
      dataType = 'time'
    } else if (type&&type==='array') {
      dataType ='array'
    } else if (type && type === 'boolean') {
      dataType='boolean'
    }
    let value = null
    switch (dataType) {
      case 'ref':
        const schema = splitLast(schemaUrl)
        value = generateMockRef(schema)
        break;
      case 'object':
        const properties = data['properties']
        if (!properties||Object.keys(properties).length===0) {
          value = generateMockString(description)
        } else {
           value = generateMockObject(properties)
        }
       
        break;
    
      case 'number':
        value = generateMockNumber(description)
        break;
    
      case 'string':
        value = generateMockString(description)
        break;
    
      case 'boolean':
        value = generateMockBoolean(description)
        break;
    
      case 'time':
        value = generateMockDate(description)
        break;
    
      case 'array':
        value = generateMockArray(items)
        break;
    
      default:
        break;
    }
    let res = null
    if (key && (dataType !== 'array')) {
       res= `'${key}':${value}`
    } else if (key&&dataType==='array') {
      res = `'${key}|5-15':[
        ${value}
      ], // ${description}`
    } else {
       res= `${value}`
    }
   return res
  }
  function generateMockBoolean(description) {
    return `Random.boolean(), //${description}`
  }
  function generateMockNumber(description) {
    return `Random.integer(), //${description}`
  }

  function generateMockString(description) {
    return `Random.csentence(3,5), //${description}`
  }
  function generateMockDate(description) {
    return `Random.date('T'), //${description}`
  }
  function generateMockObject(properties) {
   const mockObject  = Object.keys(properties).reduce((acc, cur) => {
      const key = cur
      const data = properties[key]
      const keyMock =  generateMock(key, data)
     acc = acc + ` 
      ${keyMock}`
     return acc
   }, '')
    return `{${mockObject}
    },`
  }
  function generateMockArray(items) {
    const value = generateMock('',items) 
    return value
  }
  function clipboard () {
    const clipboardUrl = new ClipboardJS('.copy_url', {
      text: function (trigger) {
        const objStr = trigger.dataset.clipboardText
        const obj = JSON.parse(objStr)
        const urlPrefix = getPrefix()
        const urlName = getUrlName(obj.url)
        const url = `export const ${urlName}  = data => request('${urlPrefix}${obj.url}', data,"${obj.method}")//${obj.note}`
        return url
      }
    })

    const clipboardMock = new ClipboardJS('.copy_mock', {
      text:function (trigger) {
        const objStr = trigger.dataset.clipboardText
        const obj = JSON.parse(objStr)
        const { url } = obj
        const response = getResponse(url, totalRes)
        const source = `
        '/mock${url}':${response}
        `
       return js_beautify(source, opts)
      }
    })

    const clipboardUrlAll = new ClipboardJS('.copy_url_all', {
      text: function (trigger) {
        const arr = trigger.dataset.clipboardText.split(';')
        const paths = new Set()
        arr.forEach(objStr => {
          const obj = JSON.parse(objStr)
          const urlPrefix = getPrefix()
          const urlName = getUrlName(obj.url)
          const url = `export const ${urlName}  = data => request('${urlPrefix}${obj.url}', data,"${obj.method}")//${obj.note}`
          paths.add(url)
        })
        return Array.from(paths).join('\n')
      }
    })

    const clipboardFunc = new ClipboardJS('.copy_func', {
      text: function (trigger) {
        const objStr = trigger.dataset.clipboardText
        const obj = JSON.parse(objStr)
        const comment = obj.comment
        const asyncName = getUrlName(obj.url)
        const fun = `
        async ${asyncName}Async() {
          let params = {
          ${comment}
          }
          let res = await api.${asyncName}(params)
          },
          `
        return fun
      }
    })
    const clipboardTable = new ClipboardJS('.copy_table', {
      text: function (trigger) {
        const table = trigger.dataset.clipboardText
        return table
      }
    })

    clipboardUrl.on('success', setClipboardDisplay)
    clipboardMock.on('success', setClipboardDisplay)
    clipboardUrlAll.on('success', setClipboardDisplay)
    clipboardFunc.on('success', setClipboardDisplay)
    clipboardTable.on('success', setClipboardDisplay)
  }
  function createSelect () {
    document.querySelector('.setting_card').insertAdjacentHTML('afterbegin',
        `
        <div class='setting_item'>
           <label for="selectUrl" class='header-label'>url截取范围:</label>
        <select name='selectUrl' id='selectUrl'>
          <option value="first"  selected = "selected">最后一级</option>
          <option value="second">最后二级</option>
        </select>
        </div>
        `
    )
  }
  function createInput () {
    document.querySelector('.setting_card').insertAdjacentHTML('afterbegin',
        `
        <div class='setting_item'>
           <label for="prefix" class='header-label'>url前缀:</label>
          <input type="text" id="urlPrefix" name="prefix" placeholder='后端微服务名'>
        </div>
         
        `
    )
  }
  function createSetting () {
    document.querySelector('#header').insertAdjacentHTML('beforeend',
        `
          <div class='setting_icon'>
           <svg t="1589098334770" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2404" width="35" height="35"><path d="M935.69113 523.130435c0-58.590609 36.797217-108.232348 88.30887-128a513.669565 513.669565 0 0 0-56.097391-135.635478 136.97113 136.97113 0 0 1-181.047652-181.092174A515.962435 515.962435 0 0 0 651.152696 22.26087 137.371826 137.371826 0 0 1 523.130435 110.569739 137.171478 137.171478 0 0 1 395.130435 22.26087a513.669565 513.669565 0 0 0-135.635478 56.141913 137.126957 137.126957 0 0 1-28.093218 152.932174 137.371826 137.371826 0 0 1-152.887652 28.16A510.21913 510.21913 0 0 0 22.26087 395.130435 137.371826 137.371826 0 0 1 110.569739 523.130435c0 58.590609-36.797217 108.232348-88.308869 128a513.669565 513.669565 0 0 0 56.141913 135.635478 136.97113 136.97113 0 0 1 180.980869 181.092174A515.650783 515.650783 0 0 0 395.130435 1024a137.371826 137.371826 0 0 1 128.022261-88.30887c58.590609 0 108.232348 36.797217 128 88.30887a513.669565 513.669565 0 0 0 135.635478-56.097391 137.126957 137.126957 0 0 1 28.093217-152.998957 137.371826 137.371826 0 0 1 152.887652-28.137739A510.21913 510.21913 0 0 0 1024 651.130435a137.171478 137.171478 0 0 1-88.30887-128.022261z m-401.719652 152.442435a141.55687 141.55687 0 1 1 0.111305-283.11374 141.55687 141.55687 0 0 1-0.111305 283.11374z" fill="#2DAA9D" p-id="2405"></path><path d="M754.042435 512c0-34.370783 21.593043-63.510261 51.801043-75.108174a301.345391 301.345391 0 0 0-32.901565-79.560348 80.361739 80.361739 0 0 1-106.22887-106.228869 302.703304 302.703304 0 0 0-79.604869-32.946087A80.584348 80.584348 0 0 1 512 269.957565 80.473043 80.473043 0 0 1 436.891826 218.156522c-27.959652 7.123478-54.761739 18.209391-79.560348 32.946087a80.450783 80.450783 0 0 1-16.473043 89.711304 80.584348 80.584348 0 0 1-89.711305 16.517565A299.341913 299.341913 0 0 0 218.156522 436.891826 80.584348 80.584348 0 0 1 269.957565 512c0 34.370783-21.593043 63.510261-51.801043 75.108174 7.123478 27.959652 18.209391 54.761739 32.946087 79.560348a80.361739 80.361739 0 0 1 106.184348 106.228869 302.525217 302.525217 0 0 0 79.604869 32.946087A80.584348 80.584348 0 0 1 512 754.042435c34.370783 0 63.510261 21.593043 75.108174 51.801043 27.959652-7.123478 54.761739-18.18713 79.560348-32.901565a80.450783 80.450783 0 0 1 16.473043-89.755826 80.584348 80.584348 0 0 1 89.711305-16.517565 299.341913 299.341913 0 0 0 32.990608-79.560348A80.473043 80.473043 0 0 1 754.042435 512z m-235.675826 89.421913a83.033043 83.033043 0 1 1 0.044521-166.066087 83.033043 83.033043 0 0 1-0.044521 166.066087z" fill="#A4E8E1" p-id="2406"></path></svg>
          </div>
          <div class='setting_card'>
           
          </div>
        `
    )
    document.querySelector('.setting_icon').onclick = changeShow
    let isShow = false
    function changeShow () {
      if (isShow) {
        isShow = false
        document.querySelector('.setting_card').style.visibility = 'hidden'
      } else {
        isShow = true
        document.querySelector('.setting_card').style.visibility = 'visible'
      }
    }
  }
  function createSearch (params) {
    document.querySelector('#header').insertAdjacentHTML('beforeend',
        `
          <div class='search_wrapper'>
            <label for="search" class='header-label'>搜索:</label>
          <input type="text" id="search" name="search" placeholder='输入汉字'>
          </div>
          
        `
    )
  }
  addSheet()
  async function init (url) {
    totalRes = await getJsonAsync(url)
    createExpand()
    createSetting()
    createSelect()
    createInput()

    createCliDisplay()
    createCopyFunc()
    createCopyUrl()
    createMock()
    createCopyUrlAll()
    createButtonTable()
   
    clipboard()
    highlight()
  }
  readyAndWatch(init)
}
)(XMLHttpRequest.prototype.open)