From b0df236dea7cf468240dc2508758351321e3cd9b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 22 Nov 2016 11:36:34 -0800 Subject: [PATCH 1/5] Rename CompositionHelper.js -> CompositionHelper.ts --- src/{CompositionHelper.js => CompositionHelper.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{CompositionHelper.js => CompositionHelper.ts} (100%) diff --git a/src/CompositionHelper.js b/src/CompositionHelper.ts similarity index 100% rename from src/CompositionHelper.js rename to src/CompositionHelper.ts From 30fcdd6ccb50294ad1c29f75299e3d354e41043d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 22 Nov 2016 11:47:18 -0800 Subject: [PATCH 2/5] tsify CompositionHelper --- src/CompositionHelper.ts | 387 ++++++++++++++++++++------------------- src/Interfaces.ts | 6 + src/xterm.js | 1 - 3 files changed, 208 insertions(+), 186 deletions(-) diff --git a/src/CompositionHelper.ts b/src/CompositionHelper.ts index 3bf829e5a4..8a29ed7227 100644 --- a/src/CompositionHelper.ts +++ b/src/CompositionHelper.ts @@ -3,211 +3,228 @@ * Copyright (c) 2014-2016, SourceLair Private Company (www.sourcelair.com (MIT License) */ -/** - * Encapsulates the logic for handling compositionstart, compositionupdate and compositionend - * events, displaying the in-progress composition to the UI and forwarding the final composition - * to the handler. - * @param {HTMLTextAreaElement} textarea The textarea that xterm uses for input. - * @param {HTMLElement} compositionView The element to display the in-progress composition in. - * @param {Terminal} terminal The Terminal to forward the finished composition to. - */ -function CompositionHelper(textarea, compositionView, terminal) { - this.textarea = textarea; - this.compositionView = compositionView; - this.terminal = terminal; +import { ITerminal } from './Interfaces'; - // Whether input composition is currently happening, eg. via a mobile keyboard, speech input - // or IME. This variable determines whether the compositionText should be displayed on the UI. - this.isComposing = false; - - // The input currently being composed, eg. via a mobile keyboard, speech input or IME. - this.compositionText = null; +interface IPosition { + start: number; + end: number; +} - // The position within the input textarea's value of the current composition. - this.compositionPosition = { start: null, end: null }; +export class CompositionHelper { + /** + * Whether input composition is currently happening, eg. via a mobile keyboard, speech input or + * IME. This variable determines whether the compositionText should be displayed on the UI. + */ + private isComposing: boolean; + + /** + * The position within the input textarea's value of the current composition. + */ + private compositionPosition: IPosition;; + + /** + * Whether a composition is in the process of being sent, setting this to false will cancel any + * in-progress composition. + */ + private isSendingComposition: boolean; + + /** + * Encapsulates the logic for handling compositionstart, compositionupdate and compositionend + * events, displaying the in-progress composition to the UI and forwarding the final composition + * to the handler. + * @param textarea The textarea that xterm uses for input. + * @param compositionView The element to display the in-progress composition in. + * @param terminal The Terminal to forward the finished composition to. + */ + constructor( + private textarea: HTMLTextAreaElement, + private compositionView: HTMLElement, + private terminal: ITerminal + ) { + this.isComposing = false; + this.isSendingComposition = false; + this.compositionPosition = { start: null, end: null }; + } - // Whether a composition is in the process of being sent, setting this to false will cancel - // any in-progress composition. - this.isSendingComposition = false; -} + /** + * Handles the compositionstart event, activating the composition view. + */ + public compositionstart() { + this.isComposing = true; + this.compositionPosition.start = this.textarea.value.length; + this.compositionView.textContent = ''; + this.compositionView.classList.add('active'); + } -/** - * Handles the compositionstart event, activating the composition view. - */ -CompositionHelper.prototype.compositionstart = function() { - this.isComposing = true; - this.compositionPosition.start = this.textarea.value.length; - this.compositionView.textContent = ''; - this.compositionView.classList.add('active'); -}; + /** + * Handles the compositionupdate event, updating the composition view. + * @param {CompositionEvent} ev The event. + */ + public compositionupdate(ev: CompositionEvent) { + this.compositionView.textContent = ev.data; + this.updateCompositionElements(); + var self = this; + setTimeout(function() { + self.compositionPosition.end = self.textarea.value.length; + }, 0); + } -/** - * Handles the compositionupdate event, updating the composition view. - * @param {CompositionEvent} ev The event. - */ -CompositionHelper.prototype.compositionupdate = function(ev) { - this.compositionView.textContent = ev.data; - this.updateCompositionElements(); - var self = this; - setTimeout(function() { - self.compositionPosition.end = self.textarea.value.length; - }, 0); -}; + /** + * Handles the compositionend event, hiding the composition view and sending the composition to + * the handler. + */ + public compositionend() { + this.finalizeComposition(true); + } -/** - * Handles the compositionend event, hiding the composition view and sending the composition to - * the handler. - */ -CompositionHelper.prototype.compositionend = function() { - this.finalizeComposition(true); -}; + /** + * Handles the keydown event, routing any necessary events to the CompositionHelper functions. + * @param ev The keydown event. + * @return Whether the Terminal should continue processing the keydown event. + */ + public keydown(ev: KeyboardEvent) { + if (this.isComposing || this.isSendingComposition) { + if (ev.keyCode === 229) { + // Continue composing if the keyCode is the "composition character" + return false; + } else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) { + // Continue composing if the keyCode is a modifier key + return false; + } else { + // Finish composition immediately. This is mainly here for the case where enter is + // pressed and the handler needs to be triggered before the command is executed. + this.finalizeComposition(false); + } + } -/** - * Handles the keydown event, routing any necessary events to the CompositionHelper functions. - * @return Whether the Terminal should continue processing the keydown event. - */ -CompositionHelper.prototype.keydown = function(ev) { - if (this.isComposing || this.isSendingComposition) { if (ev.keyCode === 229) { - // Continue composing if the keyCode is the "composition character" + // If the "composition character" is used but gets to this point it means a non-composition + // character (eg. numbers and punctuation) was pressed when the IME was active. + this.handleAnyTextareaChanges(); return false; - } else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) { - // Continue composing if the keyCode is a modifier key - return false; - } else { - // Finish composition immediately. This is mainly here for the case where enter is - // pressed and the handler needs to be triggered before the command is executed. - this.finalizeComposition(false); } - } - if (ev.keyCode === 229) { - // If the "composition character" is used but gets to this point it means a non-composition - // character (eg. numbers and punctuation) was pressed when the IME was active. - this.handleAnyTextareaChanges(); - return false; + return true; } - return true; -}; - -/** - * Finalizes the composition, resuming regular input actions. This is called when a composition - * is ending. - * @param {boolean} waitForPropogation Whether to wait for events to propogate before sending - * the input. This should be false if a non-composition keystroke is entered before the - * compositionend event is triggered, such as enter, so that the composition is send before - * the command is executed. - */ -CompositionHelper.prototype.finalizeComposition = function(waitForPropogation) { - this.compositionView.classList.remove('active'); - this.isComposing = false; - this.clearTextareaPosition(); + /** + * Finalizes the composition, resuming regular input actions. This is called when a composition + * is ending. + * @param waitForPropogation Whether to wait for events to propogate before sending + * the input. This should be false if a non-composition keystroke is entered before the + * compositionend event is triggered, such as enter, so that the composition is send before + * the command is executed. + */ + private finalizeComposition(waitForPropogation: boolean) { + this.compositionView.classList.remove('active'); + this.isComposing = false; + this.clearTextareaPosition(); + + if (!waitForPropogation) { + // Cancel any delayed composition send requests and send the input immediately. + this.isSendingComposition = false; + var input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end); + this.terminal.handler(input); + } else { + // Make a deep copy of the composition position here as a new compositionstart event may + // fire before the setTimeout executes. + var currentCompositionPosition = { + start: this.compositionPosition.start, + end: this.compositionPosition.end, + } - if (!waitForPropogation) { - // Cancel any delayed composition send requests and send the input immediately. - this.isSendingComposition = false; - var input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end); - this.terminal.handler(input); - } else { - // Make a deep copy of the composition position here as a new compositionstart event may - // fire before the setTimeout executes. - var currentCompositionPosition = { - start: this.compositionPosition.start, - end: this.compositionPosition.end, + // Since composition* events happen before the changes take place in the textarea on most + // browsers, use a setTimeout with 0ms time to allow the native compositionend event to + // complete. This ensures the correct character is retrieved, this solution was used + // because: + // - The compositionend event's data property is unreliable, at least on Chromium + // - The last compositionupdate event's data property does not always accurately describe + // the character, a counter example being Korean where an ending consonsant can move to + // the following character if the following input is a vowel. + var self = this; + this.isSendingComposition = true; + setTimeout(function () { + // Ensure that the input has not already been sent + if (self.isSendingComposition) { + self.isSendingComposition = false; + var input; + if (self.isComposing) { + // Use the end position to get the string if a new composition has started. + input = self.textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end); + } else { + // Don't use the end position here in order to pick up any characters after the + // composition has finished, for example when typing a non-composition character + // (eg. 2) after a composition character. + input = self.textarea.value.substring(currentCompositionPosition.start); + } + self.terminal.handler(input); + } + }, 0); } + } - // Since composition* events happen before the changes take place in the textarea on most - // browsers, use a setTimeout with 0ms time to allow the native compositionend event to - // complete. This ensures the correct character is retrieved, this solution was used - // because: - // - The compositionend event's data property is unreliable, at least on Chromium - // - The last compositionupdate event's data property does not always accurately describe - // the character, a counter example being Korean where an ending consonsant can move to - // the following character if the following input is a vowel. + /** + * Apply any changes made to the textarea after the current event chain is allowed to complete. + * This should be called when not currently composing but a keydown event with the "composition + * character" (229) is triggered, in order to allow non-composition text to be entered when an + * IME is active. + */ + private handleAnyTextareaChanges() { + var oldValue = this.textarea.value; var self = this; - this.isSendingComposition = true; - setTimeout(function () { - // Ensure that the input has not already been sent - if (self.isSendingComposition) { - self.isSendingComposition = false; - var input; - if (self.isComposing) { - // Use the end position to get the string if a new composition has started. - input = self.textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end); - } else { - // Don't use the end position here in order to pick up any characters after the - // composition has finished, for example when typing a non-composition character - // (eg. 2) after a composition character. - input = self.textarea.value.substring(currentCompositionPosition.start); + setTimeout(function() { + // Ignore if a composition has started since the timeout + if (!self.isComposing) { + var newValue = self.textarea.value; + var diff = newValue.replace(oldValue, ''); + if (diff.length > 0) { + self.terminal.handler(diff); } - self.terminal.handler(input); } }, 0); } -}; -/** - * Apply any changes made to the textarea after the current event chain is allowed to complete. - * This should be called when not currently composing but a keydown event with the "composition - * character" (229) is triggered, in order to allow non-composition text to be entered when an - * IME is active. - */ -CompositionHelper.prototype.handleAnyTextareaChanges = function() { - var oldValue = this.textarea.value; - var self = this; - setTimeout(function() { - // Ignore if a composition has started since the timeout - if (!self.isComposing) { - var newValue = self.textarea.value; - var diff = newValue.replace(oldValue, ''); - if (diff.length > 0) { - self.terminal.handler(diff); - } + /** + * Positions the composition view on top of the cursor and the textarea just below it (so the + * IME helper dialog is positioned correctly). + * @param dontRecurse Whether to use setTimeout to recursively trigger another update, this is + * necessary as the IME events across browsers are not consistently triggered. + */ + public updateCompositionElements(dontRecurse?: boolean) { + if (!this.isComposing) { + return; } - }, 0); -}; - -/** - * Positions the composition view on top of the cursor and the textarea just below it (so the - * IME helper dialog is positioned correctly). - */ -CompositionHelper.prototype.updateCompositionElements = function(dontRecurse) { - if (!this.isComposing) { - return; - } - 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 = 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 + '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); - } -}; - -/** - * Clears the textarea's position so that the cursor does not blink on IE. - * @private - */ -CompositionHelper.prototype.clearTextareaPosition = function() { - this.textarea.style.left = ''; - this.textarea.style.top = ''; -}; - -export { CompositionHelper }; + 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 = 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 + '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); + } + }; + + /** + * Clears the textarea's position so that the cursor does not blink on IE. + * @private + */ + private clearTextareaPosition() { + this.textarea.style.left = ''; + this.textarea.style.top = ''; + }; +} diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 14355e5727..55cceb8b46 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -4,11 +4,17 @@ */ export interface ITerminal { + element: HTMLElement; rowContainer: HTMLElement; ydisp: number; lines: string[]; rows: number; + /** + * Emit the 'data' event and populate the given data. + * @param data The data to populate in the event. + */ + handler(data: string); on(event: string, callback: () => void); scrollDisp(disp: number, suppressScrollEvent: boolean); } diff --git a/src/xterm.js b/src/xterm.js index c88423d437..0ef9427d4f 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -5129,7 +5129,6 @@ var wcwidth = (function(opts) { */ Terminal.EventEmitter = EventEmitter; -Terminal.CompositionHelper = CompositionHelper; Terminal.Viewport = Viewport; Terminal.inherits = inherits; From f24cba722a2774b1ea6511160ee28bda519a666f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 22 Nov 2016 11:48:16 -0800 Subject: [PATCH 3/5] Rename composition-helper-test.js -> CompositionHelper.test.ts --- .../composition-helper-test.js => CompositionHelper.test.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{test/composition-helper-test.js => CompositionHelper.test.ts} (100%) diff --git a/src/test/composition-helper-test.js b/src/CompositionHelper.test.ts similarity index 100% rename from src/test/composition-helper-test.js rename to src/CompositionHelper.test.ts From 3638ef808be050aa1ae3e3d5ef1fd6617952f3df Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 22 Nov 2016 11:50:08 -0800 Subject: [PATCH 4/5] tsify CompositionHelper test --- src/CompositionHelper.test.ts | 113 +++++++++++++--------------------- 1 file changed, 43 insertions(+), 70 deletions(-) diff --git a/src/CompositionHelper.test.ts b/src/CompositionHelper.test.ts index 192df05dcd..f0acd40e8c 100644 --- a/src/CompositionHelper.test.ts +++ b/src/CompositionHelper.test.ts @@ -1,20 +1,20 @@ -var assert = require('chai').assert; -var Terminal = require('../xterm'); +import { assert } from 'chai'; +import { CompositionHelper } from './CompositionHelper'; -describe('CompositionHelper', function () { +describe('CompositionHelper', () => { var terminal; var compositionHelper; var compositionView; var textarea; var handledText; - beforeEach(function () { + beforeEach(() => { compositionView = { classList: { - add: function () {}, - remove: function () {}, + add: () => {}, + remove: () => {}, }, - getBoundingClientRect: function () { + getBoundingClientRect: () => { return { width: 0 }; }, style: { @@ -32,7 +32,7 @@ describe('CompositionHelper', function () { }; terminal = { element: { - querySelector: function () { + querySelector: () => { return { offsetLeft: 0, offsetTop: 0 }; } }, @@ -41,53 +41,26 @@ describe('CompositionHelper', function () { } }; handledText = ''; - compositionHelper = new Terminal.CompositionHelper(textarea, compositionView, terminal); + compositionHelper = new CompositionHelper(textarea, compositionView, terminal); }); - describe('Public API', function () { - it('should define CompositionHelper.prototype.compositionstart', function () { - assert.isDefined(Terminal.CompositionHelper.prototype.compositionstart); - }); - it('should define CompositionHelper.prototype.compositionupdate', function () { - assert.isDefined(Terminal.CompositionHelper.prototype.compositionupdate); - }); - it('should define CompositionHelper.prototype.compositionend', function () { - assert.isDefined(Terminal.CompositionHelper.prototype.compositionend); - }); - it('should define CompositionHelper.prototype.finalizeComposition', function () { - assert.isDefined(Terminal.CompositionHelper.prototype.finalizeComposition); - }); - it('should define CompositionHelper.prototype.handleAnyTextareaChanges', function () { - assert.isDefined(Terminal.CompositionHelper.prototype.handleAnyTextareaChanges); - }); - it('should define CompositionHelper.prototype.updateCompositionElements', function () { - assert.isDefined(Terminal.CompositionHelper.prototype.updateCompositionElements); - }); - it('should define CompositionHelper.isComposing', function () { - assert.isDefined(compositionHelper.isComposing); - }); - it('should define CompositionHelper.isSendingComposition', function () { - assert.isDefined(compositionHelper.isSendingComposition); - }); - }); - - describe('Input', function () { + describe('Input', () => { it('Should insert simple characters', function (done) { // First character 'ㅇ' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇ'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'ㅇ'); // Second character 'ㅇ' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇㅇ'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'ㅇㅇ'); done(); }, 0); @@ -101,29 +74,29 @@ describe('CompositionHelper', function () { compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇ'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '아' }); textarea.value = '아'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '앙' }); textarea.value = '앙'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates assert.equal(handledText, '앙'); // Second character '앙' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = '앙ㅇ'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '아' }); textarea.value = '앙아'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '앙' }); textarea.value = '앙앙'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates assert.equal(handledText, '앙앙'); done(); }, 0); @@ -141,21 +114,21 @@ describe('CompositionHelper', function () { compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇ'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '아' }); textarea.value = '아'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates // Start second character '아' in first character compositionHelper.compositionupdate({ data: '앙' }); textarea.value = '앙'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: '아' }); textarea.value = '아아' - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates assert.equal(handledText, '아아'); done(); }, 0); @@ -170,16 +143,16 @@ describe('CompositionHelper', function () { compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'd' }); textarea.value = 'd'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: 'だ' }); textarea.value = 'だ'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates // Second character 'あ' compositionHelper.compositionupdate({ data: 'だあ' }); textarea.value = 'だあ'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'だあ'); done(); }, 0); @@ -193,20 +166,20 @@ describe('CompositionHelper', function () { compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'd' }); textarea.value = 'd'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: 'だ' }); textarea.value = 'だ'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates // Second character 'ー' compositionHelper.compositionupdate({ data: 'だー' }); textarea.value = 'だー'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates // Convert to katakana 'ダー' compositionHelper.compositionupdate({ data: 'ダー' }); textarea.value = 'ダー'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'ダー'); done(); }, 0); @@ -221,20 +194,20 @@ describe('CompositionHelper', function () { compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'い' }); textarea.value = 'い'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates // Second character 'ま' compositionHelper.compositionupdate({ data: 'いm' }); textarea.value = 'いm'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: 'いま' }); textarea.value = 'いま'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates // Convert to kanji '今' compositionHelper.compositionupdate({ data: '今' }); textarea.value = '今'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates assert.equal(handledText, '今'); done(); }, 0); @@ -249,11 +222,11 @@ describe('CompositionHelper', function () { compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇ'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); // Second character '1' (a non-composition character) textarea.value = 'ㅇ1'; - setTimeout(function() { // wait for any textarea updates + setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'ㅇ1'); done(); }, 0); From f75b7db90e7954bc30c057c3995dc2773136cb7d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 22 Nov 2016 11:54:42 -0800 Subject: [PATCH 5/5] Move CompositionHelper header comment to class --- src/CompositionHelper.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/CompositionHelper.ts b/src/CompositionHelper.ts index 8a29ed7227..a7f97ad19a 100644 --- a/src/CompositionHelper.ts +++ b/src/CompositionHelper.ts @@ -10,6 +10,11 @@ interface IPosition { end: number; } +/** + * Encapsulates the logic for handling compositionstart, compositionupdate and compositionend + * events, displaying the in-progress composition to the UI and forwarding the final composition + * to the handler. + */ export class CompositionHelper { /** * Whether input composition is currently happening, eg. via a mobile keyboard, speech input or @@ -29,9 +34,7 @@ export class CompositionHelper { private isSendingComposition: boolean; /** - * Encapsulates the logic for handling compositionstart, compositionupdate and compositionend - * events, displaying the in-progress composition to the UI and forwarding the final composition - * to the handler. + * Creates a new CompositionHelper. * @param textarea The textarea that xterm uses for input. * @param compositionView The element to display the in-progress composition in. * @param terminal The Terminal to forward the finished composition to.