自定义sql编辑器的提示信息,原来只提示匹配到的结果内容,现在需要增加匹配到的类型展示,比如输入t,则提示tid column,table1 table,timestamp() function,TABLES keyword等。
项目主要参考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;
}
在这里插入代码片
需要注意的是,由于直接从node modules中拷贝过来的文件时经过umd方式打包过的,直接引入由于模块类型问题导致无法使用,应将引入的js文件修改为es6的模块化方式。