From 63e80990883845b4b5bcb72dae0fd29de8a08467 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 25 Jun 2014 11:12:16 -0600 Subject: [PATCH] Allow successive accented characters to be inserted in React editor Refs #2732 Because we're only checking the length of the input element's selection in the React editor on textinput events and not also its content, we were mistaking some IME compositions as accented character menu insertions. Clearing the content of the input on 'compositionend' prevents this issue. --- spec/editor-component-spec.coffee | 62 ++++++++++++++++++++++--------- src/editor-component.coffee | 7 ++-- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index f1305774e..9a49914c8 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -1619,61 +1619,87 @@ describe "EditorComponent", -> expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {' describe "when IME composition is used to insert international characters", -> - buildIMECompositionEvent = (event, {data}={}) -> + inputNode = null + + buildIMECompositionEvent = (event, {data, target}={}) -> event = new Event(event) event.data = data - Object.defineProperty(event, 'target', get: -> inputNpde) + Object.defineProperty(event, 'target', get: -> target) event + beforeEach -> + inputNode = inputNode = node.querySelector('.hidden-input') + describe "when nothing is selected", -> it "inserts the chosen completion", -> - node.dispatchEvent(buildIMECompositionEvent('compositionstart')) - node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's')) + node.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode)) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'svar quicksort = function () {' - node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd')) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'sdvar quicksort = function () {' - node.dispatchEvent(buildIMECompositionEvent('compositionend')) + node.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode)) 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')) + node.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode)) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'svar quicksort = function () {' - node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd')) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'sdvar quicksort = function () {' - node.dispatchEvent(buildIMECompositionEvent('compositionend')) + node.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {' + it "allows multiple accented character to be inserted with the ' on a US international layout", -> + inputNode.value = "'" + inputNode.setSelectionRange(0, 1) + node.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode)) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: "'", target: inputNode)) + expect(editor.lineForBufferRow(0)).toBe "'var quicksort = function () {" + + node.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode)) + node.dispatchEvent(buildTextInputEvent(data: 'á', target: inputNode)) + expect(editor.lineForBufferRow(0)).toBe "ávar quicksort = function () {" + + inputNode.value = "'" + inputNode.setSelectionRange(0, 1) + node.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode)) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: "'", target: inputNode)) + expect(editor.lineForBufferRow(0)).toBe "á'var quicksort = function () {" + + node.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode)) + node.dispatchEvent(buildTextInputEvent(data: 'á', target: inputNode)) + 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')) + node.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode)) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'var ssort = function () {' - node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd')) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'var sdsort = function () {' - node.dispatchEvent(buildIMECompositionEvent('compositionend')) + node.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode)) 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')) + node.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode)) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'var ssort = function () {' - node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd')) + node.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'var sdsort = function () {' - node.dispatchEvent(buildIMECompositionEvent('compositionend')) + node.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode)) expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {' describe "commands", -> diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 2231ca219..ba1f0db78 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -356,12 +356,13 @@ EditorComponent = React.createClass # 5. textInput fired; event.data == the completion string selectedText = null - node.addEventListener 'compositionstart', => + node.addEventListener 'compositionstart', -> selectedText = editor.getSelectedText() - node.addEventListener 'compositionupdate', (event) => + node.addEventListener 'compositionupdate', (event) -> editor.insertText(event.data, select: true, undo: 'skip') - node.addEventListener 'compositionend', => + node.addEventListener 'compositionend', (event) -> editor.insertText(selectedText, select: true, undo: 'skip') + event.target.value = '' listenForCommands: -> {parentView, editor, mini} = @props