Merge remote-tracking branch 'upstream/master' into typescript_build_2
This commit is contained in:
+36
-15
@@ -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,7 +90,7 @@ function pasteHandler(ev, term) {
|
||||
*/
|
||||
function rightClickHandler(ev, term) {
|
||||
var s = document.getSelection(),
|
||||
sText = prepareTextForClipboard(s.toString()),
|
||||
selectedText = prepareTextForClipboard(s.toString()),
|
||||
clickIsOnSelection = false;
|
||||
|
||||
if (s.rangeCount) {
|
||||
@@ -89,23 +106,27 @@ function rightClickHandler(ev, term) {
|
||||
(x > rect.left) && (x < rect.right) &&
|
||||
(y > rect.top) && (y < rect.bottom)
|
||||
);
|
||||
// If we clicked on selection and selection is not a single space,
|
||||
// then mark the right click as copy-only. We check for the single
|
||||
// space selection, as this can happen when clicking on an
|
||||
// and there is not much pointing in copying a single space.
|
||||
if (clickIsOnSelection && (sText !== ' ')) {
|
||||
|
||||
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.
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-2
@@ -181,6 +181,25 @@ describe('xterm.js', function() {
|
||||
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() {
|
||||
@@ -368,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() {
|
||||
@@ -417,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() {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
+60
-46
@@ -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:
|
||||
@@ -78,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);
|
||||
@@ -234,6 +236,9 @@ function Terminal(options) {
|
||||
|
||||
this.tabs;
|
||||
this.setupStops();
|
||||
|
||||
// Store if user went browsing history in scrollback
|
||||
this.userScrolling = false;
|
||||
}
|
||||
|
||||
inherits(Terminal, EventEmitter);
|
||||
@@ -442,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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -523,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');
|
||||
@@ -633,6 +630,11 @@ Terminal.prototype.open = function(parent) {
|
||||
Terminal.brokenBold = isBoldBroken(this.document);
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is emitted when terminal has completed opening.
|
||||
*
|
||||
* @event open
|
||||
*/
|
||||
this.emit('open');
|
||||
};
|
||||
|
||||
@@ -843,7 +845,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;
|
||||
@@ -1253,7 +1255,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;
|
||||
@@ -1275,7 +1279,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);
|
||||
}
|
||||
@@ -1284,6 +1290,12 @@ Terminal.prototype.scroll = function() {
|
||||
this.updateRange(this.scrollTop);
|
||||
this.updateRange(this.scrollBottom);
|
||||
|
||||
/**
|
||||
* This event is emitted whenever the terminal is scrolled.
|
||||
* The one parameter passed is the new y display position.
|
||||
*
|
||||
* @event scroll
|
||||
*/
|
||||
this.emit('scroll', this.ydisp);
|
||||
};
|
||||
|
||||
@@ -1295,6 +1307,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) {
|
||||
@@ -1342,12 +1360,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;
|
||||
@@ -2413,6 +2425,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;
|
||||
}
|
||||
@@ -2712,7 +2729,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);
|
||||
@@ -2965,7 +2982,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;
|
||||
@@ -3138,6 +3155,12 @@ Terminal.prototype.handler = function(data) {
|
||||
* @param {string} title The title to populate in the event.
|
||||
*/
|
||||
Terminal.prototype.handleTitle = function(title) {
|
||||
/**
|
||||
* This event is emitted when the title of the terminal is changed
|
||||
* from inside the terminal. The parameter is the new title.
|
||||
*
|
||||
* @event title
|
||||
*/
|
||||
this.emit('title', title);
|
||||
};
|
||||
|
||||
@@ -4867,15 +4890,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];
|
||||
@@ -4930,8 +4944,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;
|
||||
|
||||
Reference in New Issue
Block a user