codemirror自定义sql提示

1、需求

自定义sql编辑器的提示信息,原来只提示匹配到的结果内容,现在需要增加匹配到的类型展示,比如输入t,则提示tid column,table1 table,timestamp() function,TABLES keyword等。

2、实现

项目主要参考vue-codemirror,使用组件codemirror实现,修改了codemirror中的sql-hint.js和show-hint.js文件。
1、将node modules文件夹下codemirror中部分源码包括addon,keymap,lib,mode,theme拷贝至自己的组件代码中,创建code-mirror.vue及index.js文件。其中,index.js主要用于导出及实现install方法,不做详细介绍。code-mirror.vue参考vue-codemirror中对应代码,主要包括引入对应文件,定义事件以及初始化编辑器,注意:此处引入的是我们拷贝到本地的文件,这样就可以使用修改后的代码。
2、修改sql-hint.js。sql-hint.js主要修改wrapTable、addMatches函数。
项目需要支持传入的hintOptions格式为{completeSingle:false,tables:{source1:{array:[table1,table2],type:‘source’},timestamp:{array:[],type:‘function’}},或者是{completeSingle:false,tables:{source1:{array:[{text:‘table1’,type:‘table’},{text:‘table2’,type:‘table’}],type:‘source’},timestamp:{array:[],type:‘function’}}
parseTables函数将传入的tables解析成固定的格式,主要使用的函数是wrapTable,这个函数需要修改部分代码,因为我们传入的数据类型变了;且需要对传入的第一种array数据不包含type的数据格式进行处理。

function wrapTable(name, value) {
    if (isArray(value.array)) {
        let childrenArr = []
        if (value.type === 'source') {
            childrenArr = value.array.map(item => {
                if (typeof item === 'object') {
                    return item
                } else {
                    return {
                        text: item,
                        type: 'table'
                    }
                }
            })
        } else if (value.type === 'table') {
            childrenArr = value.array.map(item => {
                if (typeof item === 'object') {
                    return item
                } else {
                    return {
                        text: item,
                        type: 'column'
                    }
                }
            })
        }
        value = { columns: childrenArr, type: value.type }

    }
    if (!value.text) value.text = name
    return value
}

在addMatches函数中,需要将result修改为既包含value又包含类型的格式。

function addMatches(result, search, wordlist, fomatter) {
    if (isArray(wordlist)) {
        for (var i = 0; i < wordlist.length; i++) {
            var type = wordlist[i].type || ''
            //如果需要控制提示信息个数可在此处处理
            if (match(search, wordlist[i])) {
                let res = fomatter(wordlist[i])
                if (typeof res === 'string') {
                    result.push({ text: res, type })
                } else {
                    result.push({ ...res, type })
                }
            }
        }
    } else {
        for (var word in wordlist) {
            if (wordlist.hasOwnProperty(word)) {
                var val = wordlist[word]
                var type = val.type || ''
                if (!val || val === true) {
                    val = word
                } else {
                    val = val.displayText ? { text: val.text, displayText: val.displayText } : val.text
                }
                //如果需要控制提示信息个数可在此处处理
                if (match(search, wordlist[i])) {
                    let res = fomatter(wordlist[i])
                    if (typeof res === 'string') {
                        result.push({ text: res, type })
                    } else {
                        result.push({ ...res, type })
                    }
                }
            }
        }
    }
}

3、show-hint函数修改。主要修改展示部分,之前只展示提示词,目前需要增加类型的展示。主要修改Widget函数

function Widget(completion, data) {
    //上面代码不做修改
    var completions = data.list;
    for (var i = 0; i < completions.length; ++i) {
        var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i];
        var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
        if (cur.className != null) className = cur.className + " " + className;
        elt.className = className;
        //源码修改部分
        var span = document.createElement('SPAN')
        span.style.color = 'white'
        span.style.cssFloat = 'right'
        let text = " " + (cur.type ? cur.type : 'keyword')
        var type = document.createTextNode(text);
        span.appendChild(type)
        if (cur.render) {
            cur.render(elt, data, cur)
        } else {
            elt.append(ownerDocument.createTextNode(cur.displayText || getText(cur)), span)
        }
        elt.hintId = i;
    }

      //后面其他代码不做修改
    return true;
}
在这里插入代码片

3、注意事项

需要注意的是,由于直接从node modules中拷贝过来的文件时经过umd方式打包过的,直接引入由于模块类型问题导致无法使用,应将引入的js文件修改为es6的模块化方式。

你可能感兴趣的:(codemirror,sql,vue.js,前端)