对于网站中需要用到代码编写功能的童鞋,不放注意下CodeMirror,支持多重语言的自动联想,自动补全,很像我们熟悉的VS编辑器等。而且我们还能定义自己的联想关键字,这几天因为项目的需要,需要在文本域中实现联想补全功能。特意研究了CodeMirror。
对于网上CodeMirror的介绍很少,官网的英文看得让人头大,这两天项目中需要用到自动补全联想功能,就研究研究了CodeMirror,顺便记下来,让更多的人收益学习。
CodeMirror官网上下载压缩文件后,解压,看到好多文件,还有好多Deom有兴趣的可以多研究研究DEOM,而我们所需要的自动补全功能实际上只需要以下7个文件。
<link rel="stylesheet" href="../lib/codemirror.css"> <script src="../lib/codemirror.js"></script> <script src="../addon/hint/show-hint.js"></script> <script src="../addon/hint/javascript-hint.js"></script> <script src="../mode/javascript/javascript.js"></script> <link rel="stylesheet" href="../addon/hint/show-hint.css"> <link rel="stylesheet" href="../doc/docs.css">
(以JS代码的自动补全功能为例)引入的这些文件,只需要把这7个文件引入项目就行了,没必要把整个解压的文件引入。
<script src="../lib/codemirror.js"></script>这个是主文件,要想使用自动补全功能,就要首先引入这个文件 <script src="../addon/hint/javascript-hint.js"></script>这个文件是提示显示所有JS关键字, <script src="../mode/javascript/javascript.js"></script>
如果只需要文本域编辑器的主动补全功能, 这个文件是根据用户输入的内容,只搜索这个以用户输入的内容为开头的关键字显示出来,如果不引入这个文件,智能提示就不会提示以用户输入的内容为开头的关键字,而是系统所预设的全部关键字。所以要引入这个文件。
现在的问题:
1:在/addon/hint/javascript-hint.js文件中找出在哪里显示这些JS关键字。
2:在/mode/javascript/javascript.js文件中找到程序是怎样根据用户输入的内容,只搜索这个以用户输入的内容为开头的关键字显示出来
对于第一个问题,其实可以把这个/addon/hint/javascript-hint.js文件中的
function getCoffeeScriptToken(editor, cur) { // This getToken, it is for coffeescript, imitates the behavior of // getTokenAt method in javascript.js, that is, returning "property" // type and treat "." as indepenent token. var token = editor.getTokenAt(cur); if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { token.end = token.start; token.string = '.'; token.type = "property"; } else if (/^\.[\w$_]*$/.test(token.string)) { token.type = "property"; token.start++; token.string = token.string.replace(/\./, ''); } return token; } CodeMirror.coffeescriptHint = function(editor, options) { return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); }; var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + "toUpperCase toLowerCase split concat match replace search").split(" "); var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); var funcProps = "prototype apply call bind".split(" ");
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
删除,没特殊的需求是不需要,这个默认的deom是以补全javascript为例子的,我们如果想改成自己的实例,就还需要修改一些地方:把
var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +"if in instanceof new null return switch throw true try typeof var void while with").split(" ");
修改成我自己的需求
var javascriptKeywords = ("薪资计算 社保计算 上月平均工资 养老保险 失业保险 sum abs qeens qees qwsa qxvc").split(" ");
但是保存运行之后还是会出现JS中的关键字,默认函数之类的东西,又研究了研究,原来是:
if (context) { // If this is a property, see if it belongs to some object we can // find in the current environment. var obj = context.pop(), base; if (obj.type.indexOf("variable") === 0) { if (options && options.additionalContext) base = options.additionalContext[obj.string]; base = base || window[obj.string]; } else if (obj.type == "string") { base = ""; } else if (obj.type == "atom") { base = 1; } else if (obj.type == "function") { if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && (typeof window.jQuery == 'function')) base = window.jQuery(); else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function')) base = window._(); } while (base != null && context.length) base = base[context.pop().string]; if (base != null) gatherCompletions(base); } else { // If not, just look in the window object and any local scope // (reading into JS mode internals to get at the local and global variables) for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); gatherCompletions(window); forEach(keywords, maybeAdd); }
这一段代码在做鬼,我就来个更直接,更暴力的办法:
直接改成这样:
if (context) { // If this is a property, see if it belongs to some object we can // find in the current environment. var obj = context.pop(), base; gatherCompletions(null); } else { // If not, just look in the window object and any local scope // (reading into JS mode internals to get at the local and global variables) for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); gatherCompletions(null); forEach(keywords, maybeAdd); }
研究了一天也研究烦了,不要怪我哦!这样一试,果然是行了。
但是如果想要使用自己数据库中的关键字该怎么办呢?研究了一下想了想,也想到了一个解决办法:
在后台写一个方法也让数据库中的字段变成var javascriptKeywords = ("薪资计算 社保计算 上月平均工资 养老保险 失业保险 sum abs qeens qees qwsa qxvc").split(" ");即可,我的方法:
protected string GetDefaultValue() { DataTable dt = BDAContext.GetObject<ICNPRStructureConfigBLL>().GetAllObjectPropertyName(); string s = string.Empty; if (dt.Rows.Count>0) { foreach (DataRow dr in dt.Rows) { s += dr["Name"] + " "; } } return s; }
在前台开始就写上 CodeMirror.javascriptKeywords = ('<%=GetDefaultValue()%>').split(" ");
但是所有的javascriptKeywords需要加上CodeMirror.,及我上面所写的。
所以我的aspx页面就是这样的:
<script type="text/javascript"> $(document).ready(function () { CodeMirror.javascriptKeywords = ('<%=GetDefaultValue()%>').split(" "); CodeMirror.commands.autocomplete = function (cm) { CodeMirror.showHint(cm, CodeMirror.javascriptHint); } var editor = CodeMirror.fromTextArea(document.getElementById("txt_FunExp"), { textWrapping: true, lineWrapping: true, lineNumbers: false, extraKeys: { "Ctrl-Space": "autocomplete" } }); }); </script>
但是又出现一个问题:输入中文时,不会智能提示出那个中文开头的短语或词组,也就是说不支持中文只能提示。又是个纠结的问题,还需要研究修改
/mode/javascript/javascript.js 文件的内容,一看,比刚才那个JS文件代码还多,我瞬间比这个文件的代码更凌乱了,没办法,慢慢研究研究吧!
也欢迎大牛们给出知道意见,看看怎么支持中文!不胜感激!
附上贴图:这是原DEOM中的实例,按下Ctrl-Space键之后,就会提示所有的JS关键字等,
任意按下一个字母,如m,再按Ctrl-Space键,就会提示出所有以m开头的单词
经本人修改后,成这样:。
另外,需要提醒的是,使用快捷键显示的话注意最好不要跟其他应用程序的的热键冲突。