diff --git a/static/js/terminal/index.js b/static/js/terminal/index.js index d577bb1..362abc8 100644 --- a/static/js/terminal/index.js +++ b/static/js/terminal/index.js @@ -70,19 +70,15 @@ function Terminal(options){ this.cols = options.cols; this.rows = options.rows; - // set ondata + // set on data callback options.ondata = typeof options.ondata === 'function' ? options.ondata : function (){}; this.ondata = options.ondata; - // set ontitle + // set on title callback options.ontitle = typeof options.ontitle === 'function' ? options.ontitle : function (){}; this.ontitle = options.ontitle; - // set onscreen - options.onscreen = typeof options.onscreen === 'function' ? options.onscreen : function (){}; - this.onscreen = options.onscreen; - - // set convert eol + // set convert end of line options.convertEOL = options.convertEOL === true; this.convertEOL = options.convertEOL; @@ -114,8 +110,8 @@ function Terminal(options){ this.charsets = [null]; // misc - this.screen = ''; - this.screenLines = []; + this.element = null; + this.children = []; this.refreshStart = null; this.refreshEnd = null; this.savedX = null; diff --git a/static/js/terminal/lib/close.js b/static/js/terminal/lib/close.js index 1a398ea..6d0801c 100644 --- a/static/js/terminal/lib/close.js +++ b/static/js/terminal/lib/close.js @@ -10,13 +10,21 @@ module.exports = function (Terminal){ */ Terminal.prototype.close = function (){ this.lines = []; - this.screen = ''; - this.screenLines = []; + this.children = []; this.readable = false; this.writable = false; this.write = function (){}; this.ondata = function (){}; - this.ontitle = function (){}; - this.onscreen = function (){}; + this.ondataTitle = function (){}; + + if (this.element) { + var parent = this.element.parentNode; + + if (parent) { + parent.removeChild(this.element); + } + + this.element = null; + } }; }; diff --git a/static/js/terminal/lib/csi/mode.js b/static/js/terminal/lib/csi/mode.js index 411cb29..24e9e03 100644 --- a/static/js/terminal/lib/csi/mode.js +++ b/static/js/terminal/lib/csi/mode.js @@ -107,7 +107,7 @@ module.exports = function (Terminal){ this.insertMode = true; break; case 20: - this.convertEol = true; + this.convertEOL = true; break; } } else if (this.prefix === '?') { @@ -322,7 +322,7 @@ module.exports = function (Terminal){ this.insertMode = false; break; case 20: - this.convertEol = false; + this.convertEOL = false; break; } } else if (this.prefix === '?') { diff --git a/static/js/terminal/lib/focused.js b/static/js/terminal/lib/focused.js index f8abcf4..7e4a494 100644 --- a/static/js/terminal/lib/focused.js +++ b/static/js/terminal/lib/focused.js @@ -7,14 +7,6 @@ module.exports = function (Terminal){ Terminal.focus = null; - /** - * isFocused - * @returns {boolean} - */ - Terminal.prototype.isFocused = function (){ - return Terminal.focus === this; - }; - /** * focus */ @@ -25,8 +17,6 @@ module.exports = function (Terminal){ Terminal.focus.blur(); } - Terminal.focus = this; - if (this.cursor) { this.showCursor(); } @@ -34,6 +24,8 @@ module.exports = function (Terminal){ if (this.cursorBlink) { this.startBlink(); } + + Terminal.focus = this; }; /** diff --git a/static/js/terminal/lib/open.js b/static/js/terminal/lib/open.js index 99043d9..12a5381 100644 --- a/static/js/terminal/lib/open.js +++ b/static/js/terminal/lib/open.js @@ -29,12 +29,35 @@ module.exports = function (Terminal){ * open */ Terminal.prototype.open = function (){ + var div; + var i = 0; + + this.element = document.createElement('div'); + this.element.className = 'ui-terminal'; + this.element.style.outline = 'none'; + + this.element.setAttribute('tabindex', '0'); + this.element.setAttribute('spellcheck', 'false'); + + // sync default bg/fg colors + this.element.style.backgroundColor = this.bgColor; + this.element.style.color = this.fgColor; + + // Create the lines for our terminal. + this.children = []; + + for (; i < this.rows; i++) { + div = document.createElement('div'); + + this.element.appendChild(div); + this.children.push(div); + } + // XXX - hack, move this somewhere else. if (Terminal.brokenBold === null) { Terminal.brokenBold = isBoldBroken(); } this.refresh(0, this.rows - 1); - this.focus(); }; }; diff --git a/static/js/terminal/lib/options.js b/static/js/terminal/lib/options.js index 6377a91..0db661c 100644 --- a/static/js/terminal/lib/options.js +++ b/static/js/terminal/lib/options.js @@ -11,6 +11,7 @@ module.exports = function (Terminal){ Terminal.cursor = true; Terminal.cursorBlink = true; Terminal.cursorBlinkSpeed = 500; + Terminal.visualBell = true; Terminal.popOnBell = true; Terminal.scrollback = 640; Terminal.screenKeys = false; @@ -23,6 +24,7 @@ module.exports = function (Terminal){ cursor: Terminal.cursor, cursorBlink: Terminal.cursorBlink, cursorBlinkSpeed: Terminal.cursorBlinkSpeed, + visualBell: Terminal.visualBell, popOnBell: Terminal.popOnBell, scrollback: Terminal.scrollback, screenKeys: Terminal.screenKeys, diff --git a/static/js/terminal/lib/refresh.js b/static/js/terminal/lib/refresh.js index 3661b9c..e1e72ef 100644 --- a/static/js/terminal/lib/refresh.js +++ b/static/js/terminal/lib/refresh.js @@ -5,21 +5,6 @@ 'use strict'; module.exports = function (Terminal){ - /** - * screen - * @param foreground - * @param background - * @param content - * @returns {string} - */ - function screen(foreground, background, content){ - var intro = '
'; - var outro = '
'; - - return intro + content + outro; - } - // Rendering Engine // In the screen buffer, each character // is stored as a an array with a character @@ -37,8 +22,14 @@ module.exports = function (Terminal){ * @param end */ Terminal.prototype.refresh = function (start, end){ + var parent = this.element ? this.element.parentNode : null; + var optimize = parent && end - start >= this.rows / 2; var x, y, i, line, out, ch, width, data, attr, fgColor, bgColor, flags, row; + if (optimize) { + parent.removeChild(this.element); + } + width = this.cols; y = start; @@ -159,11 +150,11 @@ module.exports = function (Terminal){ out += ''; } - this.screenLines[y] = '
' + out + '
'; + this.children[y].innerHTML = out; } - this.screen = screen(this.fgColor, this.bgColor, this.screenLines.join('')); - - this.onscreen.call(this, this.screen); + if (optimize) { + parent.appendChild(this.element); + } }; }; diff --git a/static/js/terminal/lib/resize.js b/static/js/terminal/lib/resize.js index 8288d6a..9199e86 100644 --- a/static/js/terminal/lib/resize.js +++ b/static/js/terminal/lib/resize.js @@ -11,7 +11,7 @@ module.exports = function (Terminal){ * @param y */ Terminal.prototype.resize = function (x, y){ - var i, j, ch; + var line, element, i, j, ch; if (x < 1) x = 1; @@ -48,16 +48,34 @@ module.exports = function (Terminal){ j = this.rows; if (j < y) { + element = this.element; + while (j++ < y) { if (this.lines.length < y + this.ybase) { this.lines.push(this.blankLine()); } + + if (this.children.length < y) { + line = this.document.createElement('div'); + + element.appendChild(line); + + this.children.push(line); + } } } else if (j > y) { while (j-- > y) { if (this.lines.length > y + this.ybase) { this.lines.pop(); } + + if (this.children.length > y) { + element = this.children.pop(); + + if (!element) continue; + + element.parentNode.removeChild(element); + } } } diff --git a/static/js/terminal/lib/write.js b/static/js/terminal/lib/write.js index 37b8c0c..2f06f7b 100644 --- a/static/js/terminal/lib/write.js +++ b/static/js/terminal/lib/write.js @@ -30,9 +30,19 @@ module.exports = function (Terminal){ */ Terminal.prototype.bell = function (){ // buffers automatically when created - var bell = new Audio('bell.wav'); + var snd = new Audio('bell.wav'); - bell.play(); + snd.play(); + + if (!this.visualBell) return; + + var context = this; + + this.element.style.borderColor = 'white'; + + setTimeout(function (){ + context.element.style.borderColor = ''; + }, 10); if (this.popOnBell) this.focus(); }; @@ -414,6 +424,7 @@ module.exports = function (Terminal){ case 2: if (this.params[1]) { this.title = this.params[1]; + this.ontitle.call(this, this.title); } break;