Greasy Fork 支持简体中文。

showDoc增强

对showDoc的增强

// ==UserScript==
// @name         showDoc增强
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  对showDoc的增强
// @author       李向
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @match        https://www.showdoc.com.cn/*
// @icon         https://www.google.com/s2/favicons?domain=showdoc.com.cn
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/clipboard.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.61.1/codemirror.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.61.1/mode/javascript/javascript.min.js
// @resource css https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.61.1/codemirror.min.css
// @resource theme https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.61.1/theme/dracula.min.css
// ==/UserScript==

(async function (open) {
    // 格式化beautify配置
    const opts = {
        indent_size: 4
    }
    let codeMirrorInstance = null
    // 初始化数据
    let info = {
        descriptionRaw: '',
        urlRaw: '',
        methodRaw: '',
        paramsListRaw: []
    }
    // 配置生成的url模版
    function createUrlCode(description, funcName, method, url) {
        return `// ${description}
        export const ${funcName} = params => http.${method}('${url}',params)`
    }
    function splitLast(str) {
        const lastIndex = str.lastIndexOf("/");
        return str.slice(lastIndex + 1);
    }
    function createFunName(str) {
        let funcName = ''
        const last = splitLast(str)
        const hasUnderline = last.includes('_')
        const isCamel = /[A-Z]/.test(last)
        if (!hasUnderline && !isCamel) {
            console.log('需要取两位');
            const lastSecond = splitLastSecond(str)

            funcName = lastSecond + '_' + last
        } else {
            funcName = last
        }
        return funcName
    }
    function highlight() {
        for (const codeblock of document.getElementsByTagName('code')) {
            hljs.highlightBlock(codeblock)
        }
    }
    function createCodeMirror() {
        if (!codeMirrorInstance) {
            codeMirrorInstance = CodeMirror.fromTextArea(document.getElementById("code"), {
                value: "剪贴板预览与编辑",
                mode: "javascript",
                theme: "dracula"
            });
        } else {
            codeMirrorInstance.setValue('剪贴板预览与编辑')
        }

    }
    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 addSheet(params) {
        GM_addStyle(GM_getResourceText("css"));
        GM_addStyle(GM_getResourceText("theme"));
        GM_addStyle(
            `
    ::-webkit-scrollbar {
        width: 3px;
        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);
    }
            .CodeMirror  {
                width: 98%;
                margin: 1rem 0;
                padding: 1em 1em;
                border-radius: 0.2rem;
                border:none !important;
                max-height:200px;
                overflow: auto;
            }
            .CodeMirror:hover {
              box-shadow:2px 2px 9px 0px #1e3b50;
            }
            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;
            }
            button {
              display: inline-block;
              position: relative;
              cursor: pointer;
              padding: 7px 7px;
              color: white;
              font-size: 0.7em;
              text-align: center;
              text-decoration: none;
              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: 5px;
              background-color:#409eff;
            }
            button + button {
              margin-left: 5px;
            }
            button:hover {
              background-color:#66a9ef;
              text-decoration: none;
              box-shadow: 0 4px 10px 0px rgba(0, 0, 0, 0.225);
            }
        `)
    }
    function dealRes(original) {
        function chunk(list, size = 2) {
            const result = [];
            for (let i = 0, len = list.length; i < len; i += size) {
                result.push(list.slice(i, i + size));
            }
            return result;
        }
        let str = original
            .replace(/[\n`-]/g, "")
            .split(" ")
            .join("");
        const list = [
            "**简要描述:**",
            "**请求URL:**",
            "**请求方式:**",
            "**参数:**",
            "**返回示例**",
            "**返回参数说明**",
            "**备注**",
        ];
        let res = [];

        list.forEach((item, index) => {
            const splitList = str.split(item);
            splitList[0] && res.push(splitList[0]);
            str = splitList[1];
        });

        const descriptionRaw = res[0];
        const urlRaw = res[1];
        const methodRaw = res[2].toLowerCase();
        const paramsOriginal = res[3]
            .replace(/[\n-:]/g, "")
            .split("|")
            .filter((item) => item);
        const paramsListRaw = chunk(paramsOriginal, 4);
        paramsListRaw.shift()
        return {
            descriptionRaw,
            urlRaw,
            methodRaw,
            paramsListRaw
        }

    }
    function readyAndWatch(func) {
        XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
            this.addEventListener('readystatechange', () => {
            }, false)

            if (url.includes('/api/page/info')) {
                func(url)

            }
            open.call(this, method, url, async, user, pass)
        }
    }
    function getJsonAsync(url) {
        return new Promise((resolve, reject) => {
            const formData = new FormData()

            let page_id = window.location.search.split('=')[1]
            if (!page_id) {
                const urlList = window.location.href.split('/')
                page_id = urlList[urlList.length - 1]
            }
            formData.append('page_id', page_id)
            formData.append('_item_pwd', null)
            const res = fetch(url, {
                method: 'POST',
                body: formData
            })
                .then(res => {
                    return res.json()
                })
                .catch(e => {
                    reject(e)
                })
            res.then(res => {
                const totalRes = res
                resolve(totalRes)
            })
        })
    }
    function createCopyUrl() {
        if (!document.querySelector('.copy_url')) {
            const titleDom = document.querySelector('#doc-title')
            const button = document.createElement('button')
            button.innerHTML = '复制Url'
            button.classList.add('copy_url')
            titleDom.prepend(button)
        }
    }
    function createCopyFunc() {
        if (!document.querySelector('.copy_func')) {
            const titleDom = document.querySelector('#doc-title')
            const button = document.createElement('button')
            button.innerHTML = '复制请求函数'
            button.classList.add('copy_func')
            titleDom.prepend(button)
        }
    }

    function createCliDisplay() {
        if (!document.querySelector('#code')) {
            document.querySelector('#p-content').insertAdjacentHTML('afterbegin',
                `<textarea id='code' class='card'>剪贴板预览与编辑</textarea>`
            )
        }

    }
    function setClipboardDisplay(e) {
        const text = e.text
        codeMirrorInstance.setValue(js_beautify(text, opts))
    }
    function clipboard() {
        const clipboardUrl = new ClipboardJS('.copy_url', {
            text: function (trigger) {
                const url = info.urlRaw.replace(/(http:\/\/xx\.com\/)?/, "")
                const methodRaw = info.methodRaw
                const funcName = createFunName(url)
                const descriptionRaw = info.descriptionRaw
                const urlFinal = createUrlCode(descriptionRaw, funcName, methodRaw, url)
                return urlFinal
            }
        })
        const clipboardFunc = new ClipboardJS('.copy_func', {
            text: function (trigger) {
                const url = info.urlRaw.replace(/(http:\/\/xx\.com\/)?/, "")
                const funcName = createFunName(url)
                let asyncName = toHump(funcName)
                let funcCode = ''
                if (info.paramsListRaw.length > 0) {
                    let comment = info.paramsListRaw.reduce((acc, cur, index, list) => {
                        if (index === list.length - 1) {
                            acc = `${acc}${cur[0]}:''//${cur[2]} ${cur[3]}`
                        } else {
                            acc = `${acc}${cur[0]}:'',//${cur[2]} ${cur[3]}
                        `
                        }
                        return acc
                    }, '')
                    funcCode = `async ${asyncName}Async() {
                        let params = {
                            ${comment}
                        }
                        let res = await api.${funcName}(params)
                      },
                    `
                } else {
                    funcCode = `async ${asyncName}Async() {
                        let res = await api.${funcName}()
                      },
                    `
                }

                return js_beautify(funcCode, opts)
            }
        })
        clipboardUrl.on('success', (e) => {
            setClipboardDisplay(e)
        })
        clipboardFunc.on('success', (e) => {
            setClipboardDisplay(e)
        })
    }
    addSheet()
    async function init(url) {
        const res = await getJsonAsync(url)
        info = dealRes(res.data.page_content)
        createCliDisplay()
        createCopyUrl()
        createCopyFunc()
        // createCopyTs()
        clipboard()
        highlight()
        createCodeMirror()
    }
    readyAndWatch(init)
})(XMLHttpRequest.prototype.open);