mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-14 12:13:22 +00:00
Bug 1020496, add getAutocompleteInfo method to get components of autocomplete attribute, r=smaug
This commit is contained in:
parent
7f12650eaa
commit
1bfbc6d5da
@ -27,6 +27,7 @@
|
||||
#include "nsMathUtils.h"
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
#include "Units.h"
|
||||
#include "mozilla/dom/AutocompleteInfoBinding.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Undefine LoadImage to prevent naming conflict with Windows.
|
||||
@ -2045,8 +2046,22 @@ public:
|
||||
*
|
||||
* @return whether aAttr was valid and can be cached.
|
||||
*/
|
||||
static AutocompleteAttrState SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
nsAString& aResult);
|
||||
static AutocompleteAttrState
|
||||
SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
nsAString& aResult,
|
||||
AutocompleteAttrState aCachedState =
|
||||
eAutocompleteAttrState_Unknown);
|
||||
|
||||
/* Variation that is used to retrieve a dictionary of the parts of the
|
||||
* autocomplete attribute.
|
||||
*
|
||||
* @return whether aAttr was valid and can be cached.
|
||||
*/
|
||||
static AutocompleteAttrState
|
||||
SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
mozilla::dom::AutocompleteInfo& aInfo,
|
||||
AutocompleteAttrState aCachedState =
|
||||
eAutocompleteAttrState_Unknown);
|
||||
|
||||
/**
|
||||
* This will parse aSource, to extract the value of the pseudo attribute
|
||||
@ -2205,8 +2220,9 @@ private:
|
||||
static void* AllocClassMatchingInfo(nsINode* aRootNode,
|
||||
const nsString* aClasses);
|
||||
|
||||
// Fills in aInfo with the tokens from the supplied autocomplete attribute.
|
||||
static AutocompleteAttrState InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal,
|
||||
nsAString& aResult);
|
||||
mozilla::dom::AutocompleteInfo& aInfo);
|
||||
|
||||
static nsIXPConnect *sXPConnect;
|
||||
|
||||
|
@ -766,17 +766,73 @@ nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput)
|
||||
|
||||
nsContentUtils::AutocompleteAttrState
|
||||
nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
nsAString& aResult)
|
||||
nsAString& aResult,
|
||||
AutocompleteAttrState aCachedState)
|
||||
{
|
||||
AutocompleteAttrState state = InternalSerializeAutocompleteAttribute(aAttr, aResult);
|
||||
if (state == eAutocompleteAttrState_Valid) {
|
||||
ASCIIToLower(aResult);
|
||||
} else {
|
||||
aResult.Truncate();
|
||||
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;
|
||||
}
|
||||
|
||||
aResult.Truncate();
|
||||
|
||||
mozilla::dom::AutocompleteInfo info;
|
||||
AutocompleteAttrState state =
|
||||
InternalSerializeAutocompleteAttribute(aAttr, info);
|
||||
if (state == eAutocompleteAttrState_Valid) {
|
||||
// Concatenate the info fields.
|
||||
aResult = info.mSection;
|
||||
|
||||
if (!info.mAddressType.IsEmpty()) {
|
||||
if (!aResult.IsEmpty()) {
|
||||
aResult += ' ';
|
||||
}
|
||||
aResult += info.mAddressType;
|
||||
}
|
||||
|
||||
if (!info.mContactType.IsEmpty()) {
|
||||
if (!aResult.IsEmpty()) {
|
||||
aResult += ' ';
|
||||
}
|
||||
aResult += info.mContactType;
|
||||
}
|
||||
|
||||
if (!info.mFieldName.IsEmpty()) {
|
||||
if (!aResult.IsEmpty()) {
|
||||
aResult += ' ';
|
||||
}
|
||||
aResult += info.mFieldName;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
nsContentUtils::AutocompleteAttrState
|
||||
nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
mozilla::dom::AutocompleteInfo& aInfo,
|
||||
AutocompleteAttrState aCachedState)
|
||||
{
|
||||
if (!aAttr ||
|
||||
aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) {
|
||||
return aCachedState;
|
||||
}
|
||||
|
||||
return InternalSerializeAutocompleteAttribute(aAttr, aInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to validate the @autocomplete tokens.
|
||||
*
|
||||
@ -784,7 +840,7 @@ nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
*/
|
||||
nsContentUtils::AutocompleteAttrState
|
||||
nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal,
|
||||
nsAString& aResult)
|
||||
mozilla::dom::AutocompleteInfo& aInfo)
|
||||
{
|
||||
// No sandbox attribute so we are done
|
||||
if (!aAttrVal) {
|
||||
@ -801,6 +857,7 @@ nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrV
|
||||
AutocompleteCategory category;
|
||||
nsAttrValue enumValue;
|
||||
|
||||
nsAutoString str;
|
||||
bool result = enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false);
|
||||
if (result) {
|
||||
// Off/Automatic/Normal categories.
|
||||
@ -809,7 +866,9 @@ nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrV
|
||||
if (numTokens > 1) {
|
||||
return eAutocompleteAttrState_Invalid;
|
||||
}
|
||||
enumValue.ToString(aResult);
|
||||
enumValue.ToString(str);
|
||||
ASCIIToLower(str);
|
||||
aInfo.mFieldName.Assign(str);
|
||||
return eAutocompleteAttrState_Valid;
|
||||
}
|
||||
|
||||
@ -837,7 +896,9 @@ nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrV
|
||||
category = eAutocompleteCategory_CONTACT;
|
||||
}
|
||||
|
||||
enumValue.ToString(aResult);
|
||||
enumValue.ToString(str);
|
||||
ASCIIToLower(str);
|
||||
aInfo.mFieldName.Assign(str);
|
||||
|
||||
// We are done if this was the only token.
|
||||
if (numTokens == 1) {
|
||||
@ -851,10 +912,10 @@ nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrV
|
||||
nsAttrValue contactFieldHint;
|
||||
result = contactFieldHint.ParseEnumValue(tokenString, kAutocompleteContactFieldHintTable, false);
|
||||
if (result) {
|
||||
aResult.Insert(' ', 0);
|
||||
nsAutoString contactFieldHintString;
|
||||
contactFieldHint.ToString(contactFieldHintString);
|
||||
aResult.Insert(contactFieldHintString, 0);
|
||||
ASCIIToLower(contactFieldHintString);
|
||||
aInfo.mContactType.Assign(contactFieldHintString);
|
||||
if (index == 0) {
|
||||
return eAutocompleteAttrState_Valid;
|
||||
}
|
||||
@ -866,16 +927,21 @@ nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrV
|
||||
// Check for billing/shipping tokens
|
||||
nsAttrValue fieldHint;
|
||||
if (fieldHint.ParseEnumValue(tokenString, kAutocompleteFieldHintTable, false)) {
|
||||
aResult.Insert(' ', 0);
|
||||
nsString fieldHintString;
|
||||
fieldHint.ToString(fieldHintString);
|
||||
aResult.Insert(fieldHintString, 0);
|
||||
ASCIIToLower(fieldHintString);
|
||||
aInfo.mAddressType.Assign(fieldHintString);
|
||||
if (index == 0) {
|
||||
return eAutocompleteAttrState_Valid;
|
||||
}
|
||||
--index;
|
||||
}
|
||||
|
||||
// Clear the fields as the autocomplete attribute is invalid.
|
||||
aInfo.mAddressType.Truncate();
|
||||
aInfo.mContactType.Truncate();
|
||||
aInfo.mFieldName.Truncate();
|
||||
|
||||
return eAutocompleteAttrState_Invalid;
|
||||
}
|
||||
|
||||
|
@ -1529,23 +1529,10 @@ HTMLInputElement::GetAutocomplete(nsAString& aValue)
|
||||
{
|
||||
aValue.Truncate(0);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1555,6 +1542,15 @@ HTMLInputElement::SetAutocomplete(const nsAString& aValue)
|
||||
return SetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete, nullptr, aValue, true);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::GetAutocompleteInfo(AutocompleteInfo& aInfo)
|
||||
{
|
||||
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
|
||||
mAutocompleteAttrState =
|
||||
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aInfo,
|
||||
mAutocompleteAttrState);
|
||||
}
|
||||
|
||||
int32_t
|
||||
HTMLInputElement::TabIndexDefault()
|
||||
{
|
||||
|
@ -370,6 +370,8 @@ public:
|
||||
SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
|
||||
}
|
||||
|
||||
void GetAutocompleteInfo(AutocompleteInfo& aInfo);
|
||||
|
||||
bool Autofocus() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::autofocus);
|
||||
|
2
content/html/content/test/forms/chrome.ini
Normal file
2
content/html/content/test/forms/chrome.ini
Normal file
@ -0,0 +1,2 @@
|
||||
[DEFAULT]
|
||||
[test_autocompleteinfo.html]
|
99
content/html/content/test/forms/test_autocompleteinfo.html
Normal file
99
content/html/content/test/forms/test_autocompleteinfo.html
Normal file
@ -0,0 +1,99 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Test getAutocompleteInfo() on <input>
|
||||
-->
|
||||
<head>
|
||||
<title>Test for getAutocompleteInfo()</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<form>
|
||||
<input id="input"/>
|
||||
</form>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
var values = [
|
||||
// Missing or empty attribute
|
||||
[undefined, {}],
|
||||
["", {}],
|
||||
|
||||
// One token
|
||||
["on", {fieldName: "on" }],
|
||||
["On", {fieldName: "on" }],
|
||||
["off", {fieldName: "off" } ],
|
||||
["username", {fieldName: "username" }],
|
||||
[" username ", {fieldName: "username" }],
|
||||
["foobar", {}],
|
||||
|
||||
// Two tokens
|
||||
["on off", {}],
|
||||
["off on", {}],
|
||||
["username tel", {}],
|
||||
["tel username ", {}],
|
||||
[" username tel ", {}],
|
||||
["tel mobile", {}],
|
||||
["tel shipping", {}],
|
||||
["shipping tel", {addressType: "shipping", fieldName: "tel"}],
|
||||
["shipPING tel", {addressType: "shipping", fieldName: "tel"}],
|
||||
["mobile tel", {contactType: "mobile", fieldName: "tel"}],
|
||||
[" MoBiLe TeL ", {contactType: "mobile", fieldName: "tel"}],
|
||||
["XXX tel", {}],
|
||||
["XXX username", {}],
|
||||
|
||||
// Three tokens
|
||||
["billing invalid tel", {}],
|
||||
["___ mobile tel", {}],
|
||||
["mobile foo tel", {}],
|
||||
["mobile tel foo", {}],
|
||||
["tel mobile billing", {}],
|
||||
["billing mobile tel", {addressType: "billing", contactType: "mobile", fieldName: "tel"}],
|
||||
[" BILLing MoBiLE tEl ", {addressType: "billing", contactType: "mobile", fieldName: "tel"}],
|
||||
["billing home tel", {addressType: "billing", contactType: "home", fieldName: "tel"}],
|
||||
|
||||
// Four tokens (invalid)
|
||||
["billing billing mobile tel", {}],
|
||||
|
||||
// Five tokens (invalid)
|
||||
["billing billing billing mobile tel", {}],
|
||||
];
|
||||
|
||||
function start() {
|
||||
const fieldid = "input";
|
||||
var field = document.getElementById(fieldid);
|
||||
for (var test of values) {
|
||||
if (typeof(test[0]) === "undefined")
|
||||
field.removeAttribute("autocomplete");
|
||||
else
|
||||
field.setAttribute("autocomplete", test[0]);
|
||||
|
||||
var info = field.getAutocompleteInfo();
|
||||
|
||||
is(info.section, "section" in test[1] ? test[1].section : "",
|
||||
"Checking autocompleteInfo.section for " + fieldid + ": " + test[0]);
|
||||
is(info.addressType, "addressType" in test[1] ? test[1].addressType : "",
|
||||
"Checking autocompleteInfo.addressType for " + fieldid + ": " + test[0]);
|
||||
is(info.contactType, "contactType" in test[1] ? test[1].contactType : "",
|
||||
"Checking autocompleteInfo.contactType for " + fieldid + ": " + test[0]);
|
||||
is(info.fieldName, "fieldName" in test[1] ? test[1].fieldName : "",
|
||||
"Checking autocompleteInfo.fieldName for " + fieldid + ": " + test[0]);
|
||||
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.forms.autocomplete.experimental", true]]}, start);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -6,7 +6,7 @@
|
||||
|
||||
MOCHITEST_MANIFESTS += ['forms/mochitest.ini', 'mochitest.ini']
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini', 'forms/chrome.ini']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
||||
|
17
dom/webidl/AutocompleteInfo.webidl
Normal file
17
dom/webidl/AutocompleteInfo.webidl
Normal file
@ -0,0 +1,17 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This dictionary is used for the input, textarea and select element's
|
||||
* getAutocompleteInfo method.
|
||||
*/
|
||||
|
||||
dictionary AutocompleteInfo {
|
||||
DOMString section = "";
|
||||
DOMString addressType = "";
|
||||
DOMString contactType = "";
|
||||
DOMString fieldName = "";
|
||||
};
|
@ -167,6 +167,9 @@ partial interface HTMLInputElement {
|
||||
readonly attribute HTMLInputElement? ownerNumberControl;
|
||||
|
||||
boolean mozIsTextField(boolean aExcludePassword);
|
||||
|
||||
[ChromeOnly]
|
||||
AutocompleteInfo getAutocompleteInfo();
|
||||
};
|
||||
|
||||
partial interface HTMLInputElement {
|
||||
|
@ -39,6 +39,7 @@ WEBIDL_FILES = [
|
||||
'AudioStreamTrack.webidl',
|
||||
'AudioTrack.webidl',
|
||||
'AudioTrackList.webidl',
|
||||
'AutocompleteInfo.webidl',
|
||||
'BarProp.webidl',
|
||||
'BatteryManager.webidl',
|
||||
'BeforeUnloadEvent.webidl',
|
||||
|
Loading…
x
Reference in New Issue
Block a user