Bug 1283915: preserve input selection properties after type change; r?smaug draft
authorDecky Coss <coss@cosstropolis.com>
Wed, 27 Jul 2016 11:04:53 -0400
changeset 400151 55964621d1e9bdbe6eb8263d80057ae3b45681ed
parent 399408 0502bd9e025edde29777ba1de4280f9b52af4663
child 528142 e428f7ffe8bde079970f2319979c44bd85631f3c
push id26078
push usercoss@cosstropolis.com
push dateFri, 12 Aug 2016 16:56:51 +0000
reviewerssmaug
bugs1283915
milestone51.0a1
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
@@ -4817,22 +4817,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>