Title: [262515] trunk
Revision
262515
Author
[email protected]
Date
2020-06-03 14:08:21 -0700 (Wed, 03 Jun 2020)

Log Message

[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):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (262514 => 262515)


--- trunk/Source/WebCore/ChangeLog	2020-06-03 20:57:44 UTC (rev 262514)
+++ trunk/Source/WebCore/ChangeLog	2020-06-03 21:08:21 UTC (rev 262515)
@@ -1,3 +1,36 @@
+2020-06-03  Wenson Hsieh  <[email protected]>
+
+        [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.
+
+        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.
+
 2020-06-03  Rob Buis  <[email protected]>
 
         Disallow responses when a response contains invalid header values

Modified: trunk/Source/WebCore/editing/TextManipulationController.cpp (262514 => 262515)


--- trunk/Source/WebCore/editing/TextManipulationController.cpp	2020-06-03 20:57:44 UTC (rev 262514)
+++ trunk/Source/WebCore/editing/TextManipulationController.cpp	2020-06-03 21:08:21 UTC (rev 262515)
@@ -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)
 {
-    using namespace HTMLNames;
+    if (input.isSearchField() || equalIgnoringASCIICase(input.attributeWithoutSynchronization(typeAttr), InputTypeNames::text()))
+        return !input.lastChangeWasUserEdit();
 
-    if (nameToCheck == valueAttr)
-        return is<HTMLInputElement>(element) && downcast<HTMLInputElement>(element).isTextButton();
+    return input.isTextButton();
+}
 
+static bool isAttributeForTextManipulation(const QualifiedName& nameToCheck)
+{
+    using namespace HTMLNames;
     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(&currentElement) } } });
                 }
             }
+
+            if (is<HTMLInputElement>(currentElement)) {
+                auto& input = downcast<HTMLInputElement>(currentElement);
+                if (shouldExtractValueForTextManipulation(input))
+                    addItem(ManipulationItemData { { }, { }, makeWeakPtr(currentElement), valueAttr, { ManipulationToken { m_tokenIdentifier.generate(), input.value(), tokenInfo(&currentElement) } } });
+            }
+
             if (!enclosingItemBoundaryElement && isEnclosingItemBoundaryElement(currentElement))
                 enclosingItemBoundaryElement = &currentElement;
         }
@@ -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;

Modified: trunk/Tools/ChangeLog (262514 => 262515)


--- trunk/Tools/ChangeLog	2020-06-03 20:57:44 UTC (rev 262514)
+++ trunk/Tools/ChangeLog	2020-06-03 21:08:21 UTC (rev 262515)
@@ -1,3 +1,17 @@
+2020-06-03  Wenson Hsieh  <[email protected]>
+
+        [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.
+
+        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):
+
 2020-06-03  Michael Saboff  <[email protected]>
 
         [iOS] TestWTF.WTF_Lock.ContendedShortSection is consistently timing out on debug simulator builds

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm (262514 => 262515)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm	2020-06-03 20:57:44 UTC (rev 262514)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm	2020-06-03 21:08:21 UTC (rev 262515)
@@ -784,6 +784,43 @@
     EXPECT_WK_STREQ("Two", items[1].tokens[0].content);
 }
 
+TEST(TextManipulation, StartTextManipulationExtractsValuesFromTextInputs)
+{
+    auto delegate = adoptNS([[TextManipulationDelegate alloc] init]);
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView _setTextManipulationDelegate:delegate.get()];
+
+    [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html>"
+        "<body>"
+        "<input type='search' value='One'>"
+        "<input type='text' value='Two'>"
+        "<input id='a' type='search'>"
+        "<input id='b' type='text'>"
+        "<input type='number' value='6'>"
+        "<input type='email' value='[email protected]'>"
+        "<input type='url' value='https://www.apple.com'>"
+        "<script>"
+        "document.getElementById('a').focus();"
+        "document.execCommand('InsertText', true, 'Three');"
+        "document.getElementById('b').focus();"
+        "document.execCommand('InsertText', true, 'Four');"
+        "</script>"
+        "</body>"];
+
+    done = false;
+    [webView _startTextManipulationsWithConfiguration:nil completion:^{
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    auto items = [delegate items];
+    EXPECT_EQ(items.count, 2UL);
+    EXPECT_EQ(items[0].tokens.count, 1UL);
+    EXPECT_EQ(items[1].tokens.count, 1UL);
+    EXPECT_WK_STREQ("One", items[0].tokens[0].content);
+    EXPECT_WK_STREQ("Two", items[1].tokens[0].content);
+}
+
 TEST(TextManipulation, StartTextManipulationExtractsVisibleLineBreaksInTextAsExcludedTokens)
 {
     auto delegate = adoptNS([[TextManipulationDelegate alloc] init]);
@@ -2206,6 +2243,45 @@
     EXPECT_WK_STREQ("<p><b>hello,</b><span> WebKit!</span> world</p>", [webView stringByEvaluatingJavaScript:@"document.body.innerHTML"]);
 }
 
+TEST(TextManipulation, CompleteTextManipulationInButtonsAndTextFields)
+{
+    auto delegate = adoptNS([[TextManipulationDelegate alloc] init]);
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView _setTextManipulationDelegate:delegate.get()];
+    [webView synchronouslyLoadHTMLString:@"<input type='text' value='hello1'><input type='submit' value='hello2'>"];
+    auto configuration = adoptNS([[_WKTextManipulationConfiguration alloc] init]);
+
+    done = false;
+    [webView _startTextManipulationsWithConfiguration:configuration.get() completion:^{
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    auto *items = [delegate items];
+    EXPECT_EQ(items.count, 2UL);
+
+    auto* firstItem = items.firstObject;
+    auto* lastItem = items.lastObject;
+    EXPECT_EQ(firstItem.tokens.count, 1UL);
+    EXPECT_EQ(lastItem.tokens.count, 1UL);
+    EXPECT_STREQ("hello1", firstItem.tokens[0].content.UTF8String);
+    EXPECT_STREQ("hello2", lastItem.tokens[0].content.UTF8String);
+
+    done = false;
+    [webView _completeTextManipulationForItems:@[
+        createItem(firstItem.identifier, {{ firstItem.tokens[0].identifier, @"world1" }}).get(),
+        createItem(lastItem.identifier, {{ lastItem.tokens[0].identifier, @"world2" }}).get()
+    ] completion:^(NSArray<NSError *> *errors) {
+        EXPECT_EQ(errors, nil);
+        done = true;
+    }];
+
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_WK_STREQ("world1", [webView stringByEvaluatingJavaScript:@"document.querySelector('input[type=text]').value"]);
+    EXPECT_WK_STREQ("world2", [webView stringByEvaluatingJavaScript:@"document.querySelector('input[type=submit]').value"]);
+}
+
 TEST(TextManipulation, TextManipulationTokenDebugDescription)
 {
     auto token = adoptNS([[_WKTextManipulationToken alloc] init]);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to