From 184068dc55d2cc2f3aaa9e43c7aa9aa54946b53d Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 19 Jun 2014 15:03:34 -0700 Subject: [PATCH] Add handlers for IME composition --- spec/editor-component-spec.coffee | 58 +++++++++++++++++++++++++++++++ src/editor-component.coffee | 27 ++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index de7439917..388280b31 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -1425,6 +1425,64 @@ describe "EditorComponent", -> node.dispatchEvent(buildTextInputEvent(data: 'x', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {' + describe "when IME composition is used to insert international characters", -> + buildIMECompositionEvent = (event, {data}={}) -> + event = new Event(event) + event.data = data + Object.defineProperty(event, 'target', get: -> inputNpde) + event + + describe "when nothing is selected", -> + it "inserts the chosen completion", -> + node.dispatchEvent(buildIMECompositionEvent('compositionstart')) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's')) + expect(editor.lineForBufferRow(0)).toBe 'svar quicksort = function () {' + + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd')) + expect(editor.lineForBufferRow(0)).toBe 'sdvar quicksort = function () {' + + node.dispatchEvent(buildIMECompositionEvent('compositionend')) + node.dispatchEvent(buildTextInputEvent(data: '速度', target: inputNode)) + expect(editor.lineForBufferRow(0)).toBe '速度var quicksort = function () {' + + it "reverts back to the original text when the completion helper is dismissed", -> + node.dispatchEvent(buildIMECompositionEvent('compositionstart')) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's')) + expect(editor.lineForBufferRow(0)).toBe 'svar quicksort = function () {' + + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd')) + expect(editor.lineForBufferRow(0)).toBe 'sdvar quicksort = function () {' + + node.dispatchEvent(buildIMECompositionEvent('compositionend')) + expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {' + + describe "when a string is selected", -> + beforeEach -> + editor.setSelectedBufferRange [[0, 4], [0, 9]] # select 'quick' + + it "inserts the chosen completion", -> + node.dispatchEvent(buildIMECompositionEvent('compositionstart')) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's')) + expect(editor.lineForBufferRow(0)).toBe 'var ssort = function () {' + + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd')) + expect(editor.lineForBufferRow(0)).toBe 'var sdsort = function () {' + + node.dispatchEvent(buildIMECompositionEvent('compositionend')) + node.dispatchEvent(buildTextInputEvent(data: '速度', target: inputNode)) + expect(editor.lineForBufferRow(0)).toBe 'var 速度sort = function () {' + + it "reverts back to the original text when the completion helper is dismissed", -> + node.dispatchEvent(buildIMECompositionEvent('compositionstart')) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's')) + expect(editor.lineForBufferRow(0)).toBe 'var ssort = function () {' + + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd')) + expect(editor.lineForBufferRow(0)).toBe 'var sdsort = function () {' + + node.dispatchEvent(buildIMECompositionEvent('compositionend')) + expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {' + describe "commands", -> describe "editor:consolidate-selections", -> it "consolidates selections on the editor model, aborting the key binding if there is only one selection", -> diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 5dfa6fdbc..fd497d91b 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -281,6 +281,33 @@ EditorComponent = React.createClass scrollViewNode.addEventListener 'scroll', @onScrollViewScroll window.addEventListener 'resize', @requestScrollViewMeasurement + @listenForIMEEvents() + + listenForIMEEvents: -> + node = @getDOMNode() + {editor} = @props + + # The IME composition events work like this: + # + # User types 's', chromium pops up the completion helper + # 1. compositionstart fired + # 2. compositionupdate fired; event.data == 's' + # User hits arrow keys to move around in completion helper + # 3. compositionupdate fired; event.data == 's' for each arry key press + # User escape to cancel + # 4. compositionend fired + # OR User chooses a completion + # 4. compositionend fired + # 5. textInput fired; event.data == the completion string + + selectedText = null + node.addEventListener 'compositionstart', => + selectedText = editor.getSelectedText() + node.addEventListener 'compositionupdate', (event) => + editor.insertText(event.data, select: true, undo: 'skip') + node.addEventListener 'compositionend', => + editor.insertText(selectedText, select: true, undo: 'skip') + listenForCommands: -> {parentView, editor, mini} = @props