CodeMirror sql部分智能提示关键字,老板希望可以自己加提示,还能支持 库.表.字段 下面我就说下我具体的做法:
第一步了解 codemirror的实现原理,
看这个很容易看出点啥,codemirror.js 主要是框架和配置类,show-hint.js 主要是显示提示框的类;
剩下的sql.js是规定了一些常用关键字,好吧其实我们可以在这里改,做下扩展嘛。我选择的是下一个sql-hint.js
第二步看下我写的sql-hint.js吧:
- /**
- * 2016/03/22 yc 重写sql-hint.js
- * @param {Object} mod
- */
- (function(mod) {
- if (typeof exports == "object" && typeof module == "object") // CommonJS
- mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
- else if (typeof define == "function" && define.amd) // AMD
- define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
- else // Plain browser env
- mod(CodeMirror);
- })(function(CodeMirror) {
- "use strict";
- var Pos = CodeMirror.Pos;
- /**
- * 从sql.js里获取keyword数组
- * @param {Object} editor
- */
- function getKeywords(editor) {
- var mode = editor.doc.modeOption;
- if (mode === "sql") mode = "text/x-sql";
- return CodeMirror.resolveMode(mode).keywords;
- };
- /**
- * 判断元素item是否存在数组arr中
- * @param {Object} arr
- * @param {Object} item
- */
- function arrayContains(arr, item) { // 判断元素item是否存在数组arr中
- if (!Array.prototype.indexOf) {
- var i = arr.length;
- while (i--) {
- if (arr[i] === item) {
- return true;
- }
- }
- return false;
- }
- return arr.indexOf(item) != -1;
- };
- function hintSql(editor, keywords, tableKeywords, getToken, options) { // 处理hint的核心函数,改名为velocityHint(也可以不做修改)
- // Find the token at the cursor,获取当前光标指定的字符串
- var cur = editor.getCursor(),
- token = getToken(editor, cur),
- tprop = token;
- return {
- list: getCompletions(token, keywords, tableKeywords, options),
- from: Pos(cur.line, fetchStartPoint(token)), // 字符串拼接的初始位置,这个很重要
- to: Pos(cur.line, token.end)
- };
- };
- /**
- * 字符拼接位置
- * @param {Object} token
- */
- function fetchStartPoint(token) {
- var index = token.string.lastIndexOf("\.");
- if (index < 0) {
- return token.start;
- } else {
- return token.start + index + 1;
- }
- // return token.start;
- };
- function sqlHint(editor, options) {
- var keywords = wordToString(getKeywords(editor)) + CodeMirror.keywords;
- return hintSql(editor, keywords, CodeMirror.tableKeywords, function(e, cur) {
- return e.getTokenAt(cur);
- }, options);
- };
- CodeMirror.registerHelper("hint", "sql", sqlHint);
- /**
- * 得到匹配的关键字数组
- * @param {Object} token
- * @param {Object} keywords
- * @param {Object} tableKeywords
- * @param {Object} options
- */
- function getCompletions(token, keywords, tableKeywords, options) {
- var found = [],
- start, pointCount, content = getWord(token.str.string, token.str.end); // found为匹配的数组
- if (content && content.length) {
- start = token.string.charAt(0); //字符串首字母
- content = content.trim().substring(0, content.lenght); //除首字母外的截取
- pointCount = (start == '\.') ? true : false; //判断最后一个字符是否是.
- }
- var result = null;
- if (start && start.trim() != '') { // 必须以$开头,这里暂时不解析${}
- var regexp = new RegExp("\\b" + content + "\\w+\\.?\\b", "gi");
- if (pointCount && tableKeywords) {
- result = tableKeywords.match(regexp);
- } else {
- result = keywords.match(regexp);
- }
- console.log('result = ' + result);
- }
- if (result && result.length) {
- for (var i = 0; i < result.length; i++) {
- if (!arrayContains(found, result[i]) && content.length <= result[i].length && pointCount) {
- if (result[i].charAt(result[i].length-1) == '.') { //如果最后一位是'.'
- found.push(result[i].substring(content.lastIndexOf("\.") + 1, result[i].length - 1));
- } else {
- found.push(result[i].substring(content.lastIndexOf("\.") + 1, result[i].length));
- }
- } else {
- found.push(result[i]);
- }
- }
- }
- return found;
- };
- /**
- * 获取当前字符串
- * @param {Object} str 当前行字符串
- * @param {Object} end 结束位置
- */
- function getWord(str, end) {
- return str.substring(str.lastIndexOf(' '), end);
- };
- /**
- * 将wordlist拼成字符串
- * @param {Object} wordlist
- */
- function wordToString(wordlist) {
- var str = '';
- for (var word in wordlist) {
- str += word + ' ';
- }
- return str;
- };
- });
注释还好啦,你比对下原来的js就会发现实现方法。其实我就是定义了外部变量然后通过赋值拓展的方式实现的。
html页面:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <title></title>
- </head>
- <script type="text/javascript" src="js/jquery-1.7.1.js"></script>
- <link rel="stylesheet" href="js/codemirror-5.2/theme/3024-day.css">
- <link type="text/css" rel="stylesheet" href="js/codemirror-5.2/lib/codemirror.css" />
- <link type="text/css" rel="stylesheet" href="js/codemirror-5.2/addon/hint/show-hint.css" />
- <script type="text/javascript" src="js/codemirror-5.2/lib/codemirror.js"></script>
- <script type="text/javascript" src="js/codemirror-5.2/mode/sql/sql.js"></script>
- <script type="text/javascript" src="js/codemirror-5.2/addon/hint/show-hint.js"></script>
- <script type="text/javascript" src="js/sql-hint.js"></script>
- <style>
- .CodeMirror {
- border: 1px solid black;
- }
- </style>
- <body>
- <h2>SQL编辑器</h2>
- <form>
- <textarea id="code" name="code"></textarea>
- </form>
- <script>
- CodeMirror.keywords = "server software ";
- CodeMirror.tableKeywords = "server.ip server.cache software.conf software.version software.tags.count ";
- var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
- lineNumbers: true,
- extraKeys: {
- "Ctrl": "autocomplete"
- }, //输入s然后ctrl就可以弹出选择项
- mode: {
- name: "text/x-mysql"
- },
- theme: "3024-day" //主题
- });
- editor.on('change', function() {
- editor.showHint(); //满足自动触发自动联想功能
- });
- </script>
- </body>
- </html>
第三步,我们来看下具体的结果: