Bug 1020697 - Implement @autocomplete for <select>. r=smaug

This commit is contained in:
Giovanni Sferro 2014-06-17 19:50:00 +02:00
parent 2b00ecc700
commit 3ef149fde8
7 changed files with 68 additions and 28 deletions

View File

@ -2040,8 +2040,11 @@ public:
* *
* @return whether aAttr was valid and can be cached. * @return whether aAttr was valid and can be cached.
*/ */
static AutocompleteAttrState SerializeAutocompleteAttribute(const nsAttrValue* aAttr, static AutocompleteAttrState
nsAString& aResult); SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
nsAString& aResult,
AutocompleteAttrState aCachedState =
eAutocompleteAttrState_Unknown);
/** /**
* This will parse aSource, to extract the value of the pseudo attribute * This will parse aSource, to extract the value of the pseudo attribute

View File

@ -855,8 +855,26 @@ nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput)
nsContentUtils::AutocompleteAttrState nsContentUtils::AutocompleteAttrState
nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr, nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
nsAString& aResult) nsAString& aResult,
AutocompleteAttrState aCachedState)
{ {
if (!aAttr ||
aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) {
return aCachedState;
}
if (aCachedState == nsContentUtils::eAutocompleteAttrState_Valid) {
uint32_t atomCount = aAttr->GetAtomCount();
for (uint32_t i = 0; i < atomCount; i++) {
if (i != 0) {
aResult.Append(' ');
}
aResult.Append(nsDependentAtomString(aAttr->AtomAt(i)));
}
nsContentUtils::ASCIIToLower(aResult);
return aCachedState;
}
AutocompleteAttrState state = InternalSerializeAutocompleteAttribute(aAttr, aResult); AutocompleteAttrState state = InternalSerializeAutocompleteAttribute(aAttr, aResult);
if (state == eAutocompleteAttrState_Valid) { if (state == eAutocompleteAttrState_Valid) {
ASCIIToLower(aResult); ASCIIToLower(aResult);

View File

@ -1520,23 +1520,10 @@ HTMLInputElement::GetAutocomplete(nsAString& aValue)
{ {
aValue.Truncate(0); aValue.Truncate(0);
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete); const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
if (!attributeVal ||
mAutocompleteAttrState == nsContentUtils::eAutocompleteAttrState_Invalid) {
return NS_OK;
}
if (mAutocompleteAttrState == nsContentUtils::eAutocompleteAttrState_Valid) {
uint32_t atomCount = attributeVal->GetAtomCount();
for (uint32_t i = 0; i < atomCount; i++) {
if (i != 0) {
aValue.Append(' ');
}
aValue.Append(nsDependentAtomString(attributeVal->AtomAt(i)));
}
nsContentUtils::ASCIIToLower(aValue);
return NS_OK;
}
mAutocompleteAttrState = nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue); mAutocompleteAttrState =
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
mAutocompleteAttrState);
return NS_OK; return NS_OK;
} }

View File

@ -104,6 +104,7 @@ HTMLSelectElement::HTMLSelectElement(already_AddRefed<nsINodeInfo>& aNodeInfo,
FromParser aFromParser) FromParser aFromParser)
: nsGenericHTMLFormElementWithState(aNodeInfo), : nsGenericHTMLFormElementWithState(aNodeInfo),
mOptions(new HTMLOptionsCollection(MOZ_THIS_IN_INITIALIZER_LIST())), mOptions(new HTMLOptionsCollection(MOZ_THIS_IN_INITIALIZER_LIST())),
mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
mIsDoneAddingChildren(!aFromParser), mIsDoneAddingChildren(!aFromParser),
mDisabledChanged(false), mDisabledChanged(false),
mMutating(false), mMutating(false),
@ -177,6 +178,16 @@ HTMLSelectElement::SetCustomValidity(const nsAString& aError)
return NS_OK; return NS_OK;
} }
void
HTMLSelectElement::GetAutocomplete(DOMString& aValue)
{
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
mAutocompleteAttrState =
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
mAutocompleteAttrState);
}
NS_IMETHODIMP NS_IMETHODIMP
HTMLSelectElement::GetForm(nsIDOMHTMLFormElement** aForm) HTMLSelectElement::GetForm(nsIDOMHTMLFormElement** aForm)
{ {
@ -1333,6 +1344,9 @@ HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
UpdateBarredFromConstraintValidation(); UpdateBarredFromConstraintValidation();
} else if (aName == nsGkAtoms::required) { } else if (aName == nsGkAtoms::required) {
UpdateValueMissingValidityState(); UpdateValueMissingValidityState();
} else if (aName == nsGkAtoms::autocomplete) {
// Clear the cached @autocomplete attribute state
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
} }
UpdateState(aNotify); UpdateState(aNotify);
@ -1420,8 +1434,13 @@ HTMLSelectElement::ParseAttribute(int32_t aNamespaceID,
const nsAString& aValue, const nsAString& aValue,
nsAttrValue& aResult) nsAttrValue& aResult)
{ {
if (aAttribute == nsGkAtoms::size && kNameSpaceID_None == aNamespaceID) { if (kNameSpaceID_None == aNamespaceID) {
if (aAttribute == nsGkAtoms::size) {
return aResult.ParsePositiveIntValue(aValue); return aResult.ParsePositiveIntValue(aValue);
} else if (aAttribute == nsGkAtoms::autocomplete) {
aResult.ParseAtomArray(aValue);
return true;
}
} }
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue, return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
aResult); aResult);

View File

@ -17,6 +17,7 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsError.h" #include "nsError.h"
#include "mozilla/dom/HTMLFormElement.h" #include "mozilla/dom/HTMLFormElement.h"
#include "nsContentUtils.h"
class nsContentList; class nsContentList;
class nsIDOMHTMLOptionElement; class nsIDOMHTMLOptionElement;
@ -159,6 +160,11 @@ public:
{ {
SetHTMLBoolAttr(nsGkAtoms::autofocus, aVal, aRv); SetHTMLBoolAttr(nsGkAtoms::autofocus, aVal, aRv);
} }
void GetAutocomplete(DOMString& aValue);
void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv)
{
SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
}
bool Disabled() const bool Disabled() const
{ {
return GetBoolAttr(nsGkAtoms::disabled); return GetBoolAttr(nsGkAtoms::disabled);
@ -605,6 +611,7 @@ protected:
/** The options[] array */ /** The options[] array */
nsRefPtr<HTMLOptionsCollection> mOptions; nsRefPtr<HTMLOptionsCollection> mOptions;
nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
/** false if the parser is in the middle of adding children. */ /** false if the parser is in the middle of adding children. */
bool mIsDoneAddingChildren; bool mIsDoneAddingChildren;
/** true if our disabled state has changed from the default **/ /** true if our disabled state has changed from the default **/

View File

@ -13,7 +13,8 @@ Test @autocomplete on <input>
<p id="display"></p> <p id="display"></p>
<div id="content" style="display: none"> <div id="content" style="display: none">
<form> <form>
<input id="field" /> <input id="input-field" />
<select id="select-field" />
</form> </form>
</div> </div>
<pre id="test"> <pre id="test">
@ -69,9 +70,8 @@ var values = [
]; ];
var types = [undefined, "hidden", "text", "search"]; // Valid types for all non-multiline hints. var types = [undefined, "hidden", "text", "search"]; // Valid types for all non-multiline hints.
var field = document.getElementById("field");
function checkAutocompleteValues(type) { function checkAutocompleteValues(field, type) {
for (var test of values) { for (var test of values) {
if (typeof(test[0]) === "undefined") if (typeof(test[0]) === "undefined")
field.removeAttribute("autocomplete"); field.removeAttribute("autocomplete");
@ -83,14 +83,18 @@ function checkAutocompleteValues(type) {
} }
function start() { function start() {
var inputField = document.getElementById("input-field");
for (var type of types) { for (var type of types) {
// Switch the input type // Switch the input type
if (typeof(type) === "undefined") if (typeof(type) === "undefined")
field.removeAttribute("type"); inputField.removeAttribute("type");
else else
field.type = type; inputField.type = type;
checkAutocompleteValues(type || ""); checkAutocompleteValues(inputField, type || "");
} }
var selectField = document.getElementById("select-field");
checkAutocompleteValues(selectField, "select");
SimpleTest.finish(); SimpleTest.finish();
} }

View File

@ -10,6 +10,8 @@
interface HTMLSelectElement : HTMLElement { interface HTMLSelectElement : HTMLElement {
[SetterThrows, Pure] [SetterThrows, Pure]
attribute boolean autofocus; attribute boolean autofocus;
[Pref="dom.forms.autocomplete.experimental", SetterThrows, Pure]
attribute DOMString autocomplete;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute boolean disabled; attribute boolean disabled;
[Pure] [Pure]