From 356377975b67ed6151a544affdcc6aab3f6ee1a1 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Fri, 4 Nov 2016 18:33:04 +0200 Subject: [PATCH 1/4] Fix right-click for Firefox and IE Fix #310 --- src/handlers/Clipboard.js | 26 +++++++++++++++----------- src/utils/Browser.js | 17 +++++++++++++++++ src/xterm.js | 24 ++++++++++++++++-------- 3 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 src/utils/Browser.js diff --git a/src/handlers/Clipboard.js b/src/handlers/Clipboard.js index cfc77c33..e3ad8704 100644 --- a/src/handlers/Clipboard.js +++ b/src/handlers/Clipboard.js @@ -86,7 +86,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) { @@ -102,23 +102,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(); @@ -130,7 +134,7 @@ function rightClickHandler(ev, term) { term.textarea.style.left = null; term.textarea.style.top = null; term.textarea.style.zIndex = null; - }, 1); + }, 4); } } diff --git a/src/utils/Browser.js b/src/utils/Browser.js new file mode 100644 index 00000000..bc789684 --- /dev/null +++ b/src/utils/Browser.js @@ -0,0 +1,17 @@ +/** + * xterm.js: xterm, in the browser + * Copyright (c) 2016, SourceLair Private Company (MIT License) + */ + +/** + * Browser utilities module. This module contains attributes and methods to help with + * identifying the current browser and platform. + * @module xterm/utils/Browser + */ + + +let userAgent = navigator.userAgent; +let platform = navigator.platform; + +export let isFirefox = !!~userAgent.indexOf('Firefox'); +export let isMSIE = !!~userAgent.indexOf('MSIE'); diff --git a/src/xterm.js b/src/xterm.js index ac570683..e1840f20 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -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 { isFirefox, isMSIE } from './utils/Browser'; /** * Terminal Emulation References: @@ -446,9 +447,21 @@ Terminal.prototype.initGlobal = function() { 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 (isFirefox || isMSIE) { + on(this.element, 'mousedown', function (ev) { + if (ev.button == 2) { + rightClickHandlerWrapper(ev); + } + }); + } else { + on(this.element, 'contextmenu', rightClickHandlerWrapper); + } }; /** @@ -523,11 +536,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 @@ -843,7 +851,7 @@ Terminal.prototype.bindMouse = function() { ? ev.which - 1 : null; - if (self.isMSIE) { + if (isMSIE) { button = button === 1 ? 0 : button === 4 ? 1 : button; } break; From d426c99866e03d2fde50aaab2bcce76cffc7256c Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Fri, 4 Nov 2016 18:41:00 +0200 Subject: [PATCH 2/4] Move all browser/platform detecting in `utils/Browser.js` --- src/utils/Browser.js | 9 +++++++++ src/utils/Generic.js | 19 +++++++++++++++++++ src/xterm.js | 33 ++++----------------------------- 3 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 src/utils/Generic.js diff --git a/src/utils/Browser.js b/src/utils/Browser.js index bc789684..e7b1180a 100644 --- a/src/utils/Browser.js +++ b/src/utils/Browser.js @@ -9,9 +9,18 @@ * @module xterm/utils/Browser */ +import { contains } from './Generic.js'; let userAgent = navigator.userAgent; let platform = navigator.platform; export let isFirefox = !!~userAgent.indexOf('Firefox'); export let isMSIE = !!~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 +export let isMac = contains(platform, ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']); +export let isIpad = platform === 'iPad'; +export let isIphone = platform === 'iPhone'; +export let isMSWindows = contains(platform, ['Windows', 'Win16', 'Win32', 'WinCE']); diff --git a/src/utils/Generic.js b/src/utils/Generic.js new file mode 100644 index 00000000..5097b610 --- /dev/null +++ b/src/utils/Generic.js @@ -0,0 +1,19 @@ +/** + * xterm.js: xterm, in the browser + * Copyright (c) 2016, SourceLair Private Company (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 + */ + +export let contains = function(el, arr) { + for (var i = 0; i < arr.length; i += 1) { + if (el === arr[i]) { + return true; + } + } + return false; +}; diff --git a/src/xterm.js b/src/xterm.js index e1840f20..63f0ac28 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -35,7 +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 { isFirefox, isMSIE } from './utils/Browser'; +import { isFirefox, isMSIE, isMac, isIpad, isIphone, isMSWindows } from './utils/Browser'; /** * Terminal Emulation References: @@ -536,22 +536,6 @@ Terminal.prototype.open = function(parent) { this.document = this.parent.ownerDocument; this.body = this.document.getElementsByTagName('body')[0]; - // 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'); @@ -2720,7 +2704,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 (!isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) { // On Mac this is a third level shift. Use instead. if (ev.keyCode >= 65 && ev.keyCode <= 90) { result.key = '\x1b' + String.fromCharCode(ev.keyCode + 32); @@ -4875,15 +4859,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]; @@ -4938,8 +4913,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); + (isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) || + (isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey); if (ev.type == 'keypress') { return thirdLevelKey; From bc70b3b37dc7b522d4aefd998f4382b1f7447a25 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Fri, 4 Nov 2016 19:36:30 +0200 Subject: [PATCH 3/4] Fix tests --- src/utils/Browser.js | 9 +++++---- src/utils/Generic.js | 14 +++++++------- src/xterm.js | 13 +++++++------ test/test.js | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/utils/Browser.js b/src/utils/Browser.js index e7b1180a..5240afad 100644 --- a/src/utils/Browser.js +++ b/src/utils/Browser.js @@ -11,8 +11,9 @@ import { contains } from './Generic.js'; -let userAgent = navigator.userAgent; -let platform = navigator.platform; +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'); @@ -20,7 +21,7 @@ export let isMSIE = !!~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 -export let isMac = contains(platform, ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']); +export let isMac = contains(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], platform); export let isIpad = platform === 'iPad'; export let isIphone = platform === 'iPhone'; -export let isMSWindows = contains(platform, ['Windows', 'Win16', 'Win32', 'WinCE']); +export let isMSWindows = contains(['Windows', 'Win16', 'Win32', 'WinCE'], platform); diff --git a/src/utils/Generic.js b/src/utils/Generic.js index 5097b610..9e48a721 100644 --- a/src/utils/Generic.js +++ b/src/utils/Generic.js @@ -9,11 +9,11 @@ * @module xterm/utils/Generic */ -export let contains = function(el, arr) { - for (var i = 0; i < arr.length; i += 1) { - if (el === arr[i]) { - return true; - } - } - return false; +/** + * 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; }; diff --git a/src/xterm.js b/src/xterm.js index 63f0ac28..7f0f2420 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -35,7 +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 { isFirefox, isMSIE, isMac, isIpad, isIphone, isMSWindows } from './utils/Browser'; +import * as Browser from './utils/Browser'; /** * Terminal Emulation References: @@ -79,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); @@ -453,7 +454,7 @@ Terminal.prototype.initGlobal = function() { rightClickHandler.call(this, ev, term); } - if (isFirefox || isMSIE) { + if (term.browser.isFirefox || term.browser.isMSIE) { on(this.element, 'mousedown', function (ev) { if (ev.button == 2) { rightClickHandlerWrapper(ev); @@ -835,7 +836,7 @@ Terminal.prototype.bindMouse = function() { ? ev.which - 1 : null; - if (isMSIE) { + if (self.browser.isMSIE) { button = button === 1 ? 0 : button === 4 ? 1 : button; } break; @@ -2704,7 +2705,7 @@ Terminal.prototype.evaluateKeyEscapeSequence = function(ev) { // ^] - group sep result.key = String.fromCharCode(29); } - } else if (!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 instead. if (ev.keyCode >= 65 && ev.keyCode <= 90) { result.key = '\x1b' + String.fromCharCode(ev.keyCode + 32); @@ -4913,8 +4914,8 @@ function indexOf(obj, el) { function isThirdLevelShift(term, ev) { var thirdLevelKey = - (isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) || - (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; diff --git a/test/test.js b/test/test.js index eb34a44e..a6bbfdc6 100644 --- a/test/test.js +++ b/test/test.js @@ -368,7 +368,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() { From b1ad564b0d92d6750212ff9d90a54a634f57d28c Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Fri, 4 Nov 2016 21:48:53 +0200 Subject: [PATCH 4/4] Actually fix tests --- test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.js b/test/test.js index a6bbfdc6..633b5278 100644 --- a/test/test.js +++ b/test/test.js @@ -417,7 +417,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() {