Comparing version 2.2.3 to 2.3.0
@@ -6,110 +6,122 @@ /** | ||
*/ | ||
(function (attach) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = attach(require('../../xterm')); | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], attach); | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
attach(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}; | ||
/** | ||
* Attaches the given terminal to the given socket. | ||
* | ||
* @param {Xterm} term - The terminal to be attached to the given socket. | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
exports.attach = function (term, socket, bidirectional, buffered) { | ||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; | ||
term.socket = socket; | ||
term._flushBuffer = function () { | ||
term.write(term._attachSocketBuffer); | ||
term._attachSocketBuffer = null; | ||
clearTimeout(term._attachSocketBufferTimer); | ||
term._attachSocketBufferTimer = null; | ||
}; | ||
term._pushToBuffer = function (data) { | ||
if (term._attachSocketBuffer) { | ||
term._attachSocketBuffer += data; | ||
} | ||
else { | ||
term._attachSocketBuffer = data; | ||
setTimeout(term._flushBuffer, 10); | ||
} | ||
}; | ||
term._getMessage = function (ev) { | ||
if (buffered) { | ||
term._pushToBuffer(ev.data); | ||
} | ||
else { | ||
term.write(ev.data); | ||
} | ||
}; | ||
term._sendData = function (data) { | ||
socket.send(data); | ||
}; | ||
socket.addEventListener('message', term._getMessage); | ||
if (bidirectional) { | ||
term.on('data', term._sendData); | ||
} | ||
socket.addEventListener('close', term.detach.bind(term, socket)); | ||
socket.addEventListener('error', term.detach.bind(term, socket)); | ||
}; | ||
/** | ||
* Detaches the given terminal from the given socket | ||
* | ||
* @param {Xterm} term - The terminal to be detached from the given socket. | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
module.exports = attach(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
exports.detach = function (term, socket) { | ||
term.off('data', term._sendData); | ||
socket = (typeof socket == 'undefined') ? term.socket : socket; | ||
if (socket) { | ||
socket.removeEventListener('message', term._getMessage); | ||
} | ||
delete term.socket; | ||
}; | ||
/** | ||
* Attaches the current terminal to the given socket | ||
* | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
define(['../../xterm'], attach); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
Xterm.prototype.attach = function (socket, bidirectional, buffered) { | ||
return exports.attach(this, socket, bidirectional, buffered); | ||
attach(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}; | ||
/** | ||
* Attaches the given terminal to the given socket. | ||
* | ||
* @param {Xterm} term - The terminal to be attached to the given socket. | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
exports.attach = function (term, socket, bidirectional, buffered) { | ||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; | ||
term.socket = socket; | ||
term._flushBuffer = function () { | ||
term.write(term._attachSocketBuffer); | ||
term._attachSocketBuffer = null; | ||
clearTimeout(term._attachSocketBufferTimer); | ||
term._attachSocketBufferTimer = null; | ||
}; | ||
/** | ||
* Detaches the current terminal from the given socket. | ||
* | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
Xterm.prototype.detach = function (socket) { | ||
return exports.detach(this, socket); | ||
term._pushToBuffer = function (data) { | ||
if (term._attachSocketBuffer) { | ||
term._attachSocketBuffer += data; | ||
} else { | ||
term._attachSocketBuffer = data; | ||
setTimeout(term._flushBuffer, 10); | ||
} | ||
}; | ||
return exports; | ||
term._getMessage = function (ev) { | ||
if (buffered) { | ||
term._pushToBuffer(ev.data); | ||
} else { | ||
term.write(ev.data); | ||
} | ||
}; | ||
term._sendData = function (data) { | ||
socket.send(data); | ||
}; | ||
socket.addEventListener('message', term._getMessage); | ||
if (bidirectional) { | ||
term.on('data', term._sendData); | ||
} | ||
socket.addEventListener('close', term.detach.bind(term, socket)); | ||
socket.addEventListener('error', term.detach.bind(term, socket)); | ||
}; | ||
/** | ||
* Detaches the given terminal from the given socket | ||
* | ||
* @param {Xterm} term - The terminal to be detached from the given socket. | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
exports.detach = function (term, socket) { | ||
term.off('data', term._sendData); | ||
socket = (typeof socket == 'undefined') ? term.socket : socket; | ||
if (socket) { | ||
socket.removeEventListener('message', term._getMessage); | ||
} | ||
delete term.socket; | ||
}; | ||
/** | ||
* Attaches the current terminal to the given socket | ||
* | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
Xterm.prototype.attach = function (socket, bidirectional, buffered) { | ||
return exports.attach(this, socket, bidirectional, buffered); | ||
}; | ||
/** | ||
* Detaches the current terminal from the given socket. | ||
* | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
Xterm.prototype.detach = function (socket) { | ||
return exports.detach(this, socket); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=attach.js.map |
@@ -13,48 +13,70 @@ /** | ||
*/ | ||
(function (fit) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = fit(require('../../xterm')); | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], fit); | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
fit(window.Terminal); | ||
} | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = fit(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], fit); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
fit(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
var exports = {}; | ||
exports.proposeGeometry = function (term) { | ||
var parentElementStyle = window.getComputedStyle(term.element.parentElement), parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')), parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17), elementStyle = window.getComputedStyle(term.element), elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')), elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')), availableHeight = parentElementHeight - elementPaddingVer, availableWidth = parentElementWidth - elementPaddingHor, container = term.rowContainer, subjectRow = term.rowContainer.firstElementChild, contentBuffer = subjectRow.innerHTML, characterHeight, rows, characterWidth, cols, geometry; | ||
subjectRow.style.display = 'inline'; | ||
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace | ||
characterWidth = subjectRow.getBoundingClientRect().width; | ||
subjectRow.style.display = ''; // Revert style before calculating height, since they differ. | ||
characterHeight = parseInt(subjectRow.offsetHeight); | ||
subjectRow.innerHTML = contentBuffer; | ||
rows = parseInt(availableHeight / characterHeight); | ||
cols = parseInt(availableWidth / characterWidth); | ||
geometry = { cols: cols, rows: rows }; | ||
return geometry; | ||
}; | ||
exports.fit = function (term) { | ||
var geometry = exports.proposeGeometry(term); | ||
term.resize(geometry.cols, geometry.rows); | ||
}; | ||
Xterm.prototype.proposeGeometry = function () { | ||
return exports.proposeGeometry(this); | ||
}; | ||
Xterm.prototype.fit = function () { | ||
return exports.fit(this); | ||
}; | ||
return exports; | ||
var exports = {}; | ||
exports.proposeGeometry = function (term) { | ||
var parentElementStyle = window.getComputedStyle(term.element.parentElement), | ||
parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')), | ||
parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17), | ||
elementStyle = window.getComputedStyle(term.element), | ||
elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')), | ||
elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')), | ||
availableHeight = parentElementHeight - elementPaddingVer, | ||
availableWidth = parentElementWidth - elementPaddingHor, | ||
container = term.rowContainer, | ||
subjectRow = term.rowContainer.firstElementChild, | ||
contentBuffer = subjectRow.innerHTML, | ||
characterHeight, | ||
rows, | ||
characterWidth, | ||
cols, | ||
geometry; | ||
subjectRow.style.display = 'inline'; | ||
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace | ||
characterWidth = subjectRow.getBoundingClientRect().width; | ||
subjectRow.style.display = ''; // Revert style before calculating height, since they differ. | ||
characterHeight = parseInt(subjectRow.offsetHeight); | ||
subjectRow.innerHTML = contentBuffer; | ||
rows = parseInt(availableHeight / characterHeight); | ||
cols = parseInt(availableWidth / characterWidth); | ||
geometry = {cols: cols, rows: rows}; | ||
return geometry; | ||
}; | ||
exports.fit = function (term) { | ||
var geometry = exports.proposeGeometry(term); | ||
term.resize(geometry.cols, geometry.rows); | ||
}; | ||
Xterm.prototype.proposeGeometry = function () { | ||
return exports.proposeGeometry(this); | ||
}; | ||
Xterm.prototype.fit = function () { | ||
return exports.fit(this); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=fit.js.map |
@@ -7,45 +7,45 @@ /** | ||
(function (fullscreen) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = fullscreen(require('../../xterm')); | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = fullscreen(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], fullscreen); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
fullscreen(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
var exports = {}; | ||
/** | ||
* Toggle the given terminal's fullscreen mode. | ||
* @param {Xterm} term - The terminal to toggle full screen mode | ||
* @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false) | ||
*/ | ||
exports.toggleFullScreen = function (term, fullscreen) { | ||
var fn; | ||
if (typeof fullscreen == 'undefined') { | ||
fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add'; | ||
} else if (!fullscreen) { | ||
fn = 'remove'; | ||
} else { | ||
fn = 'add'; | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], fullscreen); | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
fullscreen(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
var exports = {}; | ||
/** | ||
* Toggle the given terminal's fullscreen mode. | ||
* @param {Xterm} term - The terminal to toggle full screen mode | ||
* @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false) | ||
*/ | ||
exports.toggleFullScreen = function (term, fullscreen) { | ||
var fn; | ||
if (typeof fullscreen == 'undefined') { | ||
fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add'; | ||
} | ||
else if (!fullscreen) { | ||
fn = 'remove'; | ||
} | ||
else { | ||
fn = 'add'; | ||
} | ||
term.element.classList[fn]('fullscreen'); | ||
}; | ||
Xterm.prototype.toggleFullscreen = function (fullscreen) { | ||
exports.toggleFullScreen(this, fullscreen); | ||
}; | ||
return exports; | ||
term.element.classList[fn]('fullscreen'); | ||
}; | ||
Xterm.prototype.toggleFullscreen = function (fullscreen) { | ||
exports.toggleFullScreen(this, fullscreen); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=fullscreen.js.map |
@@ -6,161 +6,203 @@ /** | ||
*/ | ||
(function (linkify) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = linkify(require('../../xterm')); | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = linkify(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], linkify); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
linkify(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}, | ||
protocolClause = '(https?:\\/\\/)', | ||
domainCharacterSet = '[\\da-z\\.-]+', | ||
negatedDomainCharacterSet = '[^\\da-z\\.-]+', | ||
domainBodyClause = '(' + domainCharacterSet + ')', | ||
tldClause = '([a-z\\.]{2,6})', | ||
ipClause = '((\\d{1,3}\\.){3}\\d{1,3})', | ||
portClause = '(:\\d{1,5})', | ||
hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + ')' + portClause + '?', | ||
pathClause = '(\\/[\\/\\w\\.-]*)*', | ||
negatedPathCharacterSet = '[^\\/\\w\\.-]+', | ||
bodyClause = hostClause + pathClause, | ||
start = '(?:^|' + negatedDomainCharacterSet + ')(', | ||
end = ')($|' + negatedPathCharacterSet + ')', | ||
lenientUrlClause = start + protocolClause + '?' + bodyClause + end, | ||
strictUrlClause = start + protocolClause + bodyClause + end, | ||
lenientUrlRegex = new RegExp(lenientUrlClause), | ||
strictUrlRegex = new RegExp(strictUrlClause); | ||
/** | ||
* Converts all valid URLs found in the given terminal line into | ||
* hyperlinks. The terminal line can be either the HTML element itself | ||
* or the index of the termina line in the children of the terminal | ||
* rows container. | ||
* | ||
* @param {Xterm} terminal - The terminal that owns the given line. | ||
* @param {number|HTMLDivElement} line - The terminal line that should get | ||
* "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
* @emits linkify | ||
* @emits linkify:line | ||
*/ | ||
exports.linkifyTerminalLine = function (terminal, line, lenient, target) { | ||
if (typeof line == 'number') { | ||
line = terminal.rowContainer.children[line]; | ||
} else if (! (line instanceof HTMLDivElement)) { | ||
var message = 'The "line" argument should be either a number'; | ||
message += ' or an HTMLDivElement'; | ||
throw new TypeError(message); | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], linkify); | ||
if (typeof target === 'undefined') { | ||
target = ''; | ||
} else { | ||
target = 'target="' + target + '"'; | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
linkify(window.Terminal); | ||
var buffer = document.createElement('span'), | ||
nodes = line.childNodes; | ||
for (var j=0; j<nodes.length; j++) { | ||
var node = nodes[j], | ||
match; | ||
/** | ||
* Since we cannot access the TextNode's HTML representation | ||
* from the instance itself, we assign its data as textContent | ||
* to a dummy buffer span, in order to retrieve the TextNode's | ||
* HTML representation from the buffer's innerHTML. | ||
*/ | ||
buffer.textContent = node.data; | ||
var nodeHTML = buffer.innerHTML; | ||
/** | ||
* Apply function only on TextNodes | ||
*/ | ||
if (node.nodeType != node.TEXT_NODE) { | ||
continue; | ||
} | ||
var url = exports.findLinkMatch(node.data, lenient); | ||
if (!url) { | ||
continue; | ||
} | ||
var startsWithProtocol = new RegExp('^' + protocolClause), | ||
urlHasProtocol = url.match(startsWithProtocol), | ||
href = (urlHasProtocol) ? url : 'http://' + url, | ||
link = '<a href="' + href + '" ' + target + '>' + url + '</a>', | ||
newHTML = nodeHTML.replace(url, link); | ||
line.innerHTML = line.innerHTML.replace(nodeHTML, newHTML); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}, protocolClause = '(https?:\\/\\/)', domainCharacterSet = '[\\da-z\\.-]+', negatedDomainCharacterSet = '[^\\da-z\\.-]+', domainBodyClause = '(' + domainCharacterSet + ')', tldClause = '([a-z\\.]{2,6})', ipClause = '((\\d{1,3}\\.){3}\\d{1,3})', portClause = '(:\\d{1,5})', hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + ')' + portClause + '?', pathClause = '(\\/[\\/\\w\\.-]*)*', negatedPathCharacterSet = '[^\\/\\w\\.-]+', bodyClause = hostClause + pathClause, start = '(?:^|' + negatedDomainCharacterSet + ')(', end = ')($|' + negatedPathCharacterSet + ')', lenientUrlClause = start + protocolClause + '?' + bodyClause + end, strictUrlClause = start + protocolClause + bodyClause + end, lenientUrlRegex = new RegExp(lenientUrlClause), strictUrlRegex = new RegExp(strictUrlClause); | ||
/** | ||
* Converts all valid URLs found in the given terminal line into | ||
* hyperlinks. The terminal line can be either the HTML element itself | ||
* or the index of the termina line in the children of the terminal | ||
* rows container. | ||
* This event gets emitted when conversion of all URL susbtrings | ||
* to HTML anchor elements (links) has finished, for a specific | ||
* line of the current Xterm instance. | ||
* | ||
* @param {Xterm} terminal - The terminal that owns the given line. | ||
* @param {number|HTMLDivElement} line - The terminal line that should get | ||
* "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
* @emits linkify | ||
* @emits linkify:line | ||
* @event linkify:line | ||
*/ | ||
exports.linkifyTerminalLine = function (terminal, line, lenient, target) { | ||
if (typeof line == 'number') { | ||
line = terminal.rowContainer.children[line]; | ||
} | ||
else if (!(line instanceof HTMLDivElement)) { | ||
var message = 'The "line" argument should be either a number'; | ||
message += ' or an HTMLDivElement'; | ||
throw new TypeError(message); | ||
} | ||
if (typeof target === 'undefined') { | ||
target = ''; | ||
} | ||
else { | ||
target = 'target="' + target + '"'; | ||
} | ||
var buffer = document.createElement('span'), nodes = line.childNodes; | ||
for (var j = 0; j < nodes.length; j++) { | ||
var node = nodes[j], match; | ||
/** | ||
* Since we cannot access the TextNode's HTML representation | ||
* from the instance itself, we assign its data as textContent | ||
* to a dummy buffer span, in order to retrieve the TextNode's | ||
* HTML representation from the buffer's innerHTML. | ||
*/ | ||
buffer.textContent = node.data; | ||
var nodeHTML = buffer.innerHTML; | ||
/** | ||
* Apply function only on TextNodes | ||
*/ | ||
if (node.nodeType != node.TEXT_NODE) { | ||
continue; | ||
} | ||
var url = exports.findLinkMatch(node.data, lenient); | ||
if (!url) { | ||
continue; | ||
} | ||
var startsWithProtocol = new RegExp('^' + protocolClause), urlHasProtocol = url.match(startsWithProtocol), href = (urlHasProtocol) ? url : 'http://' + url, link = '<a href="' + href + '" ' + target + '>' + url + '</a>', newHTML = nodeHTML.replace(url, link); | ||
line.innerHTML = line.innerHTML.replace(nodeHTML, newHTML); | ||
} | ||
/** | ||
* This event gets emitted when conversion of all URL susbtrings | ||
* to HTML anchor elements (links) has finished, for a specific | ||
* line of the current Xterm instance. | ||
* | ||
* @event linkify:line | ||
*/ | ||
terminal.emit('linkify:line', line); | ||
}; | ||
terminal.emit('linkify:line', line); | ||
}; | ||
/** | ||
* Finds a link within a block of text. | ||
* | ||
* @param {string} text - The text to search . | ||
* @param {boolean} lenient - Whether to use the lenient search. | ||
* @return {string} A URL. | ||
*/ | ||
exports.findLinkMatch = function (text, lenient) { | ||
var match = text.match(lenient ? lenientUrlRegex : strictUrlRegex); | ||
if (!match || match.length === 0) { | ||
return null; | ||
} | ||
return match[1]; | ||
} | ||
/** | ||
* Converts all valid URLs found in the terminal view into hyperlinks. | ||
* | ||
* @param {Xterm} terminal - The terminal that should get "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
* @emits linkify | ||
* @emits linkify:line | ||
*/ | ||
exports.linkify = function (terminal, lenient, target) { | ||
var rows = terminal.rowContainer.children; | ||
lenient = (typeof lenient == "boolean") ? lenient : true; | ||
for (var i=0; i<rows.length; i++) { | ||
var line = rows[i]; | ||
exports.linkifyTerminalLine(terminal, line, lenient, target); | ||
} | ||
/** | ||
* Finds a link within a block of text. | ||
* This event gets emitted when conversion of all URL substrings to | ||
* HTML anchor elements (links) has finished for the current Xterm | ||
* instance's view. | ||
* | ||
* @param {string} text - The text to search . | ||
* @param {boolean} lenient - Whether to use the lenient search. | ||
* @return {string} A URL. | ||
* @event linkify | ||
*/ | ||
exports.findLinkMatch = function (text, lenient) { | ||
var match = text.match(lenient ? lenientUrlRegex : strictUrlRegex); | ||
if (!match || match.length === 0) { | ||
return null; | ||
} | ||
return match[1]; | ||
}; | ||
/** | ||
* Converts all valid URLs found in the terminal view into hyperlinks. | ||
* | ||
* @param {Xterm} terminal - The terminal that should get "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
* @emits linkify | ||
* @emits linkify:line | ||
*/ | ||
exports.linkify = function (terminal, lenient, target) { | ||
var rows = terminal.rowContainer.children; | ||
lenient = (typeof lenient == "boolean") ? lenient : true; | ||
for (var i = 0; i < rows.length; i++) { | ||
var line = rows[i]; | ||
exports.linkifyTerminalLine(terminal, line, lenient, target); | ||
} | ||
/** | ||
* This event gets emitted when conversion of all URL substrings to | ||
* HTML anchor elements (links) has finished for the current Xterm | ||
* instance's view. | ||
* | ||
* @event linkify | ||
*/ | ||
terminal.emit('linkify'); | ||
}; | ||
/** | ||
* Extend Xterm prototype. | ||
*/ | ||
/** | ||
* Converts all valid URLs found in the current terminal linte into | ||
* hyperlinks. | ||
* | ||
* @memberof Xterm | ||
* @param {number|HTMLDivElement} line - The terminal line that should get | ||
* "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
*/ | ||
Xterm.prototype.linkifyTerminalLine = function (line, lenient, target) { | ||
return exports.linkifyTerminalLine(this, line, lenient, target); | ||
}; | ||
/** | ||
* Converts all valid URLs found in the current terminal into hyperlinks. | ||
* | ||
* @memberof Xterm | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
*/ | ||
Xterm.prototype.linkify = function (lenient, target) { | ||
return exports.linkify(this, lenient, target); | ||
}; | ||
return exports; | ||
terminal.emit('linkify'); | ||
}; | ||
/** | ||
* Extend Xterm prototype. | ||
*/ | ||
/** | ||
* Converts all valid URLs found in the current terminal linte into | ||
* hyperlinks. | ||
* | ||
* @memberof Xterm | ||
* @param {number|HTMLDivElement} line - The terminal line that should get | ||
* "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
*/ | ||
Xterm.prototype.linkifyTerminalLine = function (line, lenient, target) { | ||
return exports.linkifyTerminalLine(this, line, lenient, target); | ||
}; | ||
/** | ||
* Converts all valid URLs found in the current terminal into hyperlinks. | ||
* | ||
* @memberof Xterm | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
*/ | ||
Xterm.prototype.linkify = function (lenient, target) { | ||
return exports.linkify(this, lenient, target); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=linkify.js.map |
@@ -7,117 +7,130 @@ /** | ||
*/ | ||
(function (attach) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = attach(require('../../xterm')); | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], attach); | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
attach(window.Terminal); | ||
} | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = attach(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], attach); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
attach(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}; | ||
/** | ||
* Attaches the given terminal to the given socket. | ||
* | ||
* @param {Xterm} term - The terminal to be attached to the given socket. | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
exports.terminadoAttach = function (term, socket, bidirectional, buffered) { | ||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; | ||
term.socket = socket; | ||
term._flushBuffer = function () { | ||
term.write(term._attachSocketBuffer); | ||
term._attachSocketBuffer = null; | ||
clearTimeout(term._attachSocketBufferTimer); | ||
term._attachSocketBufferTimer = null; | ||
}; | ||
term._pushToBuffer = function (data) { | ||
if (term._attachSocketBuffer) { | ||
term._attachSocketBuffer += data; | ||
} | ||
else { | ||
term._attachSocketBuffer = data; | ||
setTimeout(term._flushBuffer, 10); | ||
} | ||
}; | ||
term._getMessage = function (ev) { | ||
var data = JSON.parse(ev.data); | ||
if (data[0] == "stdout") { | ||
if (buffered) { | ||
term._pushToBuffer(data[1]); | ||
} | ||
else { | ||
term.write(data[1]); | ||
} | ||
} | ||
}; | ||
term._sendData = function (data) { | ||
socket.send(JSON.stringify(['stdin', data])); | ||
}; | ||
term._setSize = function (size) { | ||
socket.send(JSON.stringify(['set_size', size.rows, size.cols])); | ||
}; | ||
socket.addEventListener('message', term._getMessage); | ||
if (bidirectional) { | ||
term.on('data', term._sendData); | ||
} | ||
term.on('resize', term._setSize); | ||
socket.addEventListener('close', term.terminadoDetach.bind(term, socket)); | ||
socket.addEventListener('error', term.terminadoDetach.bind(term, socket)); | ||
'use strict'; | ||
var exports = {}; | ||
/** | ||
* Attaches the given terminal to the given socket. | ||
* | ||
* @param {Xterm} term - The terminal to be attached to the given socket. | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
exports.terminadoAttach = function (term, socket, bidirectional, buffered) { | ||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; | ||
term.socket = socket; | ||
term._flushBuffer = function () { | ||
term.write(term._attachSocketBuffer); | ||
term._attachSocketBuffer = null; | ||
clearTimeout(term._attachSocketBufferTimer); | ||
term._attachSocketBufferTimer = null; | ||
}; | ||
/** | ||
* Detaches the given terminal from the given socket | ||
* | ||
* @param {Xterm} term - The terminal to be detached from the given socket. | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
exports.terminadoDetach = function (term, socket) { | ||
term.off('data', term._sendData); | ||
socket = (typeof socket == 'undefined') ? term.socket : socket; | ||
if (socket) { | ||
socket.removeEventListener('message', term._getMessage); | ||
term._pushToBuffer = function (data) { | ||
if (term._attachSocketBuffer) { | ||
term._attachSocketBuffer += data; | ||
} else { | ||
term._attachSocketBuffer = data; | ||
setTimeout(term._flushBuffer, 10); | ||
} | ||
}; | ||
term._getMessage = function (ev) { | ||
var data = JSON.parse(ev.data) | ||
if( data[0] == "stdout" ) { | ||
if (buffered) { | ||
term._pushToBuffer(data[1]); | ||
} else { | ||
term.write(data[1]); | ||
} | ||
delete term.socket; | ||
} | ||
}; | ||
/** | ||
* Attaches the current terminal to the given socket | ||
* | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
Xterm.prototype.terminadoAttach = function (socket, bidirectional, buffered) { | ||
return exports.terminadoAttach(this, socket, bidirectional, buffered); | ||
term._sendData = function (data) { | ||
socket.send(JSON.stringify(['stdin', data])); | ||
}; | ||
/** | ||
* Detaches the current terminal from the given socket. | ||
* | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
Xterm.prototype.terminadoDetach = function (socket) { | ||
return exports.terminadoDetach(this, socket); | ||
term._setSize = function (size) { | ||
socket.send(JSON.stringify(['set_size', size.rows, size.cols])); | ||
}; | ||
return exports; | ||
socket.addEventListener('message', term._getMessage); | ||
if (bidirectional) { | ||
term.on('data', term._sendData); | ||
} | ||
term.on('resize', term._setSize); | ||
socket.addEventListener('close', term.terminadoDetach.bind(term, socket)); | ||
socket.addEventListener('error', term.terminadoDetach.bind(term, socket)); | ||
}; | ||
/** | ||
* Detaches the given terminal from the given socket | ||
* | ||
* @param {Xterm} term - The terminal to be detached from the given socket. | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
exports.terminadoDetach = function (term, socket) { | ||
term.off('data', term._sendData); | ||
socket = (typeof socket == 'undefined') ? term.socket : socket; | ||
if (socket) { | ||
socket.removeEventListener('message', term._getMessage); | ||
} | ||
delete term.socket; | ||
}; | ||
/** | ||
* Attaches the current terminal to the given socket | ||
* | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
Xterm.prototype.terminadoAttach = function (socket, bidirectional, buffered) { | ||
return exports.terminadoAttach(this, socket, bidirectional, buffered); | ||
}; | ||
/** | ||
* Detaches the current terminal from the given socket. | ||
* | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
Xterm.prototype.terminadoDetach = function (socket) { | ||
return exports.terminadoDetach(this, socket); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=terminado.js.map |
@@ -6,110 +6,122 @@ /** | ||
*/ | ||
(function (attach) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = attach(require('../../xterm')); | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], attach); | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
attach(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}; | ||
/** | ||
* Attaches the given terminal to the given socket. | ||
* | ||
* @param {Xterm} term - The terminal to be attached to the given socket. | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
exports.attach = function (term, socket, bidirectional, buffered) { | ||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; | ||
term.socket = socket; | ||
term._flushBuffer = function () { | ||
term.write(term._attachSocketBuffer); | ||
term._attachSocketBuffer = null; | ||
clearTimeout(term._attachSocketBufferTimer); | ||
term._attachSocketBufferTimer = null; | ||
}; | ||
term._pushToBuffer = function (data) { | ||
if (term._attachSocketBuffer) { | ||
term._attachSocketBuffer += data; | ||
} | ||
else { | ||
term._attachSocketBuffer = data; | ||
setTimeout(term._flushBuffer, 10); | ||
} | ||
}; | ||
term._getMessage = function (ev) { | ||
if (buffered) { | ||
term._pushToBuffer(ev.data); | ||
} | ||
else { | ||
term.write(ev.data); | ||
} | ||
}; | ||
term._sendData = function (data) { | ||
socket.send(data); | ||
}; | ||
socket.addEventListener('message', term._getMessage); | ||
if (bidirectional) { | ||
term.on('data', term._sendData); | ||
} | ||
socket.addEventListener('close', term.detach.bind(term, socket)); | ||
socket.addEventListener('error', term.detach.bind(term, socket)); | ||
}; | ||
/** | ||
* Detaches the given terminal from the given socket | ||
* | ||
* @param {Xterm} term - The terminal to be detached from the given socket. | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
module.exports = attach(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
exports.detach = function (term, socket) { | ||
term.off('data', term._sendData); | ||
socket = (typeof socket == 'undefined') ? term.socket : socket; | ||
if (socket) { | ||
socket.removeEventListener('message', term._getMessage); | ||
} | ||
delete term.socket; | ||
}; | ||
/** | ||
* Attaches the current terminal to the given socket | ||
* | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
define(['../../xterm'], attach); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
Xterm.prototype.attach = function (socket, bidirectional, buffered) { | ||
return exports.attach(this, socket, bidirectional, buffered); | ||
attach(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}; | ||
/** | ||
* Attaches the given terminal to the given socket. | ||
* | ||
* @param {Xterm} term - The terminal to be attached to the given socket. | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
exports.attach = function (term, socket, bidirectional, buffered) { | ||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; | ||
term.socket = socket; | ||
term._flushBuffer = function () { | ||
term.write(term._attachSocketBuffer); | ||
term._attachSocketBuffer = null; | ||
clearTimeout(term._attachSocketBufferTimer); | ||
term._attachSocketBufferTimer = null; | ||
}; | ||
/** | ||
* Detaches the current terminal from the given socket. | ||
* | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
Xterm.prototype.detach = function (socket) { | ||
return exports.detach(this, socket); | ||
term._pushToBuffer = function (data) { | ||
if (term._attachSocketBuffer) { | ||
term._attachSocketBuffer += data; | ||
} else { | ||
term._attachSocketBuffer = data; | ||
setTimeout(term._flushBuffer, 10); | ||
} | ||
}; | ||
return exports; | ||
term._getMessage = function (ev) { | ||
if (buffered) { | ||
term._pushToBuffer(ev.data); | ||
} else { | ||
term.write(ev.data); | ||
} | ||
}; | ||
term._sendData = function (data) { | ||
socket.send(data); | ||
}; | ||
socket.addEventListener('message', term._getMessage); | ||
if (bidirectional) { | ||
term.on('data', term._sendData); | ||
} | ||
socket.addEventListener('close', term.detach.bind(term, socket)); | ||
socket.addEventListener('error', term.detach.bind(term, socket)); | ||
}; | ||
/** | ||
* Detaches the given terminal from the given socket | ||
* | ||
* @param {Xterm} term - The terminal to be detached from the given socket. | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
exports.detach = function (term, socket) { | ||
term.off('data', term._sendData); | ||
socket = (typeof socket == 'undefined') ? term.socket : socket; | ||
if (socket) { | ||
socket.removeEventListener('message', term._getMessage); | ||
} | ||
delete term.socket; | ||
}; | ||
/** | ||
* Attaches the current terminal to the given socket | ||
* | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
Xterm.prototype.attach = function (socket, bidirectional, buffered) { | ||
return exports.attach(this, socket, bidirectional, buffered); | ||
}; | ||
/** | ||
* Detaches the current terminal from the given socket. | ||
* | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
Xterm.prototype.detach = function (socket) { | ||
return exports.detach(this, socket); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=attach.js.map |
@@ -13,48 +13,70 @@ /** | ||
*/ | ||
(function (fit) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = fit(require('../../xterm')); | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], fit); | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
fit(window.Terminal); | ||
} | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = fit(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], fit); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
fit(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
var exports = {}; | ||
exports.proposeGeometry = function (term) { | ||
var parentElementStyle = window.getComputedStyle(term.element.parentElement), parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')), parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17), elementStyle = window.getComputedStyle(term.element), elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')), elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')), availableHeight = parentElementHeight - elementPaddingVer, availableWidth = parentElementWidth - elementPaddingHor, container = term.rowContainer, subjectRow = term.rowContainer.firstElementChild, contentBuffer = subjectRow.innerHTML, characterHeight, rows, characterWidth, cols, geometry; | ||
subjectRow.style.display = 'inline'; | ||
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace | ||
characterWidth = subjectRow.getBoundingClientRect().width; | ||
subjectRow.style.display = ''; // Revert style before calculating height, since they differ. | ||
characterHeight = parseInt(subjectRow.offsetHeight); | ||
subjectRow.innerHTML = contentBuffer; | ||
rows = parseInt(availableHeight / characterHeight); | ||
cols = parseInt(availableWidth / characterWidth); | ||
geometry = { cols: cols, rows: rows }; | ||
return geometry; | ||
}; | ||
exports.fit = function (term) { | ||
var geometry = exports.proposeGeometry(term); | ||
term.resize(geometry.cols, geometry.rows); | ||
}; | ||
Xterm.prototype.proposeGeometry = function () { | ||
return exports.proposeGeometry(this); | ||
}; | ||
Xterm.prototype.fit = function () { | ||
return exports.fit(this); | ||
}; | ||
return exports; | ||
var exports = {}; | ||
exports.proposeGeometry = function (term) { | ||
var parentElementStyle = window.getComputedStyle(term.element.parentElement), | ||
parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')), | ||
parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17), | ||
elementStyle = window.getComputedStyle(term.element), | ||
elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')), | ||
elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')), | ||
availableHeight = parentElementHeight - elementPaddingVer, | ||
availableWidth = parentElementWidth - elementPaddingHor, | ||
container = term.rowContainer, | ||
subjectRow = term.rowContainer.firstElementChild, | ||
contentBuffer = subjectRow.innerHTML, | ||
characterHeight, | ||
rows, | ||
characterWidth, | ||
cols, | ||
geometry; | ||
subjectRow.style.display = 'inline'; | ||
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace | ||
characterWidth = subjectRow.getBoundingClientRect().width; | ||
subjectRow.style.display = ''; // Revert style before calculating height, since they differ. | ||
characterHeight = parseInt(subjectRow.offsetHeight); | ||
subjectRow.innerHTML = contentBuffer; | ||
rows = parseInt(availableHeight / characterHeight); | ||
cols = parseInt(availableWidth / characterWidth); | ||
geometry = {cols: cols, rows: rows}; | ||
return geometry; | ||
}; | ||
exports.fit = function (term) { | ||
var geometry = exports.proposeGeometry(term); | ||
term.resize(geometry.cols, geometry.rows); | ||
}; | ||
Xterm.prototype.proposeGeometry = function () { | ||
return exports.proposeGeometry(this); | ||
}; | ||
Xterm.prototype.fit = function () { | ||
return exports.fit(this); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=fit.js.map |
@@ -7,45 +7,45 @@ /** | ||
(function (fullscreen) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = fullscreen(require('../../xterm')); | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = fullscreen(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], fullscreen); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
fullscreen(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
var exports = {}; | ||
/** | ||
* Toggle the given terminal's fullscreen mode. | ||
* @param {Xterm} term - The terminal to toggle full screen mode | ||
* @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false) | ||
*/ | ||
exports.toggleFullScreen = function (term, fullscreen) { | ||
var fn; | ||
if (typeof fullscreen == 'undefined') { | ||
fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add'; | ||
} else if (!fullscreen) { | ||
fn = 'remove'; | ||
} else { | ||
fn = 'add'; | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], fullscreen); | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
fullscreen(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
var exports = {}; | ||
/** | ||
* Toggle the given terminal's fullscreen mode. | ||
* @param {Xterm} term - The terminal to toggle full screen mode | ||
* @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false) | ||
*/ | ||
exports.toggleFullScreen = function (term, fullscreen) { | ||
var fn; | ||
if (typeof fullscreen == 'undefined') { | ||
fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add'; | ||
} | ||
else if (!fullscreen) { | ||
fn = 'remove'; | ||
} | ||
else { | ||
fn = 'add'; | ||
} | ||
term.element.classList[fn]('fullscreen'); | ||
}; | ||
Xterm.prototype.toggleFullscreen = function (fullscreen) { | ||
exports.toggleFullScreen(this, fullscreen); | ||
}; | ||
return exports; | ||
term.element.classList[fn]('fullscreen'); | ||
}; | ||
Xterm.prototype.toggleFullscreen = function (fullscreen) { | ||
exports.toggleFullScreen(this, fullscreen); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=fullscreen.js.map |
@@ -6,161 +6,203 @@ /** | ||
*/ | ||
(function (linkify) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = linkify(require('../../xterm')); | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = linkify(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], linkify); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
linkify(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}, | ||
protocolClause = '(https?:\\/\\/)', | ||
domainCharacterSet = '[\\da-z\\.-]+', | ||
negatedDomainCharacterSet = '[^\\da-z\\.-]+', | ||
domainBodyClause = '(' + domainCharacterSet + ')', | ||
tldClause = '([a-z\\.]{2,6})', | ||
ipClause = '((\\d{1,3}\\.){3}\\d{1,3})', | ||
portClause = '(:\\d{1,5})', | ||
hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + ')' + portClause + '?', | ||
pathClause = '(\\/[\\/\\w\\.-]*)*', | ||
negatedPathCharacterSet = '[^\\/\\w\\.-]+', | ||
bodyClause = hostClause + pathClause, | ||
start = '(?:^|' + negatedDomainCharacterSet + ')(', | ||
end = ')($|' + negatedPathCharacterSet + ')', | ||
lenientUrlClause = start + protocolClause + '?' + bodyClause + end, | ||
strictUrlClause = start + protocolClause + bodyClause + end, | ||
lenientUrlRegex = new RegExp(lenientUrlClause), | ||
strictUrlRegex = new RegExp(strictUrlClause); | ||
/** | ||
* Converts all valid URLs found in the given terminal line into | ||
* hyperlinks. The terminal line can be either the HTML element itself | ||
* or the index of the termina line in the children of the terminal | ||
* rows container. | ||
* | ||
* @param {Xterm} terminal - The terminal that owns the given line. | ||
* @param {number|HTMLDivElement} line - The terminal line that should get | ||
* "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
* @emits linkify | ||
* @emits linkify:line | ||
*/ | ||
exports.linkifyTerminalLine = function (terminal, line, lenient, target) { | ||
if (typeof line == 'number') { | ||
line = terminal.rowContainer.children[line]; | ||
} else if (! (line instanceof HTMLDivElement)) { | ||
var message = 'The "line" argument should be either a number'; | ||
message += ' or an HTMLDivElement'; | ||
throw new TypeError(message); | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], linkify); | ||
if (typeof target === 'undefined') { | ||
target = ''; | ||
} else { | ||
target = 'target="' + target + '"'; | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
linkify(window.Terminal); | ||
var buffer = document.createElement('span'), | ||
nodes = line.childNodes; | ||
for (var j=0; j<nodes.length; j++) { | ||
var node = nodes[j], | ||
match; | ||
/** | ||
* Since we cannot access the TextNode's HTML representation | ||
* from the instance itself, we assign its data as textContent | ||
* to a dummy buffer span, in order to retrieve the TextNode's | ||
* HTML representation from the buffer's innerHTML. | ||
*/ | ||
buffer.textContent = node.data; | ||
var nodeHTML = buffer.innerHTML; | ||
/** | ||
* Apply function only on TextNodes | ||
*/ | ||
if (node.nodeType != node.TEXT_NODE) { | ||
continue; | ||
} | ||
var url = exports.findLinkMatch(node.data, lenient); | ||
if (!url) { | ||
continue; | ||
} | ||
var startsWithProtocol = new RegExp('^' + protocolClause), | ||
urlHasProtocol = url.match(startsWithProtocol), | ||
href = (urlHasProtocol) ? url : 'http://' + url, | ||
link = '<a href="' + href + '" ' + target + '>' + url + '</a>', | ||
newHTML = nodeHTML.replace(url, link); | ||
line.innerHTML = line.innerHTML.replace(nodeHTML, newHTML); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}, protocolClause = '(https?:\\/\\/)', domainCharacterSet = '[\\da-z\\.-]+', negatedDomainCharacterSet = '[^\\da-z\\.-]+', domainBodyClause = '(' + domainCharacterSet + ')', tldClause = '([a-z\\.]{2,6})', ipClause = '((\\d{1,3}\\.){3}\\d{1,3})', portClause = '(:\\d{1,5})', hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + ')' + portClause + '?', pathClause = '(\\/[\\/\\w\\.-]*)*', negatedPathCharacterSet = '[^\\/\\w\\.-]+', bodyClause = hostClause + pathClause, start = '(?:^|' + negatedDomainCharacterSet + ')(', end = ')($|' + negatedPathCharacterSet + ')', lenientUrlClause = start + protocolClause + '?' + bodyClause + end, strictUrlClause = start + protocolClause + bodyClause + end, lenientUrlRegex = new RegExp(lenientUrlClause), strictUrlRegex = new RegExp(strictUrlClause); | ||
/** | ||
* Converts all valid URLs found in the given terminal line into | ||
* hyperlinks. The terminal line can be either the HTML element itself | ||
* or the index of the termina line in the children of the terminal | ||
* rows container. | ||
* This event gets emitted when conversion of all URL susbtrings | ||
* to HTML anchor elements (links) has finished, for a specific | ||
* line of the current Xterm instance. | ||
* | ||
* @param {Xterm} terminal - The terminal that owns the given line. | ||
* @param {number|HTMLDivElement} line - The terminal line that should get | ||
* "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
* @emits linkify | ||
* @emits linkify:line | ||
* @event linkify:line | ||
*/ | ||
exports.linkifyTerminalLine = function (terminal, line, lenient, target) { | ||
if (typeof line == 'number') { | ||
line = terminal.rowContainer.children[line]; | ||
} | ||
else if (!(line instanceof HTMLDivElement)) { | ||
var message = 'The "line" argument should be either a number'; | ||
message += ' or an HTMLDivElement'; | ||
throw new TypeError(message); | ||
} | ||
if (typeof target === 'undefined') { | ||
target = ''; | ||
} | ||
else { | ||
target = 'target="' + target + '"'; | ||
} | ||
var buffer = document.createElement('span'), nodes = line.childNodes; | ||
for (var j = 0; j < nodes.length; j++) { | ||
var node = nodes[j], match; | ||
/** | ||
* Since we cannot access the TextNode's HTML representation | ||
* from the instance itself, we assign its data as textContent | ||
* to a dummy buffer span, in order to retrieve the TextNode's | ||
* HTML representation from the buffer's innerHTML. | ||
*/ | ||
buffer.textContent = node.data; | ||
var nodeHTML = buffer.innerHTML; | ||
/** | ||
* Apply function only on TextNodes | ||
*/ | ||
if (node.nodeType != node.TEXT_NODE) { | ||
continue; | ||
} | ||
var url = exports.findLinkMatch(node.data, lenient); | ||
if (!url) { | ||
continue; | ||
} | ||
var startsWithProtocol = new RegExp('^' + protocolClause), urlHasProtocol = url.match(startsWithProtocol), href = (urlHasProtocol) ? url : 'http://' + url, link = '<a href="' + href + '" ' + target + '>' + url + '</a>', newHTML = nodeHTML.replace(url, link); | ||
line.innerHTML = line.innerHTML.replace(nodeHTML, newHTML); | ||
} | ||
/** | ||
* This event gets emitted when conversion of all URL susbtrings | ||
* to HTML anchor elements (links) has finished, for a specific | ||
* line of the current Xterm instance. | ||
* | ||
* @event linkify:line | ||
*/ | ||
terminal.emit('linkify:line', line); | ||
}; | ||
terminal.emit('linkify:line', line); | ||
}; | ||
/** | ||
* Finds a link within a block of text. | ||
* | ||
* @param {string} text - The text to search . | ||
* @param {boolean} lenient - Whether to use the lenient search. | ||
* @return {string} A URL. | ||
*/ | ||
exports.findLinkMatch = function (text, lenient) { | ||
var match = text.match(lenient ? lenientUrlRegex : strictUrlRegex); | ||
if (!match || match.length === 0) { | ||
return null; | ||
} | ||
return match[1]; | ||
} | ||
/** | ||
* Converts all valid URLs found in the terminal view into hyperlinks. | ||
* | ||
* @param {Xterm} terminal - The terminal that should get "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
* @emits linkify | ||
* @emits linkify:line | ||
*/ | ||
exports.linkify = function (terminal, lenient, target) { | ||
var rows = terminal.rowContainer.children; | ||
lenient = (typeof lenient == "boolean") ? lenient : true; | ||
for (var i=0; i<rows.length; i++) { | ||
var line = rows[i]; | ||
exports.linkifyTerminalLine(terminal, line, lenient, target); | ||
} | ||
/** | ||
* Finds a link within a block of text. | ||
* This event gets emitted when conversion of all URL substrings to | ||
* HTML anchor elements (links) has finished for the current Xterm | ||
* instance's view. | ||
* | ||
* @param {string} text - The text to search . | ||
* @param {boolean} lenient - Whether to use the lenient search. | ||
* @return {string} A URL. | ||
* @event linkify | ||
*/ | ||
exports.findLinkMatch = function (text, lenient) { | ||
var match = text.match(lenient ? lenientUrlRegex : strictUrlRegex); | ||
if (!match || match.length === 0) { | ||
return null; | ||
} | ||
return match[1]; | ||
}; | ||
/** | ||
* Converts all valid URLs found in the terminal view into hyperlinks. | ||
* | ||
* @param {Xterm} terminal - The terminal that should get "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
* @emits linkify | ||
* @emits linkify:line | ||
*/ | ||
exports.linkify = function (terminal, lenient, target) { | ||
var rows = terminal.rowContainer.children; | ||
lenient = (typeof lenient == "boolean") ? lenient : true; | ||
for (var i = 0; i < rows.length; i++) { | ||
var line = rows[i]; | ||
exports.linkifyTerminalLine(terminal, line, lenient, target); | ||
} | ||
/** | ||
* This event gets emitted when conversion of all URL substrings to | ||
* HTML anchor elements (links) has finished for the current Xterm | ||
* instance's view. | ||
* | ||
* @event linkify | ||
*/ | ||
terminal.emit('linkify'); | ||
}; | ||
/** | ||
* Extend Xterm prototype. | ||
*/ | ||
/** | ||
* Converts all valid URLs found in the current terminal linte into | ||
* hyperlinks. | ||
* | ||
* @memberof Xterm | ||
* @param {number|HTMLDivElement} line - The terminal line that should get | ||
* "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
*/ | ||
Xterm.prototype.linkifyTerminalLine = function (line, lenient, target) { | ||
return exports.linkifyTerminalLine(this, line, lenient, target); | ||
}; | ||
/** | ||
* Converts all valid URLs found in the current terminal into hyperlinks. | ||
* | ||
* @memberof Xterm | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
*/ | ||
Xterm.prototype.linkify = function (lenient, target) { | ||
return exports.linkify(this, lenient, target); | ||
}; | ||
return exports; | ||
terminal.emit('linkify'); | ||
}; | ||
/** | ||
* Extend Xterm prototype. | ||
*/ | ||
/** | ||
* Converts all valid URLs found in the current terminal linte into | ||
* hyperlinks. | ||
* | ||
* @memberof Xterm | ||
* @param {number|HTMLDivElement} line - The terminal line that should get | ||
* "linkified". | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
*/ | ||
Xterm.prototype.linkifyTerminalLine = function (line, lenient, target) { | ||
return exports.linkifyTerminalLine(this, line, lenient, target); | ||
}; | ||
/** | ||
* Converts all valid URLs found in the current terminal into hyperlinks. | ||
* | ||
* @memberof Xterm | ||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is | ||
* false, the regex requires a protocol clause. Defaults to true. | ||
* @param {string} target - Sets target="" attribute with value provided to links. | ||
* Default doesn't set target attribute | ||
*/ | ||
Xterm.prototype.linkify = function (lenient, target) { | ||
return exports.linkify(this, lenient, target); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=linkify.js.map |
@@ -7,117 +7,130 @@ /** | ||
*/ | ||
(function (attach) { | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = attach(require('../../xterm')); | ||
} | ||
else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], attach); | ||
} | ||
else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
attach(window.Terminal); | ||
} | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
/* | ||
* CommonJS environment | ||
*/ | ||
module.exports = attach(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
/* | ||
* Require.js is available | ||
*/ | ||
define(['../../xterm'], attach); | ||
} else { | ||
/* | ||
* Plain browser environment | ||
*/ | ||
attach(window.Terminal); | ||
} | ||
})(function (Xterm) { | ||
'use strict'; | ||
var exports = {}; | ||
/** | ||
* Attaches the given terminal to the given socket. | ||
* | ||
* @param {Xterm} term - The terminal to be attached to the given socket. | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
exports.terminadoAttach = function (term, socket, bidirectional, buffered) { | ||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; | ||
term.socket = socket; | ||
term._flushBuffer = function () { | ||
term.write(term._attachSocketBuffer); | ||
term._attachSocketBuffer = null; | ||
clearTimeout(term._attachSocketBufferTimer); | ||
term._attachSocketBufferTimer = null; | ||
}; | ||
term._pushToBuffer = function (data) { | ||
if (term._attachSocketBuffer) { | ||
term._attachSocketBuffer += data; | ||
} | ||
else { | ||
term._attachSocketBuffer = data; | ||
setTimeout(term._flushBuffer, 10); | ||
} | ||
}; | ||
term._getMessage = function (ev) { | ||
var data = JSON.parse(ev.data); | ||
if (data[0] == "stdout") { | ||
if (buffered) { | ||
term._pushToBuffer(data[1]); | ||
} | ||
else { | ||
term.write(data[1]); | ||
} | ||
} | ||
}; | ||
term._sendData = function (data) { | ||
socket.send(JSON.stringify(['stdin', data])); | ||
}; | ||
term._setSize = function (size) { | ||
socket.send(JSON.stringify(['set_size', size.rows, size.cols])); | ||
}; | ||
socket.addEventListener('message', term._getMessage); | ||
if (bidirectional) { | ||
term.on('data', term._sendData); | ||
} | ||
term.on('resize', term._setSize); | ||
socket.addEventListener('close', term.terminadoDetach.bind(term, socket)); | ||
socket.addEventListener('error', term.terminadoDetach.bind(term, socket)); | ||
'use strict'; | ||
var exports = {}; | ||
/** | ||
* Attaches the given terminal to the given socket. | ||
* | ||
* @param {Xterm} term - The terminal to be attached to the given socket. | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
exports.terminadoAttach = function (term, socket, bidirectional, buffered) { | ||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; | ||
term.socket = socket; | ||
term._flushBuffer = function () { | ||
term.write(term._attachSocketBuffer); | ||
term._attachSocketBuffer = null; | ||
clearTimeout(term._attachSocketBufferTimer); | ||
term._attachSocketBufferTimer = null; | ||
}; | ||
/** | ||
* Detaches the given terminal from the given socket | ||
* | ||
* @param {Xterm} term - The terminal to be detached from the given socket. | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
exports.terminadoDetach = function (term, socket) { | ||
term.off('data', term._sendData); | ||
socket = (typeof socket == 'undefined') ? term.socket : socket; | ||
if (socket) { | ||
socket.removeEventListener('message', term._getMessage); | ||
term._pushToBuffer = function (data) { | ||
if (term._attachSocketBuffer) { | ||
term._attachSocketBuffer += data; | ||
} else { | ||
term._attachSocketBuffer = data; | ||
setTimeout(term._flushBuffer, 10); | ||
} | ||
}; | ||
term._getMessage = function (ev) { | ||
var data = JSON.parse(ev.data) | ||
if( data[0] == "stdout" ) { | ||
if (buffered) { | ||
term._pushToBuffer(data[1]); | ||
} else { | ||
term.write(data[1]); | ||
} | ||
delete term.socket; | ||
} | ||
}; | ||
/** | ||
* Attaches the current terminal to the given socket | ||
* | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
Xterm.prototype.terminadoAttach = function (socket, bidirectional, buffered) { | ||
return exports.terminadoAttach(this, socket, bidirectional, buffered); | ||
term._sendData = function (data) { | ||
socket.send(JSON.stringify(['stdin', data])); | ||
}; | ||
/** | ||
* Detaches the current terminal from the given socket. | ||
* | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
Xterm.prototype.terminadoDetach = function (socket) { | ||
return exports.terminadoDetach(this, socket); | ||
term._setSize = function (size) { | ||
socket.send(JSON.stringify(['set_size', size.rows, size.cols])); | ||
}; | ||
return exports; | ||
socket.addEventListener('message', term._getMessage); | ||
if (bidirectional) { | ||
term.on('data', term._sendData); | ||
} | ||
term.on('resize', term._setSize); | ||
socket.addEventListener('close', term.terminadoDetach.bind(term, socket)); | ||
socket.addEventListener('error', term.terminadoDetach.bind(term, socket)); | ||
}; | ||
/** | ||
* Detaches the given terminal from the given socket | ||
* | ||
* @param {Xterm} term - The terminal to be detached from the given socket. | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
exports.terminadoDetach = function (term, socket) { | ||
term.off('data', term._sendData); | ||
socket = (typeof socket == 'undefined') ? term.socket : socket; | ||
if (socket) { | ||
socket.removeEventListener('message', term._getMessage); | ||
} | ||
delete term.socket; | ||
}; | ||
/** | ||
* Attaches the current terminal to the given socket | ||
* | ||
* @param {WebSocket} socket - The socket to attach the current terminal. | ||
* @param {boolean} bidirectional - Whether the terminal should send data | ||
* to the socket as well. | ||
* @param {boolean} buffered - Whether the rendering of incoming data | ||
* should happen instantly or at a maximum | ||
* frequency of 1 rendering per 10ms. | ||
*/ | ||
Xterm.prototype.terminadoAttach = function (socket, bidirectional, buffered) { | ||
return exports.terminadoAttach(this, socket, bidirectional, buffered); | ||
}; | ||
/** | ||
* Detaches the current terminal from the given socket. | ||
* | ||
* @param {WebSocket} socket - The socket from which to detach the current | ||
* terminal. | ||
*/ | ||
Xterm.prototype.terminadoDetach = function (socket) { | ||
return exports.terminadoDetach(this, socket); | ||
}; | ||
return exports; | ||
}); | ||
//# sourceMappingURL=terminado.js.map |
@@ -1,17 +0,3 @@ | ||
/** | ||
* @license MIT | ||
*/ | ||
"use strict"; | ||
/** | ||
* Encapsulates the logic for handling compositionstart, compositionupdate and compositionend | ||
* events, displaying the in-progress composition to the UI and forwarding the final composition | ||
* to the handler. | ||
*/ | ||
var CompositionHelper = (function () { | ||
/** | ||
* Creates a new CompositionHelper. | ||
* @param textarea The textarea that xterm uses for input. | ||
* @param compositionView The element to display the in-progress composition in. | ||
* @param terminal The Terminal to forward the finished composition to. | ||
*/ | ||
function CompositionHelper(textarea, compositionView, terminal) { | ||
@@ -25,6 +11,2 @@ this.textarea = textarea; | ||
} | ||
; | ||
/** | ||
* Handles the compositionstart event, activating the composition view. | ||
*/ | ||
CompositionHelper.prototype.compositionstart = function () { | ||
@@ -36,39 +18,22 @@ this.isComposing = true; | ||
}; | ||
/** | ||
* Handles the compositionupdate event, updating the composition view. | ||
* @param {CompositionEvent} ev The event. | ||
*/ | ||
CompositionHelper.prototype.compositionupdate = function (ev) { | ||
var _this = this; | ||
this.compositionView.textContent = ev.data; | ||
this.updateCompositionElements(); | ||
var self = this; | ||
setTimeout(function () { | ||
self.compositionPosition.end = self.textarea.value.length; | ||
_this.compositionPosition.end = _this.textarea.value.length; | ||
}, 0); | ||
}; | ||
/** | ||
* Handles the compositionend event, hiding the composition view and sending the composition to | ||
* the handler. | ||
*/ | ||
CompositionHelper.prototype.compositionend = function () { | ||
this.finalizeComposition(true); | ||
}; | ||
/** | ||
* Handles the keydown event, routing any necessary events to the CompositionHelper functions. | ||
* @param ev The keydown event. | ||
* @return Whether the Terminal should continue processing the keydown event. | ||
*/ | ||
CompositionHelper.prototype.keydown = function (ev) { | ||
if (this.isComposing || this.isSendingComposition) { | ||
if (ev.keyCode === 229) { | ||
// Continue composing if the keyCode is the "composition character" | ||
return false; | ||
} | ||
else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) { | ||
// Continue composing if the keyCode is a modifier key | ||
return false; | ||
} | ||
else { | ||
// Finish composition immediately. This is mainly here for the case where enter is | ||
// pressed and the handler needs to be triggered before the command is executed. | ||
this.finalizeComposition(false); | ||
@@ -78,4 +43,2 @@ } | ||
if (ev.keyCode === 229) { | ||
// If the "composition character" is used but gets to this point it means a non-composition | ||
// character (eg. numbers and punctuation) was pressed when the IME was active. | ||
this.handleAnyTextareaChanges(); | ||
@@ -86,11 +49,4 @@ return false; | ||
}; | ||
/** | ||
* Finalizes the composition, resuming regular input actions. This is called when a composition | ||
* is ending. | ||
* @param waitForPropogation Whether to wait for events to propogate before sending | ||
* the input. This should be false if a non-composition keystroke is entered before the | ||
* compositionend event is triggered, such as enter, so that the composition is send before | ||
* the command is executed. | ||
*/ | ||
CompositionHelper.prototype.finalizeComposition = function (waitForPropogation) { | ||
var _this = this; | ||
this.compositionView.classList.remove('active'); | ||
@@ -100,3 +56,2 @@ this.isComposing = false; | ||
if (!waitForPropogation) { | ||
// Cancel any delayed composition send requests and send the input immediately. | ||
this.isSendingComposition = false; | ||
@@ -107,34 +62,18 @@ var input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end); | ||
else { | ||
// Make a deep copy of the composition position here as a new compositionstart event may | ||
// fire before the setTimeout executes. | ||
var currentCompositionPosition = { | ||
var currentCompositionPosition_1 = { | ||
start: this.compositionPosition.start, | ||
end: this.compositionPosition.end, | ||
}; | ||
// Since composition* events happen before the changes take place in the textarea on most | ||
// browsers, use a setTimeout with 0ms time to allow the native compositionend event to | ||
// complete. This ensures the correct character is retrieved, this solution was used | ||
// because: | ||
// - The compositionend event's data property is unreliable, at least on Chromium | ||
// - The last compositionupdate event's data property does not always accurately describe | ||
// the character, a counter example being Korean where an ending consonsant can move to | ||
// the following character if the following input is a vowel. | ||
var self = this; | ||
this.isSendingComposition = true; | ||
setTimeout(function () { | ||
// Ensure that the input has not already been sent | ||
if (self.isSendingComposition) { | ||
self.isSendingComposition = false; | ||
var input; | ||
if (self.isComposing) { | ||
// Use the end position to get the string if a new composition has started. | ||
input = self.textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end); | ||
if (_this.isSendingComposition) { | ||
_this.isSendingComposition = false; | ||
var input = void 0; | ||
if (_this.isComposing) { | ||
input = _this.textarea.value.substring(currentCompositionPosition_1.start, currentCompositionPosition_1.end); | ||
} | ||
else { | ||
// Don't use the end position here in order to pick up any characters after the | ||
// composition has finished, for example when typing a non-composition character | ||
// (eg. 2) after a composition character. | ||
input = self.textarea.value.substring(currentCompositionPosition.start); | ||
input = _this.textarea.value.substring(currentCompositionPosition_1.start); | ||
} | ||
self.terminal.handler(input); | ||
_this.terminal.handler(input); | ||
} | ||
@@ -144,18 +83,11 @@ }, 0); | ||
}; | ||
/** | ||
* Apply any changes made to the textarea after the current event chain is allowed to complete. | ||
* This should be called when not currently composing but a keydown event with the "composition | ||
* character" (229) is triggered, in order to allow non-composition text to be entered when an | ||
* IME is active. | ||
*/ | ||
CompositionHelper.prototype.handleAnyTextareaChanges = function () { | ||
var _this = this; | ||
var oldValue = this.textarea.value; | ||
var self = this; | ||
setTimeout(function () { | ||
// Ignore if a composition has started since the timeout | ||
if (!self.isComposing) { | ||
var newValue = self.textarea.value; | ||
if (!_this.isComposing) { | ||
var newValue = _this.textarea.value; | ||
var diff = newValue.replace(oldValue, ''); | ||
if (diff.length > 0) { | ||
self.terminal.handler(diff); | ||
_this.terminal.handler(diff); | ||
} | ||
@@ -165,9 +97,4 @@ } | ||
}; | ||
/** | ||
* Positions the composition view on top of the cursor and the textarea just below it (so the | ||
* IME helper dialog is positioned correctly). | ||
* @param dontRecurse Whether to use setTimeout to recursively trigger another update, this is | ||
* necessary as the IME events across browsers are not consistently triggered. | ||
*/ | ||
CompositionHelper.prototype.updateCompositionElements = function (dontRecurse) { | ||
var _this = this; | ||
if (!this.isComposing) { | ||
@@ -178,4 +105,2 @@ return; | ||
if (cursor) { | ||
// Take .xterm-rows offsetTop into account as well in case it's positioned absolutely within | ||
// the .xterm element. | ||
var xtermRows = this.terminal.element.querySelector('.xterm-rows'); | ||
@@ -187,4 +112,2 @@ var cursorTop = xtermRows.offsetTop + cursor.offsetTop; | ||
this.compositionView.style.lineHeight = cursor.offsetHeight + 'px'; | ||
// Sync the textarea to the exact position of the composition view so the IME knows where the | ||
// text is. | ||
var compositionViewBounds = this.compositionView.getBoundingClientRect(); | ||
@@ -198,10 +121,6 @@ this.textarea.style.left = cursor.offsetLeft + 'px'; | ||
if (!dontRecurse) { | ||
setTimeout(this.updateCompositionElements.bind(this, true), 0); | ||
setTimeout(function () { return _this.updateCompositionElements(true); }, 0); | ||
} | ||
}; | ||
; | ||
/** | ||
* Clears the textarea's position so that the cursor does not blink on IE. | ||
* @private | ||
*/ | ||
CompositionHelper.prototype.clearTextareaPosition = function () { | ||
@@ -215,2 +134,3 @@ this.textarea.style.left = ''; | ||
exports.CompositionHelper = CompositionHelper; | ||
//# sourceMappingURL=CompositionHelper.js.map | ||
//# sourceMappingURL=CompositionHelper.js.map |
@@ -47,3 +47,2 @@ "use strict"; | ||
it('Should insert simple characters', function (done) { | ||
// First character 'ㅇ' | ||
compositionHelper.compositionstart(); | ||
@@ -56,3 +55,2 @@ compositionHelper.compositionupdate({ data: 'ㅇ' }); | ||
chai_1.assert.equal(handledText, 'ㅇ'); | ||
// Second character 'ㅇ' | ||
compositionHelper.compositionstart(); | ||
@@ -72,3 +70,2 @@ compositionHelper.compositionupdate({ data: 'ㅇ' }); | ||
it('Should insert complex characters', function (done) { | ||
// First character '앙' | ||
compositionHelper.compositionstart(); | ||
@@ -87,3 +84,2 @@ compositionHelper.compositionupdate({ data: 'ㅇ' }); | ||
chai_1.assert.equal(handledText, '앙'); | ||
// Second character '앙' | ||
compositionHelper.compositionstart(); | ||
@@ -113,3 +109,2 @@ compositionHelper.compositionupdate({ data: 'ㅇ' }); | ||
it('Should insert complex characters that change with following character', function (done) { | ||
// First character '아' | ||
compositionHelper.compositionstart(); | ||
@@ -122,3 +117,2 @@ compositionHelper.compositionupdate({ data: 'ㅇ' }); | ||
setTimeout(function () { | ||
// Start second character '아' in first character | ||
compositionHelper.compositionupdate({ data: '앙' }); | ||
@@ -143,3 +137,2 @@ textarea.value = '앙'; | ||
it('Should insert multi-characters compositions', function (done) { | ||
// First character 'だ' | ||
compositionHelper.compositionstart(); | ||
@@ -152,3 +145,2 @@ compositionHelper.compositionupdate({ data: 'd' }); | ||
setTimeout(function () { | ||
// Second character 'あ' | ||
compositionHelper.compositionupdate({ data: 'だあ' }); | ||
@@ -167,3 +159,2 @@ textarea.value = 'だあ'; | ||
it('Should insert multi-character compositions that are converted to other characters with the same length', function (done) { | ||
// First character 'だ' | ||
compositionHelper.compositionstart(); | ||
@@ -176,7 +167,5 @@ compositionHelper.compositionupdate({ data: 'd' }); | ||
setTimeout(function () { | ||
// Second character 'ー' | ||
compositionHelper.compositionupdate({ data: 'だー' }); | ||
textarea.value = 'だー'; | ||
setTimeout(function () { | ||
// Convert to katakana 'ダー' | ||
compositionHelper.compositionupdate({ data: 'ダー' }); | ||
@@ -196,3 +185,2 @@ textarea.value = 'ダー'; | ||
it('Should insert multi-character compositions that are converted to other characters with different lengths', function (done) { | ||
// First character 'い' | ||
compositionHelper.compositionstart(); | ||
@@ -202,3 +190,2 @@ compositionHelper.compositionupdate({ data: 'い' }); | ||
setTimeout(function () { | ||
// Second character 'ま' | ||
compositionHelper.compositionupdate({ data: 'いm' }); | ||
@@ -210,3 +197,2 @@ textarea.value = 'いm'; | ||
setTimeout(function () { | ||
// Convert to kanji '今' | ||
compositionHelper.compositionupdate({ data: '今' }); | ||
@@ -226,3 +212,2 @@ textarea.value = '今'; | ||
it('Should insert non-composition characters input immediately after composition characters', function (done) { | ||
// First character 'ㅇ' | ||
compositionHelper.compositionstart(); | ||
@@ -233,3 +218,2 @@ compositionHelper.compositionupdate({ data: 'ㅇ' }); | ||
compositionHelper.compositionend(); | ||
// Second character '1' (a non-composition character) | ||
textarea.value = 'ㅇ1'; | ||
@@ -244,2 +228,3 @@ setTimeout(function () { | ||
}); | ||
//# sourceMappingURL=CompositionHelper.test.js.map | ||
//# sourceMappingURL=CompositionHelper.test.js.map |
@@ -1,51 +0,55 @@ | ||
/** | ||
* @license MIT | ||
*/ | ||
"use strict"; | ||
function EventEmitter() { | ||
this._events = this._events || {}; | ||
} | ||
exports.EventEmitter = EventEmitter; | ||
EventEmitter.prototype.addListener = function (type, listener) { | ||
this._events[type] = this._events[type] || []; | ||
this._events[type].push(listener); | ||
}; | ||
EventEmitter.prototype.on = EventEmitter.prototype.addListener; | ||
EventEmitter.prototype.removeListener = function (type, listener) { | ||
if (!this._events[type]) | ||
return; | ||
var obj = this._events[type], i = obj.length; | ||
while (i--) { | ||
if (obj[i] === listener || obj[i].listener === listener) { | ||
obj.splice(i, 1); | ||
; | ||
var EventEmitter = (function () { | ||
function EventEmitter() { | ||
this._events = this._events || {}; | ||
} | ||
EventEmitter.prototype.on = function (type, listener) { | ||
this._events[type] = this._events[type] || []; | ||
this._events[type].push(listener); | ||
}; | ||
EventEmitter.prototype.off = function (type, listener) { | ||
if (!this._events[type]) { | ||
return; | ||
} | ||
} | ||
}; | ||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener; | ||
EventEmitter.prototype.removeAllListeners = function (type) { | ||
if (this._events[type]) | ||
delete this._events[type]; | ||
}; | ||
EventEmitter.prototype.once = function (type, listener) { | ||
var self = this; | ||
function on() { | ||
var args = Array.prototype.slice.call(arguments); | ||
this.removeListener(type, on); | ||
return listener.apply(this, args); | ||
} | ||
on.listener = listener; | ||
return this.on(type, on); | ||
}; | ||
EventEmitter.prototype.emit = function (type) { | ||
if (!this._events[type]) | ||
return; | ||
var args = Array.prototype.slice.call(arguments, 1), obj = this._events[type], l = obj.length, i = 0; | ||
for (; i < l; i++) { | ||
obj[i].apply(this, args); | ||
} | ||
}; | ||
EventEmitter.prototype.listeners = function (type) { | ||
return this._events[type] = this._events[type] || []; | ||
}; | ||
//# sourceMappingURL=EventEmitter.js.map | ||
var obj = this._events[type]; | ||
var i = obj.length; | ||
while (i--) { | ||
if (obj[i] === listener || obj[i].listener === listener) { | ||
obj.splice(i, 1); | ||
return; | ||
} | ||
} | ||
}; | ||
EventEmitter.prototype.removeAllListeners = function (type) { | ||
if (this._events[type]) { | ||
delete this._events[type]; | ||
} | ||
}; | ||
EventEmitter.prototype.once = function (type, listener) { | ||
function on() { | ||
var args = Array.prototype.slice.call(arguments); | ||
this.off(type, on); | ||
return listener.apply(this, args); | ||
} | ||
on.listener = listener; | ||
return this.on(type, on); | ||
}; | ||
EventEmitter.prototype.emit = function (type) { | ||
if (!this._events[type]) { | ||
return; | ||
} | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
var obj = this._events[type]; | ||
for (var i = 0; i < obj.length; i++) { | ||
obj[i].apply(this, args); | ||
} | ||
}; | ||
EventEmitter.prototype.listeners = function (type) { | ||
return this._events[type] || []; | ||
}; | ||
return EventEmitter; | ||
}()); | ||
exports.EventEmitter = EventEmitter; | ||
//# sourceMappingURL=EventEmitter.js.map |
@@ -1,19 +0,4 @@ | ||
/** | ||
* Clipboard handler module: exports methods for handling all clipboard-related events in the | ||
* terminal. | ||
* @module xterm/handlers/Clipboard | ||
* @license MIT | ||
*/ | ||
"use strict"; | ||
/** | ||
* Prepares text copied from terminal selection, to be saved in the clipboard by: | ||
* 1. stripping all trailing white spaces | ||
* 2. converting all non-breaking spaces to regular spaces | ||
* @param {string} text The copied text that needs processing for storing in clipboard | ||
* @returns {string} | ||
*/ | ||
function prepareTextForClipboard(text) { | ||
var space = String.fromCharCode(32), nonBreakingSpace = String.fromCharCode(160), allNonBreakingSpaces = new RegExp(nonBreakingSpace, 'g'), processedText = text.split('\n').map(function (line) { | ||
// Strip all trailing white spaces and convert all non-breaking spaces | ||
// to regular spaces. | ||
var processedLine = line.replace(/\s+$/g, '').replace(allNonBreakingSpaces, space); | ||
@@ -25,9 +10,3 @@ return processedLine; | ||
exports.prepareTextForClipboard = prepareTextForClipboard; | ||
/** | ||
* Binds copy functionality to the given terminal. | ||
* @param {ClipboardEvent} ev The original copy event to be handled | ||
*/ | ||
function copyHandler(ev, term) { | ||
// We cast `window` to `any` type, because TypeScript has not declared the `clipboardData` | ||
// property that we use below for Internet Explorer. | ||
var copiedText = window.getSelection().toString(), text = prepareTextForClipboard(copiedText); | ||
@@ -40,10 +19,5 @@ if (term.browser.isMSIE) { | ||
} | ||
ev.preventDefault(); // Prevent or the original text will be copied. | ||
ev.preventDefault(); | ||
} | ||
exports.copyHandler = copyHandler; | ||
/** | ||
* Redirect the clipboard's data to the terminal's input handler. | ||
* @param {ClipboardEvent} ev The original paste event to be handled | ||
* @param {Terminal} term The terminal on which to apply the handled paste event | ||
*/ | ||
function pasteHandler(ev, term) { | ||
@@ -71,15 +45,2 @@ ev.stopPropagation(); | ||
exports.pasteHandler = pasteHandler; | ||
/** | ||
* Bind to right-click event and allow right-click copy and paste. | ||
* | ||
* **Logic** | ||
* If text is selected and right-click happens on selected text, then | ||
* do nothing to allow seamless copying. | ||
* If no text is selected or right-click is outside of the selection | ||
* area, then bring the terminal's input below the cursor, in order to | ||
* trigger the event on the textarea and allow-right click paste, without | ||
* caring about disappearing selection. | ||
* @param {MouseEvent} ev The original right click event to be handled | ||
* @param {Terminal} term The terminal on which to apply the handled paste event | ||
*/ | ||
function rightClickHandler(ev, term) { | ||
@@ -97,6 +58,2 @@ var s = document.getSelection(), selectedText = prepareTextForClipboard(s.toString()), clickIsOnSelection = false, x = ev.clientX, y = ev.clientY; | ||
} | ||
// If we clicked on selection and selection is not a single space, | ||
// then mark the right click as copy-only. We check for the single | ||
// space selection, as this can happen when clicking on an | ||
// and there is not much pointing in copying a single space. | ||
if (selectedText.match(/^\s$/) || !selectedText.length) { | ||
@@ -106,3 +63,2 @@ clickIsOnSelection = false; | ||
} | ||
// Bring textarea at the cursor position | ||
if (!clickIsOnSelection) { | ||
@@ -116,3 +72,2 @@ term.textarea.style.position = 'fixed'; | ||
term.textarea.focus(); | ||
// Reset the terminal textarea's styling | ||
setTimeout(function () { | ||
@@ -129,2 +84,3 @@ term.textarea.style.position = null; | ||
exports.rightClickHandler = rightClickHandler; | ||
//# sourceMappingURL=Clipboard.js.map | ||
//# sourceMappingURL=Clipboard.js.map |
@@ -7,8 +7,7 @@ "use strict"; | ||
var nonBreakingSpace = String.fromCharCode(160), copiedText = 'echo' + nonBreakingSpace + 'hello' + nonBreakingSpace, processedText = Clipboard.prepareTextForClipboard(copiedText); | ||
// No trailing spaces | ||
chai_1.assert.equal(processedText.match(/\s+$/), null); | ||
// No non-breaking space | ||
chai_1.assert.equal(processedText.indexOf(nonBreakingSpace), -1); | ||
}); | ||
}); | ||
//# sourceMappingURL=Clipboard.test.js.map | ||
//# sourceMappingURL=Clipboard.test.js.map |
@@ -1,5 +0,3 @@ | ||
/** | ||
* @license MIT | ||
*/ | ||
"use strict"; | ||
//# sourceMappingURL=Interfaces.js.map | ||
//# sourceMappingURL=Interfaces.js.map |
@@ -46,2 +46,3 @@ var assert = require('chai').assert; | ||
}); | ||
//# sourceMappingURL=linkify-test.js.map | ||
//# sourceMappingURL=linkify-test.js.map |
@@ -6,6 +6,6 @@ var assert = require('chai').assert; | ||
Terminal.loadAddon('attach'); | ||
// Test that addon was loaded successfully | ||
assert.equal(typeof Terminal.prototype.attach, 'function'); | ||
}); | ||
}); | ||
//# sourceMappingURL=test.js.map | ||
//# sourceMappingURL=test.js.map |
var glob = require('glob'); | ||
var fs = require('fs'); | ||
var pty = require('pty.js'); | ||
var os = require('os'); | ||
var pty = require('node-pty'); | ||
var sleep = require('sleep'); | ||
var Terminal = require('../xterm'); | ||
if (os.platform() === 'win32') { | ||
return; | ||
} | ||
var CONSOLE_LOG = console.log; | ||
// expect files need terminal at 80x25! | ||
var COLS = 80; | ||
var ROWS = 25; | ||
/** some helpers for pty interaction */ | ||
// we need a pty in between to get the termios decorations | ||
// for the basic test cases a raw pty device is enough | ||
var primitive_pty = pty.native.open(COLS, ROWS); | ||
// fake sychronous pty write - read | ||
// we just pipe the data from slave to master as a child program would do | ||
// pty.js opens pipe fds with O_NONBLOCK | ||
// just wait 10ms instead of setting fds to blocking mode | ||
function pty_write_read(s) { | ||
@@ -25,8 +21,5 @@ fs.writeSync(primitive_pty.slave, s); | ||
} | ||
// make sure raw pty is at x=0 and has no pending data | ||
function pty_reset() { | ||
pty_write_read('\r\n'); | ||
} | ||
/* debug helpers */ | ||
// generate colorful noisy output to compare xterm and emulator cell states | ||
function formatError(in_, out_, expected) { | ||
@@ -49,12 +42,10 @@ function addLineNumber(start, color) { | ||
} | ||
// simple debug output of terminal cells | ||
function terminalToString(term) { | ||
var result = ''; | ||
var line_s = ''; | ||
for (var line = 0; line < term.rows; ++line) { | ||
for (var line = term.ybase; line < term.ybase + term.rows; line++) { | ||
line_s = ''; | ||
for (var cell = 0; cell < term.cols; ++cell) { | ||
line_s += term.lines[line][cell][1]; | ||
line_s += term.lines.get(line)[cell][1]; | ||
} | ||
// rtrim empty cells as xterm does | ||
line_s = line_s.replace(/\s+$/, ''); | ||
@@ -66,3 +57,2 @@ result += line_s; | ||
} | ||
/** tests */ | ||
describe('xterm output comparison', function () { | ||
@@ -73,11 +63,18 @@ var xterm; | ||
xterm.refresh = function () { }; | ||
xterm.viewport = { | ||
syncScrollArea: function () { } | ||
}; | ||
}); | ||
// omit stack trace for escape sequence files | ||
Error.stackTraceLimit = 0; | ||
var files = glob.sync('**/escape_sequence_files/*.in'); | ||
// only successful tests for now | ||
var successful = [0, 2, 6, 12, 13, 18, 20, 22, 27, 28]; | ||
console.log(files); | ||
for (var a in successful) { | ||
var i = successful[a]; | ||
var skip = [ | ||
10, 16, 17, 19, 32, 33, 34, 35, 36, 39, | ||
40, 42, 43, 44, 45, 46, 47, 48, 49, 50, | ||
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, | ||
63, 68 | ||
]; | ||
for (var i = 0; i < files.length; i++) { | ||
if (skip.indexOf(i) >= 0) { | ||
continue; | ||
} | ||
(function (filename) { | ||
@@ -88,12 +85,12 @@ it(filename.split('/').slice(-1)[0], function () { | ||
var from_pty = pty_write_read(in_file); | ||
// uncomment this to get log from terminal | ||
console.log = function () { }; | ||
xterm.write(from_pty); | ||
xterm.writeBuffer.push(from_pty); | ||
xterm.innerWrite(); | ||
var from_emulator = terminalToString(xterm); | ||
console.log = CONSOLE_LOG; | ||
var expected = fs.readFileSync(filename.split('.')[0] + '.text', 'utf8'); | ||
if (from_emulator != expected) { | ||
// uncomment to get noisy output | ||
//throw new Error(formatError(in_file, from_emulator, expected)); | ||
throw new Error('mismatch'); | ||
var expectedRightTrimmed = expected.split('\n').map(function (l) { | ||
return l.replace(/\s+$/, ''); | ||
}).join('\n'); | ||
if (from_emulator != expectedRightTrimmed) { | ||
throw new Error(formatError(in_file, from_emulator, expected)); | ||
} | ||
@@ -104,2 +101,3 @@ }); | ||
}); | ||
//# sourceMappingURL=escape-sequences-test.js.map | ||
//# sourceMappingURL=escape-sequences-test.js.map |
@@ -15,9 +15,16 @@ var assert = require('chai').assert; | ||
}; | ||
xterm.write = function (data) { | ||
xterm.writeBuffer.push(data); | ||
xterm.innerWrite(); | ||
}; | ||
xterm.element = { | ||
classList: { | ||
toggle: function () { } | ||
} | ||
}; | ||
}); | ||
describe('getOption', function () { | ||
it('should retrieve the option correctly', function () { | ||
// In the `options` namespace. | ||
xterm.options.cursorBlink = true; | ||
assert.equal(xterm.getOption('cursorBlink'), true); | ||
// On the Terminal instance | ||
delete xterm.options.cursorBlink; | ||
@@ -46,3 +53,3 @@ xterm.cursorBlink = false; | ||
it('should clear a buffer equal to rows', function () { | ||
var promptLine = xterm.lines[xterm.ybase + xterm.y]; | ||
var promptLine = xterm.lines.get(xterm.ybase + xterm.y); | ||
xterm.clear(); | ||
@@ -53,13 +60,12 @@ assert.equal(xterm.y, 0); | ||
assert.equal(xterm.lines.length, xterm.rows); | ||
assert.deepEqual(xterm.lines[0], promptLine); | ||
assert.deepEqual(xterm.lines.get(0), promptLine); | ||
for (var i = 1; i < xterm.rows; i++) { | ||
assert.deepEqual(xterm.lines[0], xterm.blankLine()); | ||
assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); | ||
} | ||
}); | ||
it('should clear a buffer larger than rows', function () { | ||
// Fill the buffer with dummy rows | ||
for (var i = 0; i < xterm.rows * 2; i++) { | ||
xterm.write('test\n'); | ||
} | ||
var promptLine = xterm.lines[xterm.ybase + xterm.y]; | ||
var promptLine = xterm.lines.get(xterm.ybase + xterm.y); | ||
xterm.clear(); | ||
@@ -70,9 +76,9 @@ assert.equal(xterm.y, 0); | ||
assert.equal(xterm.lines.length, xterm.rows); | ||
assert.deepEqual(xterm.lines[0], promptLine); | ||
assert.deepEqual(xterm.lines.get(0), promptLine); | ||
for (var i = 1; i < xterm.rows; i++) { | ||
assert.deepEqual(xterm.lines[i], xterm.blankLine()); | ||
assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); | ||
} | ||
}); | ||
it('should not break the prompt when cleared twice', function () { | ||
var promptLine = xterm.lines[xterm.ybase + xterm.y]; | ||
var promptLine = xterm.lines.get(xterm.ybase + xterm.y); | ||
xterm.clear(); | ||
@@ -84,5 +90,5 @@ xterm.clear(); | ||
assert.equal(xterm.lines.length, xterm.rows); | ||
assert.deepEqual(xterm.lines[0], promptLine); | ||
assert.deepEqual(xterm.lines.get(0), promptLine); | ||
for (var i = 1; i < xterm.rows; i++) { | ||
assert.deepEqual(xterm.lines[i], xterm.blankLine()); | ||
assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); | ||
} | ||
@@ -183,3 +189,2 @@ }); | ||
it('should scroll down, when a key is pressed and terminal is scrolled up', function () { | ||
// Override evaluateKeyEscapeSequence to return cancel code | ||
xterm.evaluateKeyEscapeSequence = function () { | ||
@@ -198,7 +203,5 @@ return { key: 'a' }; | ||
xterm.keyDown(event); | ||
// Ensure that now the terminal is scrolled to bottom | ||
assert.equal(xterm.ydisp, xterm.ybase); | ||
}); | ||
it('should not scroll down, when a custom keydown handler prevents the event', function () { | ||
// Add some output to the terminal | ||
for (var i = 0; i < xterm.rows * 3; i++) { | ||
@@ -221,38 +224,28 @@ xterm.writeln('test'); | ||
it('should return the correct escape sequence for unmodified keys', function () { | ||
// Backspace | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 8 }).key, '\x7f'); // ^? | ||
// Tab | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 8 }).key, '\x7f'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 9 }).key, '\t'); | ||
// Return/enter | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 13 }).key, '\r'); // CR | ||
// Escape | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 13 }).key, '\r'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 27 }).key, '\x1b'); | ||
// Page up, page down | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 33 }).key, '\x1b[5~'); // CSI 5 ~ | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 34 }).key, '\x1b[6~'); // CSI 6 ~ | ||
// End, Home | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 35 }).key, '\x1b[F'); // SS3 F | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1b[H'); // SS3 H | ||
// Left, up, right, down arrows | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 37 }).key, '\x1b[D'); // CSI D | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 38 }).key, '\x1b[A'); // CSI A | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 39 }).key, '\x1b[C'); // CSI C | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 40 }).key, '\x1b[B'); // CSI B | ||
// Insert | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 45 }).key, '\x1b[2~'); // CSI 2 ~ | ||
// Delete | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 46 }).key, '\x1b[3~'); // CSI 3 ~ | ||
// F1-F12 | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 112 }).key, '\x1bOP'); // SS3 P | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 113 }).key, '\x1bOQ'); // SS3 Q | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 114 }).key, '\x1bOR'); // SS3 R | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 115 }).key, '\x1bOS'); // SS3 S | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 116 }).key, '\x1b[15~'); // CSI 1 5 ~ | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 117 }).key, '\x1b[17~'); // CSI 1 7 ~ | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 118 }).key, '\x1b[18~'); // CSI 1 8 ~ | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 119 }).key, '\x1b[19~'); // CSI 1 9 ~ | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 120 }).key, '\x1b[20~'); // CSI 2 0 ~ | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 121 }).key, '\x1b[21~'); // CSI 2 1 ~ | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 122 }).key, '\x1b[23~'); // CSI 2 3 ~ | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 123 }).key, '\x1b[24~'); // CSI 2 4 ~ | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 33 }).key, '\x1b[5~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 34 }).key, '\x1b[6~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 35 }).key, '\x1b[F'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1b[H'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 37 }).key, '\x1b[D'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 38 }).key, '\x1b[A'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 39 }).key, '\x1b[C'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 40 }).key, '\x1b[B'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 45 }).key, '\x1b[2~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 46 }).key, '\x1b[3~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 112 }).key, '\x1bOP'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 113 }).key, '\x1bOQ'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 114 }).key, '\x1bOR'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 115 }).key, '\x1bOS'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 116 }).key, '\x1b[15~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 117 }).key, '\x1b[17~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 118 }).key, '\x1b[18~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 119 }).key, '\x1b[19~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 120 }).key, '\x1b[20~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 121 }).key, '\x1b[21~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 122 }).key, '\x1b[23~'); | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 123 }).key, '\x1b[24~'); | ||
}); | ||
@@ -269,26 +262,40 @@ it('should return \\x1b[3;5~ for ctrl+delete', function () { | ||
it('should return \\x1b[5D for ctrl+left', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[1;5D'); | ||
}); | ||
it('should return \\x1b[5C for ctrl+right', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[1;5C'); | ||
}); | ||
it('should return \\x1b[5A for ctrl+up', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 38 }).key, '\x1b[1;5A'); | ||
}); | ||
it('should return \\x1b[5B for ctrl+down', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 40 }).key, '\x1b[1;5B'); | ||
}); | ||
// Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100 | ||
// http://unix.stackexchange.com/a/108106 | ||
it('should return \\x1b[5D for alt+left', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D | ||
describe('On non-macOS platforms', function () { | ||
beforeEach(function () { | ||
xterm.browser.isMac = false; | ||
}); | ||
it('should return \\x1b[5D for alt+left', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1b[1;5D'); | ||
}); | ||
it('should return \\x1b[5C for alt+right', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1b[1;5C'); | ||
}); | ||
}); | ||
it('should return \\x1b[5C for alt+right', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C | ||
describe('On macOS platforms', function () { | ||
beforeEach(function () { | ||
xterm.browser.isMac = true; | ||
}); | ||
it('should return \\x1bb for alt+left', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1bb'); | ||
}); | ||
it('should return \\x1bf for alt+right', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1bf'); | ||
}); | ||
}); | ||
it('should return \\x1b[5A for alt+up', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 38 }).key, '\x1b[1;5A'); | ||
}); | ||
it('should return \\x1b[5B for alt+down', function () { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 40 }).key, '\x1b[1;5B'); | ||
}); | ||
@@ -418,8 +425,7 @@ it('should return the correct escape sequence for modified F1-F12 keys', function () { | ||
}); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 64 })); // @ | ||
// Firefox | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 64 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 64, keyCode: 0 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 92 })); // \ | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 92 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 92, keyCode: 0 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 124 })); // | | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 124 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 124, keyCode: 0 })); | ||
@@ -451,7 +457,7 @@ }); | ||
}); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 64 })); // @ | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 64 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 64, keyCode: 0 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 92 })); // \ | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 92 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 92, keyCode: 0 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 124 })); // | | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 124 })); | ||
xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 124, keyCode: 0 })); | ||
@@ -466,7 +472,7 @@ }); | ||
xterm.write(high + String.fromCharCode(i)); | ||
var tchar = xterm.lines[0][0]; | ||
var tchar = xterm.lines.get(0)[0]; | ||
expect(tchar[1]).eql(high + String.fromCharCode(i)); | ||
expect(tchar[1].length).eql(2); | ||
expect(tchar[2]).eql(1); | ||
expect(xterm.lines[0][1][1]).eql(' '); | ||
expect(xterm.lines.get(0)[1][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -480,5 +486,5 @@ } | ||
xterm.write(high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.x - 1][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.x - 1][1].length).eql(2); | ||
expect(xterm.lines[1][0][1]).eql(' '); | ||
expect(xterm.lines.get(0)[xterm.x - 1][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines.get(0)[xterm.x - 1][1].length).eql(2); | ||
expect(xterm.lines.get(1)[0][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -493,6 +499,6 @@ } | ||
xterm.write('a' + high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.cols - 1][1]).eql('a'); | ||
expect(xterm.lines[1][0][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines[1][0][1].length).eql(2); | ||
expect(xterm.lines[1][1][1]).eql(' '); | ||
expect(xterm.lines.get(0)[xterm.cols - 1][1]).eql('a'); | ||
expect(xterm.lines.get(1)[0][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines.get(1)[0][1].length).eql(2); | ||
expect(xterm.lines.get(1)[1][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -507,5 +513,5 @@ } | ||
xterm.write('a' + high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.cols - 1][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.cols - 1][1].length).eql(2); | ||
expect(xterm.lines[1][1][1]).eql(' '); | ||
expect(xterm.lines.get(0)[xterm.cols - 1][1]).eql('a'); | ||
expect(xterm.lines.get(0)[xterm.cols - 1][1].length).eql(1); | ||
expect(xterm.lines.get(1)[1][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -519,7 +525,7 @@ } | ||
xterm.write(String.fromCharCode(i)); | ||
var tchar = xterm.lines[0][0]; | ||
var tchar = xterm.lines.get(0)[0]; | ||
expect(tchar[1]).eql(high + String.fromCharCode(i)); | ||
expect(tchar[1].length).eql(2); | ||
expect(tchar[2]).eql(1); | ||
expect(xterm.lines[0][1][1]).eql(' '); | ||
expect(xterm.lines.get(0)[1][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -532,5 +538,5 @@ } | ||
xterm.write('cafe\u0301'); | ||
expect(xterm.lines[0][3][1]).eql('e\u0301'); | ||
expect(xterm.lines[0][3][1].length).eql(2); | ||
expect(xterm.lines[0][3][2]).eql(1); | ||
expect(xterm.lines.get(0)[3][1]).eql('e\u0301'); | ||
expect(xterm.lines.get(0)[3][1].length).eql(2); | ||
expect(xterm.lines.get(0)[3][2]).eql(1); | ||
}); | ||
@@ -540,8 +546,8 @@ it('café - end of line', function () { | ||
xterm.write('cafe\u0301'); | ||
expect(xterm.lines[0][xterm.cols - 1][1]).eql('e\u0301'); | ||
expect(xterm.lines[0][xterm.cols - 1][1].length).eql(2); | ||
expect(xterm.lines[0][xterm.cols - 1][2]).eql(1); | ||
expect(xterm.lines[0][1][1]).eql(' '); | ||
expect(xterm.lines[0][1][1].length).eql(1); | ||
expect(xterm.lines[0][1][2]).eql(1); | ||
expect(xterm.lines.get(0)[xterm.cols - 1][1]).eql('e\u0301'); | ||
expect(xterm.lines.get(0)[xterm.cols - 1][1].length).eql(2); | ||
expect(xterm.lines.get(0)[xterm.cols - 1][2]).eql(1); | ||
expect(xterm.lines.get(0)[1][1]).eql(' '); | ||
expect(xterm.lines.get(0)[1][1].length).eql(1); | ||
expect(xterm.lines.get(0)[1][2]).eql(1); | ||
}); | ||
@@ -552,3 +558,3 @@ it('multiple combined é', function () { | ||
for (var i = 0; i < xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
expect(tchar[1]).eql('e\u0301'); | ||
@@ -558,3 +564,3 @@ expect(tchar[1].length).eql(2); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('e\u0301'); | ||
@@ -568,3 +574,3 @@ expect(tchar[1].length).eql(2); | ||
for (var i = 0; i < xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
expect(tchar[1]).eql('\uD800\uDC00\u0301'); | ||
@@ -574,3 +580,3 @@ expect(tchar[1].length).eql(3); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('\uD800\uDC00\u0301'); | ||
@@ -597,3 +603,3 @@ expect(tchar[1].length).eql(3); | ||
for (var i = 0; i < xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (i % 2) { | ||
@@ -610,3 +616,3 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('¥'); | ||
@@ -621,3 +627,3 @@ expect(tchar[1].length).eql(1); | ||
for (var i = 1; i < xterm.cols - 1; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (!(i % 2)) { | ||
@@ -634,7 +640,7 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[0][xterm.cols - 1]; | ||
tchar = xterm.lines.get(0)[xterm.cols - 1]; | ||
expect(tchar[1]).eql(' '); | ||
expect(tchar[1].length).eql(1); | ||
expect(tchar[2]).eql(1); | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('¥'); | ||
@@ -649,3 +655,3 @@ expect(tchar[1].length).eql(1); | ||
for (var i = 1; i < xterm.cols - 1; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (!(i % 2)) { | ||
@@ -662,7 +668,7 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[0][xterm.cols - 1]; | ||
tchar = xterm.lines.get(0)[xterm.cols - 1]; | ||
expect(tchar[1]).eql(' '); | ||
expect(tchar[1].length).eql(1); | ||
expect(tchar[2]).eql(1); | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('¥\u0301'); | ||
@@ -676,3 +682,3 @@ expect(tchar[1].length).eql(2); | ||
for (var i = 0; i < xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (i % 2) { | ||
@@ -689,3 +695,3 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('¥\u0301'); | ||
@@ -700,3 +706,3 @@ expect(tchar[1].length).eql(2); | ||
for (var i = 1; i < xterm.cols - 1; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (!(i % 2)) { | ||
@@ -713,7 +719,7 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[0][xterm.cols - 1]; | ||
tchar = xterm.lines.get(0)[xterm.cols - 1]; | ||
expect(tchar[1]).eql(' '); | ||
expect(tchar[1].length).eql(1); | ||
expect(tchar[2]).eql(1); | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('\ud843\ude6d\u0301'); | ||
@@ -727,3 +733,3 @@ expect(tchar[1].length).eql(3); | ||
for (var i = 0; i < xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (i % 2) { | ||
@@ -740,3 +746,3 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('\ud843\ude6d\u0301'); | ||
@@ -754,7 +760,7 @@ expect(tchar[1].length).eql(3); | ||
xterm.write('abcde'); | ||
expect(xterm.lines[0].length).eql(xterm.cols); | ||
expect(xterm.lines[0][10][1]).eql('a'); | ||
expect(xterm.lines[0][14][1]).eql('e'); | ||
expect(xterm.lines[0][15][1]).eql('0'); | ||
expect(xterm.lines[0][79][1]).eql('4'); | ||
expect(xterm.lines.get(0).length).eql(xterm.cols); | ||
expect(xterm.lines.get(0)[10][1]).eql('a'); | ||
expect(xterm.lines.get(0)[14][1]).eql('e'); | ||
expect(xterm.lines.get(0)[15][1]).eql('0'); | ||
expect(xterm.lines.get(0)[79][1]).eql('4'); | ||
}); | ||
@@ -767,8 +773,8 @@ it('fullwidth - insert', function () { | ||
xterm.write('¥¥¥'); | ||
expect(xterm.lines[0].length).eql(xterm.cols); | ||
expect(xterm.lines[0][10][1]).eql('¥'); | ||
expect(xterm.lines[0][11][1]).eql(''); | ||
expect(xterm.lines[0][14][1]).eql('¥'); | ||
expect(xterm.lines[0][15][1]).eql(''); | ||
expect(xterm.lines[0][79][1]).eql('3'); | ||
expect(xterm.lines.get(0).length).eql(xterm.cols); | ||
expect(xterm.lines.get(0)[10][1]).eql('¥'); | ||
expect(xterm.lines.get(0)[11][1]).eql(''); | ||
expect(xterm.lines.get(0)[14][1]).eql('¥'); | ||
expect(xterm.lines.get(0)[15][1]).eql(''); | ||
expect(xterm.lines.get(0)[79][1]).eql('3'); | ||
}); | ||
@@ -781,14 +787,15 @@ it('fullwidth - right border', function () { | ||
xterm.write('a'); | ||
expect(xterm.lines[0].length).eql(xterm.cols); | ||
expect(xterm.lines[0][10][1]).eql('a'); | ||
expect(xterm.lines[0][11][1]).eql('¥'); | ||
expect(xterm.lines[0][79][1]).eql(' '); // fullwidth char got replaced | ||
expect(xterm.lines.get(0).length).eql(xterm.cols); | ||
expect(xterm.lines.get(0)[10][1]).eql('a'); | ||
expect(xterm.lines.get(0)[11][1]).eql('¥'); | ||
expect(xterm.lines.get(0)[79][1]).eql(' '); | ||
xterm.write('b'); | ||
expect(xterm.lines[0].length).eql(xterm.cols); | ||
expect(xterm.lines[0][11][1]).eql('b'); | ||
expect(xterm.lines[0][12][1]).eql('¥'); | ||
expect(xterm.lines[0][79][1]).eql(''); // empty cell after fullwidth | ||
expect(xterm.lines.get(0).length).eql(xterm.cols); | ||
expect(xterm.lines.get(0)[11][1]).eql('b'); | ||
expect(xterm.lines.get(0)[12][1]).eql('¥'); | ||
expect(xterm.lines.get(0)[79][1]).eql(''); | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=test.js.map | ||
//# sourceMappingURL=test.js.map |
@@ -1,9 +0,4 @@ | ||
/** | ||
* Attributes and methods to help with identifying the current browser and platform. | ||
* @module xterm/utils/Browser | ||
* @license MIT | ||
*/ | ||
"use strict"; | ||
var Generic_js_1 = require("./Generic.js"); | ||
var isNode = (typeof navigator == 'undefined') ? true : false; | ||
var Generic_1 = require("./Generic"); | ||
var isNode = (typeof navigator === 'undefined') ? true : false; | ||
var userAgent = (isNode) ? 'node' : navigator.userAgent; | ||
@@ -13,9 +8,7 @@ var platform = (isNode) ? 'node' : navigator.platform; | ||
exports.isMSIE = !!~userAgent.indexOf('MSIE') || !!~userAgent.indexOf('Trident'); | ||
// Find the users platform. We use this to interpret the meta key | ||
// and ISO third level shifts. | ||
// http://stackoverflow.com/q/19877924/577598 | ||
exports.isMac = Generic_js_1.contains(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], platform); | ||
exports.isMac = Generic_1.contains(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], platform); | ||
exports.isIpad = platform === 'iPad'; | ||
exports.isIphone = platform === 'iPhone'; | ||
exports.isMSWindows = Generic_js_1.contains(['Windows', 'Win16', 'Win32', 'WinCE'], platform); | ||
//# sourceMappingURL=Browser.js.map | ||
exports.isMSWindows = Generic_1.contains(['Windows', 'Win16', 'Win32', 'WinCE'], platform); | ||
//# sourceMappingURL=Browser.js.map |
@@ -1,15 +0,8 @@ | ||
/** | ||
* Generic utilities module with methods that can be helpful at different parts of the code base. | ||
* @module xterm/utils/Generic | ||
* @license MIT | ||
*/ | ||
"use strict"; | ||
/** | ||
* Return if the given array contains the given element | ||
* @param {Array} array The array to search for the given element. | ||
* @param {Object} el The element to look for into the array | ||
*/ | ||
exports.contains = function (arr, el) { | ||
function contains(arr, el) { | ||
return arr.indexOf(el) >= 0; | ||
}; | ||
//# sourceMappingURL=Generic.js.map | ||
} | ||
exports.contains = contains; | ||
; | ||
//# sourceMappingURL=Generic.js.map |
@@ -1,22 +0,8 @@ | ||
/** | ||
* @license MIT | ||
*/ | ||
"use strict"; | ||
/** | ||
* Represents the viewport of a terminal, the visible area within the larger buffer of output. | ||
* Logic for the virtual scroll bar is included in this object. | ||
*/ | ||
var Viewport = (function () { | ||
/** | ||
* Creates a new Viewport. | ||
* @param terminal The terminal this viewport belongs to. | ||
* @param viewportElement The DOM element acting as the viewport. | ||
* @param scrollArea The DOM element acting as the scroll area. | ||
* @param charMeasureElement A DOM element used to measure the character size of. the terminal. | ||
*/ | ||
function Viewport(terminal, viewportElement, scrollArea, charMeasureElement) { | ||
function Viewport(terminal, viewportElement, scrollArea, charMeasure) { | ||
this.terminal = terminal; | ||
this.viewportElement = viewportElement; | ||
this.scrollArea = scrollArea; | ||
this.charMeasureElement = charMeasureElement; | ||
this.charMeasure = charMeasure; | ||
this.currentRowHeight = 0; | ||
@@ -30,16 +16,9 @@ this.lastRecordedBufferLength = 0; | ||
} | ||
/** | ||
* Refreshes row height, setting line-height, viewport height and scroll area height if | ||
* necessary. | ||
* @param charSize A character size measurement bounding rect object, if it doesn't exist it will | ||
* be created. | ||
*/ | ||
Viewport.prototype.refresh = function (charSize) { | ||
var size = charSize || this.charMeasureElement.getBoundingClientRect(); | ||
if (size.height > 0) { | ||
var rowHeightChanged = size.height !== this.currentRowHeight; | ||
Viewport.prototype.refresh = function () { | ||
if (this.charMeasure.height > 0) { | ||
var rowHeightChanged = this.charMeasure.height !== this.currentRowHeight; | ||
if (rowHeightChanged) { | ||
this.currentRowHeight = size.height; | ||
this.viewportElement.style.lineHeight = size.height + 'px'; | ||
this.terminal.rowContainer.style.lineHeight = size.height + 'px'; | ||
this.currentRowHeight = this.charMeasure.height; | ||
this.viewportElement.style.lineHeight = this.charMeasure.height + 'px'; | ||
this.terminal.rowContainer.style.lineHeight = this.charMeasure.height + 'px'; | ||
} | ||
@@ -49,13 +28,9 @@ var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows; | ||
this.lastRecordedViewportHeight = this.terminal.rows; | ||
this.viewportElement.style.height = size.height * this.terminal.rows + 'px'; | ||
this.viewportElement.style.height = this.charMeasure.height * this.terminal.rows + 'px'; | ||
} | ||
this.scrollArea.style.height = (size.height * this.lastRecordedBufferLength) + 'px'; | ||
this.scrollArea.style.height = (this.charMeasure.height * this.lastRecordedBufferLength) + 'px'; | ||
} | ||
}; | ||
/** | ||
* Updates dimensions and synchronizes the scroll area if necessary. | ||
*/ | ||
Viewport.prototype.syncScrollArea = function () { | ||
if (this.lastRecordedBufferLength !== this.terminal.lines.length) { | ||
// If buffer height changed | ||
this.lastRecordedBufferLength = this.terminal.lines.length; | ||
@@ -65,13 +40,9 @@ this.refresh(); | ||
else if (this.lastRecordedViewportHeight !== this.terminal.rows) { | ||
// If viewport height changed | ||
this.refresh(); | ||
} | ||
else { | ||
// If size has changed, refresh viewport | ||
var size = this.charMeasureElement.getBoundingClientRect(); | ||
if (size.height !== this.currentRowHeight) { | ||
this.refresh(size); | ||
if (this.charMeasure.height !== this.currentRowHeight) { | ||
this.refresh(); | ||
} | ||
} | ||
// Sync scrollTop | ||
var scrollTop = this.terminal.ydisp * this.currentRowHeight; | ||
@@ -82,7 +53,2 @@ if (this.viewportElement.scrollTop !== scrollTop) { | ||
}; | ||
/** | ||
* Handles scroll events on the viewport, calculating the new viewport and requesting the | ||
* terminal to scroll to it. | ||
* @param ev The scroll event. | ||
*/ | ||
Viewport.prototype.onScroll = function (ev) { | ||
@@ -93,14 +59,6 @@ var newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight); | ||
}; | ||
/** | ||
* Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual | ||
* scrolling to `onScroll`, this event needs to be attached manually by the consumer of | ||
* `Viewport`. | ||
* @param ev The mouse wheel event. | ||
*/ | ||
Viewport.prototype.onWheel = function (ev) { | ||
if (ev.deltaY === 0) { | ||
// Do nothing if it's not a vertical scroll event | ||
return; | ||
} | ||
// Fallback to WheelEvent.DOM_DELTA_PIXEL | ||
var multiplier = 1; | ||
@@ -114,3 +72,2 @@ if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { | ||
this.viewportElement.scrollTop += ev.deltaY * multiplier; | ||
// Prevent the page from scrolling when the terminal scrolls | ||
ev.preventDefault(); | ||
@@ -122,2 +79,3 @@ }; | ||
exports.Viewport = Viewport; | ||
//# sourceMappingURL=Viewport.js.map | ||
//# sourceMappingURL=Viewport.js.map |
@@ -7,3 +7,3 @@ "use strict"; | ||
var viewportElement; | ||
var charMeasureElement; | ||
var charMeasure; | ||
var viewport; | ||
@@ -36,8 +36,6 @@ var scrollAreaElement; | ||
}; | ||
charMeasureElement = { | ||
getBoundingClientRect: function () { | ||
return { width: null, height: CHARACTER_HEIGHT }; | ||
} | ||
charMeasure = { | ||
height: CHARACTER_HEIGHT | ||
}; | ||
viewport = new Viewport_1.Viewport(terminal, viewportElement, scrollAreaElement, charMeasureElement); | ||
viewport = new Viewport_1.Viewport(terminal, viewportElement, scrollAreaElement, charMeasure); | ||
}); | ||
@@ -48,5 +46,3 @@ describe('refresh', function () { | ||
chai_1.assert.equal(terminal.rowContainer.style.lineHeight, CHARACTER_HEIGHT + 'px'); | ||
charMeasureElement.getBoundingClientRect = function () { | ||
return { width: null, height: 1 }; | ||
}; | ||
charMeasure.height = 1; | ||
viewport.refresh(); | ||
@@ -62,5 +58,3 @@ chai_1.assert.equal(viewportElement.style.lineHeight, '1px'); | ||
chai_1.assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); | ||
charMeasureElement.getBoundingClientRect = function () { | ||
return { width: null, height: 20 }; | ||
}; | ||
charMeasure.height = 20; | ||
viewport.refresh(); | ||
@@ -85,2 +79,3 @@ chai_1.assert.equal(viewportElement.style.height, 20 + 'px'); | ||
}); | ||
//# sourceMappingURL=Viewport.test.js.map | ||
//# sourceMappingURL=Viewport.test.js.map |
{ | ||
"name": "xterm", | ||
"version": "2.2.3", | ||
"description": "Full xterm terminal, in your browser", | ||
"version": "2.3.0", | ||
"ignore": [ | ||
@@ -13,2 +14,4 @@ "demo", | ||
"files": [ | ||
"*.js", | ||
"*.json", | ||
"dist/*.css", | ||
@@ -42,23 +45,33 @@ "dist/**/*.css", | ||
"docdash": "0.4.0", | ||
"exorcist": "^0.4.0", | ||
"express": "4.13.4", | ||
"express-ws": "2.0.0-rc.1", | ||
"fs-extra": "^1.0.0", | ||
"glob": "^7.0.5", | ||
"gulp": "^3.9.1", | ||
"gulp-cli": "^1.2.2", | ||
"gulp-sourcemaps": "1.9.1", | ||
"gulp-typescript": "^3.1.3", | ||
"jsdoc": "3.4.3", | ||
"merge-stream": "^1.0.1", | ||
"mocha": "2.5.3", | ||
"node-pty": "^0.4.1", | ||
"nodemon": "1.10.2", | ||
"pty.js": "0.3.1", | ||
"sleep": "^3.0.1", | ||
"sorcery": "^0.10.0", | ||
"tsify": "^3.0.0", | ||
"tslint": "^4.0.2", | ||
"typescript": "^2.0.3" | ||
"typescript": "^2.0.3", | ||
"vinyl-buffer": "^1.0.0", | ||
"vinyl-source-stream": "^1.1.0" | ||
}, | ||
"scripts": { | ||
"start": "nodemon --watch src --watch addons --watch demo --exec bash -c './bin/build && node demo/app'", | ||
"lint": "tslint src/**/*.ts", | ||
"prestart": "npm run build", | ||
"start": "node demo/app", | ||
"dev": "nodemon -e js,ts --watch src --watch demo --exec npm start", | ||
"lint": "tslint src/*.ts src/**/*.ts", | ||
"test": "mocha --recursive ./lib", | ||
"build:docs": "jsdoc -c jsdoc.json", | ||
"build": "./bin/build", | ||
"prepublish": "tsc" | ||
"build": "gulp build", | ||
"prepublish": "npm run build" | ||
} | ||
} |
@@ -5,7 +5,7 @@ import { assert } from 'chai'; | ||
describe('CompositionHelper', () => { | ||
var terminal; | ||
var compositionHelper; | ||
var compositionView; | ||
var textarea; | ||
var handledText; | ||
let terminal; | ||
let compositionHelper; | ||
let compositionView; | ||
let textarea; | ||
let handledText; | ||
@@ -129,3 +129,3 @@ beforeEach(() => { | ||
compositionHelper.compositionupdate({ data: '아' }); | ||
textarea.value = '아아' | ||
textarea.value = '아아'; | ||
setTimeout(() => { // wait for any textarea updates | ||
@@ -192,3 +192,3 @@ compositionHelper.compositionend(); | ||
}, 0); | ||
}) | ||
}); | ||
@@ -195,0 +195,0 @@ it('Should insert multi-character compositions that are converted to other characters with different lengths', function (done) { |
@@ -27,3 +27,3 @@ /** | ||
*/ | ||
private compositionPosition: IPosition;; | ||
private compositionPosition: IPosition; | ||
@@ -69,5 +69,4 @@ /** | ||
this.updateCompositionElements(); | ||
var self = this; | ||
setTimeout(function() { | ||
self.compositionPosition.end = self.textarea.value.length; | ||
setTimeout(() => { | ||
this.compositionPosition.end = this.textarea.value.length; | ||
}, 0); | ||
@@ -130,3 +129,3 @@ } | ||
this.isSendingComposition = false; | ||
var input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end); | ||
const input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end); | ||
this.terminal.handler(input); | ||
@@ -136,6 +135,6 @@ } else { | ||
// fire before the setTimeout executes. | ||
var currentCompositionPosition = { | ||
const currentCompositionPosition = { | ||
start: this.compositionPosition.start, | ||
end: this.compositionPosition.end, | ||
} | ||
}; | ||
@@ -150,12 +149,11 @@ // Since composition* events happen before the changes take place in the textarea on most | ||
// the following character if the following input is a vowel. | ||
var self = this; | ||
this.isSendingComposition = true; | ||
setTimeout(function () { | ||
setTimeout(() => { | ||
// Ensure that the input has not already been sent | ||
if (self.isSendingComposition) { | ||
self.isSendingComposition = false; | ||
var input; | ||
if (self.isComposing) { | ||
if (this.isSendingComposition) { | ||
this.isSendingComposition = false; | ||
let input; | ||
if (this.isComposing) { | ||
// Use the end position to get the string if a new composition has started. | ||
input = self.textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end); | ||
input = this.textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end); | ||
} else { | ||
@@ -165,5 +163,5 @@ // Don't use the end position here in order to pick up any characters after the | ||
// (eg. 2) after a composition character. | ||
input = self.textarea.value.substring(currentCompositionPosition.start); | ||
input = this.textarea.value.substring(currentCompositionPosition.start); | ||
} | ||
self.terminal.handler(input); | ||
this.terminal.handler(input); | ||
} | ||
@@ -181,11 +179,10 @@ }, 0); | ||
private handleAnyTextareaChanges() { | ||
var oldValue = this.textarea.value; | ||
var self = this; | ||
setTimeout(function() { | ||
const oldValue = this.textarea.value; | ||
setTimeout(() => { | ||
// Ignore if a composition has started since the timeout | ||
if (!self.isComposing) { | ||
var newValue = self.textarea.value; | ||
var diff = newValue.replace(oldValue, ''); | ||
if (!this.isComposing) { | ||
const newValue = this.textarea.value; | ||
const diff = newValue.replace(oldValue, ''); | ||
if (diff.length > 0) { | ||
self.terminal.handler(diff); | ||
this.terminal.handler(diff); | ||
} | ||
@@ -206,8 +203,8 @@ } | ||
} | ||
var cursor = <HTMLElement>this.terminal.element.querySelector('.terminal-cursor'); | ||
const cursor = <HTMLElement>this.terminal.element.querySelector('.terminal-cursor'); | ||
if (cursor) { | ||
// Take .xterm-rows offsetTop into account as well in case it's positioned absolutely within | ||
// the .xterm element. | ||
var xtermRows = <HTMLElement>this.terminal.element.querySelector('.xterm-rows'); | ||
var cursorTop = xtermRows.offsetTop + cursor.offsetTop; | ||
const xtermRows = <HTMLElement>this.terminal.element.querySelector('.xterm-rows'); | ||
const cursorTop = xtermRows.offsetTop + cursor.offsetTop; | ||
@@ -220,3 +217,3 @@ this.compositionView.style.left = cursor.offsetLeft + 'px'; | ||
// text is. | ||
var compositionViewBounds = this.compositionView.getBoundingClientRect(); | ||
const compositionViewBounds = this.compositionView.getBoundingClientRect(); | ||
this.textarea.style.left = cursor.offsetLeft + 'px'; | ||
@@ -229,3 +226,3 @@ this.textarea.style.top = cursorTop + 'px'; | ||
if (!dontRecurse) { | ||
setTimeout(this.updateCompositionElements.bind(this, true), 0); | ||
setTimeout(() => this.updateCompositionElements(true), 0); | ||
} | ||
@@ -232,0 +229,0 @@ }; |
@@ -21,6 +21,15 @@ /** | ||
textarea: HTMLTextAreaElement; | ||
ybase: number; | ||
ydisp: number; | ||
lines: string[]; | ||
lines: ICircularList<string>; | ||
rows: number; | ||
cols: number; | ||
browser: IBrowser; | ||
writeBuffer: string[]; | ||
children: HTMLElement[]; | ||
cursorHidden: boolean; | ||
cursorState: number; | ||
x: number; | ||
y: number; | ||
defAttr: number; | ||
@@ -35,2 +44,70 @@ /** | ||
cancel(ev: Event, force?: boolean); | ||
log(text: string): void; | ||
emit(event: string, data: any); | ||
} | ||
interface ICircularList<T> { | ||
length: number; | ||
maxLength: number; | ||
forEach(callbackfn: (value: T, index: number, array: T[]) => void): void; | ||
get(index: number): T; | ||
set(index: number, value: T): void; | ||
push(value: T): void; | ||
pop(): T; | ||
splice(start: number, deleteCount: number, ...items: T[]): void; | ||
trimStart(count: number): void; | ||
shiftElements(start: number, count: number, offset: number): void; | ||
} | ||
/** | ||
* Handles actions generated by the parser. | ||
*/ | ||
export interface IInputHandler { | ||
addChar(char: string, code: number): void; | ||
/** C0 BEL */ bell(): void; | ||
/** C0 LF */ lineFeed(): void; | ||
/** C0 CR */ carriageReturn(): void; | ||
/** C0 BS */ backspace(): void; | ||
/** C0 HT */ tab(): void; | ||
/** C0 SO */ shiftOut(): void; | ||
/** C0 SI */ shiftIn(): void; | ||
/** CSI @ */ insertChars(params?: number[]): void; | ||
/** CSI A */ cursorUp(params?: number[]): void; | ||
/** CSI B */ cursorDown(params?: number[]): void; | ||
/** CSI C */ cursorForward(params?: number[]): void; | ||
/** CSI D */ cursorBackward(params?: number[]): void; | ||
/** CSI E */ cursorNextLine(params?: number[]): void; | ||
/** CSI F */ cursorPrecedingLine(params?: number[]): void; | ||
/** CSI G */ cursorCharAbsolute(params?: number[]): void; | ||
/** CSI H */ cursorPosition(params?: number[]): void; | ||
/** CSI I */ cursorForwardTab(params?: number[]): void; | ||
/** CSI J */ eraseInDisplay(params?: number[]): void; | ||
/** CSI K */ eraseInLine(params?: number[]): void; | ||
/** CSI L */ insertLines(params?: number[]): void; | ||
/** CSI M */ deleteLines(params?: number[]): void; | ||
/** CSI P */ deleteChars(params?: number[]): void; | ||
/** CSI S */ scrollUp(params?: number[]): void; | ||
/** CSI T */ scrollDown(params?: number[]): void; | ||
/** CSI X */ eraseChars(params?: number[]): void; | ||
/** CSI Z */ cursorBackwardTab(params?: number[]): void; | ||
/** CSI ` */ charPosAbsolute(params?: number[]): void; | ||
/** CSI a */ HPositionRelative(params?: number[]): void; | ||
/** CSI b */ repeatPrecedingCharacter(params?: number[]): void; | ||
/** CSI c */ sendDeviceAttributes(params?: number[]): void; | ||
/** CSI d */ linePosAbsolute(params?: number[]): void; | ||
/** CSI e */ VPositionRelative(params?: number[]): void; | ||
/** CSI f */ HVPosition(params?: number[]): void; | ||
/** CSI g */ tabClear(params?: number[]): void; | ||
/** CSI h */ setMode(params?: number[]): void; | ||
/** CSI l */ resetMode(params?: number[]): void; | ||
/** CSI m */ charAttributes(params?: number[]): void; | ||
/** CSI n */ deviceStatus(params?: number[]): void; | ||
/** CSI p */ softReset(params?: number[]): void; | ||
/** CSI q */ setCursorStyle(params?: number[]): void; | ||
/** CSI r */ setScrollRegion(params?: number[]): void; | ||
/** CSI s */ saveCursor(params?: number[]): void; | ||
/** CSI u */ restoreCursor(params?: number[]): void; | ||
} |
var glob = require('glob'); | ||
var fs = require('fs'); | ||
var pty = require('pty.js'); | ||
var os = require('os'); | ||
var pty = require('node-pty'); | ||
var sleep = require('sleep'); | ||
var Terminal = require('../xterm'); | ||
if (os.platform() === 'win32') { | ||
// Skip tests on Windows since pty.open isn't supported | ||
return; | ||
} | ||
var CONSOLE_LOG = console.log; | ||
@@ -59,6 +65,6 @@ | ||
var line_s = ''; | ||
for (var line=0; line<term.rows; ++line) { | ||
for (var line = term.ybase; line < term.ybase + term.rows; line++) { | ||
line_s = ''; | ||
for (var cell=0; cell<term.cols; ++cell) { | ||
line_s += term.lines[line][cell][1]; | ||
line_s += term.lines.get(line)[cell][1]; | ||
} | ||
@@ -80,2 +86,5 @@ // rtrim empty cells as xterm does | ||
xterm.refresh = function() {}; | ||
xterm.viewport = { | ||
syncScrollArea: function() {} | ||
}; | ||
}); | ||
@@ -87,7 +96,13 @@ | ||
// only successful tests for now | ||
var successful = [0, 2, 6, 12, 13, 18, 20, 22, 27, 28]; | ||
console.log(files); | ||
for (var a in successful) { | ||
var i = successful[a]; | ||
(function(filename){ | ||
var skip = [ | ||
10, 16, 17, 19, 32, 33, 34, 35, 36, 39, | ||
40, 42, 43, 44, 45, 46, 47, 48, 49, 50, | ||
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, | ||
63, 68 | ||
]; | ||
for (var i = 0; i < files.length; i++) { | ||
if (skip.indexOf(i) >= 0) { | ||
continue; | ||
} | ||
(function(filename) { | ||
it(filename.split('/').slice(-1)[0], function () { | ||
@@ -98,11 +113,20 @@ pty_reset(); | ||
// uncomment this to get log from terminal | ||
console.log = function(){}; | ||
xterm.write(from_pty); | ||
//console.log = function(){}; | ||
// Perform a synchronous .write(data) | ||
xterm.writeBuffer.push(from_pty); | ||
xterm.innerWrite(); | ||
var from_emulator = terminalToString(xterm); | ||
console.log = CONSOLE_LOG; | ||
var expected = fs.readFileSync(filename.split('.')[0] + '.text', 'utf8'); | ||
if (from_emulator != expected) { | ||
// Some of the tests have whitespace on the right of lines, we trim all the linex | ||
// from xterm.js so ignore this for now at least. | ||
var expectedRightTrimmed = expected.split('\n').map(function (l) { | ||
return l.replace(/\s+$/, ''); | ||
}).join('\n'); | ||
if (from_emulator != expectedRightTrimmed) { | ||
// uncomment to get noisy output | ||
//throw new Error(formatError(in_file, from_emulator, expected)); | ||
throw new Error('mismatch'); | ||
throw new Error(formatError(in_file, from_emulator, expected)); | ||
// throw new Error('mismatch'); | ||
} | ||
@@ -109,0 +133,0 @@ }); |
@@ -17,2 +17,12 @@ var assert = require('chai').assert; | ||
}; | ||
// Force synchronous writes | ||
xterm.write = function(data) { | ||
xterm.writeBuffer.push(data); | ||
xterm.innerWrite(); | ||
}; | ||
xterm.element = { | ||
classList: { | ||
toggle: function(){} | ||
} | ||
}; | ||
}); | ||
@@ -52,3 +62,3 @@ | ||
it('should clear a buffer equal to rows', function() { | ||
var promptLine = xterm.lines[xterm.ybase + xterm.y]; | ||
var promptLine = xterm.lines.get(xterm.ybase + xterm.y); | ||
xterm.clear(); | ||
@@ -59,5 +69,5 @@ assert.equal(xterm.y, 0); | ||
assert.equal(xterm.lines.length, xterm.rows); | ||
assert.deepEqual(xterm.lines[0], promptLine); | ||
assert.deepEqual(xterm.lines.get(0), promptLine); | ||
for (var i = 1; i < xterm.rows; i++) { | ||
assert.deepEqual(xterm.lines[0], xterm.blankLine()); | ||
assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); | ||
} | ||
@@ -71,3 +81,3 @@ }); | ||
var promptLine = xterm.lines[xterm.ybase + xterm.y]; | ||
var promptLine = xterm.lines.get(xterm.ybase + xterm.y); | ||
xterm.clear(); | ||
@@ -78,9 +88,9 @@ assert.equal(xterm.y, 0); | ||
assert.equal(xterm.lines.length, xterm.rows); | ||
assert.deepEqual(xterm.lines[0], promptLine); | ||
assert.deepEqual(xterm.lines.get(0), promptLine); | ||
for (var i = 1; i < xterm.rows; i++) { | ||
assert.deepEqual(xterm.lines[i], xterm.blankLine()); | ||
assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); | ||
} | ||
}); | ||
it('should not break the prompt when cleared twice', function() { | ||
var promptLine = xterm.lines[xterm.ybase + xterm.y]; | ||
var promptLine = xterm.lines.get(xterm.ybase + xterm.y); | ||
xterm.clear(); | ||
@@ -92,5 +102,5 @@ xterm.clear(); | ||
assert.equal(xterm.lines.length, xterm.rows); | ||
assert.deepEqual(xterm.lines[0], promptLine); | ||
assert.deepEqual(xterm.lines.get(0), promptLine); | ||
for (var i = 1; i < xterm.rows; i++) { | ||
assert.deepEqual(xterm.lines[i], xterm.blankLine()); | ||
assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); | ||
} | ||
@@ -295,10 +305,29 @@ }); | ||
}); | ||
// Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100 | ||
// http://unix.stackexchange.com/a/108106 | ||
it('should return \\x1b[5D for alt+left', function() { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D | ||
describe('On non-macOS platforms', function() { | ||
beforeEach(function() { | ||
xterm.browser.isMac = false; | ||
}); | ||
// Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100 | ||
// http://unix.stackexchange.com/a/108106 | ||
it('should return \\x1b[5D for alt+left', function() { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D | ||
}); | ||
it('should return \\x1b[5C for alt+right', function() { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C | ||
}); | ||
}); | ||
it('should return \\x1b[5C for alt+right', function() { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C | ||
describe('On macOS platforms', function() { | ||
beforeEach(function() { | ||
xterm.browser.isMac = true; | ||
}); | ||
it('should return \\x1bb for alt+left', function() { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1bb'); // CSI 5 D | ||
}); | ||
it('should return \\x1bf for alt+right', function() { | ||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1bf'); // CSI 5 C | ||
}); | ||
}); | ||
it('should return \\x1b[5A for alt+up', function() { | ||
@@ -534,7 +563,7 @@ assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A | ||
xterm.write(high + String.fromCharCode(i)); | ||
var tchar = xterm.lines[0][0]; | ||
var tchar = xterm.lines.get(0)[0]; | ||
expect(tchar[1]).eql(high + String.fromCharCode(i)); | ||
expect(tchar[1].length).eql(2); | ||
expect(tchar[2]).eql(1); | ||
expect(xterm.lines[0][1][1]).eql(' '); | ||
expect(xterm.lines.get(0)[1][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -548,5 +577,5 @@ } | ||
xterm.write(high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.x-1][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.x-1][1].length).eql(2); | ||
expect(xterm.lines[1][0][1]).eql(' '); | ||
expect(xterm.lines.get(0)[xterm.x-1][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines.get(0)[xterm.x-1][1].length).eql(2); | ||
expect(xterm.lines.get(1)[0][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -561,6 +590,6 @@ } | ||
xterm.write('a' + high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.cols-1][1]).eql('a'); | ||
expect(xterm.lines[1][0][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines[1][0][1].length).eql(2); | ||
expect(xterm.lines[1][1][1]).eql(' '); | ||
expect(xterm.lines.get(0)[xterm.cols-1][1]).eql('a'); | ||
expect(xterm.lines.get(1)[0][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines.get(1)[0][1].length).eql(2); | ||
expect(xterm.lines.get(1)[1][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -575,5 +604,6 @@ } | ||
xterm.write('a' + high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.cols-1][1]).eql(high + String.fromCharCode(i)); | ||
expect(xterm.lines[0][xterm.cols-1][1].length).eql(2); | ||
expect(xterm.lines[1][1][1]).eql(' '); | ||
// auto wraparound mode should cut off the rest of the line | ||
expect(xterm.lines.get(0)[xterm.cols-1][1]).eql('a'); | ||
expect(xterm.lines.get(0)[xterm.cols-1][1].length).eql(1); | ||
expect(xterm.lines.get(1)[1][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -587,7 +617,7 @@ } | ||
xterm.write(String.fromCharCode(i)); | ||
var tchar = xterm.lines[0][0]; | ||
var tchar = xterm.lines.get(0)[0]; | ||
expect(tchar[1]).eql(high + String.fromCharCode(i)); | ||
expect(tchar[1].length).eql(2); | ||
expect(tchar[2]).eql(1); | ||
expect(xterm.lines[0][1][1]).eql(' '); | ||
expect(xterm.lines.get(0)[1][1]).eql(' '); | ||
xterm.reset(); | ||
@@ -601,5 +631,5 @@ } | ||
xterm.write('cafe\u0301'); | ||
expect(xterm.lines[0][3][1]).eql('e\u0301'); | ||
expect(xterm.lines[0][3][1].length).eql(2); | ||
expect(xterm.lines[0][3][2]).eql(1); | ||
expect(xterm.lines.get(0)[3][1]).eql('e\u0301'); | ||
expect(xterm.lines.get(0)[3][1].length).eql(2); | ||
expect(xterm.lines.get(0)[3][2]).eql(1); | ||
}); | ||
@@ -609,8 +639,8 @@ it('café - end of line', function() { | ||
xterm.write('cafe\u0301'); | ||
expect(xterm.lines[0][xterm.cols-1][1]).eql('e\u0301'); | ||
expect(xterm.lines[0][xterm.cols-1][1].length).eql(2); | ||
expect(xterm.lines[0][xterm.cols-1][2]).eql(1); | ||
expect(xterm.lines[0][1][1]).eql(' '); | ||
expect(xterm.lines[0][1][1].length).eql(1); | ||
expect(xterm.lines[0][1][2]).eql(1); | ||
expect(xterm.lines.get(0)[xterm.cols-1][1]).eql('e\u0301'); | ||
expect(xterm.lines.get(0)[xterm.cols-1][1].length).eql(2); | ||
expect(xterm.lines.get(0)[xterm.cols-1][2]).eql(1); | ||
expect(xterm.lines.get(0)[1][1]).eql(' '); | ||
expect(xterm.lines.get(0)[1][1].length).eql(1); | ||
expect(xterm.lines.get(0)[1][2]).eql(1); | ||
}); | ||
@@ -621,3 +651,3 @@ it('multiple combined é', function() { | ||
for (var i=0; i<xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
expect(tchar[1]).eql('e\u0301'); | ||
@@ -627,3 +657,3 @@ expect(tchar[1].length).eql(2); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('e\u0301'); | ||
@@ -637,3 +667,3 @@ expect(tchar[1].length).eql(2); | ||
for (var i=0; i<xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
expect(tchar[1]).eql('\uD800\uDC00\u0301'); | ||
@@ -643,3 +673,3 @@ expect(tchar[1].length).eql(3); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('\uD800\uDC00\u0301'); | ||
@@ -667,3 +697,3 @@ expect(tchar[1].length).eql(3); | ||
for (var i=0; i<xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (i % 2) { | ||
@@ -679,3 +709,3 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('¥'); | ||
@@ -690,3 +720,3 @@ expect(tchar[1].length).eql(1); | ||
for (var i=1; i<xterm.cols-1; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (!(i % 2)) { | ||
@@ -702,7 +732,7 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[0][xterm.cols-1]; | ||
tchar = xterm.lines.get(0)[xterm.cols-1]; | ||
expect(tchar[1]).eql(' '); | ||
expect(tchar[1].length).eql(1); | ||
expect(tchar[2]).eql(1); | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('¥'); | ||
@@ -717,3 +747,3 @@ expect(tchar[1].length).eql(1); | ||
for (var i=1; i<xterm.cols-1; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (!(i % 2)) { | ||
@@ -729,7 +759,7 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[0][xterm.cols-1]; | ||
tchar = xterm.lines.get(0)[xterm.cols-1]; | ||
expect(tchar[1]).eql(' '); | ||
expect(tchar[1].length).eql(1); | ||
expect(tchar[2]).eql(1); | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('¥\u0301'); | ||
@@ -743,3 +773,3 @@ expect(tchar[1].length).eql(2); | ||
for (var i=0; i<xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (i % 2) { | ||
@@ -755,3 +785,3 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('¥\u0301'); | ||
@@ -766,3 +796,3 @@ expect(tchar[1].length).eql(2); | ||
for (var i=1; i<xterm.cols-1; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (!(i % 2)) { | ||
@@ -778,7 +808,7 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[0][xterm.cols-1]; | ||
tchar = xterm.lines.get(0)[xterm.cols-1]; | ||
expect(tchar[1]).eql(' '); | ||
expect(tchar[1].length).eql(1); | ||
expect(tchar[2]).eql(1); | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('\ud843\ude6d\u0301'); | ||
@@ -792,3 +822,3 @@ expect(tchar[1].length).eql(3); | ||
for (var i=0; i<xterm.cols; ++i) { | ||
var tchar = xterm.lines[0][i]; | ||
var tchar = xterm.lines.get(0)[i]; | ||
if (i % 2) { | ||
@@ -804,3 +834,3 @@ expect(tchar[1]).eql(''); | ||
} | ||
tchar = xterm.lines[1][0]; | ||
tchar = xterm.lines.get(1)[0]; | ||
expect(tchar[1]).eql('\ud843\ude6d\u0301'); | ||
@@ -819,7 +849,7 @@ expect(tchar[1].length).eql(3); | ||
xterm.write('abcde'); | ||
expect(xterm.lines[0].length).eql(xterm.cols); | ||
expect(xterm.lines[0][10][1]).eql('a'); | ||
expect(xterm.lines[0][14][1]).eql('e'); | ||
expect(xterm.lines[0][15][1]).eql('0'); | ||
expect(xterm.lines[0][79][1]).eql('4'); | ||
expect(xterm.lines.get(0).length).eql(xterm.cols); | ||
expect(xterm.lines.get(0)[10][1]).eql('a'); | ||
expect(xterm.lines.get(0)[14][1]).eql('e'); | ||
expect(xterm.lines.get(0)[15][1]).eql('0'); | ||
expect(xterm.lines.get(0)[79][1]).eql('4'); | ||
}); | ||
@@ -832,8 +862,8 @@ it('fullwidth - insert', function() { | ||
xterm.write('¥¥¥'); | ||
expect(xterm.lines[0].length).eql(xterm.cols); | ||
expect(xterm.lines[0][10][1]).eql('¥'); | ||
expect(xterm.lines[0][11][1]).eql(''); | ||
expect(xterm.lines[0][14][1]).eql('¥'); | ||
expect(xterm.lines[0][15][1]).eql(''); | ||
expect(xterm.lines[0][79][1]).eql('3'); | ||
expect(xterm.lines.get(0).length).eql(xterm.cols); | ||
expect(xterm.lines.get(0)[10][1]).eql('¥'); | ||
expect(xterm.lines.get(0)[11][1]).eql(''); | ||
expect(xterm.lines.get(0)[14][1]).eql('¥'); | ||
expect(xterm.lines.get(0)[15][1]).eql(''); | ||
expect(xterm.lines.get(0)[79][1]).eql('3'); | ||
}); | ||
@@ -846,13 +876,13 @@ it('fullwidth - right border', function() { | ||
xterm.write('a'); | ||
expect(xterm.lines[0].length).eql(xterm.cols); | ||
expect(xterm.lines[0][10][1]).eql('a'); | ||
expect(xterm.lines[0][11][1]).eql('¥'); | ||
expect(xterm.lines[0][79][1]).eql(' '); // fullwidth char got replaced | ||
expect(xterm.lines.get(0).length).eql(xterm.cols); | ||
expect(xterm.lines.get(0)[10][1]).eql('a'); | ||
expect(xterm.lines.get(0)[11][1]).eql('¥'); | ||
expect(xterm.lines.get(0)[79][1]).eql(' '); // fullwidth char got replaced | ||
xterm.write('b'); | ||
expect(xterm.lines[0].length).eql(xterm.cols); | ||
expect(xterm.lines[0][11][1]).eql('b'); | ||
expect(xterm.lines[0][12][1]).eql('¥'); | ||
expect(xterm.lines[0][79][1]).eql(''); // empty cell after fullwidth | ||
expect(xterm.lines.get(0).length).eql(xterm.cols); | ||
expect(xterm.lines.get(0)[11][1]).eql('b'); | ||
expect(xterm.lines.get(0)[12][1]).eql('¥'); | ||
expect(xterm.lines.get(0)[79][1]).eql(''); // empty cell after fullwidth | ||
}); | ||
}); | ||
}); |
@@ -5,7 +5,7 @@ import { assert } from 'chai'; | ||
describe('Viewport', () => { | ||
var terminal; | ||
var viewportElement; | ||
var charMeasureElement; | ||
var viewport; | ||
var scrollAreaElement; | ||
let terminal; | ||
let viewportElement; | ||
let charMeasure; | ||
let viewport; | ||
let scrollAreaElement; | ||
@@ -38,8 +38,6 @@ const CHARACTER_HEIGHT = 10; | ||
}; | ||
charMeasureElement = { | ||
getBoundingClientRect: () => { | ||
return { width: null, height: CHARACTER_HEIGHT }; | ||
} | ||
charMeasure = { | ||
height: CHARACTER_HEIGHT | ||
}; | ||
viewport = new Viewport(terminal, viewportElement, scrollAreaElement, charMeasureElement); | ||
viewport = new Viewport(terminal, viewportElement, scrollAreaElement, charMeasure); | ||
}); | ||
@@ -51,5 +49,3 @@ | ||
assert.equal(terminal.rowContainer.style.lineHeight, CHARACTER_HEIGHT + 'px'); | ||
charMeasureElement.getBoundingClientRect = () => { | ||
return { width: null, height: 1 }; | ||
}; | ||
charMeasure.height = 1; | ||
viewport.refresh(); | ||
@@ -65,5 +61,3 @@ assert.equal(viewportElement.style.lineHeight, '1px'); | ||
assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); | ||
charMeasureElement.getBoundingClientRect = () => { | ||
return { width: null, height: 20 }; | ||
}; | ||
charMeasure.height = 20; | ||
viewport.refresh(); | ||
@@ -70,0 +64,0 @@ assert.equal(viewportElement.style.height, 20 + 'px'); |
@@ -6,2 +6,3 @@ /** | ||
import { ITerminal } from './Interfaces'; | ||
import { CharMeasure } from './utils/CharMeasure'; | ||
@@ -28,3 +29,3 @@ /** | ||
private scrollArea: HTMLElement, | ||
private charMeasureElement: HTMLElement | ||
private charMeasure: CharMeasure | ||
) { | ||
@@ -48,17 +49,16 @@ this.currentRowHeight = 0; | ||
*/ | ||
private refresh(charSize?: ClientRect): void { | ||
var size = charSize || this.charMeasureElement.getBoundingClientRect(); | ||
if (size.height > 0) { | ||
var rowHeightChanged = size.height !== this.currentRowHeight; | ||
private refresh(): void { | ||
if (this.charMeasure.height > 0) { | ||
const rowHeightChanged = this.charMeasure.height !== this.currentRowHeight; | ||
if (rowHeightChanged) { | ||
this.currentRowHeight = size.height; | ||
this.viewportElement.style.lineHeight = size.height + 'px'; | ||
this.terminal.rowContainer.style.lineHeight = size.height + 'px'; | ||
this.currentRowHeight = this.charMeasure.height; | ||
this.viewportElement.style.lineHeight = this.charMeasure.height + 'px'; | ||
this.terminal.rowContainer.style.lineHeight = this.charMeasure.height + 'px'; | ||
} | ||
var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows; | ||
const viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows; | ||
if (rowHeightChanged || viewportHeightChanged) { | ||
this.lastRecordedViewportHeight = this.terminal.rows; | ||
this.viewportElement.style.height = size.height * this.terminal.rows + 'px'; | ||
this.viewportElement.style.height = this.charMeasure.height * this.terminal.rows + 'px'; | ||
} | ||
this.scrollArea.style.height = (size.height * this.lastRecordedBufferLength) + 'px'; | ||
this.scrollArea.style.height = (this.charMeasure.height * this.lastRecordedBufferLength) + 'px'; | ||
} | ||
@@ -80,5 +80,4 @@ } | ||
// If size has changed, refresh viewport | ||
var size = this.charMeasureElement.getBoundingClientRect(); | ||
if (size.height !== this.currentRowHeight) { | ||
this.refresh(size); | ||
if (this.charMeasure.height !== this.currentRowHeight) { | ||
this.refresh(); | ||
} | ||
@@ -88,3 +87,3 @@ } | ||
// Sync scrollTop | ||
var scrollTop = this.terminal.ydisp * this.currentRowHeight; | ||
const scrollTop = this.terminal.ydisp * this.currentRowHeight; | ||
if (this.viewportElement.scrollTop !== scrollTop) { | ||
@@ -101,4 +100,4 @@ this.viewportElement.scrollTop = scrollTop; | ||
private onScroll(ev: Event) { | ||
var newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight); | ||
var diff = newRow - this.terminal.ydisp; | ||
const newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight); | ||
const diff = newRow - this.terminal.ydisp; | ||
this.terminal.scrollDisp(diff, true); | ||
@@ -119,3 +118,3 @@ } | ||
// Fallback to WheelEvent.DOM_DELTA_PIXEL | ||
var multiplier = 1; | ||
let multiplier = 1; | ||
if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { | ||
@@ -122,0 +121,0 @@ multiplier = this.currentRowHeight; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
1354662
122
23322
0
138
0
26
13