[Text manipulation] Extract the value attribute in inputs of type "text" and "search"
https://bugs.webkit.org/show_bug.cgi?id=212706
<rdar://problem/63876969>
Reviewed by Tim Horton.
Source/WebCore:
Allow text manipulation to extract text for the value of text fields that were not last modified by user input.
Aside from button types, it generally doesn't make sense to perform text manipulation over arbitrary input
element values, especially for text field types such as passwords, URLs, emails, and numbers. However, some
webpages set the `value` of inputs to implement `placeholder`-like behavior in text fields, and we need to be
compatible with this.
Tests: TextManipulation.StartTextManipulationExtractsValuesFromTextInputs
TextManipulation.CompleteTextManipulationInButtonsAndTextFields
* editing/TextManipulationController.cpp:
(WebCore::shouldExtractValueForTextManipulation):
Unfortunately, we need to check the type attribute here against "text", since inputs of type "date" and "time"
fall back to text fields on macOS, and we still want to avoid extracting values for these.
(WebCore::isAttributeForTextManipulation):
Pull the `value` attribute of this out into a separate method, above.
(WebCore::TextManipulationController::observeParagraphs):
(WebCore::TextManipulationController::replace):
Treat the text field value separately from other attributes by calling `HTMLInputElement::value()` upon
extraction, and `HTMLInputElement::setValue()` upon replacement.
Tools:
Add a new test case (similar to the existing test `StartTextManipulationExtractsValuesFromButtonInputs`) to
verify that we extract text from the `value` of inputs of type "text" and "search".
* TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm:
(TestWebKitAPI::TEST):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@262515 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/editing/TextManipulationController.cpp b/Source/WebCore/editing/TextManipulationController.cpp
index 38b0e44..c1b3778 100644
--- a/Source/WebCore/editing/TextManipulationController.cpp
+++ b/Source/WebCore/editing/TextManipulationController.cpp
@@ -36,6 +36,7 @@
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
+#include "InputTypeNames.h"
#include "NodeTraversal.h"
#include "PseudoElement.h"
#include "Range.h"
@@ -219,13 +220,17 @@
Optional<String> m_text;
};
-static bool isAttributeForTextManipulation(const Element& element, const QualifiedName& nameToCheck)
+static bool shouldExtractValueForTextManipulation(const HTMLInputElement& input)
+{
+ if (input.isSearchField() || equalIgnoringASCIICase(input.attributeWithoutSynchronization(typeAttr), InputTypeNames::text()))
+ return !input.lastChangeWasUserEdit();
+
+ return input.isTextButton();
+}
+
+static bool isAttributeForTextManipulation(const QualifiedName& nameToCheck)
{
using namespace HTMLNames;
-
- if (nameToCheck == valueAttr)
- return is<HTMLInputElement>(element) && downcast<HTMLInputElement>(element).isTextButton();
-
static const QualifiedName* const attributeNames[] = {
&titleAttr.get(),
&altAttr.get(),
@@ -380,10 +385,17 @@
if (currentElement.hasAttributes()) {
for (auto& attribute : currentElement.attributesIterator()) {
- if (isAttributeForTextManipulation(currentElement, attribute.name()))
+ if (isAttributeForTextManipulation(attribute.name()))
addItem(ManipulationItemData { Position(), Position(), makeWeakPtr(currentElement), attribute.name(), { ManipulationToken { m_tokenIdentifier.generate(), attribute.value(), tokenInfo(¤tElement) } } });
}
}
+
+ if (is<HTMLInputElement>(currentElement)) {
+ auto& input = downcast<HTMLInputElement>(currentElement);
+ if (shouldExtractValueForTextManipulation(input))
+ addItem(ManipulationItemData { { }, { }, makeWeakPtr(currentElement), valueAttr, { ManipulationToken { m_tokenIdentifier.generate(), input.value(), tokenInfo(¤tElement) } } });
+ }
+
if (!enclosingItemBoundaryElement && isEnclosingItemBoundaryElement(currentElement))
enclosingItemBoundaryElement = ¤tElement;
}
@@ -616,6 +628,8 @@
}
if (item.attributeName == nullQName())
element->setTextContent(newValue.toString());
+ else if (item.attributeName == valueAttr && is<HTMLInputElement>(*element))
+ downcast<HTMLInputElement>(*element).setValue(newValue.toString());
else
element->setAttribute(item.attributeName, newValue.toString());
return WTF::nullopt;