Bug 1283915 - Preserve input selection properties after type change. r=smaug
authorDecky Coss <coss@cosstropolis.com>
Wed, 27 Jul 2016 11:04:53 -0400
changeset 353280 3f709b7217a686f8f149f85725512fffe5ee9b09
parent 353279 53bbfa02d45dedb9299573f7d1b12d37fce5116c
child 353281 34766b5100b9aabde48da7bb2a63e0f02d9a5fd6
push id1324
push usermtabara@mozilla.com
push dateMon, 16 Jan 2017 13:07:44 +0000
treeherdermozilla-release@a01c49833940 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1283915
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1283915 - Preserve input selection properties after type change. r=smaug MozReview-Commit-ID: 7xJKc3vIpTY
dom/html/HTMLInputElement.cpp
dom/html/nsTextEditorState.cpp
dom/html/nsTextEditorState.h
dom/html/test/forms/mochitest.ini
dom/html/test/forms/test_bug1283915.html
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -4821,22 +4821,32 @@ HTMLInputElement::HandleTypeChange(uint8
   ValueModeType aOldValueMode = GetValueMode();
   uint8_t oldType = mType;
   nsAutoString aOldValue;
 
   if (aOldValueMode == VALUE_MODE_VALUE) {
     GetValue(aOldValue);
   }
 
+  nsTextEditorState::SelectionProperties sp;
+
+  if (GetEditorState()) {
+    sp = mInputData.mState->GetSelectionProperties();
+  }
+
   // We already have a copy of the value, lets free it and changes the type.
   FreeData();
   mType = aNewType;
 
   if (IsSingleLineTextControl()) {
+
     mInputData.mState = new nsTextEditorState(this);
+    if (!sp.IsDefault()) {
+      mInputData.mState->SetSelectionProperties(sp);
+    }
   }
 
   /**
    * The following code is trying to reproduce the algorithm described here:
    * http://www.whatwg.org/specs/web-apps/current-work/complete.html#input-type-change
    */
   switch (GetValueMode()) {
     case VALUE_MODE_DEFAULT:
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -1531,16 +1531,29 @@ nsTextEditorState::GetSelectionPropertie
     HTMLInputElement* number = GetParentNumberControl(mBoundFrame);
     if (number) {
       return number->GetSelectionProperties();
     }
   }
   return mSelectionProperties;
 }
 
+void
+nsTextEditorState::SetSelectionProperties(nsTextEditorState::SelectionProperties& aProps)
+{
+  if (mBoundFrame) {
+    mBoundFrame->SetSelectionRange(aProps.GetStart(),
+                                   aProps.GetEnd(),
+                                   aProps.GetDirection());
+  } else {
+    mSelectionProperties = aProps;
+  }
+}
+
+
 HTMLInputElement*
 nsTextEditorState::GetParentNumberControl(nsFrame* aFrame) const
 {
   MOZ_ASSERT(aFrame);
   nsIContent* content = aFrame->GetContent();
   MOZ_ASSERT(content);
   nsIContent* parent = content->GetParent();
   if (!parent) {
--- a/dom/html/nsTextEditorState.h
+++ b/dom/html/nsTextEditorState.h
@@ -255,16 +255,17 @@ public:
     private:
       int32_t mStart, mEnd;
       bool mIsDirty = false;
       nsITextControlFrame::SelectionDirection mDirection;
   };
 
   bool IsSelectionCached() const;
   SelectionProperties& GetSelectionProperties();
+  void SetSelectionProperties(SelectionProperties& aProps);
   void WillInitEagerly() { mSelectionRestoreEagerInit = true; }
   bool HasNeverInitializedBefore() const { return !mEverInited; }
 
   void UpdateEditableState(bool aNotify) {
     if (mRootNode) {
       mRootNode->UpdateEditableState(aNotify);
     }
   }
--- a/dom/html/test/forms/mochitest.ini
+++ b/dom/html/test/forms/mochitest.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 support-files =
   save_restore_radio_groups.sjs
   test_input_number_data.js
   !/dom/html/test/reflect.js
 
 [test_bug1039548.html]
+[test_bug1283915.html]
 [test_bug1286509.html]
 skip-if = os == "android" || appname == "b2g" # up/down arrow keys not supported on android/b2g
 [test_button_attributes_reflection.html]
 [test_input_radio_radiogroup.html]
 [test_input_radio_required.html]
 [test_change_event.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_datalist_element.html]
new file mode 100644
--- /dev/null
+++ b/dom/html/test/forms/test_bug1283915.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1283915
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1283915</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1283915 **/
+
+  SimpleTest.waitForExplicitFinish();
+
+  function isCursorAtEnd(field){
+    is(field.selectionStart, field.value.length);
+    is(field.selectionEnd, field.value.length);
+  }
+
+  function test() {
+    var tField = document.getElementById("textField");
+    tField.focus();
+
+    synthesizeKey("a", {});
+    is(tField.value, "a");
+    isCursorAtEnd(tField);
+    document.body.offsetWidth; // frame must be created after type change
+
+    synthesizeKey("b", {});
+    is(tField.value, "ab");
+    isCursorAtEnd(tField);
+
+    synthesizeKey("c", {});
+    is(tField.value, "abc");
+    isCursorAtEnd(tField);
+
+    var nField = document.getElementById("numField");
+    nField.focus();
+
+    synthesizeKey("1", {});
+    is(nField.value, "1");
+    isCursorAtEnd(nField);
+    document.body.offsetWidth;
+
+    synthesizeKey("2", {});
+    is(nField.value, "12");
+    isCursorAtEnd(nField);
+
+    synthesizeKey("3", {});
+    is(nField.value, "123");
+    isCursorAtEnd(nField);
+
+    SimpleTest.finish();
+  }
+
+  SimpleTest.waitForFocus(test);
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1283915">Mozilla Bug 1283915</a>
+<p id="display"></p>
+<input id="textField" type="text" oninput="if (this.type !='password') this.type = 'password';">
+<input id="numField" type="text" oninput="if (this.type !='number') this.type = 'number';">
+<pre id="test">
+</pre>
+</body>
+</html>