Commit cf19b4d5 authored by ziran.sun@samsung.com's avatar ziran.sun@samsung.com

Add Autofill preview support for <select> input fields

The <select> preview is set with yellow background inline with Input and
TextArea Element preview css settings.

R=dhollowa@chromium.org, isherman@chromium.org, jhawkins@chromium.org, tkent@chromium.org
BUG=58719

Review URL: https://codereview.chromium.org/138433002

git-svn-id: svn://svn.chromium.org/blink/trunk@169476 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent d8b8311f
......@@ -66,6 +66,12 @@ instead of "initial value".
| <div>
| id="inner-editor"
| "suggested value"
| <select>
| id="select"
| <option>
| "CA"
| <option>
| "TX"
| "input.value: initial value"
| "internals.suggestedValue(input): suggested value"
| "input.selectionStart: 0"
......@@ -74,3 +80,5 @@ instead of "initial value".
| "internals.suggestedValue(month): 2014-01"
| "textarea.value: initial value"
| "internals.suggestedValue(textarea): suggested value"
| "select.value: "
| "internals.suggestedValue(select): TX"
......@@ -4,7 +4,7 @@
<p id="description">This test setting suggested values on an input element
and a textarea element. The dump below should have the "suggested value"
instead of "initial value".</p>
<pre><input id="test" type="text" value="initial value"><input id="month" type="month"><textarea id="textarea"></textarea></pre>
<pre><input id="test" type="text" value="initial value"><input id="month" type="month"><textarea id="textarea"></textarea><select id="select"><option>CA</option><option>TX</option></select></pre>
<script src="../../resources/dump-as-markup.js"></script>
<script>
......@@ -12,6 +12,8 @@ var input = document.getElementById('test');
var month = document.getElementById('month');
var textarea = document.getElementById('textarea');
textarea.value = "initial value";
var select = document.getElementById('select');
select.selectedIndex = -1;
var result = document.getElementById('result');
if (!window.internals)
testFailed('This test requires internals object');
......@@ -22,6 +24,7 @@ else {
internals.setSuggestedValue(input, 'suggested value');
internals.setSuggestedValue(month, '2014-01');
internals.setSuggestedValue(textarea, 'suggested value');
internals.setSuggestedValue(select, 'TX');
Markup.description(document.getElementById('description').textContent)
......@@ -34,7 +37,9 @@ else {
addTextResult('internals.suggestedValue(month)');
addTextResult('textarea.value');
addTextResult('internals.suggestedValue(textarea)');
addTextResult('select.value');
addTextResult('internals.suggestedValue(select)');
Markup.dump(input.parentNode);
}
......
......@@ -66,6 +66,12 @@ instead of "initial value".
| <div>
| id="inner-editor"
| "suggested value"
| <select>
| id="select"
| <option>
| "CA"
| <option>
| "TX"
| "input.value: initial value"
| "internals.suggestedValue(input): suggested value"
| "input.selectionStart: 0"
......@@ -74,3 +80,5 @@ instead of "initial value".
| "internals.suggestedValue(month): 2014-01"
| "textarea.value: initial value"
| "internals.suggestedValue(textarea): suggested value"
| "select.value: "
| "internals.suggestedValue(select): TX"
......@@ -66,6 +66,12 @@ instead of "initial value".
| <div>
| id="inner-editor"
| "suggested value"
| <select>
| id="select"
| <option>
| "CA"
| <option>
| "TX"
| "input.value: initial value"
| "internals.suggestedValue(input): suggested value"
| "input.selectionStart: 0"
......@@ -74,3 +80,5 @@ instead of "initial value".
| "internals.suggestedValue(month): 2014-01"
| "textarea.value: initial value"
| "internals.suggestedValue(textarea): suggested value"
| "select.value: "
| "internals.suggestedValue(select): TX"
......@@ -686,7 +686,7 @@ input[type="file"] {
text-align: start !important;
}
input:-webkit-autofill, textarea:-webkit-autofill {
input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {
background-color: #FAFFBD !important;
background-image:none !important;
color: #000000 !important;
......
......@@ -73,6 +73,7 @@ HTMLSelectElement::HTMLSelectElement(Document& document, HTMLFormElement* form)
, m_multiple(false)
, m_activeSelectionState(false)
, m_shouldRecalcListItems(false)
, m_suggestedIndex(-1)
{
ScriptWrappable::init(this);
}
......@@ -203,7 +204,7 @@ void HTMLSelectElement::add(HTMLElement* element, HTMLElement* before, Exception
// Make sure the element is ref'd and deref'd so we don't leak it.
RefPtr<HTMLElement> protectNewChild(element);
if (!element || !(element->hasLocalName(optionTag) || element->hasLocalName(hrTag)))
if (!element || !(isHTMLOptionElement(element) || isHTMLHRElement(element)))
return;
insertBefore(element, before, exceptionState);
......@@ -223,7 +224,7 @@ String HTMLSelectElement::value() const
{
const Vector<HTMLElement*>& items = listItems();
for (unsigned i = 0; i < items.size(); i++) {
if (items[i]->hasLocalName(optionTag) && toHTMLOptionElement(items[i])->selected())
if (isHTMLOptionElement(items[i]) && toHTMLOptionElement(items[i])->selected())
return toHTMLOptionElement(items[i])->value();
}
return "";
......@@ -241,7 +242,7 @@ void HTMLSelectElement::setValue(const String &value)
const Vector<HTMLElement*>& items = listItems();
unsigned optionIndex = 0;
for (unsigned i = 0; i < items.size(); i++) {
if (items[i]->hasLocalName(optionTag)) {
if (isHTMLOptionElement(items[i])) {
if (toHTMLOptionElement(items[i])->value() == value) {
setSelectedIndex(optionIndex);
return;
......@@ -253,6 +254,40 @@ void HTMLSelectElement::setValue(const String &value)
setSelectedIndex(-1);
}
String HTMLSelectElement::suggestedValue() const
{
const Vector<HTMLElement*>& items = listItems();
for (unsigned i = 0; i < items.size(); ++i) {
if (isHTMLOptionElement(items[i]) && m_suggestedIndex >= 0) {
if (i == static_cast<unsigned>(m_suggestedIndex))
return toHTMLOptionElement(items[i])->value();
}
}
return "";
}
void HTMLSelectElement::setSuggestedValue(const String& value)
{
if (value.isNull()) {
setSuggestedIndex(-1);
return;
}
const Vector<HTMLElement*>& items = listItems();
unsigned optionIndex = 0;
for (unsigned i = 0; i < items.size(); ++i) {
if (isHTMLOptionElement(items[i])) {
if (toHTMLOptionElement(items[i])->value() == value) {
setSuggestedIndex(optionIndex);
return;
}
optionIndex++;
}
}
setSuggestedIndex(-1);
}
bool HTMLSelectElement::isPresentationAttribute(const QualifiedName& name) const
{
if (name == alignAttr) {
......@@ -441,7 +476,7 @@ void HTMLSelectElement::setLength(unsigned newLen, ExceptionState& exceptionStat
size_t optionIndex = 0;
for (size_t i = 0; i < items.size(); ++i) {
Element* item = items[i];
if (item->hasLocalName(optionTag) && optionIndex++ >= newLen) {
if (isHTMLOptionElement(items[i]) && optionIndex++ >= newLen) {
ASSERT(item->parentNode());
itemsToRemove.append(item);
}
......@@ -797,6 +832,22 @@ void HTMLSelectElement::setSelectedIndex(int index)
selectOption(index, DeselectOtherOptions);
}
int HTMLSelectElement::suggestedIndex() const
{
return m_suggestedIndex;
}
void HTMLSelectElement::setSuggestedIndex(int suggestedIndex)
{
m_suggestedIndex = suggestedIndex;
if (RenderObject* renderer = this->renderer()) {
renderer->updateFromElement();
if (renderer->isListBox())
toRenderListBox(renderer)->scrollToRevealElementAtListIndex(suggestedIndex);
}
}
void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, bool optionIsSelected)
{
ASSERT(option->ownerSelectElement() == this);
......@@ -939,7 +990,7 @@ size_t HTMLSelectElement::searchOptionsForValue(const String& value, size_t list
const Vector<HTMLElement*>& items = listItems();
size_t loopEndIndex = std::min(items.size(), listIndexEnd);
for (size_t i = listIndexStart; i < loopEndIndex; ++i) {
if (!items[i]->hasLocalName(optionTag))
if (!isHTMLOptionElement(items[i]))
continue;
if (toHTMLOptionElement(items[i])->value() == value)
return i;
......@@ -957,7 +1008,7 @@ void HTMLSelectElement::restoreFormControlState(const FormControlState& state)
return;
for (size_t i = 0; i < itemsSize; ++i) {
if (!items[i]->hasLocalName(optionTag))
if (!isHTMLOptionElement(items[i]))
continue;
toHTMLOptionElement(items[i])->setSelectedState(false);
}
......
......@@ -44,6 +44,8 @@ public:
int selectedIndex() const;
void setSelectedIndex(int);
int suggestedIndex() const;
void setSuggestedIndex(int);
void optionSelectedByUser(int index, bool dispatchChangeEvent, bool allowMultipleSelection = false);
......@@ -67,6 +69,8 @@ public:
String value() const;
void setValue(const String&);
String suggestedValue() const;
void setSuggestedValue(const String&);
PassRefPtr<HTMLOptionsCollection> options();
PassRefPtr<HTMLCollection> selectedOptions();
......@@ -204,6 +208,7 @@ private:
bool m_multiple;
bool m_activeSelectionState;
mutable bool m_shouldRecalcListItems;
int m_suggestedIndex;
};
} // namespace
......
......@@ -426,7 +426,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint&
applyTextTransform(style(), itemText, ' ');
Color textColor = element->renderStyle() ? resolveColor(element->renderStyle(), CSSPropertyColor) : resolveColor(CSSPropertyColor);
if (isOptionElement && toHTMLOptionElement(*element).selected()) {
if (isOptionElement && ((toHTMLOptionElement(*element).selected() && select->suggestedIndex() < 0) || listIndex == select->suggestedIndex())) {
if (frame()->selection().isFocusedAndActive() && document().focusedElement() == node())
textColor = RenderTheme::theme().activeListBoxSelectionForegroundColor();
// Honor the foreground color for disabled items
......@@ -460,7 +460,7 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint&
HTMLElement* element = listItems[listIndex];
Color backColor;
if (isHTMLOptionElement(*element) && toHTMLOptionElement(*element).selected()) {
if (isHTMLOptionElement(*element) && ((toHTMLOptionElement(*element).selected() && selectElement()->suggestedIndex() < 0) || listIndex == selectElement()->suggestedIndex())) {
if (frame()->selection().isFocusedAndActive() && document().focusedElement() == node())
backColor = RenderTheme::theme().activeListBoxSelectionBackgroundColor();
else
......
......@@ -201,10 +201,14 @@ void RenderMenuList::updateFromElement()
m_optionsChanged = false;
}
if (m_popupIsVisible)
if (m_popupIsVisible) {
m_popup->updateFromElement();
else
setTextFromOption(selectElement()->selectedIndex());
} else {
if (selectElement()->suggestedIndex() >= 0)
setTextFromOption(selectElement()->suggestedIndex());
else
setTextFromOption(selectElement()->selectedIndex());
}
}
void RenderMenuList::setTextFromOption(int optionIndex)
......
......@@ -1013,6 +1013,10 @@ String Internals::suggestedValue(Element* element, ExceptionState& exceptionStat
if (isHTMLTextAreaElement(*element))
suggestedValue = toHTMLTextAreaElement(*element).suggestedValue();
if (isHTMLSelectElement(*element))
suggestedValue = toHTMLSelectElement(*element).suggestedValue();
return suggestedValue;
}
......@@ -1033,6 +1037,9 @@ void Internals::setSuggestedValue(Element* element, const String& value, Excepti
if (isHTMLTextAreaElement(*element))
toHTMLTextAreaElement(*element).setSuggestedValue(value);
if (isHTMLSelectElement(*element))
toHTMLSelectElement(*element).setSuggestedValue(value);
}
void Internals::setEditingValue(Element* element, const String& value, ExceptionState& exceptionState)
......
......@@ -119,6 +119,8 @@ void WebFormControlElement::setSuggestedValue(const WebString& value)
unwrap<HTMLInputElement>()->setSuggestedValue(value);
if (isHTMLTextAreaElement(*m_private))
unwrap<HTMLTextAreaElement>()->setSuggestedValue(value);
if (isHTMLSelectElement(*m_private))
unwrap<HTMLSelectElement>()->setSuggestedValue(value);
}
WebString WebFormControlElement::suggestedValue() const
......@@ -127,6 +129,8 @@ WebString WebFormControlElement::suggestedValue() const
return constUnwrap<HTMLInputElement>()->suggestedValue();
if (isHTMLTextAreaElement(*m_private))
return constUnwrap<HTMLTextAreaElement>()->suggestedValue();
if (isHTMLSelectElement(*m_private))
return constUnwrap<HTMLSelectElement>()->suggestedValue();
return WebString();
}
......
......@@ -73,13 +73,16 @@ public:
BLINK_EXPORT void setValue(const WebString&, bool sendChangeEvent = false);
// Returns value of element. For select element, it returns the value of
// the selected option if present. If no selected option, an empty string
// is returned. For any other types of elements, a null string is returned.
// is returned. If element doesn't fall into input element, textarea element
// and select element categories, a null string is returned.
BLINK_EXPORT WebString value() const;
// Sets suggested value for element. The goal of introducing suggested value
// is to not leak any information to JavaScript.
// Sets suggested value for element. For select element it finds the option
// with value matches the given parameter and make the option as the suggested
// selection. The goal of introducing suggested value is to not leak any information
// to JavaScript.
BLINK_EXPORT void setSuggestedValue(const WebString&);
// Returns suggested value for input element or textarea element. If neither
// input element nor textarea element, a null string is returned.
// Returns suggested value of element. If element doesn't fall into input element,
// textarea element and select element categories, a null string is returned.
BLINK_EXPORT WebString suggestedValue() const;
// Returns the non-sanitized, exact value inside the text input field
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment