diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/codeq/console.js | 159 |
1 files changed, 73 insertions, 86 deletions
diff --git a/js/codeq/console.js b/js/codeq/console.js index ebf09cc..20f3a90 100644 --- a/js/codeq/console.js +++ b/js/codeq/console.js @@ -176,70 +176,27 @@ currentHistoryIndex = -1, instanceNumber = instanceCounter++, // unique instace number, to be used with stuff tied to this instance, e.g.: jqElt events, life-cycle debug output - renderSpan = function (lineDescriptor, startCol, length) { + renderLine = function (lineDescriptor) { var jqLine = lineDescriptor.jqLine, content = lineDescriptor.content, - classes = lineDescriptor.classNames, - endCol = startCol + length, - N = classes ? classes.length : 0, + classes = lineDescriptor.classNames || [], + cursor = currentRow == lineDescriptor.row ? currentCol : null, + startCol = 0, i = 0, spans = [], // what to render, items are of the form {'content': string, 'cssClass': string} - entry, classSpan, jq, span, s, prefixDelta, suffixDelta, e; - // seek out the first css class - while (i < N) { - entry = classes[i]; - if (((entry.start + entry.length) > startCol) && (entry.start < endCol)) break; - i++; - } - if (i < N) { - // render the first span - e = entry.start + entry.length; // end column of this css class - prefixDelta = entry.start < startCol ? startCol - entry.start : 0; - suffixDelta = e > endCol ? e - endCol : 0; - classSpan = entry.length - prefixDelta - suffixDelta; - span = {'content': content.substr(startCol, classSpan), 'cssClass': entry.name}; - spans.push(span); - startCol += classSpan; - i++; - // render the rest - while ((startCol < endCol) && (i < N)) { - entry = classes[i]; - e = entry.start + entry.length; // end column of this css class - prefixDelta = entry.start < startCol ? startCol - entry.start : 0; - suffixDelta = e > endCol ? e - endCol : 0; - classSpan = entry.length - prefixDelta - suffixDelta; - s = content.substr(startCol, classSpan); - if (entry.name === span.cssClass) { - span.content += s; // join content where the class is the same + entry, jq, e, beforeCursor, afterCursor, name, + addOrMergeSpan = function (content, className) { + if (spans.length > 0 && className === spans[spans.length-1].cssClass) { + // join content to previous span where the class is the same + spans[spans.length-1].content += content; } else { - span = {'content': s, 'cssClass': entry.name}; - spans.push(span); + // add a new span for a new class + spans.push({'content': content, 'cssClass': className}); } - startCol += classSpan; - i++; - } - } - // render any leftover - if (startCol < endCol) { - entry = makeClassDescriptor('', startCol, endCol - startCol); - spans.push({'content': content.substring(startCol, endCol), 'cssClass': ''}); - } - // render spans - for (i = 0; i < spans.length; i++) { - span = spans[i]; - jq = $('<span class="cq-con-text ' + span.cssClass + '"></span>'); - jqLine.append(jq); - jq.text(span.content); - } - return entry; // return the last entry used - }, - - renderLine = function (lineDescriptor) { - var jqLine = lineDescriptor.jqLine, - content = lineDescriptor.content, - jqCursor, classDescriptor; + }; + // get or create line if (!jqLine) { jqLine = $('<pre class="cq-con-line"></pre>'); if (lineDescriptor.row == 0) { @@ -258,33 +215,47 @@ jqLine.empty(); } - if (currentRow == lineDescriptor.row) { - // mark the cursor in the current line - if (currentCol >= content.length) { - // cursor after the last character - renderSpan(lineDescriptor, 0, content.length); - jqCursor = $('<span class="cq-con-cursor"> </span>'); - jqLine.append(jqCursor); - } - else if (currentCol <= 0) { - // cursor at the first character - classDescriptor = lineDescriptor.classNames[0] || makeClassDescriptor('', 0, content.length); - jqCursor = $('<span class="cq-con-cursor ' + classDescriptor.name + '"></span>'); - jqLine.append(jqCursor); - jqCursor.text(content.charAt(0)); - renderSpan(lineDescriptor, 1, content.length - 1); + // create spans + while (startCol < content.length) { + entry = i < classes.length ? classes[i] + : makeClassDescriptor('', startCol, content.length - startCol); + e = entry.start + entry.length; // end column of this css class + if (cursor !== null && cursor >= entry.start && cursor < e) { + // cursor is in this span + beforeCursor = content.substr(startCol, cursor - startCol); + if (beforeCursor) { + addOrMergeSpan(beforeCursor, entry.name); + } + + spans.push({'content': content.charAt(cursor), 'cssClass': 'cq-con-cursor ' + entry.name}); + afterCursor = content.substr(cursor + 1, e - cursor - 1); + if (afterCursor) { + spans.push({'content': afterCursor, 'cssClass': entry.name}); + } } else { - // cursor somewhere in between - classDescriptor = renderSpan(lineDescriptor, 0, currentCol); - jqCursor = $('<span class="cq-con-cursor ' + classDescriptor.name + '"></span>'); - jqLine.append(jqCursor); - jqCursor.text(content.charAt(currentCol)); - renderSpan(lineDescriptor, currentCol + 1, content.length - currentCol - 1); + // cursor is not in this span + addOrMergeSpan(content.substr(startCol, entry.length), entry.name); } + startCol += entry.length; + i++; } - else { - renderSpan(lineDescriptor, 0, content.length); + // add a fake space if cursor is at end of line + if (cursor !== null && cursor >= content.length) { + name = entry ? entry.name : ''; + spans.push({'content': ' ', 'cssClass': 'cq-con-cursor ' + name}); + } + + // render spans + for (i = 0; i < spans.length; i++) { + jq = $('<span class="cq-con-text ' + spans[i].cssClass + '"></span>'); + jqLine.append(jq); + jq.text(spans[i].content); + } + + // (re-)render cursor if it is in the current line + if (cursor !== null) { + renderCursor(); } }, @@ -891,8 +862,27 @@ clipboardPasteInProgress = false, // whether the previous keydown was a CTRL+V or shift+insert aKeyIsDown = false, // whether a key is currently pressed: if it's not and there is input, then we got a paste via mouse + cursorBlinkRate = (options && options.cursorBlinkRate) || 750, // default: 750 ms blinkTimer = null, + renderCursor = function () { + if (blinkTimer) { + clearInterval(blinkTimer); + blinkTimer = null; + } + if (jqInput.is(':focus')) { + jqContent.find('.cq-con-cursor').addClass('inverted'); + if ((typeof cursorBlinkRate === 'number') && (cursorBlinkRate >= 50)) { // have some sense of sanity + blinkTimer = setInterval(function () { + jqContent.find('.cq-con-cursor').toggleClass('inverted'); + }, cursorBlinkRate); + } + } + else { + jqContent.find('.cq-con-cursor').removeClass('inverted'); + } + }, + i, j, a, b, c; // copy default key handlers @@ -956,6 +946,10 @@ aKeyIsDown = false; }); + jqInput.on('blur focus', function () { + renderCursor(); + }); + if ('oninput' in jqInput[0]) { // the element supports input events, use them in preference to keypress events jqInput.on('input', function (evt) { @@ -982,13 +976,6 @@ }); } - // start the cursor blinking if so instructed - if ((typeof cursorBlinkRate === 'number') && (cursorBlinkRate >= 50)) { // have some sense of sanity - blinkTimer = setInterval(function () { - jqContent.find('.cq-con-cursor').toggleClass('inverted'); - }, cursorBlinkRate); - } - // emit greeting if provided if (options && options.greeting) { lines.push({content: options.greeting, className: 'greeting'}); |