# HG changeset patch # User Jan Jongboom Bug 1059163 - Add a mutation observer to contenteditable elements to detect selection changes that nsISelectionPrivate misses diff --git a/dom/inputmethod/forms.js b/dom/inputmethod/forms.js --- a/dom/inputmethod/forms.js +++ b/dom/inputmethod/forms.js @@ -219,17 +219,18 @@ let FormAssistant = { isKeyboardOpened: false, selectionStart: -1, selectionEnd: -1, textBeforeCursor: "", textAfterCursor: "", scrollIntoViewTimeout: null, _focusedElement: null, _focusCounter: 0, // up one for every time we focus a new element - _observer: null, + _focusDeleteObserver: null, + _focusContentObserver: null, _documentEncoder: null, _editor: null, _editing: false, _selectionPrivate: null, get focusedElement() { if (this._focusedElement && Cu.isDeadWrapper(this._focusedElement)) this._focusedElement = null; @@ -245,19 +246,23 @@ let FormAssistant = { setFocusedElement: function fa_setFocusedElement(element) { let self = this; if (element === this.focusedElement) return; if (this.focusedElement) { this.focusedElement.removeEventListener('compositionend', this); - if (this._observer) { - this._observer.disconnect(); - this._observer = null; + if (this._focusDeleteObserver) { + this._focusDeleteObserver.disconnect(); + this._focusDeleteObserver = null; + } + if (this._focusContentObserver) { + this._focusContentObserver.disconnect(); + this._focusContentObserver = null; } if (this._selectionPrivate) { this._selectionPrivate.removeSelectionListener(this); this._selectionPrivate = null; } } this._documentEncoder = null; @@ -287,33 +292,46 @@ let FormAssistant = { if (selection) { this._selectionPrivate = selection.QueryInterface(Ci.nsISelectionPrivate); this._selectionPrivate.addSelectionListener(this); } } // If our focusedElement is removed from DOM we want to handle it properly let MutationObserver = element.ownerDocument.defaultView.MutationObserver; - this._observer = new MutationObserver(function(mutations) { + this._focusDeleteObserver = new MutationObserver(function(mutations) { var del = [].some.call(mutations, function(m) { return [].some.call(m.removedNodes, function(n) { return n.contains(element); }); }); if (del && element === self.focusedElement) { self.hideKeyboard(); self.selectionStart = -1; self.selectionEnd = -1; } }); - this._observer.observe(element.ownerDocument.body, { + this._focusDeleteObserver.observe(element.ownerDocument.body, { childList: true, subtree: true }); + + // If contenteditable, also add a mutation observer on its content and + // call selectionChanged when a change occurs + if (isContentEditable(element)) { + this._focusContentObserver = new MutationObserver(function() { + this.updateSelection(); + }.bind(this)); + + this._focusContentObserver.observe(element, { + childList: true, + subtree: true + }); + } } this.focusedElement = element; }, notifySelectionChanged: function(aDocument, aSelection, aReason) { this.updateSelection(); }, diff --git a/dom/inputmethod/mochitest/file_test_contenteditable.html b/dom/inputmethod/mochitest/file_test_contenteditable.html new file mode 100644 --- /dev/null +++ b/dom/inputmethod/mochitest/file_test_contenteditable.html @@ -0,0 +1,17 @@ + + + +
Jan Jongboom
+ + + diff --git a/dom/inputmethod/mochitest/mochitest.ini b/dom/inputmethod/mochitest/mochitest.ini --- a/dom/inputmethod/mochitest/mochitest.ini +++ b/dom/inputmethod/mochitest/mochitest.ini @@ -1,22 +1,24 @@ [DEFAULT] # Not supported on Android, bug 983015 for B2G emulator skip-if = (toolkit == 'android' || toolkit == 'gonk') || e10s support-files = inputmethod_common.js file_inputmethod.html file_inputmethod_1043828.html file_test_app.html + file_test_contenteditable.html file_test_sendkey_cancel.html file_test_sms_app.html [test_basic.html] [test_bug944397.html] [test_bug949059.html] [test_bug953044.html] [test_bug960946.html] [test_bug978918.html] [test_bug1026997.html] [test_bug1043828.html] +[test_bug1059163.html] [test_delete_focused_element.html] [test_sendkey_cancel.html] [test_two_inputs.html] diff --git a/dom/inputmethod/mochitest/test_bug1059163.html b/dom/inputmethod/mochitest/test_bug1059163.html new file mode 100644 --- /dev/null +++ b/dom/inputmethod/mochitest/test_bug1059163.html @@ -0,0 +1,72 @@ + + + + + Basic test for repeat sendKey events + + + + + +Mozilla Bug 1059163 +

+
+
+
+ + +