[ChromeDriver] Update sendKeysToElement focus behavior when targeting contenteditable element.

This change updates chromedriver to call focus.js if the element is a non-text element.
This is specifically to fix some cases where browser based text editors use <body contenteditable=true>
to create a text area of sorts.

Before this change, but after https://crrev.com/674640, we were not resetting focus to the body
element as it was considered already focused. This results in sendkeys being lost.

We now call focus on any non-text elements, which still abides by the W3C SendKeys spec change
incoming https://github.com/w3c/webdriver/issues/1430 as carat preservation behavior is only
specified for text-type inputs.

Additionally, this change also updates focus.js javascript to not move carat after a focus.
Which was erroneously not updated in https://crrev.com/674640

Bug: chromedriver:3006
Change-Id: Ie4d4bab3eb45aec64a586cbfa786968601a06189
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1700475
Commit-Queue: Stanley Hon <stahon@microsoft.com>
Reviewed-by: John Chen <johnchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#678908}
diff --git a/chrome/test/chromedriver/element_commands.cc b/chrome/test/chromedriver/element_commands.cc
index 28e16573..fd52ec7 100644
--- a/chrome/test/chromedriver/element_commands.cc
+++ b/chrome/test/chromedriver/element_commands.cc
@@ -91,9 +91,12 @@
                          const base::ListValue* key_list) {
   // If we were previously focused, we don't need to focus again.
   // But also, later we don't move the carat if we were already in focus.
+  // However, non-text elements such as contenteditable elements needs to be
+  // focused to ensure the keys will end up being sent to the correct place.
+  // So in the case of non-text elements, we still focusToElement.
   bool wasPreviouslyFocused = false;
   IsElementFocused(session, web_view, element_id, &wasPreviouslyFocused);
-  if (!wasPreviouslyFocused) {
+  if (!wasPreviouslyFocused || !is_text) {
     Status status = FocusToElement(session, web_view, element_id);
     if (status.IsError())
       return Status(kElementNotInteractable);
@@ -481,8 +484,16 @@
                                key_list);
     }
     // If element_type is in textControlTypes, sendKeys should append
-    bool is_text = is_input && textControlTypes.find(element_type) !=
-                                   textControlTypes.end();
+    bool is_textControlType = is_input && textControlTypes.find(element_type) !=
+                                              textControlTypes.end();
+    // If the element is a textarea, sendKeys should also append
+    bool is_textarea = false;
+    status = IsElementAttributeEqualToIgnoreCase(
+        session, web_view, element_id, "tagName", "textarea", &is_textarea);
+    if (status.IsError())
+      return status;
+    bool is_text = is_textControlType || is_textarea;
+
     return SendKeysToElement(session, web_view, element_id, is_text, key_list);
   }
 }
diff --git a/chrome/test/chromedriver/js/focus.js b/chrome/test/chromedriver/js/focus.js
index 7030796b..98f8233 100644
--- a/chrome/test/chromedriver/js/focus.js
+++ b/chrome/test/chromedriver/js/focus.js
@@ -9,9 +9,7 @@
   // because this may cause us to lose the current cursor position in the
   // element.
   // Secondly, we focus the target element.
-  // Thirdly, if the target element is newly focused and is a text input, we
-  // set the cursor position at the end.
-  // Fourthly, we check if the new active element is the target element. If not,
+  // Thirdly, we check if the new active element is the target element. If not,
   // we throw an error.
   // Additional notes:
   //   - |document.activeElement| is the currently focused element, or body if
@@ -28,16 +26,6 @@
   if (element != prevActiveElement && prevActiveElement)
     prevActiveElement.blur();
   element.focus();
-  if (element != prevActiveElement && element.value &&
-      element.value.length && element.setSelectionRange) {
-    try {
-      element.setSelectionRange(element.value.length, element.value.length);
-    } catch (error) {
-      if (!(error instanceof TypeError) && !(error instanceof DOMException &&
-          error.code == DOMException.INVALID_STATE_ERR))
-        throw error;
-    }
-  }
 
   var activeElement = doc.activeElement;
   // If the element is in a shadow DOM, then as far as the document is