From cc86a8881623d10ee8ddb365ec37894e0052fced Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 4 Nov 2015 18:51:30 -0500 Subject: [PATCH 1/5] Persist current attributes through composition input --- src/trix/controllers/input_controller.coffee | 20 ++++++++++++++++++-- test/src/system/text_formatting_test.coffee | 17 +++++++++++++++++ test/src/test_helpers/input_helpers.coffee | 7 ++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/trix/controllers/input_controller.coffee b/src/trix/controllers/input_controller.coffee index 41fb7f558..4a1bf8ea4 100644 --- a/src/trix/controllers/input_controller.coffee +++ b/src/trix/controllers/input_controller.coffee @@ -236,14 +236,16 @@ class Trix.InputController extends Trix.BasicObject event.preventDefault() compositionstart: (event) -> - @mutationObserver.stop() + @insertPlaceholder() @setInputSummary(composing: true, compositionStart: event.data) compositionupdate: (event) -> + @selectPlaceholder() @setInputSummary(composing: true, compositionUpdate: event.data) compositionend: (event) -> - @mutationObserver.start() + @selectPlaceholder() + composedString = event.data @setInputSummary(composing: true, compositionEnd: composedString) @@ -334,6 +336,20 @@ class Trix.InputController extends Trix.BasicObject # Private + placeholder = " " + + insertPlaceholder: -> + unless @selectionIsExpanded() + @placeholderPosition = @responder?.getPosition() + @setInputSummary(textAdded: placeholder) + @responder?.insertString(placeholder) + @requestRender() + + selectPlaceholder: -> + if @placeholderPosition? + @responder?.setSelectedRange([@placeholderPosition, @placeholderPosition + placeholder.length]) + @placeholderPosition = null + handleInput: (callback) -> try @delegate?.inputControllerWillHandleInput() diff --git a/test/src/system/text_formatting_test.coffee b/test/src/system/text_formatting_test.coffee index a14b6b665..aa30e8dc6 100644 --- a/test/src/system/text_formatting_test.coffee +++ b/test/src/system/text_formatting_test.coffee @@ -143,3 +143,20 @@ editorTest "key command activates toolbar button", (done) -> typeToolbarKeyCommand attribute: "bold", -> ok isToolbarButtonActive(attribute: "bold") done() + +editorTest "composing formatted text", (expectDocument) -> + typeCharacters "abc", -> + clickToolbarButton attribute: "bold", -> + composeString "def", -> + expectAttributes([0, 3], {}) + expectAttributes([3, 6], bold: true) + expectDocument("abcdef\n") + +editorTest "composing away from formatted text", (expectDocument) -> + clickToolbarButton attribute: "bold", -> + typeCharacters "abc", -> + clickToolbarButton attribute: "bold", -> + composeString "def", -> + expectAttributes([0, 3], bold: true) + expectAttributes([3, 6], {}) + expectDocument("abcdef\n") diff --git a/test/src/test_helpers/input_helpers.coffee b/test/src/test_helpers/input_helpers.coffee index 3f04154e1..1f8127a14 100644 --- a/test/src/test_helpers/input_helpers.coffee +++ b/test/src/test_helpers/input_helpers.coffee @@ -71,7 +71,12 @@ for code, name of Trix.InputController.keyNames insertNode(node, callback) else updated = true - compose(string.slice(0, index++), "update", continueComposition) + # The cursor doesn't acually move like this during a composition, but + # it can move and cause the location range and current attributes to change. + # Moving the cursor and then putting it back is enough exercise those changes. + moveCursor "left", -> + moveCursor "right", -> + compose(string.slice(0, index++), "update", continueComposition) else started = true compose(string.slice(0, index++), "start", continueComposition) From 7874f0a9d9032b5fdf428b3c1e0a7a85e8856bd1 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Thu, 5 Nov 2015 09:14:31 -0500 Subject: [PATCH 2/5] Fix pressing return after a canceled composition A "canceled" composition happens on Android when you place the cursor at the end of a word and don't change it. A `compositionend` event is sent, but doesn't follow a `compositionstart` or `compositionupdate`. --- src/trix/controllers/input_controller.coffee | 10 +++++----- test/src/system/basic_input_test.coffee | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/trix/controllers/input_controller.coffee b/src/trix/controllers/input_controller.coffee index 4a1bf8ea4..992237623 100644 --- a/src/trix/controllers/input_controller.coffee +++ b/src/trix/controllers/input_controller.coffee @@ -246,13 +246,13 @@ class Trix.InputController extends Trix.BasicObject compositionend: (event) -> @selectPlaceholder() - composedString = event.data - @setInputSummary(composing: true, compositionEnd: composedString) + {compositionStart} = @inputSummary + {data} = event - if composedString? and composedString isnt @inputSummary.compositionStart + if compositionStart? and data? and compositionStart isnt data @delegate?.inputControllerWillPerformTyping() - @responder?.insertString(composedString) - {added, removed} = summarizeStringChange(@inputSummary.compositionStart, composedString) + @responder?.insertString(data) + {added, removed} = summarizeStringChange(compositionStart, data) @setInputSummary(textAdded: added, didDelete: Boolean(removed)) input: (event) -> diff --git a/test/src/system/basic_input_test.coffee b/test/src/system/basic_input_test.coffee index 926a90ab2..ce64e4484 100644 --- a/test/src/system/basic_input_test.coffee +++ b/test/src/system/basic_input_test.coffee @@ -31,6 +31,12 @@ editorTest "pressing return", (expectDocument) -> typeCharacters "c", -> expectDocument "ab\nc\n" +editorTest "pressing return after a canceled composition", (expectDocument) -> + typeCharacters "ab", -> + triggerEvent document.activeElement, "compositionend", data: "ab" + pressKey "return", -> + expectDocument "ab\n\n" + editorTest "cursor left", (expectDocument) -> typeCharacters "ac", -> moveCursor "left", -> From 0e21c177dcff832f3a1aee28543f7dd1d2d7b28e Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Thu, 5 Nov 2015 09:16:31 -0500 Subject: [PATCH 3/5] Consolidate composition tests --- test/src/system/basic_input_test.coffee | 16 --------- test/src/system/composition_input_test.coffee | 34 +++++++++++++++++++ test/src/system/text_formatting_test.coffee | 17 ---------- 3 files changed, 34 insertions(+), 33 deletions(-) create mode 100644 test/src/system/composition_input_test.coffee diff --git a/test/src/system/basic_input_test.coffee b/test/src/system/basic_input_test.coffee index ce64e4484..5feefde14 100644 --- a/test/src/system/basic_input_test.coffee +++ b/test/src/system/basic_input_test.coffee @@ -4,16 +4,6 @@ editorTest "typing", (expectDocument) -> typeCharacters "abc", -> expectDocument "abc\n" -editorTest "composing", (expectDocument) -> - composeString "abc", -> - expectDocument "abc\n" - -editorTest "typing and composing", (expectDocument) -> - typeCharacters "a", -> - composeString "bcd", -> - typeCharacters "e", -> - expectDocument "abcde\n" - editorTest "backspacing", (expectDocument) -> typeCharacters "abc\b", -> assertLocationRange(index: 0, offset: 2) @@ -31,12 +21,6 @@ editorTest "pressing return", (expectDocument) -> typeCharacters "c", -> expectDocument "ab\nc\n" -editorTest "pressing return after a canceled composition", (expectDocument) -> - typeCharacters "ab", -> - triggerEvent document.activeElement, "compositionend", data: "ab" - pressKey "return", -> - expectDocument "ab\n\n" - editorTest "cursor left", (expectDocument) -> typeCharacters "ac", -> moveCursor "left", -> diff --git a/test/src/system/composition_input_test.coffee b/test/src/system/composition_input_test.coffee new file mode 100644 index 000000000..f3680dba9 --- /dev/null +++ b/test/src/system/composition_input_test.coffee @@ -0,0 +1,34 @@ +editorModule "Composition input", template: "editor_empty" + +editorTest "composing", (expectDocument) -> + composeString "abc", -> + expectDocument "abc\n" + +editorTest "typing and composing", (expectDocument) -> + typeCharacters "a", -> + composeString "bcd", -> + typeCharacters "e", -> + expectDocument "abcde\n" + +editorTest "pressing return after a canceled composition", (expectDocument) -> + typeCharacters "ab", -> + triggerEvent document.activeElement, "compositionend", data: "ab" + pressKey "return", -> + expectDocument "ab\n\n" + +editorTest "composing formatted text", (expectDocument) -> + typeCharacters "abc", -> + clickToolbarButton attribute: "bold", -> + composeString "def", -> + expectAttributes([0, 3], {}) + expectAttributes([3, 6], bold: true) + expectDocument("abcdef\n") + +editorTest "composing away from formatted text", (expectDocument) -> + clickToolbarButton attribute: "bold", -> + typeCharacters "abc", -> + clickToolbarButton attribute: "bold", -> + composeString "def", -> + expectAttributes([0, 3], bold: true) + expectAttributes([3, 6], {}) + expectDocument("abcdef\n") diff --git a/test/src/system/text_formatting_test.coffee b/test/src/system/text_formatting_test.coffee index aa30e8dc6..a14b6b665 100644 --- a/test/src/system/text_formatting_test.coffee +++ b/test/src/system/text_formatting_test.coffee @@ -143,20 +143,3 @@ editorTest "key command activates toolbar button", (done) -> typeToolbarKeyCommand attribute: "bold", -> ok isToolbarButtonActive(attribute: "bold") done() - -editorTest "composing formatted text", (expectDocument) -> - typeCharacters "abc", -> - clickToolbarButton attribute: "bold", -> - composeString "def", -> - expectAttributes([0, 3], {}) - expectAttributes([3, 6], bold: true) - expectDocument("abcdef\n") - -editorTest "composing away from formatted text", (expectDocument) -> - clickToolbarButton attribute: "bold", -> - typeCharacters "abc", -> - clickToolbarButton attribute: "bold", -> - composeString "def", -> - expectAttributes([0, 3], bold: true) - expectAttributes([3, 6], {}) - expectDocument("abcdef\n") From 6119e15931963a8ef9c9525e6d65ebb97d651e17 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Thu, 5 Nov 2015 09:36:19 -0500 Subject: [PATCH 4/5] Move placeholder methods into Composition --- src/trix/controllers/input_controller.coffee | 27 ++++++++------------ src/trix/models/composition.coffee | 14 ++++++++++ 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/trix/controllers/input_controller.coffee b/src/trix/controllers/input_controller.coffee index 992237623..2bec2686d 100644 --- a/src/trix/controllers/input_controller.coffee +++ b/src/trix/controllers/input_controller.coffee @@ -236,15 +236,22 @@ class Trix.InputController extends Trix.BasicObject event.preventDefault() compositionstart: (event) -> - @insertPlaceholder() + unless @selectionIsExpanded() + textAdded = @responder?.insertPlaceholder() + @setInputSummary({textAdded}) + @requestRender() + @setInputSummary(composing: true, compositionStart: event.data) compositionupdate: (event) -> - @selectPlaceholder() + if @responder?.selectPlaceholder() + @responder?.forgetPlaceholder() + @setInputSummary(composing: true, compositionUpdate: event.data) compositionend: (event) -> - @selectPlaceholder() + if @responder?.selectPlaceholder() + @responder?.forgetPlaceholder() {compositionStart} = @inputSummary {data} = event @@ -336,20 +343,6 @@ class Trix.InputController extends Trix.BasicObject # Private - placeholder = " " - - insertPlaceholder: -> - unless @selectionIsExpanded() - @placeholderPosition = @responder?.getPosition() - @setInputSummary(textAdded: placeholder) - @responder?.insertString(placeholder) - @requestRender() - - selectPlaceholder: -> - if @placeholderPosition? - @responder?.setSelectedRange([@placeholderPosition, @placeholderPosition + placeholder.length]) - @placeholderPosition = null - handleInput: (callback) -> try @delegate?.inputControllerWillHandleInput() diff --git a/src/trix/models/composition.coffee b/src/trix/models/composition.coffee index c28fe8ead..697c04807 100644 --- a/src/trix/models/composition.coffee +++ b/src/trix/models/composition.coffee @@ -187,6 +187,20 @@ class Trix.Composition extends Trix.BasicObject @removeCurrentAttribute(block.getLastAttribute()) @setSelection(startPosition) + placeholder = " " + + insertPlaceholder: -> + @placeholderPosition = @getPosition() + @insertString(placeholder) + placeholder + + selectPlaceholder: -> + if @placeholderPosition? + @setSelectedRange([@placeholderPosition, @placeholderPosition + placeholder.length]) + + forgetPlaceholder: -> + @placeholderPosition = null + # Current attributes hasCurrentAttribute: (attributeName) -> From f9a924288bbe3ba5677b0e14ab8b4914404c3310 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Thu, 5 Nov 2015 10:09:21 -0500 Subject: [PATCH 5/5] Ensure truthy value is returned --- src/trix/models/composition.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/trix/models/composition.coffee b/src/trix/models/composition.coffee index 697c04807..5a0ffdcb8 100644 --- a/src/trix/models/composition.coffee +++ b/src/trix/models/composition.coffee @@ -197,6 +197,7 @@ class Trix.Composition extends Trix.BasicObject selectPlaceholder: -> if @placeholderPosition? @setSelectedRange([@placeholderPosition, @placeholderPosition + placeholder.length]) + true forgetPlaceholder: -> @placeholderPosition = null