From acad5db74baf202e26cb2ba2e8f32c3d6ae0ef63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Thu, 17 Sep 2015 18:13:06 +0200 Subject: Refactored hint handling into a separate module. --- js/codeq/hint.js | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 js/codeq/hint.js (limited to 'js/codeq/hint.js') diff --git a/js/codeq/hint.js b/js/codeq/hint.js new file mode 100644 index 0000000..ffae638 --- /dev/null +++ b/js/codeq/hint.js @@ -0,0 +1,149 @@ +/** + * Creates a hint handler, displaying hints inside the provided jqHints
. + */ + +(function () { + // constants + var firstCharacterPos = {'line': 0, 'ch': 0}, + sel_no_scroll = {'scroll': false}; + + codeq.makeHinter = function (jqHints, jqEditor, editor, hintDefs) { + var hintCounter = 0, // for generating unique class-names + hintCleaners = [], + clearHints = function () { + var i; + for (i = hintCleaners.length - 1; i >= 0; i--) { + hintCleaners[i](); + } + hintCleaners.length = 0; + hintCounter = 0; + }, + addMark = function (start, end) { + var posStart = editor.posFromIndex(start), + posEnd = editor.posFromIndex(end), + doc = editor.getDoc(), + mark = doc.markText(posStart, posEnd, {'className': 'editor-mark _emark_' + hintCounter}), + result = {'start': posStart, 'end': posEnd, 'mark': mark, 'className': '_emark_' + hintCounter}; + hintCleaners.push(function () { mark.clear(); mark = null; doc = null; result.mark = null; }); + hintCounter++; + return result; + }, + processTemplate = function (template, args) { + if (!args) + return template; + return template.replace(/\[%=(\w+)%\]/g, function(match, name) { + return args[name]; + }); + }, + typeHandlers = { + 'static': function (type, template, serverHint) { + codeq.log.debug('Processing static hint'); + var message = processTemplate(template, serverHint.args); + jqHints.append('
' + message + '
'); + // no hint cleaner here, a static hint remains on the screen + }, + + 'popup': function (type, template, serverHint) { + codeq.log.debug('Processing popup hint'); + var message = processTemplate(template, serverHint.args), + mark = addMark(serverHint.start, serverHint.end), // add the mark + jqMark = jqEditor.find('.' + mark.className); + + jqMark.popover({'content': message, 'html': true, 'placement': 'auto bottom', 'trigger': 'hover focus click', 'container': 'body'}); + hintCleaners.push(function () { if (jqMark) { jqMark.popover('destroy'); jqMark = null; } }); + + mark.mark.on('', function () {}); + }, + + 'dropdown': function (type, template, serverHint) { + codeq.log.debug('Processing dropdown hint'); + var completion = null, // the completion object, created in showHint() + close = function () { + if (completion) { + completion.close(); + completion = null; + } + }; + + if (/*(editor.listSelections().length > 1) ||*/ editor.somethingSelected()) { + // showHint() doesn't work if a selection is activeparts + editor.setSelection(firstCharacterPos, firstCharacterPos, sel_no_scroll); // deselect anything + } + + editor.showHint({ + hint: function () { + var hints = { + list: serverHint.choices, + from: editor.posFromIndex(serverHint.start), + to: editor.posFromIndex(serverHint.end) + }; + completion = editor.state.completionActive; + return hints; + }, + completeOnSingleClick: true, + completeSingle: false + }); + + hintCleaners.push(close); + } + }; + + return { + /** + * Processes and display appropriately the server hints. + * TODO: sort hints so static and popup hints come first, and a (single) drop-down hint last + * + * @param {ServerHint[]} serverHints an array of hints from the server + */ + 'handle': function (serverHints) { + var n = serverHints.length, + /** number */ i, + /** ServerHint */ serverHint, + /** HintDefinition */ hintDef, + hintType, hintTemplate, t, fn, indices; + clearHints(); + for (i = 0; i < n; i++) { + serverHint = serverHints[i]; + hintDef = hintDefs[serverHint.id]; + if (serverHint.indices) { + indices = serverHint.indices + for (i = 0; i < indices.length; i++) { + hintDef = hintDef[indices[i]]; + if (!hintDef) + break; + } + } + if (!hintDef) { + codeq.log.error('Undefined hint ' + serverHint.id + ' with indices ' + serverHint.indices); + continue; + } + t = typeof hintDef; + if (t === 'object') { + hintType = hintDef.type; + hintTemplate = hintDef.message; + } + else if (t === 'string') { + hintType = 'static'; + hintTemplate = hintDef; + } + else { + codeq.log.error('Unsupported hint definition: ' + t); + continue; + } + + fn = typeHandlers[hintType]; + if (!fn) codeq.log.error('Unsupported hint type: ' + hintType); + else fn(hintType, hintTemplate, serverHint); + } + }, + + 'destroy': function () { + clearHints(); + jqHints.empty(); + jqHints = null; + jqEditor = null; + editor = null; + } + }; + }; +})(); \ No newline at end of file -- cgit v1.2.1 From 31cc69df82abce2250505c1e088d3f787a521a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Thu, 17 Sep 2015 19:46:34 +0200 Subject: Implemented support for an array of static hints, which are displayed in sequence after pressing the "more" button. --- js/codeq/hint.js | 64 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 10 deletions(-) (limited to 'js/codeq/hint.js') diff --git a/js/codeq/hint.js b/js/codeq/hint.js index ffae638..c22f39f 100644 --- a/js/codeq/hint.js +++ b/js/codeq/hint.js @@ -10,6 +10,7 @@ codeq.makeHinter = function (jqHints, jqEditor, editor, hintDefs) { var hintCounter = 0, // for generating unique class-names hintCleaners = [], + clearHints = function () { var i; for (i = hintCleaners.length - 1; i >= 0; i--) { @@ -18,6 +19,7 @@ hintCleaners.length = 0; hintCounter = 0; }, + addMark = function (start, end) { var posStart = editor.posFromIndex(start), posEnd = editor.posFromIndex(end), @@ -28,6 +30,7 @@ hintCounter++; return result; }, + processTemplate = function (template, args) { if (!args) return template; @@ -35,11 +38,49 @@ return args[name]; }); }, + typeHandlers = { 'static': function (type, template, serverHint) { - codeq.log.debug('Processing static hint'); - var message = processTemplate(template, serverHint.args); - jqHints.append('
' + message + '
'); + var jqContainer, jqButton, promise, i, lastIndex; + if (template instanceof Array) { // unwrap the template if there's only one + if (template.length == 0) template = ''; + else if (template.length == 1) template = template[0] + ''; + } + if (template instanceof Array) { + codeq.log.debug('Processing an array of static hints'); + jqContainer = $('
'); + jqButton = $(''); // TODO: translate "more" + jqHints.append(jqContainer); + lastIndex = template.length - 1; + promise = Q(); + for (i = 0; i <= lastIndex; i++) { + promise = promise.then((function (tmpl, index) { + return Q.Promise(function (resolve, reject) { + var message = processTemplate(tmpl, serverHint.args), + onClick; + jqContainer.append('
' + message + '
'); + if (index < lastIndex) { + onClick = function () { + jqButton.off('click', onClick); + jqButton.remove(); + resolve(); + }; + jqContainer.append(jqButton); + jqButton.on('click', onClick); + } + else { + resolve(); + } + }); + })(template[i], i)); + } + promise.done(); + } + else { + codeq.log.debug('Processing a single static hint'); + var message = processTemplate(template, serverHint.args); + jqHints.append('
' + message + '
'); + } // no hint cleaner here, a static hint remains on the screen }, @@ -102,21 +143,24 @@ /** HintDefinition */ hintDef, hintType, hintTemplate, t, fn, indices; clearHints(); + mainLoop: for (i = 0; i < n; i++) { serverHint = serverHints[i]; hintDef = hintDefs[serverHint.id]; + if (!hintDef) { + codeq.log.error('Undefined hint ' + serverHint.id); + continue; + } if (serverHint.indices) { - indices = serverHint.indices + indices = serverHint.indices; for (i = 0; i < indices.length; i++) { hintDef = hintDef[indices[i]]; - if (!hintDef) - break; + if (!hintDef) { + codeq.log.error('Undefined hint ' + serverHint.id + ' with indices ' + serverHint.indices); + continue mainLoop; + } } } - if (!hintDef) { - codeq.log.error('Undefined hint ' + serverHint.id + ' with indices ' + serverHint.indices); - continue; - } t = typeof hintDef; if (t === 'object') { hintType = hintDef.type; -- cgit v1.2.1