Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
521d7dbdaa | ||
|
|
2cba2ff3d4 | ||
|
|
547db92693 | ||
|
|
bf334238b7 | ||
|
|
5808de648b | ||
|
|
9ab0455b05 | ||
|
|
55ab36662a | ||
|
|
b1ad564b0d | ||
|
|
bc70b3b37d | ||
|
|
d426c99866 | ||
|
|
356377975b | ||
|
|
0de3d839e6 | ||
|
|
0fcd6b1d22 | ||
|
|
99b5464392 | ||
|
|
70965a8fd6 | ||
|
|
77ca15497c | ||
|
|
26de9fe4c5 | ||
|
|
00dcb4f6e3 | ||
|
|
996c641a79 | ||
|
|
a077860464 | ||
|
|
5e68acfc76 | ||
|
|
269540bfed | ||
|
|
868f15173d | ||
|
|
06a93344bb | ||
|
|
e8e7870be2 | ||
|
|
a9417c6878 | ||
|
|
605d61b64f | ||
|
|
8feaacf57e | ||
|
|
553c651166 | ||
|
|
1ec0bac9c6 | ||
|
|
b1c6ae8a06 | ||
|
|
8a124d0b35 | ||
|
|
0ad02a4afa | ||
|
|
9389f899d7 | ||
|
|
050a34921b | ||
|
|
32e878db81 | ||
|
|
0bf7bf56a5 | ||
|
|
e5d130b698 | ||
|
|
941e57a218 | ||
|
|
c02eea6ad3 | ||
|
|
fe0d878b23 | ||
|
|
763f148fa1 | ||
|
|
8f0ada708f | ||
|
|
8117999ab3 | ||
|
|
10dd22a3d4 | ||
|
|
fe54da34f8 | ||
|
|
09de0f31fa | ||
|
|
6ee524864e | ||
|
|
8fd350f0fc | ||
|
|
ebbeeefd86 | ||
|
|
76a890aa74 | ||
|
|
5ce522a401 |
@@ -11,3 +11,4 @@ example/*.log
|
||||
docs/
|
||||
npm-debug.log
|
||||
/.idea/
|
||||
.env
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "xterm.terminado",
|
||||
"main": "terminado.js",
|
||||
"private": true
|
||||
}
|
||||
@@ -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
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"name": "xterm.js",
|
||||
"version": "2.0.0",
|
||||
"ignore": ["demo", "test", ".gitignore"]
|
||||
"version": "2.1.0",
|
||||
"ignore": ["demo", "test", ".gitignore"],
|
||||
"main": [
|
||||
"dist/xterm.js",
|
||||
"dist/xterm.css"
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+2206
File diff suppressed because it is too large
Load Diff
Vendored
+2235
File diff suppressed because it is too large
Load Diff
Vendored
+27
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xterm",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.0",
|
||||
"ignore": [
|
||||
"demo",
|
||||
"test",
|
||||
|
||||
@@ -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
@@ -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
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
@@ -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,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
@@ -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
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user