Bug 1020698 - Implement @autocomplete for <textarea>. r=baku
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Wed, 08 Nov 2017 21:35:04 -0800
changeset 702176 b693fb4f900d51d3fda7300de6405a40b99ede4f
parent 702175 20fbea037bce2e3b262fe528214c1dc1afd033c0
child 702177 4a65f0921a8545c8ec5f0f0de2b9557dbec66a89
push id90414
push usermozilla@noorenberghe.ca
push dateWed, 22 Nov 2017 21:44:13 +0000
reviewersbaku
bugs1020698
milestone59.0a1
Bug 1020698 - Implement @autocomplete for <textarea>. r=baku The dom.forms.autocomplete.formautofill check in nsContentUtils::InternalSerializeAutocompleteAttribute will control if values other than "on" and "off" are supported. MozReview-Commit-ID: 48X3OzvuOpV
dom/base/nsContentUtils.cpp
dom/html/HTMLTextAreaElement.cpp
dom/html/HTMLTextAreaElement.h
dom/html/test/forms/mochitest.ini
dom/html/test/forms/test_autocomplete.html
dom/html/test/forms/test_input_autocomplete.html
dom/webidl/HTMLTextAreaElement.webidl
testing/web-platform/meta/html/dom/interfaces.html.ini
testing/web-platform/meta/html/dom/reflection-forms.html.ini
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -1132,17 +1132,17 @@ nsContentUtils::SerializeAutocompleteAtt
  *
  * @return {AutocompleteAttrState} The state of the attribute (invalid/valid).
  */
 nsContentUtils::AutocompleteAttrState
 nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal,
                                                        mozilla::dom::AutocompleteInfo& aInfo,
                                                        bool aGrantAllValidValue)
 {
-  // No sandbox attribute so we are done
+  // No autocomplete attribute so we are done
   if (!aAttrVal) {
     return eAutocompleteAttrState_Invalid;
   }
 
   uint32_t numTokens = aAttrVal->GetAtomCount();
   if (!numTokens) {
     return eAutocompleteAttrState_Invalid;
   }
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -58,16 +58,17 @@ HTMLTextAreaElement::HTMLTextAreaElement
     mLastValueChangeWasInteractive(false),
     mHandlingSelect(false),
     mDoneAddingChildren(!aFromParser),
     mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
     mDisabledChanged(false),
     mCanShowInvalidUI(true),
     mCanShowValidUI(true),
     mIsPreviewEnabled(false),
+    mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
     mState(this)
 {
   AddMutationObserver(this);
 
   // Set up our default state.  By default we're enabled (since we're
   // a control type that can be disabled but not actually disabled
   // right now), optional, and valid.  We are NOT readwrite by default
   // until someone calls UpdateEditableState on us, apparently!  Also
@@ -431,16 +432,19 @@ HTMLTextAreaElement::ParseAttribute(int3
         aAttribute == nsGkAtoms::minlength) {
       return aResult.ParseNonNegativeIntValue(aValue);
     } else if (aAttribute == nsGkAtoms::cols) {
       aResult.ParseIntWithFallback(aValue, DEFAULT_COLS);
       return true;
     } else if (aAttribute == nsGkAtoms::rows) {
       aResult.ParseIntWithFallback(aValue, DEFAULT_ROWS_TEXTAREA);
       return true;
+    } else if (aAttribute == nsGkAtoms::autocomplete) {
+      aResult.ParseAtomArray(aValue);
+      return true;
     }
   }
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
 void
 HTMLTextAreaElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
@@ -1055,16 +1059,19 @@ HTMLTextAreaElement::AfterSetAttr(int32_
       }
 
       UpdateValueMissingValidityState();
 
       // This *has* to be called *after* validity has changed.
       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
         UpdateBarredFromConstraintValidation();
       }
+    } else if (aName == nsGkAtoms::autocomplete) {
+      // Clear the cached @autocomplete attribute state.
+      mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
     } else if (aName == nsGkAtoms::maxlength) {
       UpdateTooLongValidityState();
     } else if (aName == nsGkAtoms::minlength) {
       UpdateTooShortValidityState();
     }
   }
 
   return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName, aValue,
@@ -1364,10 +1371,20 @@ HTMLTextAreaElement::FieldSetDisabledCha
 }
 
 JSObject*
 HTMLTextAreaElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLTextAreaElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
+void
+HTMLTextAreaElement::GetAutocomplete(DOMString& aValue)
+{
+  const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
+
+  mAutocompleteAttrState =
+    nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
+                                                   mAutocompleteAttrState);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -176,16 +176,21 @@ public:
   void     UpdateTooLongValidityState();
   void     UpdateTooShortValidityState();
   void     UpdateValueMissingValidityState();
   void     UpdateBarredFromConstraintValidation();
   nsresult GetValidationMessage(nsAString& aValidationMessage,
                                 ValidityStateType aType) override;
 
   // Web IDL binding methods
+  void GetAutocomplete(DOMString& aValue);
+  void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
+  }
   bool Autofocus()
   {
     return GetBoolAttr(nsGkAtoms::autofocus);
   }
   void SetAutofocus(bool aAutoFocus, ErrorResult& aError)
   {
     SetHTMLBoolAttr(nsGkAtoms::autofocus, aAutoFocus, aError);
   }
@@ -342,16 +347,18 @@ protected:
   /** Whether our disabled state has changed from the default **/
   bool                     mDisabledChanged;
   /** Whether we should make :-moz-ui-invalid apply on the element. **/
   bool                     mCanShowInvalidUI;
   /** Whether we should make :-moz-ui-valid apply on the element. **/
   bool                     mCanShowValidUI;
   bool                     mIsPreviewEnabled;
 
+  nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
+
   void FireChangeEventIfNeeded();
 
   nsString mFocusedValue;
 
   /** The state of the text editor (selection controller and the editor) **/
   nsTextEditorState mState;
 
   NS_IMETHOD SelectAll(nsPresContext* aPresContext);
--- a/dom/html/test/forms/mochitest.ini
+++ b/dom/html/test/forms/mochitest.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 support-files =
   save_restore_radio_groups.sjs
   test_input_number_data.js
   !/dom/html/test/reflect.js
   FAIL.html
   PASS.html
 
+[test_autocomplete.html]
 [test_bug1039548.html]
 [test_bug1283915.html]
 [test_bug1286509.html]
 skip-if = os == "android" # up/down arrow keys not supported on android
 [test_button_attributes_reflection.html]
 [test_input_radio_indeterminate.html]
 [test_input_radio_radiogroup.html]
 [test_input_radio_required.html]
@@ -20,17 +21,16 @@ skip-if = os == "android" # up/down arro
 [test_form_attribute-2.html]
 [test_form_attribute-3.html]
 [test_form_attribute-4.html]
 [test_form_attributes_reflection.html]
 [test_form_named_getter_dynamic.html]
 [test_formaction_attribute.html]
 [test_formnovalidate_attribute.html]
 [test_input_attributes_reflection.html]
-[test_input_autocomplete.html]
 [test_input_color_input_change_events.html]
 [test_input_color_picker_initial.html]
 [test_input_color_picker_popup.html]
 skip-if = android_version == '18' # Android, bug 1147974
 [test_input_color_picker_update.html]
 skip-if = android_version == '18' # Android, bug 1147974
 [test_input_date_bad_input.html]
 [test_input_date_key_events.html]
rename from dom/html/test/forms/test_input_autocomplete.html
rename to dom/html/test/forms/test_autocomplete.html
--- a/dom/html/test/forms/test_input_autocomplete.html
+++ b/dom/html/test/forms/test_autocomplete.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <html>
 <!--
-Test @autocomplete on <input>
+Test @autocomplete on <input>/<select>/<textarea>
 -->
 <head>
-  <title>Test for &lt;input autocomplete='…'&gt;</title>
+  <title>Test for @autocomplete</title>
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
 <script>
 "use strict";
 
 var values = [
   // @autocomplete content attribute, expected IDL attribute value
 
@@ -103,28 +103,33 @@ function start() {
       inputField.removeAttribute("type");
     else
       inputField.type = type;
     checkAutocompleteValues(inputField, type || "");
   }
 
   var selectField = document.getElementById("select-field");
   checkAutocompleteValues(selectField, "select");
+
+  var textarea = document.getElementById("textarea");
+  checkAutocompleteValues(textarea, "textarea");
+
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({"set": [["dom.forms.autocomplete.formautofill", true]]}, start);
 </script>
 </head>
 
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
   <form>
     <input id="input-field" />
     <select id="select-field" />
+    <textarea id="textarea"></textarea>
   </form>
 </div>
 <pre id="test">
 </pre>
 </body>
 </html>
--- a/dom/webidl/HTMLTextAreaElement.webidl
+++ b/dom/webidl/HTMLTextAreaElement.webidl
@@ -11,17 +11,18 @@
  * and create derivative works of this document.
  */
 
 interface nsIEditor;
 interface XULControllers;
 
 [HTMLConstructor]
 interface HTMLTextAreaElement : HTMLElement {
-           // attribute DOMString autocomplete;
+  [CEReactions, SetterThrows, Pure]
+           attribute DOMString autocomplete;
   [CEReactions, SetterThrows, Pure]
            attribute boolean autofocus;
   [CEReactions, SetterThrows, Pure]
            attribute unsigned long cols;
            // attribute DOMString dirName;
   [CEReactions, SetterThrows, Pure]
            attribute boolean disabled;
   [Pure]
--- a/testing/web-platform/meta/html/dom/interfaces.html.ini
+++ b/testing/web-platform/meta/html/dom/interfaces.html.ini
@@ -1067,28 +1067,22 @@
     expected: FAIL
 
   [HTMLButtonElement interface: document.createElement("button") must inherit property "menu" with the proper type (11)]
     expected: FAIL
 
   [HTMLButtonElement interface: document.createElement("button") must inherit property "labels" with the proper type (18)]
     expected: FAIL
 
-  [HTMLTextAreaElement interface: attribute autocomplete]
-    expected: FAIL
-
   [HTMLTextAreaElement interface: attribute dirName]
     expected: FAIL
 
   [HTMLTextAreaElement interface: attribute inputMode]
     expected: FAIL
 
-  [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "autocomplete" with the proper type (0)]
-    expected: FAIL
-
   [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "dirName" with the proper type (3)]
     expected: FAIL
 
   [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "inputMode" with the proper type (6)]
     expected: FAIL
 
   [HTMLKeygenElement interface: existence and properties of interface object]
     expected: FAIL
@@ -3815,19 +3809,16 @@
     expected: FAIL
 
   [HTMLInputElement interface: createInput("reset") must inherit property "dirName" with the proper type]
     expected: FAIL
 
   [HTMLInputElement interface: createInput("button") must inherit property "dirName" with the proper type]
     expected: FAIL
 
-  [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "autocomplete" with the proper type]
-    expected: FAIL
-
   [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "dirName" with the proper type]
     expected: FAIL
 
   [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "inputMode" with the proper type]
     expected: FAIL
 
   [HTMLScriptElement interface: document.createElement("script") must inherit property "noModule" with the proper type]
     expected: FAIL
--- a/testing/web-platform/meta/html/dom/reflection-forms.html.ini
+++ b/testing/web-platform/meta/html/dom/reflection-forms.html.ini
@@ -3458,67 +3458,16 @@
     expected: FAIL
 
   [input.inputMode: IDL set to "KANA-NAME"]
     expected: FAIL
 
   [input.inputMode: IDL set to "Kana-name"]
     expected: FAIL
 
-  [textarea.autocomplete: typeof IDL attribute]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL get with DOM attribute unset]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to ""]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f  foo "]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to undefined]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to 7]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to 1.5]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to true]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to false]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to object "[object Object\]"]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to NaN]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to Infinity]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to -Infinity]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to "\\0"]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to null]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to object "test-toString"]
-    expected: FAIL
-
-  [textarea.autocomplete: IDL set to object "test-valueOf"]
-    expected: FAIL
-
   [textarea.inputMode: setAttribute() to "kana-name"]
     expected: FAIL
 
   [textarea.inputMode: setAttribute() to "xkana-name"]
     expected: FAIL
 
   [textarea.inputMode: setAttribute() to "kana-name\\0"]
     expected: FAIL