I have finally solved this myself. I am not a JS expert, but I share my solution in case it is useful for someone else.
IMPORTANT: I got the original code from this project. That project was with Angular and Angular-codemirror dependency. I was not using Angular anywhere in my app so I extracted and adjusted it to use it without Angular.
The goal is to be able to define a dictionary/map of words that will be used for the autocomplete. The solution is very simple. At a parent of myTextAreaId
element you must create a span/div like this:
<div class="codeMirrorDictionaryHintDiv" codemirror-dictionary-hint="[ 'Soccer', 'Cricket', 'Baseball', 'Kho Kho' ]"></div>
Then...the code, will lookup the closest
element with css class codeMirrorDictionaryHintDiv
, will extract the attribute codemirror-dictionary-hint
, will evaluate that in order to get a Javascript array out of it, and then simply set that as the input dictionary for the hint function.
The code is:
var dictionary = [];
try {
// JSON.parse fails loudly, requiring a try-catch to prevent error propagation
var dictionary = JSON.parse(
document.getElementById('myTextAreaId')
.closest('.codeMirrorDictionaryHintDiv')
.getAttribute('codemirror-dictionary-hint')
) || [];
} catch(e) {}
// Register our custom Codemirror hint plugin.
CodeMirror.registerHelper('hint', 'dictionaryHint', function(editor) {
var cur = editor.getCursor();
var curLine = editor.getLine(cur.line);
var start = cur.ch;
var end = start;
while (end < curLine.length && /[\w$]/.test(curLine.charAt(end))) ++end;
while (start && /[\w$]/.test(curLine.charAt(start - 1))) --start;
var curWord = start !== end && curLine.slice(start, end);
var regex = new RegExp('^' + curWord, 'i');
return {
list: (!curWord ? [] : dictionary.filter(function(item) {
return item.match(regex);
})).sort(),
from: CodeMirror.Pos(cur.line, start),
to: CodeMirror.Pos(cur.line, end)
}
});
CodeMirror.commands.autocomplete = function(cm) {
CodeMirror.showHint(cm, CodeMirror.hint.dictionaryHint);
};