Compare commits

...
50 Commits
Author SHA1 Message Date
Paris Kasidiaris 521d7dbdaa Bump version to 2.1.0
Signed-off-by: Paris Kasidiaris <paris@sourcelair.com>
2016-11-08 22:51:33 +00:00
Paris Kasidiaris 2cba2ff3d4 Merge pull request #345 from hiro-su/fix-ie11-right-click-paste
Fix the right click paste in IE11
2016-11-08 13:21:12 +02:00
hiro-su 547db92693 Fix the right click paste in IE11 2016-11-08 14:56:57 +09:00
Paris Kasidiaris bf334238b7 Merge pull request #339 from hiro-su/fix-ie11-copy-event
Fixed copy event in IE11
2016-11-05 15:27:50 +00:00
hiro-su 5808de648b Fixed copy event in IE11 2016-11-05 23:55:34 +09:00
Paris Kasidiaris 9ab0455b05 Merge pull request #342 from sourcelair/issue-#310-cross-browser-right-click
Make right-click work on all browsers
2016-11-04 20:40:53 +00:00
Paris Kasidiaris 55ab36662a Merge pull request #336 from sourcelair/issue-#216-no-auto-scroll-on-output
Stop auto scrolling to bottom on output
2016-11-04 19:55:07 +00:00
Paris Kasidiaris b1ad564b0d Actually fix tests 2016-11-04 21:48:53 +02:00
Paris Kasidiaris bc70b3b37d Fix tests 2016-11-04 19:36:30 +02:00
Paris Kasidiaris d426c99866 Move all browser/platform detecting in utils/Browser.js 2016-11-04 18:41:00 +02:00
Paris Kasidiaris 356377975b Fix right-click for Firefox and IE
Fix #310
2016-11-04 18:33:04 +02:00
Paris Kasidiaris 0de3d839e6 Improve experience and add test
- Scroll to bottom on keydown (when scrolled up)
- Add test to ensure above behavior
2016-11-04 12:29:17 +00:00
Paris Kasidiaris 0fcd6b1d22 Merge pull request #337 from IanLewis/master
Add main property to bower.json
2016-11-04 09:35:24 +00:00
Ian Lewis 99b5464392 Add main property to bower.json
This patch adds the main property to the project's bower.json for better
interoperability with tools like wiredep etc.
2016-11-03 17:56:58 +05:30
Paris Kasidiaris 70965a8fd6 Merge pull request #334 from hiro-su/fix-ie11-paste-key
Fixed paste key in IE11
2016-11-02 09:19:18 +00:00
hiro-su 77ca15497c Fixed paste key in IE11 2016-11-02 11:17:37 +09:00
Paris Kasidiaris 26de9fe4c5 Merge pull request #332 from sourcelair/issue-#331-fix-no-selection-range
Consider click not on selection, when s.rangeCount is 0
2016-10-31 18:52:48 +00:00
Paris Kasidiaris 00dcb4f6e3 Consider click not on selection, when s.rangeCount is 0 2016-10-31 15:06:00 +02:00
Daniel Imms 996c641a79 Merge pull request #328 from Tyriar/327_fix_random_line_wrap
Force nowrap on each line
2016-10-27 07:52:48 -07:00
Daniel Imms a077860464 Force nowrap on each line
Fixes #327
2016-10-26 18:07:55 -07:00
Mikko Karvonen 5e68acfc76 Quick fix to prevent terminal scrolling when user is looking into scrollback. 2016-10-25 13:54:57 +03:00
Daniel Imms 269540bfed Merge pull request #323 from Tyriar/322_ime_bad_position
Fix the textarea in the composition view's pos when composing
2016-10-24 14:58:41 -07:00
Daniel Imms 868f15173d Fix the textarea in the composition view's pos when composing
Fixes #322
2016-10-24 11:06:25 -07:00
Paris Kasidiaris 06a93344bb Merge pull request #321 from sourcelair/issue-#313-document-terminal-constructor
Issue #313 document terminal constructor
2016-10-24 19:01:37 +03:00
Paris Kasidiaris e8e7870be2 Remove geometry option from terminal consttructor 2016-10-23 17:55:37 +03:00
Paris Kasidiaris a9417c6878 Fix term.geometry and document it in constructor options
Set `term.geometry` on terminal creation and on resize
2016-10-23 14:22:00 +00:00
Paris Kasidiaris 605d61b64f Ignore .env files that set the environment 2016-10-23 14:22:00 +00:00
Daniel Imms 8feaacf57e Merge pull request #320 from Tyriar/299_keep_textarea_in_viewport
Correctly size and position the composition view
2016-10-23 07:16:28 -07:00
Daniel Imms 553c651166 Correctly size and position the composition view 2016-10-22 16:27:17 -07:00
Daniel Imms 1ec0bac9c6 Keep composition textarea within viewport
Part of #299
2016-10-22 15:41:55 -07:00
Paris Kasidiaris b1c6ae8a06 Merge pull request #303 from staticfloat/sf/terminado
Add `Terminado` example
2016-10-17 21:03:49 +03:00
Daniel Imms 8a124d0b35 Merge pull request #308 from Tyriar/294_scroll
Implement scrollPages, scrollToTop, scrollToBottom and add scroll tests
2016-10-10 08:33:09 -07:00
Daniel Imms 0ad02a4afa Add note that negative scrolls up on scrollPages 2016-10-10 08:25:01 -07:00
Daniel Imms 9389f899d7 Merge pull request #309 from Tyriar/fix_indentation
Fix jsdoc indentation
2016-10-10 08:20:56 -07:00
Paris Kasidiaris 050a34921b Merge pull request #304 from sourcelair/update-addons-paths
Make add-ons load Terminal from dist
2016-10-10 10:12:50 +03:00
Daniel Imms 32e878db81 Fix jsdoc indentation 2016-10-09 13:23:22 -07:00
Daniel Imms 0bf7bf56a5 Add jsdoc to scrollTo functions 2016-10-09 13:20:33 -07:00
Daniel Imms e5d130b698 Add scrollToBottom 2016-10-09 13:19:11 -07:00
Daniel Imms 941e57a218 Add tests for scrollPages 2016-10-09 13:10:18 -07:00
Daniel Imms c02eea6ad3 Add tests for scrollDisp 2016-10-09 13:08:08 -07:00
Daniel Imms fe0d878b23 Implement scrollPages 2016-10-09 12:51:58 -07:00
Paris Kasidiaris 763f148fa1 Remove __dirname usage from loadAddon 2016-10-09 13:17:17 +03:00
Elliot Saba 8f0ada708f Make naming a little more self-consistent 2016-10-08 20:09:34 -07:00
Paris Kasidiaris 8117999ab3 Fix tests 2016-10-08 12:22:18 +03:00
Elliot Saba 10dd22a3d4 Rename Terminado attach and detach functions 2016-10-08 00:36:08 -07:00
Elliot Saba fe54da34f8 Add terminado.js, an addon for connecting to Terminado backends 2016-10-07 13:33:10 -07:00
Daniel Imms 09de0f31fa Merge pull request #301 from Tyriar/300_top_textarea_helper
Add top to textarea helper
2016-10-05 09:33:08 -07:00
Paris Kasidiaris 6ee524864e Make add-ons load the latest built version 2016-10-05 13:23:45 +03:00
Elliot Saba 8fd350f0fc Add Terminado example 2016-10-05 00:32:39 -07:00
Daniel Imms ebbeeefd86 Add top to textarea helper
Fixes #300
2016-10-04 19:03:15 -07:00
22 changed files with 654 additions and 159 deletions
+1
View File
@@ -11,3 +11,4 @@ example/*.log
docs/
npm-debug.log
/.idea/
.env
+4
View File
@@ -14,9 +14,13 @@ Daniel Imms <daimms@microsoft.com>
Daniel Risacher <drisacher@gmail.com>
Dan Kaplun <dbkaplun@twitch.tv>
Darin Morrison <freebroccolo@users.noreply.github.com>
Elliot Saba <staticfloat@gmail.com>
hiro-su <h.sugipon@gmail.com>
Ian Lewis <ianlewis@google.com>
imoses <ido@twiggle.com>
Jean Bruenn <himself@jeanbruenn.info>
Jörg Breitbart <jerch@rockborn.de>
Mikko Karvonen <mikko.karvonen@arm.com>
Paris Kasidiaris <pariskasidiaris@gmail.com>
Paris Kasidiaris <paris@sourcelair.com>
runarberg <runar@greenqloud.com>
+2 -2
View File
@@ -11,12 +11,12 @@
/*
* CommonJS environment
*/
module.exports = attach(require('../../src/xterm'));
module.exports = attach(require('../../dist/xterm'));
} else if (typeof define == 'function') {
/*
* Require.js is available
*/
define(['../../src/xterm'], attach);
define(['../../dist/xterm'], attach);
} else {
/*
* Plain browser environment
+2 -2
View File
@@ -16,12 +16,12 @@
/*
* CommonJS environment
*/
module.exports = fit(require('../../src/xterm'));
module.exports = fit(require('../../dist/xterm'));
} else if (typeof define == 'function') {
/*
* Require.js is available
*/
define(['../../src/xterm'], fit);
define(['../../dist/xterm'], fit);
} else {
/*
* Plain browser environment
+2 -2
View File
@@ -15,12 +15,12 @@
/*
* CommonJS environment
*/
module.exports = fullscreen(require('../../src/xterm'));
module.exports = fullscreen(require('../../dist/xterm'));
} else if (typeof define == 'function') {
/*
* Require.js is available
*/
define(['../../src/xterm'], fullscreen);
define(['../../dist/xterm'], fullscreen);
} else {
/*
* Plain browser environment
+2 -2
View File
@@ -3,12 +3,12 @@
/*
* CommonJS environment
*/
module.exports = linkify(require('../../src/xterm'));
module.exports = linkify(require('../../dist/xterm'));
} else if (typeof define == 'function') {
/*
* Require.js is available
*/
define(['../../src/xterm'], linkify);
define(['../../dist/xterm'], linkify);
} else {
/*
* Plain browser environment
+5
View File
@@ -0,0 +1,5 @@
{
"name": "xterm.terminado",
"main": "terminado.js",
"private": true
}
+142
View File
@@ -0,0 +1,142 @@
/*
* Implements the attach method that
* attaches the terminal to a Terminado WebSocket stream.
*
* The bidirectional argument indicates, whether the terminal should
* send data to the socket as well and is true, by default.
*/
(function (attach) {
if (typeof exports === 'object' && typeof module === 'object') {
/*
* CommonJS environment
*/
module.exports = attach(require('../../src/xterm'));
} else if (typeof define == 'function') {
/*
* Require.js is available
*/
define(['../../src/xterm'], attach);
} else {
/*
* Plain browser environment
*/
attach(window.Terminal);
}
})(function (Xterm) {
'use strict';
/**
* This module provides methods for attaching a terminal to a WebSocket
* stream.
*
* @module xterm/addons/attach/attach
*/
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));
};
/**
* 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;
});
+6 -2
View File
@@ -1,5 +1,9 @@
{
"name": "xterm.js",
"version": "2.0.1",
"ignore": ["demo", "test", ".gitignore"]
"version": "2.1.0",
"ignore": ["demo", "test", ".gitignore"],
"main": [
"dist/xterm.js",
"dist/xterm.css"
]
}
+10
View File
@@ -61,9 +61,14 @@
position: absolute;
opacity: 0;
left: -9999em;
top: -9999em;
width: 0;
height: 0;
z-index: -10;
/** Prevent wrapping so the IME appears against the textarea at the correct position */
white-space: nowrap;
overflow: hidden;
resize: none;
}
.terminal .terminal-cursor {
@@ -117,6 +122,11 @@
top: 0;
}
.terminal .xterm-rows > div {
/* Lines containing spans and text nodes ocassionally wrap despite being the same width (#327) */
white-space: nowrap;
}
.terminal .xterm-scroll-area {
visibility: hidden;
}
+156 -58
View File
@@ -184,11 +184,23 @@ CompositionHelper.prototype.updateCompositionElements = function (dontRecurse) {
}
var cursor = 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 = this.terminal.element.querySelector('.xterm-rows');
var cursorTop = xtermRows.offsetTop + cursor.offsetTop;
this.compositionView.style.left = cursor.offsetLeft + 'px';
this.compositionView.style.top = cursor.offsetTop + 'px';
this.compositionView.style.top = cursorTop + 'px';
this.compositionView.style.height = cursor.offsetHeight + 'px';
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();
this.textarea.style.left = cursor.offsetLeft + compositionViewBounds.width + 'px';
this.textarea.style.top = cursor.offsetTop + cursor.offsetHeight + 'px';
this.textarea.style.left = cursor.offsetLeft + 'px';
this.textarea.style.top = cursorTop + 'px';
this.textarea.style.width = compositionViewBounds.width + 'px';
this.textarea.style.height = compositionViewBounds.height + 'px';
this.textarea.style.lineHeight = compositionViewBounds.height + 'px';
}
if (!dontRecurse) {
setTimeout(this.updateCompositionElements.bind(this, true), 0);
@@ -442,11 +454,16 @@ function prepareTextForClipboard(text) {
* Binds copy functionality to the given terminal.
* @param {ClipboardEvent} ev The original copy event to be handled
*/
function copyHandler(ev) {
function copyHandler(ev, term) {
var copiedText = window.getSelection().toString(),
text = prepareTextForClipboard(copiedText);
ev.clipboardData.setData('text/plain', text);
if (term.browser.isMSIE) {
window.clipboardData.setData('Text', text);
} else {
ev.clipboardData.setData('text/plain', text);
}
ev.preventDefault(); // Prevent or the original text will be copied.
}
@@ -457,11 +474,23 @@ function copyHandler(ev) {
*/
function pasteHandler(ev, term) {
ev.stopPropagation();
if (ev.clipboardData) {
var text = ev.clipboardData.getData('text/plain');
var dispatchPaste = function dispatchPaste(text) {
term.handler(text);
term.textarea.value = '';
return term.cancel(ev);
};
if (term.browser.isMSIE) {
if (window.clipboardData) {
var text = window.clipboardData.getData('Text');
dispatchPaste(text);
}
} else {
if (ev.clipboardData) {
var text = ev.clipboardData.getData('text/plain');
dispatchPaste(text);
}
}
}
@@ -480,37 +509,41 @@ function pasteHandler(ev, term) {
*/
function rightClickHandler(ev, term) {
var s = document.getSelection(),
sText = prepareTextForClipboard(s.toString()),
r = s.getRangeAt(0);
selectedText = prepareTextForClipboard(s.toString()),
clickIsOnSelection = false;
var x = ev.clientX,
y = ev.clientY;
if (s.rangeCount) {
var r = s.getRangeAt(0),
cr = r.getClientRects(),
x = ev.clientX,
y = ev.clientY,
i,
rect;
var cr = r.getClientRects(),
clickIsOnSelection = false,
i,
rect;
for (i = 0; i < cr.length; i++) {
rect = cr[i];
clickIsOnSelection = x > rect.left && x < rect.right && y > rect.top && y < rect.bottom;
for (i = 0; i < cr.length; i++) {
rect = cr[i];
clickIsOnSelection = x > rect.left && x < rect.right && y > rect.top && y < rect.bottom;
if (clickIsOnSelection) {
break;
}
}
// 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 &nbsp;
// and there is not much pointing in copying a single space.
// Single space is char
if (clickIsOnSelection && sText !== ' ') {
break;
if (selectedText.match(/^\s$/) || !selectedText.length) {
clickIsOnSelection = false;
}
}
// Bring textarea at the cursor position
if (!clickIsOnSelection) {
term.textarea.style.position = 'fixed';
term.textarea.style.width = '10px';
term.textarea.style.height = '10px';
term.textarea.style.left = x + 'px';
term.textarea.style.top = y + 'px';
term.textarea.style.width = '20px';
term.textarea.style.height = '20px';
term.textarea.style.left = x - 10 + 'px';
term.textarea.style.top = y - 10 + 'px';
term.textarea.style.zIndex = 1000;
term.textarea.focus();
@@ -522,7 +555,7 @@ function rightClickHandler(ev, term) {
term.textarea.style.left = null;
term.textarea.style.top = null;
term.textarea.style.zIndex = null;
}, 1);
}, 4);
}
}
@@ -532,7 +565,67 @@ exports.pasteHandler = pasteHandler;
exports.rightClickHandler = rightClickHandler;
},{}],5:[function(_dereq_,module,exports){
(function (__dirname){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isMSWindows = exports.isIphone = exports.isIpad = exports.isMac = exports.isMSIE = exports.isFirefox = undefined;
var _Generic = _dereq_('./Generic.js');
var isNode = typeof navigator == 'undefined' ? true : false; /**
* xterm.js: xterm, in the browser
* Copyright (c) 2016, SourceLair Private Company <www.sourcelair.com> (MIT License)
*/
/**
* Browser utilities module. This module contains attributes and methods to help with
* identifying the current browser and platform.
* @module xterm/utils/Browser
*/
var userAgent = isNode ? 'node' : navigator.userAgent;
var platform = isNode ? 'node' : navigator.platform;
var isFirefox = exports.isFirefox = !!~userAgent.indexOf('Firefox');
var isMSIE = 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
var isMac = exports.isMac = (0, _Generic.contains)(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], platform);
var isIpad = exports.isIpad = platform === 'iPad';
var isIphone = exports.isIphone = platform === 'iPhone';
var isMSWindows = exports.isMSWindows = (0, _Generic.contains)(['Windows', 'Win16', 'Win32', 'WinCE'], platform);
},{"./Generic.js":6}],6:[function(_dereq_,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
/**
* xterm.js: xterm, in the browser
* Copyright (c) 2016, SourceLair Private Company <www.sourcelair.com> (MIT License)
*/
/**
* Generic utilities module. This module contains generic methods that can be helpful at
* different parts of the code base.
* @module xterm/utils/Generic
*/
/**
* 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
*/
var contains = exports.contains = function contains(arr, el) {
return arr.indexOf(el) >= 0;
};
},{}],7:[function(_dereq_,module,exports){
'use strict';var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};/**
* xterm.js: xterm, in the browser
* Copyright (c) 2014-2014, SourceLair Private Company <www.sourcelair.com> (MIT License)
@@ -564,7 +657,7 @@ exports.rightClickHandler = rightClickHandler;
* The original design remains. The terminal itself
* has been extended to include xterm CSI codes, among
* other features.
*/var _CompositionHelper=_dereq_('./CompositionHelper.js');var _EventEmitter=_dereq_('./EventEmitter.js');var _Viewport=_dereq_('./Viewport.js');var _Clipboard=_dereq_('./handlers/Clipboard.js');/**
*/var _CompositionHelper=_dereq_('./CompositionHelper.js');var _EventEmitter=_dereq_('./EventEmitter.js');var _Viewport=_dereq_('./Viewport.js');var _Clipboard=_dereq_('./handlers/Clipboard.js');var _Browser=_dereq_('./utils/Browser');var Browser=_interopRequireWildcard(_Browser);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}}/**
* Terminal Emulation References:
* http://vt100.net/
* http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt
@@ -582,14 +675,16 @@ var document=typeof window!='undefined'?window.document:null;/**
* Creates a new `Terminal` object.
*
* @param {object} options An object containing a set of options, the available options are:
* - cursorBlink (boolean): Whether the terminal cursor blinks
* - `cursorBlink` (boolean): Whether the terminal cursor blinks
* - `cols` (number): The number of columns of the terminal (horizontal size)
* - `rows` (number): The number of rows of the terminal (vertical size)
*
* @public
* @class Xterm Xterm
* @alias module:xterm/src/xterm
*/function Terminal(options){var self=this;if(!(this instanceof Terminal)){return new Terminal(arguments[0],arguments[1],arguments[2]);}self.cancel=Terminal.cancel;_EventEmitter.EventEmitter.call(this);if(typeof options==='number'){options={cols:arguments[0],rows:arguments[1],handler:arguments[2]};}options=options||{};Object.keys(Terminal.defaults).forEach(function(key){if(options[key]==null){options[key]=Terminal.options[key];if(Terminal[key]!==Terminal.defaults[key]){options[key]=Terminal[key];}}self[key]=options[key];});if(options.colors.length===8){options.colors=options.colors.concat(Terminal._colors.slice(8));}else if(options.colors.length===16){options.colors=options.colors.concat(Terminal._colors.slice(16));}else if(options.colors.length===10){options.colors=options.colors.slice(0,-2).concat(Terminal._colors.slice(8,-2),options.colors.slice(-2));}else if(options.colors.length===18){options.colors=options.colors.concat(Terminal._colors.slice(16,-2),options.colors.slice(-2));}this.colors=options.colors;this.options=options;// this.context = options.context || window;
*/function Terminal(options){var self=this;if(!(this instanceof Terminal)){return new Terminal(arguments[0],arguments[1],arguments[2]);}self.browser=Browser;self.cancel=Terminal.cancel;_EventEmitter.EventEmitter.call(this);if(typeof options==='number'){options={cols:arguments[0],rows:arguments[1],handler:arguments[2]};}options=options||{};Object.keys(Terminal.defaults).forEach(function(key){if(options[key]==null){options[key]=Terminal.options[key];if(Terminal[key]!==Terminal.defaults[key]){options[key]=Terminal[key];}}self[key]=options[key];});if(options.colors.length===8){options.colors=options.colors.concat(Terminal._colors.slice(8));}else if(options.colors.length===16){options.colors=options.colors.concat(Terminal._colors.slice(16));}else if(options.colors.length===10){options.colors=options.colors.slice(0,-2).concat(Terminal._colors.slice(8,-2),options.colors.slice(-2));}else if(options.colors.length===18){options.colors=options.colors.concat(Terminal._colors.slice(16,-2),options.colors.slice(-2));}this.colors=options.colors;this.options=options;// this.context = options.context || window;
// this.document = options.document || document;
this.parent=options.body||options.parent||(document?document.getElementsByTagName('body')[0]:null);this.cols=options.cols||options.geometry[0];this.rows=options.rows||options.geometry[1];if(options.handler){this.on('data',options.handler);}/**
this.parent=options.body||options.parent||(document?document.getElementsByTagName('body')[0]:null);this.cols=options.cols||options.geometry[0];this.rows=options.rows||options.geometry[1];this.geometry=[this.cols,this.rows];if(options.handler){this.on('data',options.handler);}/**
* The scroll position of the y cursor, ie. ybase + y = the y position within the entire
* buffer
*/this.ybase=0;/**
@@ -612,7 +707,8 @@ this.readable=true;this.writable=true;this.defAttr=0<<18|257<<9|256<<0;this.curA
this.surrogate_high='';/**
* An array of all lines in the entire buffer, including the prompt. The lines are array of
* characters which are 2-length arrays where [0] is an attribute and [1] is the character.
*/this.lines=[];var i=this.rows;while(i--){this.lines.push(this.blankLine());}this.tabs;this.setupStops();}inherits(Terminal,_EventEmitter.EventEmitter);/**
*/this.lines=[];var i=this.rows;while(i--){this.lines.push(this.blankLine());}this.tabs;this.setupStops();// Store if user went browsing history in scrollback
this.userScrolling=false;}inherits(Terminal,_EventEmitter.EventEmitter);/**
* back_color_erase feature for xterm.
*/Terminal.prototype.eraseAttr=function(){// if (this.is('screen')) return this.defAttr;
return this.defAttr&~0x1ff|this.curAttr&0x1ff;};/**
@@ -650,7 +746,7 @@ i=0;for(;i<24;i++){r=8+i*10;out(r,r,r);}function out(r,g,b){colors.push('#'+hex(
*/Terminal.bindBlur=function(term){on(term.textarea,'blur',function(ev){term.refresh(term.y,term.y);if(term.sendFocus){term.send('\x1b[O');}term.element.classList.remove('focus');Terminal.focus=null;term.emit('blur',{terminal:term});});};/**
* Initialize default behavior
*/Terminal.prototype.initGlobal=function(){var term=this;Terminal.bindKeys(this);Terminal.bindFocus(this);Terminal.bindBlur(this);// Bind clipboard functionality
on(this.element,'copy',_Clipboard.copyHandler);on(this.textarea,'paste',function(ev){_Clipboard.pasteHandler.call(this,ev,term);});on(this.element,'contextmenu',function(ev){_Clipboard.rightClickHandler.call(this,ev,term);});};/**
on(this.element,'copy',function(ev){_Clipboard.copyHandler.call(this,ev,term);});on(this.textarea,'paste',function(ev){_Clipboard.pasteHandler.call(this,ev,term);});function rightClickHandlerWrapper(ev){_Clipboard.rightClickHandler.call(this,ev,term);}if(term.browser.isFirefox){on(this.element,'mousedown',function(ev){if(ev.button==2){rightClickHandlerWrapper(ev);}});}else{on(this.element,'contextmenu',rightClickHandlerWrapper);}};/**
* Apply key handling to the terminal
*/Terminal.bindKeys=function(term){on(term.element,'keydown',function(ev){if(document.activeElement!=this){return;}term.keyDown(ev);},true);on(term.element,'keypress',function(ev){if(document.activeElement!=this){return;}term.keyPress(ev);},true);on(term.element,'keyup',term.focus.bind(term));on(term.textarea,'keydown',function(ev){term.keyDown(ev);},true);on(term.textarea,'keypress',function(ev){term.keyPress(ev);// Truncate the textarea's value, since it is not needed
this.value='';},true);on(term.textarea,'compositionstart',term.compositionHelper.compositionstart.bind(term.compositionHelper));on(term.textarea,'compositionupdate',term.compositionHelper.compositionupdate.bind(term.compositionHelper));on(term.textarea,'compositionend',term.compositionHelper.compositionend.bind(term.compositionHelper));term.on('refresh',term.compositionHelper.updateCompositionElements.bind(term.compositionHelper));};/**
@@ -662,11 +758,7 @@ this.value='';},true);on(term.textarea,'compositionstart',term.compositionHelper
*
* @param {HTMLElement} parent The element to create the terminal within.
*/Terminal.prototype.open=function(parent){var self=this,i=0,div;this.parent=parent||this.parent;if(!this.parent){throw new Error('Terminal requires a parent element.');}// Grab global elements
this.context=this.parent.ownerDocument.defaultView;this.document=this.parent.ownerDocument;this.body=this.document.getElementsByTagName('body')[0];// Parse User-Agent
if(this.context.navigator&&this.context.navigator.userAgent){this.isMSIE=!!~this.context.navigator.userAgent.indexOf('MSIE');}// Find the users platform. We use this to interpret the meta key
// and ISO third level shifts.
// http://stackoverflow.com/q/19877924/577598
if(this.context.navigator&&this.context.navigator.platform){this.isMac=contains(this.context.navigator.platform,['Macintosh','MacIntel','MacPPC','Mac68K']);this.isIpad=this.context.navigator.platform==='iPad';this.isIphone=this.context.navigator.platform==='iPhone';this.isMSWindows=contains(this.context.navigator.platform,['Windows','Win16','Win32','WinCE']);}//Create main element container
this.context=this.parent.ownerDocument.defaultView;this.document=this.parent.ownerDocument;this.body=this.document.getElementsByTagName('body')[0];//Create main element container
this.element=this.document.createElement('div');this.element.classList.add('terminal');this.element.classList.add('xterm');this.element.classList.add('xterm-theme-'+this.theme);this.element.style.height;this.element.setAttribute('tabindex',0);this.viewportElement=document.createElement('div');this.viewportElement.classList.add('xterm-viewport');this.element.appendChild(this.viewportElement);this.viewportScrollArea=document.createElement('div');this.viewportScrollArea.classList.add('xterm-scroll-area');this.viewportElement.appendChild(this.viewportScrollArea);// Create the container that will hold the lines of the terminal and then
// produce the lines the lines.
this.rowContainer=document.createElement('div');this.rowContainer.classList.add('xterm-rows');this.element.appendChild(this.rowContainer);this.children=[];// Create the container that will hold helpers like the textarea for
@@ -685,7 +777,7 @@ if(Terminal.brokenBold==null){Terminal.brokenBold=isBoldBroken(this.document);}t
* @param {string} addon The name of the addon to load
* @static
*/Terminal.loadAddon=function(addon,callback){if((typeof exports==='undefined'?'undefined':_typeof(exports))==='object'&&(typeof module==='undefined'?'undefined':_typeof(module))==='object'){// CommonJS
return _dereq_(__dirname+'/../addons/'+addon);}else if(typeof define=='function'){// RequireJS
return _dereq_('../addons/'+addon);}else if(typeof define=='function'){// RequireJS
return _dereq_(['../addons/'+addon+'/'+addon],callback);}else{console.error('Cannot load a module without a CommonJS or RequireJS environment.');return false;}};/**
* XTerm mouse events
* http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
@@ -732,7 +824,7 @@ button&=3;pos.x-=32;pos.y-=32;if(button===0)button=2;else if(button===1)button=4
// 3 = release
// wheel up/down:
// 1, and 2 - with 64 added
switch(ev.overrideType||ev.type){case'mousedown':button=ev.button!=null?+ev.button:ev.which!=null?ev.which-1:null;if(self.isMSIE){button=button===1?0:button===4?1:button;}break;case'mouseup':button=3;break;case'DOMMouseScroll':button=ev.detail<0?64:65;break;case'wheel':button=ev.wheelDeltaY>0?64:65;break;}// next three bits are the modifiers:
switch(ev.overrideType||ev.type){case'mousedown':button=ev.button!=null?+ev.button:ev.which!=null?ev.which-1:null;if(self.browser.isMSIE){button=button===1?0:button===4?1:button;}break;case'mouseup':button=3;break;case'DOMMouseScroll':button=ev.detail<0?64:65;break;case'wheel':button=ev.wheelDeltaY>0?64:65;break;}// next three bits are the modifiers:
// 4 = shift, 8 = meta, 16 = control
shift=ev.shiftKey?4:0;meta=ev.metaKey?8:0;ctrl=ev.ctrlKey?16:0;mod=shift|meta|ctrl;// no mods
if(self.vt200Mouse){// ctrl only
@@ -812,24 +904,31 @@ if(flags&1&&fg<8)fg+=8;}if(flags&Terminal.flags.INVISIBLE){classNames.push('xter
* Display the cursor element
*/Terminal.prototype.showCursor=function(){if(!this.cursorState){this.cursorState=1;this.refresh(this.y,this.y);}};/**
* Scroll the terminal
*/Terminal.prototype.scroll=function(){var row;if(++this.ybase===this.scrollback){this.ybase=this.ybase/2|0;this.lines=this.lines.slice(-(this.ybase+this.rows)+1);}this.ydisp=this.ybase;// last line
*/Terminal.prototype.scroll=function(){var row;if(++this.ybase===this.scrollback){this.ybase=this.ybase/2|0;this.lines=this.lines.slice(-(this.ybase+this.rows)+1);}if(!this.userScrolling){this.ydisp=this.ybase;}// last line
row=this.ybase+this.rows-1;// subtract the bottom scroll region
row-=this.rows-1-this.scrollBottom;if(row===this.lines.length){// potential optimization:
// pushing is faster than splicing
// when they amount to the same
// behavior.
this.lines.push(this.blankLine());}else{// add our new line
this.lines.splice(row,0,this.blankLine());}if(this.scrollTop!==0){if(this.ybase!==0){this.ybase--;this.ydisp=this.ybase;}this.lines.splice(this.ybase+this.scrollTop,1);}// this.maxRange();
this.lines.splice(row,0,this.blankLine());}if(this.scrollTop!==0){if(this.ybase!==0){this.ybase--;if(!this.userScrolling){this.ydisp=this.ybase;}}this.lines.splice(this.ybase+this.scrollTop,1);}// this.maxRange();
this.updateRange(this.scrollTop);this.updateRange(this.scrollBottom);this.emit('scroll',this.ydisp);};/**
* Scroll the display of the terminal
* @param {number} disp The number of lines to scroll down (negatives scroll up).
* @param {boolean} suppressScrollEvent Don't emit the scroll event as scrollDisp. This is used
* to avoid unwanted events being handled by the veiwport when the event was triggered from the
* viewport originally.
*/Terminal.prototype.scrollDisp=function(disp,suppressScrollEvent){this.ydisp+=disp;if(this.ydisp>this.ybase){this.ydisp=this.ybase;}else if(this.ydisp<0){this.ydisp=0;}if(!suppressScrollEvent){this.emit('scroll',this.ydisp);}this.refresh(0,this.rows-1);};/**
*/Terminal.prototype.scrollDisp=function(disp,suppressScrollEvent){if(disp<0){this.userScrolling=true;}else if(disp+this.ydisp>=this.ybase){this.userScrolling=false;}this.ydisp+=disp;if(this.ydisp>this.ybase){this.ydisp=this.ybase;}else if(this.ydisp<0){this.ydisp=0;}if(!suppressScrollEvent){this.emit('scroll',this.ydisp);}this.refresh(0,this.rows-1);};/**
* Scroll the display of the terminal by a number of pages.
* @param {number} pageCount The number of pages to scroll (negative scrolls up).
*/Terminal.prototype.scrollPages=function(pageCount){this.scrollDisp(pageCount*(this.rows-1));};/**
* Scrolls the display of the terminal to the top.
*/Terminal.prototype.scrollToTop=function(){this.scrollDisp(-this.ydisp);};/**
* Scrolls the display of the terminal to the bottom.
*/Terminal.prototype.scrollToBottom=function(){this.scrollDisp(this.ybase-this.ydisp);};/**
* Writes text to the terminal.
* @param {string} text The text to write to the terminal.
*/Terminal.prototype.write=function(data){var l=data.length,i=0,j,cs,ch,code,low,ch_width,row;this.refreshStart=this.y;this.refreshEnd=this.y;if(this.ybase!==this.ydisp){this.ydisp=this.ybase;this.emit('scroll',this.ydisp);this.maxRange();}// apply leftover surrogate high from last write
*/Terminal.prototype.write=function(data){var l=data.length,i=0,j,cs,ch,code,low,ch_width,row;this.refreshStart=this.y;this.refreshEnd=this.y;// apply leftover surrogate high from last write
if(this.surrogate_high){data=this.surrogate_high+data;this.surrogate_high='';}for(;i<l;i++){ch=data[i];// FIXME: higher chars than 0xa0 are not allowed in escape sequences
// --> maybe move to default
code=data.charCodeAt(i);if(0xD800<=code&&code<=0xDBFF){// we got a surrogate high
@@ -1204,7 +1303,8 @@ if(ch==='\x1b'||ch==='\x07'){if(ch==='\x1b')i++;this.state=normal;}break;}}this.
* Key Resources:
* - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
* @param {KeyboardEvent} ev The keydown event to be handled.
*/Terminal.prototype.keyDown=function(ev){if(this.customKeydownHandler&&this.customKeydownHandler(ev)===false){return false;}if(!this.compositionHelper.keydown.bind(this.compositionHelper)(ev)){return false;}var self=this;var result=this.evaluateKeyEscapeSequence(ev);if(result.scrollDisp){this.scrollDisp(result.scrollDisp);return this.cancel(ev,true);}if(isThirdLevelShift(this,ev)){return true;}if(result.cancel){// The event is canceled at the end already, is this necessary?
*/Terminal.prototype.keyDown=function(ev){// Scroll down to prompt, whenever the user presses a key.
if(this.ybase!==this.ydisp){this.scrollToBottom();}if(this.customKeydownHandler&&this.customKeydownHandler(ev)===false){return false;}if(!this.compositionHelper.keydown.bind(this.compositionHelper)(ev)){return false;}var self=this;var result=this.evaluateKeyEscapeSequence(ev);if(result.scrollDisp){this.scrollDisp(result.scrollDisp);return this.cancel(ev,true);}if(isThirdLevelShift(this,ev)){return true;}if(result.cancel){// The event is canceled at the end already, is this necessary?
this.cancel(ev,true);}if(!result.key){return true;}this.emit('keydown',ev);this.emit('key',result.key,ev);this.showCursor();this.handler(result.key);return this.cancel(ev,true);};/**
* Returns an object that determines how a KeyboardEvent should be handled. The key of the
* returned value is the new key code to pass to the PTY.
@@ -1248,7 +1348,7 @@ result.key=String.fromCharCode(0);}else if(ev.keyCode>=51&&ev.keyCode<=55){// es
result.key=String.fromCharCode(ev.keyCode-51+27);}else if(ev.keyCode===56){// delete
result.key=String.fromCharCode(127);}else if(ev.keyCode===219){// ^[ - escape
result.key=String.fromCharCode(27);}else if(ev.keyCode===221){// ^] - group sep
result.key=String.fromCharCode(29);}}else if(!this.isMac&&ev.altKey&&!ev.ctrlKey&&!ev.metaKey){// On Mac this is a third level shift. Use <Esc> instead.
result.key=String.fromCharCode(29);}}else if(!this.browser.isMac&&ev.altKey&&!ev.ctrlKey&&!ev.metaKey){// On Mac this is a third level shift. Use <Esc> instead.
if(ev.keyCode>=65&&ev.keyCode<=90){result.key='\x1b'+String.fromCharCode(ev.keyCode+32);}else if(ev.keyCode===192){result.key='\x1b`';}else if(ev.keyCode>=48&&ev.keyCode<=57){result.key='\x1b'+(ev.keyCode-48);}}break;}return result;};/**
* Set the G level of the terminal
* @param g
@@ -1290,7 +1390,7 @@ this.lines.push(this.blankLine());}}if(this.children.length<y){this.insertRow();
while(j-->y){if(this.lines.length>y+this.ybase){if(this.lines.length>this.ybase+this.y+1){// The line is a blank line below the cursor, remove it
this.lines.pop();}else{// The line is the cursor, scroll down
this.ybase++;this.ydisp++;}}if(this.children.length>y){el=this.children.shift();if(!el)continue;el.parentNode.removeChild(el);}}}this.rows=y;// Make sure that the cursor stays on screen
if(this.y>=y){this.y=y-1;}if(addToY){this.y+=addToY;}if(this.x>=x){this.x=x-1;}this.scrollTop=0;this.scrollBottom=y-1;this.refresh(0,this.rows-1);this.normal=null;this.emit('resize',{terminal:this,cols:x,rows:y});};/**
if(this.y>=y){this.y=y-1;}if(addToY){this.y+=addToY;}if(this.x>=x){this.x=x-1;}this.scrollTop=0;this.scrollBottom=y-1;this.refresh(0,this.rows-1);this.normal=null;this.geometry=[this.cols,this.rows];this.emit('resize',{terminal:this,cols:x,rows:y});};/**
* Updates the range of rows to refresh
* @param {number} y The number of rows to refresh next.
*/Terminal.prototype.updateRange=function(y){if(y<this.refreshStart)this.refreshStart=y;if(y>this.refreshEnd)this.refreshEnd=y;// if (y > this.refreshEnd) {
@@ -1300,7 +1400,7 @@ if(this.y>=y){this.y=y-1;}if(addToY){this.y+=addToY;}if(this.x>=x){this.x=x-1;}t
// }
// }
};/**
* Set the range of refreshing to the maximyum value
* Set the range of refreshing to the maximum value
*/Terminal.prototype.maxRange=function(){this.refreshStart=0;this.refreshEnd=this.rows-1;};/**
* Setup the tab stops.
* @param {number} i
@@ -1337,9 +1437,9 @@ return;}this.lines=[this.lines[this.ybase+this.y]];this.ydisp=0;this.ybase=0;thi
* Evaluate if the current erminal is the given argument.
* @param {object} term The terminal to evaluate
*/Terminal.prototype.is=function(term){var name=this.termName;return(name+'').indexOf(term)===0;};/**
* Emit the 'data' event and populate the given data.
* @param {string} data The data to populate in the event.
*/Terminal.prototype.handler=function(data){this.emit('data',data);};/**
* Emit the 'data' event and populate the given data.
* @param {string} data The data to populate in the event.
*/Terminal.prototype.handler=function(data){this.emit('data',data);};/**
* Emit the 'title' event and populate the given title.
* @param {string} title The title to populate in the event.
*/Terminal.prototype.handleTitle=function(title){this.emit('title',title);};/**
@@ -1857,8 +1957,8 @@ this.refresh(0,this.rows-1);this.showCursor();}break;}}};/**
* CSI Ps S Scroll up Ps lines (default = 1) (SU).
*/Terminal.prototype.scrollUp=function(params){var param=params[0]||1;while(param--){this.lines.splice(this.ybase+this.scrollTop,1);this.lines.splice(this.ybase+this.scrollBottom,0,this.blankLine());}// this.maxRange();
this.updateRange(this.scrollTop);this.updateRange(this.scrollBottom);};/**
* CSI Ps T Scroll down Ps lines (default = 1) (SD).
*/Terminal.prototype.scrollDown=function(params){var param=params[0]||1;while(param--){this.lines.splice(this.ybase+this.scrollBottom,1);this.lines.splice(this.ybase+this.scrollTop,0,this.blankLine());}// this.maxRange();
* CSI Ps T Scroll down Ps lines (default = 1) (SD).
*/Terminal.prototype.scrollDown=function(params){var param=params[0]||1;while(param--){this.lines.splice(this.ybase+this.scrollBottom,1);this.lines.splice(this.ybase+this.scrollTop,0,this.blankLine());}// this.maxRange();
this.updateRange(this.scrollTop);this.updateRange(this.scrollBottom);};/**
* CSI Ps ; Ps ; Ps ; Ps ; Ps T
* Initiate highlight mouse tracking. Parameters are
@@ -2103,9 +2203,9 @@ Terminal.charsets.Swiss=null;// (=
Terminal.charsets.ISOLatin=null;// /A
/**
* Helpers
*/function contains(el,arr){for(var i=0;i<arr.length;i+=1){if(el===arr[i]){return true;}}return false;}function on(el,type,handler,capture){if(!Array.isArray(el)){el=[el];}el.forEach(function(element){element.addEventListener(type,handler,capture||false);});}function off(el,type,handler,capture){el.removeEventListener(type,handler,capture||false);}function cancel(ev,force){if(!this.cancelEvents&&!force){return;}ev.preventDefault();ev.stopPropagation();return false;}function inherits(child,parent){function f(){this.constructor=child;}f.prototype=parent.prototype;child.prototype=new f();}// if bold is broken, we can't
*/function on(el,type,handler,capture){if(!Array.isArray(el)){el=[el];}el.forEach(function(element){element.addEventListener(type,handler,capture||false);});}function off(el,type,handler,capture){el.removeEventListener(type,handler,capture||false);}function cancel(ev,force){if(!this.cancelEvents&&!force){return;}ev.preventDefault();ev.stopPropagation();return false;}function inherits(child,parent){function f(){this.constructor=child;}f.prototype=parent.prototype;child.prototype=new f();}// if bold is broken, we can't
// use it in the terminal.
function isBoldBroken(document){var body=document.getElementsByTagName('body')[0];var el=document.createElement('span');el.innerHTML='hello world';body.appendChild(el);var w1=el.scrollWidth;el.style.fontWeight='bold';var w2=el.scrollWidth;body.removeChild(el);return w1!==w2;}function indexOf(obj,el){var i=obj.length;while(i--){if(obj[i]===el)return i;}return-1;}function isThirdLevelShift(term,ev){var thirdLevelKey=term.isMac&&ev.altKey&&!ev.ctrlKey&&!ev.metaKey||term.isMSWindows&&ev.altKey&&ev.ctrlKey&&!ev.metaKey;if(ev.type=='keypress'){return thirdLevelKey;}// Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events)
function isBoldBroken(document){var body=document.getElementsByTagName('body')[0];var el=document.createElement('span');el.innerHTML='hello world';body.appendChild(el);var w1=el.scrollWidth;el.style.fontWeight='bold';var w2=el.scrollWidth;body.removeChild(el);return w1!==w2;}function indexOf(obj,el){var i=obj.length;while(i--){if(obj[i]===el)return i;}return-1;}function isThirdLevelShift(term,ev){var thirdLevelKey=term.browser.isMac&&ev.altKey&&!ev.ctrlKey&&!ev.metaKey||term.browser.isMSWindows&&ev.altKey&&ev.ctrlKey&&!ev.metaKey;if(ev.type=='keypress'){return thirdLevelKey;}// Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events)
return thirdLevelKey&&(!ev.keyCode||ev.keyCode>47);}function matchColor(r1,g1,b1){var hash=r1<<16|g1<<8|b1;if(matchColor._cache[hash]!=null){return matchColor._cache[hash];}var ldiff=Infinity,li=-1,i=0,c,r2,g2,b2,diff;for(;i<Terminal.vcolors.length;i++){c=Terminal.vcolors[i];r2=c[0];g2=c[1];b2=c[2];diff=matchColor.distance(r1,g1,b1,r2,g2,b2);if(diff===0){li=i;break;}if(diff<ldiff){ldiff=diff;li=i;}}return matchColor._cache[hash]=li;}matchColor._cache={};// http://stackoverflow.com/questions/1633828
matchColor.distance=function(r1,g1,b1,r2,g2,b2){return Math.pow(30*(r1-r2),2)+Math.pow(59*(g1-g2),2)+Math.pow(11*(b1-b2),2);};function each(obj,iter,con){if(obj.forEach)return obj.forEach(iter,con);for(var i=0;i<obj.length;i++){iter.call(con,obj[i],i,obj);}}function keys(obj){if(Object.keys)return Object.keys(obj);var key,keys=[];for(key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)){keys.push(key);}}return keys;}var wcwidth=function(opts){// extracted from https://www.cl.cam.ac.uk/%7Emgk25/ucs/wcwidth.c
// combining characters
@@ -2130,8 +2230,6 @@ ucs>=0xffe0&&ucs<=0xffe6||ucs>=0x20000&&ucs<=0x2fffd||ucs>=0x30000&&ucs<=0x3fffd
* @param {function} callback The function to call when the event is triggered.
*/Terminal.on=on;Terminal.off=off;Terminal.cancel=cancel;module.exports=Terminal;
}).call(this,"/src")
},{"./CompositionHelper.js":1,"./EventEmitter.js":2,"./Viewport.js":3,"./handlers/Clipboard.js":4}]},{},[5])(5)
},{"./CompositionHelper.js":1,"./EventEmitter.js":2,"./Viewport.js":3,"./handlers/Clipboard.js":4,"./utils/Browser":5}]},{},[7])(7)
});
//# sourceMappingURL=xterm.js.map
+8 -4
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "xterm",
"version": "2.0.1",
"version": "2.1.0",
"ignore": [
"demo",
"test",
+15 -3
View File
@@ -178,11 +178,23 @@ CompositionHelper.prototype.updateCompositionElements = function(dontRecurse) {
}
var cursor = 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 = this.terminal.element.querySelector('.xterm-rows');
var cursorTop = xtermRows.offsetTop + cursor.offsetTop;
this.compositionView.style.left = cursor.offsetLeft + 'px';
this.compositionView.style.top = cursor.offsetTop + 'px';
this.compositionView.style.top = cursorTop + 'px';
this.compositionView.style.height = cursor.offsetHeight + 'px';
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();
this.textarea.style.left = cursor.offsetLeft + compositionViewBounds.width + 'px';
this.textarea.style.top = (cursor.offsetTop + cursor.offsetHeight) + 'px';
this.textarea.style.left = cursor.offsetLeft + 'px';
this.textarea.style.top = cursorTop + 'px';
this.textarea.style.width = compositionViewBounds.width + 'px';
this.textarea.style.height = compositionViewBounds.height + 'px';
this.textarea.style.lineHeight = compositionViewBounds.height + 'px';
}
if (!dontRecurse) {
setTimeout(this.updateCompositionElements.bind(this, true), 0);
+46 -25
View File
@@ -35,11 +35,16 @@ function prepareTextForClipboard(text) {
* Binds copy functionality to the given terminal.
* @param {ClipboardEvent} ev The original copy event to be handled
*/
function copyHandler (ev) {
function copyHandler(ev, term) {
var copiedText = window.getSelection().toString(),
text = prepareTextForClipboard(copiedText);
ev.clipboardData.setData('text/plain', text);
if (term.browser.isMSIE) {
window.clipboardData.setData('Text', text);
} else {
ev.clipboardData.setData('text/plain', text);
}
ev.preventDefault(); // Prevent or the original text will be copied.
}
@@ -50,11 +55,23 @@ function copyHandler (ev) {
*/
function pasteHandler(ev, term) {
ev.stopPropagation();
if (ev.clipboardData) {
var text = ev.clipboardData.getData('text/plain');
var dispatchPaste = function(text) {
term.handler(text);
term.textarea.value = '';
return term.cancel(ev);
};
if (term.browser.isMSIE) {
if (window.clipboardData) {
var text = window.clipboardData.getData('Text');
dispatchPaste(text);
}
} else {
if (ev.clipboardData) {
var text = ev.clipboardData.getData('text/plain');
dispatchPaste(text);
}
}
}
@@ -73,39 +90,43 @@ function pasteHandler(ev, term) {
*/
function rightClickHandler(ev, term) {
var s = document.getSelection(),
sText = prepareTextForClipboard(s.toString()),
r = s.getRangeAt(0);
selectedText = prepareTextForClipboard(s.toString()),
clickIsOnSelection = false;
var x = ev.clientX,
y = ev.clientY;
if (s.rangeCount) {
var r = s.getRangeAt(0),
cr = r.getClientRects(),
x = ev.clientX,
y = ev.clientY,
i, rect;
var cr = r.getClientRects(),
clickIsOnSelection = false,
i, rect;
for (i=0; i<cr.length; i++) {
rect = cr[i];
clickIsOnSelection = (
(x > rect.left) && (x < rect.right) &&
(y > rect.top) && (y < rect.bottom)
);
for (i=0; i<cr.length; i++) {
rect = cr[i];
clickIsOnSelection = (
(x > rect.left) && (x < rect.right) &&
(y > rect.top) && (y < rect.bottom)
);
if (clickIsOnSelection) {
break;
}
}
// 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 &nbsp;
// and there is not much pointing in copying a single space.
// Single space is char
if (clickIsOnSelection && (sText !== ' ')) {
break;
if (selectedText.match(/^\s$/) || !selectedText.length) {
clickIsOnSelection = false;
}
}
// Bring textarea at the cursor position
if (!clickIsOnSelection) {
term.textarea.style.position = 'fixed';
term.textarea.style.width = '10px';
term.textarea.style.height = '10px';
term.textarea.style.left = x + 'px';
term.textarea.style.top = y + 'px';
term.textarea.style.width = '20px';
term.textarea.style.height = '20px';
term.textarea.style.left = (x - 10) + 'px';
term.textarea.style.top = (y - 10) + 'px';
term.textarea.style.zIndex = 1000;
term.textarea.focus();
@@ -117,7 +138,7 @@ function rightClickHandler(ev, term) {
term.textarea.style.left = null;
term.textarea.style.top = null;
term.textarea.style.zIndex = null;
}, 1);
}, 4);
}
}
+27
View File
@@ -0,0 +1,27 @@
/**
* xterm.js: xterm, in the browser
* Copyright (c) 2016, SourceLair Private Company <www.sourcelair.com> (MIT License)
*/
/**
* Browser utilities module. This module contains attributes and methods to help with
* identifying the current browser and platform.
* @module xterm/utils/Browser
*/
import { contains } from './Generic.js';
let isNode = (typeof navigator == 'undefined') ? true : false;
let userAgent = (isNode) ? 'node' : navigator.userAgent;
let platform = (isNode) ? 'node' : navigator.platform;
export let isFirefox = !!~userAgent.indexOf('Firefox');
export let 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
export let isMac = contains(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], platform);
export let isIpad = platform === 'iPad';
export let isIphone = platform === 'iPhone';
export let isMSWindows = contains(['Windows', 'Win16', 'Win32', 'WinCE'], platform);
+19
View File
@@ -0,0 +1,19 @@
/**
* xterm.js: xterm, in the browser
* Copyright (c) 2016, SourceLair Private Company <www.sourcelair.com> (MIT License)
*/
/**
* Generic utilities module. This module contains generic methods that can be helpful at
* different parts of the code base.
* @module xterm/utils/Generic
*/
/**
* 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
*/
export let contains = function(arr, el) {
return arr.indexOf(el) >= 0;
};
+10
View File
@@ -61,9 +61,14 @@
position: absolute;
opacity: 0;
left: -9999em;
top: -9999em;
width: 0;
height: 0;
z-index: -10;
/** Prevent wrapping so the IME appears against the textarea at the correct position */
white-space: nowrap;
overflow: hidden;
resize: none;
}
.terminal .terminal-cursor {
@@ -117,6 +122,11 @@
top: 0;
}
.terminal .xterm-rows > div {
/* Lines containing spans and text nodes ocassionally wrap despite being the same width (#327) */
white-space: nowrap;
}
.terminal .xterm-scroll-area {
visibility: hidden;
}
+76 -53
View File
@@ -35,6 +35,7 @@ import { CompositionHelper } from './CompositionHelper.js';
import { EventEmitter } from './EventEmitter.js';
import { Viewport } from './Viewport.js';
import { rightClickHandler, pasteHandler, copyHandler } from './handlers/Clipboard.js';
import * as Browser from './utils/Browser';
/**
* Terminal Emulation References:
@@ -63,7 +64,9 @@ var normal = 0, escaped = 1, csi = 2, osc = 3, charset = 4, dcs = 5, ignore = 6;
* Creates a new `Terminal` object.
*
* @param {object} options An object containing a set of options, the available options are:
* - cursorBlink (boolean): Whether the terminal cursor blinks
* - `cursorBlink` (boolean): Whether the terminal cursor blinks
* - `cols` (number): The number of columns of the terminal (horizontal size)
* - `rows` (number): The number of rows of the terminal (vertical size)
*
* @public
* @class Xterm Xterm
@@ -76,6 +79,7 @@ function Terminal(options) {
return new Terminal(arguments[0], arguments[1], arguments[2]);
}
self.browser = Browser;
self.cancel = Terminal.cancel;
EventEmitter.call(this);
@@ -125,6 +129,7 @@ function Terminal(options) {
this.cols = options.cols || options.geometry[0];
this.rows = options.rows || options.geometry[1];
this.geometry = [this.cols, this.rows];
if (options.handler) {
this.on('data', options.handler);
@@ -231,6 +236,9 @@ function Terminal(options) {
this.tabs;
this.setupStops();
// Store if user went browsing history in scrollback
this.userScrolling = false;
}
inherits(Terminal, EventEmitter);
@@ -439,13 +447,26 @@ Terminal.prototype.initGlobal = function() {
Terminal.bindBlur(this);
// Bind clipboard functionality
on(this.element, 'copy', copyHandler);
on(this.element, 'copy', function (ev) {
copyHandler.call(this, ev, term);
});
on(this.textarea, 'paste', function (ev) {
pasteHandler.call(this, ev, term);
});
on(this.element, 'contextmenu', function (ev) {
function rightClickHandlerWrapper (ev) {
rightClickHandler.call(this, ev, term);
});
}
if (term.browser.isFirefox) {
on(this.element, 'mousedown', function (ev) {
if (ev.button == 2) {
rightClickHandlerWrapper(ev);
}
});
} else {
on(this.element, 'contextmenu', rightClickHandlerWrapper);
}
};
/**
@@ -520,27 +541,6 @@ Terminal.prototype.open = function(parent) {
this.document = this.parent.ownerDocument;
this.body = this.document.getElementsByTagName('body')[0];
// Parse User-Agent
if (this.context.navigator && this.context.navigator.userAgent) {
this.isMSIE = !!~this.context.navigator.userAgent.indexOf('MSIE');
}
// Find the users platform. We use this to interpret the meta key
// and ISO third level shifts.
// http://stackoverflow.com/q/19877924/577598
if (this.context.navigator && this.context.navigator.platform) {
this.isMac = contains(
this.context.navigator.platform,
['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']
);
this.isIpad = this.context.navigator.platform === 'iPad';
this.isIphone = this.context.navigator.platform === 'iPhone';
this.isMSWindows = contains(
this.context.navigator.platform,
['Windows', 'Win16', 'Win32', 'WinCE']
);
}
//Create main element container
this.element = this.document.createElement('div');
this.element.classList.add('terminal');
@@ -642,7 +642,7 @@ Terminal.prototype.open = function(parent) {
Terminal.loadAddon = function(addon, callback) {
if (typeof exports === 'object' && typeof module === 'object') {
// CommonJS
return require(__dirname + '/../addons/' + addon);
return require('../addons/' + addon);
} else if (typeof define == 'function') {
// RequireJS
return require(['../addons/' + addon + '/' + addon], callback);
@@ -840,7 +840,7 @@ Terminal.prototype.bindMouse = function() {
? ev.which - 1
: null;
if (self.isMSIE) {
if (self.browser.isMSIE) {
button = button === 1 ? 0 : button === 4 ? 1 : button;
}
break;
@@ -1250,7 +1250,9 @@ Terminal.prototype.scroll = function() {
this.lines = this.lines.slice(-(this.ybase + this.rows) + 1);
}
this.ydisp = this.ybase;
if (!this.userScrolling) {
this.ydisp = this.ybase;
}
// last line
row = this.ybase + this.rows - 1;
@@ -1272,7 +1274,9 @@ Terminal.prototype.scroll = function() {
if (this.scrollTop !== 0) {
if (this.ybase !== 0) {
this.ybase--;
this.ydisp = this.ybase;
if (!this.userScrolling) {
this.ydisp = this.ybase;
}
}
this.lines.splice(this.ybase + this.scrollTop, 1);
}
@@ -1292,6 +1296,12 @@ Terminal.prototype.scroll = function() {
* viewport originally.
*/
Terminal.prototype.scrollDisp = function(disp, suppressScrollEvent) {
if (disp < 0) {
this.userScrolling = true;
} else if (disp + this.ydisp >= this.ybase) {
this.userScrolling = false;
}
this.ydisp += disp;
if (this.ydisp > this.ybase) {
@@ -1307,6 +1317,28 @@ Terminal.prototype.scrollDisp = function(disp, suppressScrollEvent) {
this.refresh(0, this.rows - 1);
};
/**
* Scroll the display of the terminal by a number of pages.
* @param {number} pageCount The number of pages to scroll (negative scrolls up).
*/
Terminal.prototype.scrollPages = function(pageCount) {
this.scrollDisp(pageCount * (this.rows - 1));
}
/**
* Scrolls the display of the terminal to the top.
*/
Terminal.prototype.scrollToTop = function() {
this.scrollDisp(-this.ydisp);
}
/**
* Scrolls the display of the terminal to the bottom.
*/
Terminal.prototype.scrollToBottom = function() {
this.scrollDisp(this.ybase - this.ydisp);
}
/**
* Writes text to the terminal.
* @param {string} text The text to write to the terminal.
@@ -1317,12 +1349,6 @@ Terminal.prototype.write = function(data) {
this.refreshStart = this.y;
this.refreshEnd = this.y;
if (this.ybase !== this.ydisp) {
this.ydisp = this.ybase;
this.emit('scroll', this.ydisp);
this.maxRange();
}
// apply leftover surrogate high from last write
if (this.surrogate_high) {
data = this.surrogate_high + data;
@@ -2388,6 +2414,11 @@ Terminal.prototype.attachCustomKeydownHandler = function(customKeydownHandler) {
* @param {KeyboardEvent} ev The keydown event to be handled.
*/
Terminal.prototype.keyDown = function(ev) {
// Scroll down to prompt, whenever the user presses a key.
if (this.ybase !== this.ydisp) {
this.scrollToBottom();
}
if (this.customKeydownHandler && this.customKeydownHandler(ev) === false) {
return false;
}
@@ -2687,7 +2718,7 @@ Terminal.prototype.evaluateKeyEscapeSequence = function(ev) {
// ^] - group sep
result.key = String.fromCharCode(29);
}
} else if (!this.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) {
} else if (!this.browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) {
// On Mac this is a third level shift. Use <Esc> instead.
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
result.key = '\x1b' + String.fromCharCode(ev.keyCode + 32);
@@ -2920,6 +2951,7 @@ Terminal.prototype.resize = function(x, y) {
this.normal = null;
this.geometry = [this.cols, this.rows];
this.emit('resize', {terminal: this, cols: x, rows: y});
};
@@ -2939,7 +2971,7 @@ Terminal.prototype.updateRange = function(y) {
};
/**
* Set the range of refreshing to the maximyum value
* Set the range of refreshing to the maximum value
*/
Terminal.prototype.maxRange = function() {
this.refreshStart = 0;
@@ -3099,9 +3131,9 @@ Terminal.prototype.is = function(term) {
/**
* Emit the 'data' event and populate the given data.
* @param {string} data The data to populate in the event.
*/
* Emit the 'data' event and populate the given data.
* @param {string} data The data to populate in the event.
*/
Terminal.prototype.handler = function(data) {
this.emit('data', data);
};
@@ -4344,8 +4376,8 @@ Terminal.prototype.scrollUp = function(params) {
/**
* CSI Ps T Scroll down Ps lines (default = 1) (SD).
*/
* CSI Ps T Scroll down Ps lines (default = 1) (SD).
*/
Terminal.prototype.scrollDown = function(params) {
var param = params[0] || 1;
while (param--) {
@@ -4841,15 +4873,6 @@ Terminal.charsets.ISOLatin = null; // /A
* Helpers
*/
function contains(el, arr) {
for (var i = 0; i < arr.length; i += 1) {
if (el === arr[i]) {
return true;
}
}
return false;
}
function on(el, type, handler, capture) {
if (!Array.isArray(el)) {
el = [el];
@@ -4904,8 +4927,8 @@ function indexOf(obj, el) {
function isThirdLevelShift(term, ev) {
var thirdLevelKey =
(term.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
(term.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
(term.browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
(term.browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
if (ev.type == 'keypress') {
return thirdLevelKey;
+1 -1
View File
@@ -1,5 +1,5 @@
var assert = require('chai').assert;
var Terminal = require('../../src/xterm');
var Terminal = require('../../dist/xterm');
var linkify = require('../../addons/linkify/linkify');
describe('linkify addon', function () {
+3 -2
View File
@@ -1,10 +1,11 @@
var assert = require('chai').assert;
var Terminal = require('../../src/xterm');
var distTerminal = require('../../dist/xterm');
describe('xterm.js addons', function() {
it('should load addons with Terminal.loadAddon', function () {
Terminal.loadAddon('attach');
// Test that function was loaded successfully
assert.equal(typeof Terminal.prototype.attach, 'function');
// Test that addon was loaded successfully
assert.equal(typeof distTerminal.prototype.attach, 'function');
});
});
+116 -2
View File
@@ -88,6 +88,120 @@ describe('xterm.js', function() {
});
});
describe('scroll', function() {
describe('scrollDisp', function() {
var startYDisp;
beforeEach(function() {
for (var i = 0; i < xterm.rows * 2; i++) {
xterm.writeln('test');
}
startYDisp = xterm.rows + 1;
});
it('should scroll a single line', function() {
assert.equal(xterm.ydisp, startYDisp);
xterm.scrollDisp(-1);
assert.equal(xterm.ydisp, startYDisp - 1);
xterm.scrollDisp(1);
assert.equal(xterm.ydisp, startYDisp);
});
it('should scroll multiple lines', function() {
assert.equal(xterm.ydisp, startYDisp);
xterm.scrollDisp(-5);
assert.equal(xterm.ydisp, startYDisp - 5);
xterm.scrollDisp(5);
assert.equal(xterm.ydisp, startYDisp);
});
it('should not scroll beyond the bounds of the buffer', function() {
assert.equal(xterm.ydisp, startYDisp);
xterm.scrollDisp(1);
assert.equal(xterm.ydisp, startYDisp);
for (var i = 0; i < startYDisp; i++) {
xterm.scrollDisp(-1);
}
assert.equal(xterm.ydisp, 0);
xterm.scrollDisp(-1);
assert.equal(xterm.ydisp, 0);
});
});
describe('scrollPages', function() {
var startYDisp;
beforeEach(function() {
for (var i = 0; i < xterm.rows * 3; i++) {
xterm.writeln('test');
}
startYDisp = (xterm.rows * 2) + 1;
});
it('should scroll a single page', function() {
assert.equal(xterm.ydisp, startYDisp);
xterm.scrollPages(-1);
assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1));
xterm.scrollPages(1);
assert.equal(xterm.ydisp, startYDisp);
});
it('should scroll a multiple pages', function() {
assert.equal(xterm.ydisp, startYDisp);
xterm.scrollPages(-2);
assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1) * 2);
xterm.scrollPages(2);
assert.equal(xterm.ydisp, startYDisp);
});
});
describe('scrollToTop', function() {
beforeEach(function() {
for (var i = 0; i < xterm.rows * 3; i++) {
xterm.writeln('test');
}
});
it('should scroll to the top', function() {
assert.notEqual(xterm.ydisp, 0);
xterm.scrollToTop();
assert.equal(xterm.ydisp, 0);
});
});
describe('scrollToBottom', function() {
var startYDisp;
beforeEach(function() {
for (var i = 0; i < xterm.rows * 3; i++) {
xterm.writeln('test');
}
startYDisp = (xterm.rows * 2) + 1;
});
it('should scroll to the bottom', function() {
xterm.scrollDisp(-1);
xterm.scrollToBottom();
assert.equal(xterm.ydisp, startYDisp);
xterm.scrollPages(-1);
xterm.scrollToBottom();
assert.equal(xterm.ydisp, startYDisp);
xterm.scrollToTop();
xterm.scrollToBottom();
assert.equal(xterm.ydisp, startYDisp);
});
});
describe('keyDown', function () {
it('should scroll down, when a key is pressed and terminal is scrolled up', function () {
var terminal = new Terminal();
// Do not process the keyDown event, to avoid side-effects
terminal.attachCustomKeydownHandler(function () {
return false;
});
terminal.ydisp = 0;
terminal.ybase = 40;
terminal.keyDown();
// Ensure that now the terminal is scrolled to bottom
assert.equal(terminal.ydisp, terminal.ybase);
});
});
});
describe('evaluateKeyEscapeSequence', function() {
it('should return the correct escape sequence for unmodified keys', function() {
// Backspace
@@ -273,7 +387,7 @@ describe('xterm.js', function() {
describe('On Mac OS', function() {
beforeEach(function() {
xterm.isMac = true;
xterm.browser.isMac = true;
});
it('should not interfere with the alt key on keyDown', function() {
@@ -322,7 +436,7 @@ describe('xterm.js', function() {
describe('On MS Windows', function() {
beforeEach(function() {
xterm.isMSWindows = true;
xterm.browser.isMSWindows = true;
});
it('should not interfere with the alt + ctrl key on keyDown', function() {