Commit 6a4948b1 authored by Mike Dougherty's avatar Mike Dougherty Committed by Commit Bot

Inject suggestion_controller.js with chrome js bundle.

Frame messaging enables autofill to work in iframes. |suggestion_controller.js|
needs to also be injected into all frames in order use the JSSuggestionManager
APIs. (Such as navigating to the previous and next form items.)

Bug: None
Cq-Include-Trybots: luci.chromium.try:ios-simulator-cronet;luci.chromium.try:ios-simulator-full-configs
Change-Id: I69c47b8245cca136e200a0129f6bb79e093aa630
Reviewed-on: https://chromium-review.googlesource.com/1239372
Commit-Queue: Mike Dougherty <michaeldo@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarMoe Ahmadi <mahmadi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#593831}
parent abd1f2ca
......@@ -35,7 +35,6 @@ source_set("browser") {
]
deps = [
":injected_js",
"//base",
"//components/autofill/core/browser",
"//components/autofill/core/common",
......@@ -72,13 +71,6 @@ source_set("test_support") {
]
}
js_compile_checked("injected_js") {
visibility = [ ":browser" ]
sources = [
"resources/suggestion_controller.js",
]
}
source_set("unit_tests") {
testonly = true
configs += [ "//build/config/compiler:enable_arc" ]
......
......@@ -5,13 +5,17 @@
#ifndef COMPONENTS_AUTOFILL_IOS_BROWSER_JS_SUGGESTION_MANAGER_H_
#define COMPONENTS_AUTOFILL_IOS_BROWSER_JS_SUGGESTION_MANAGER_H_
#import "ios/web/public/web_state/js/crw_js_injection_manager.h"
@class CRWJSInjectionReceiver;
#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
// Loads the JavaScript file, suggestion_manager.js, which contains form parsing
// and autofill functions.
@interface JsSuggestionManager : CRWJSInjectionManager
@interface JsSuggestionManager : NSObject
// Designated initializer. |receiver| should not be nil.
- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// Focuses the next focusable element in tab order. No action if there is no
// such element.
......
......@@ -22,15 +22,23 @@ NSString* JSONEscape(NSString* str) {
}
} // namespace
@implementation JsSuggestionManager
@implementation JsSuggestionManager {
// The injection receiver used to evaluate JavaScript.
CRWJSInjectionReceiver* _receiver;
}
- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver {
DCHECK(receiver);
self = [super init];
if (self) {
_receiver = receiver;
}
return self;
}
#pragma mark -
#pragma mark ProtectedMethods
- (NSString*)scriptPath {
return @"suggestion_controller";
}
- (void)selectNextElement {
[self selectElementAfterForm:@"" field:@""];
}
......@@ -39,7 +47,7 @@ NSString* JSONEscape(NSString* str) {
NSString* selectNextElementJS = [NSString
stringWithFormat:@"__gCrWeb.suggestion.selectNextElement(%@, %@)",
JSONEscape(formName), JSONEscape(fieldName)];
[self executeJavaScript:selectNextElementJS completionHandler:nil];
[_receiver executeJavaScript:selectNextElementJS completionHandler:nil];
}
- (void)selectPreviousElement {
......@@ -50,7 +58,7 @@ NSString* JSONEscape(NSString* str) {
NSString* selectPreviousElementJS = [NSString
stringWithFormat:@"__gCrWeb.suggestion.selectPreviousElement(%@, %@)",
JSONEscape(formName), JSONEscape(fieldName)];
[self executeJavaScript:selectPreviousElementJS completionHandler:nil];
[_receiver executeJavaScript:selectPreviousElementJS completionHandler:nil];
}
- (void)fetchPreviousAndNextElementsPresenceWithCompletionHandler:
......@@ -65,7 +73,6 @@ NSString* JSONEscape(NSString* str) {
completionHandler:
(void (^)(BOOL, BOOL))completionHandler {
DCHECK(completionHandler);
DCHECK([self hasBeenInjected]);
NSString* escapedFormName = JSONEscape(formName);
NSString* escapedFieldName = JSONEscape(fieldName);
NSString* JS = [NSString
......@@ -74,14 +81,15 @@ NSString* JSONEscape(NSString* str) {
@".toString()",
escapedFormName, escapedFieldName, escapedFormName,
escapedFieldName];
[self executeJavaScript:JS completionHandler:^(id result, NSError* error) {
[_receiver executeJavaScript:JS
completionHandler:^(id result, NSError* error) {
// The result maybe an empty string here due to 2 reasons:
// 1) When there is an exception running the JS
// 2) There is a race when the page is changing due to which
// JSSuggestionManager has not yet injected __gCrWeb.suggestion object
// Handle this case gracefully.
// If a page has overridden Array.toString, the string returned may not
// contain a ",", hence this is a defensive measure to early return.
// JSSuggestionManager has not yet injected __gCrWeb.suggestion
// object Handle this case gracefully. If a page has overridden
// Array.toString, the string returned may not contain a ",",
// hence this is a defensive measure to early return.
NSArray* components = [result componentsSeparatedByString:@","];
if (components.count != 2) {
completionHandler(NO, NO);
......@@ -90,7 +98,8 @@ NSString* JSONEscape(NSString* str) {
DCHECK([components[0] isEqualToString:@"true"] ||
[components[0] isEqualToString:@"false"]);
BOOL hasPreviousElement = [components[0] isEqualToString:@"true"];
BOOL hasPreviousElement =
[components[0] isEqualToString:@"true"];
DCHECK([components[1] isEqualToString:@"true"] ||
[components[1] isEqualToString:@"false"]);
BOOL hasNextElement = [components[1] isEqualToString:@"true"];
......@@ -99,7 +108,7 @@ NSString* JSONEscape(NSString* str) {
}
- (void)closeKeyboard {
[self executeJavaScript:@"document.activeElement.blur()"
[_receiver executeJavaScript:@"document.activeElement.blur()"
completionHandler:nil];
}
......
......@@ -9,6 +9,7 @@
* TODO(crbug.com/647084): Enable checkTypes error for this file.
* @suppress {checkTypes}
*/
goog.provide('__crWeb.suggestion');
/* Beginning of anonymous object. */
(function() {
......
......@@ -169,17 +169,6 @@ AutofillSuggestionState::AutofillSuggestionState(
- (void)processPage:(web::WebState*)webState {
[self resetSuggestionState];
web::URLVerificationTrustLevel trustLevel =
web::URLVerificationTrustLevel::kNone;
const GURL pageURL(webState->GetCurrentURL(&trustLevel));
if (trustLevel != web::URLVerificationTrustLevel::kAbsolute) {
DLOG(WARNING) << "Page load not handled on untrusted page";
return;
}
if (web::UrlHasWebScheme(pageURL) && webState->ContentIsHTML())
[_jsSuggestionManager inject];
}
- (void)setWebViewProxy:(id<CRWWebViewProxy>)webViewProxy {
......
......@@ -8,9 +8,9 @@
#include "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "ios/chrome/browser/web/chrome_web_client.h"
#include "ios/chrome/browser/web/chrome_web_test.h"
#import "ios/web/public/test/js_test_util.h"
#import "ios/web/public/test/web_js_test.h"
#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
#import "ios/web/public/web_state/web_state.h"
#import "testing/gtest_mac.h"
......@@ -22,12 +22,12 @@
namespace {
// Test fixture to test suggestions.
class JsSuggestionManagerTest : public web::WebJsTest<ChromeWebTest> {
class JsSuggestionManagerTest : public ChromeWebTest {
protected:
void SetUp() override;
JsSuggestionManagerTest()
: web::WebJsTest<ChromeWebTest>(@[ @"suggestion_controller" ]) {}
// Loads the given HTML and initializes the Autofill JS scripts.
void LoadHtml(NSString* html);
: ChromeWebTest(std::make_unique<ChromeWebClient>()) {}
// Helper method that initializes a form with three fields. Can be used to
// test whether adding an attribute on the second field causes it to be
// skipped (or not, as is appropriate) by selectNextElement.
......@@ -39,17 +39,15 @@ class JsSuggestionManagerTest : public web::WebJsTest<ChromeWebTest> {
JsSuggestionManager* manager_;
};
void JsSuggestionManagerTest::LoadHtml(NSString* html) {
WebJsTest<ChromeWebTest>::LoadHtml(html);
manager_ =
static_cast<JsSuggestionManager*>([web_state()->GetJSInjectionReceiver()
instanceOfClass:[JsSuggestionManager class]]);
[manager_ inject];
void JsSuggestionManagerTest::SetUp() {
ChromeWebTest::SetUp();
manager_ = [[JsSuggestionManager alloc]
initWithReceiver:web_state()->GetJSInjectionReceiver()];
}
TEST_F(JsSuggestionManagerTest, InitAndInject) {
LoadHtml(@"<html></html>");
EXPECT_TRUE([manager_ hasBeenInjected]);
EXPECT_NSEQ(@"object", ExecuteJavaScript(@"typeof __gCrWeb.suggestion"));
}
TEST_F(JsSuggestionManagerTest, SelectElementInTabOrder) {
......@@ -69,7 +67,7 @@ TEST_F(JsSuggestionManagerTest, SelectElementInTabOrder) {
"<input id='-1 (1)' tabIndex=-1 href='http://www.w3schools.com'>-1 </a>"
"<input id='0 (3)' tabIndex=0 href='http://www.w3schools.com'>0 (3)</a>"
"</body></html>";
LoadHtmlAndInject(htmlFragment);
LoadHtml(htmlFragment);
// clang-format off
NSDictionary* next_expected_ids = @ {
......@@ -90,19 +88,20 @@ TEST_F(JsSuggestionManagerTest, SelectElementInTabOrder) {
for (NSString* element_id : next_expected_ids) {
NSString* expected_id = [next_expected_ids objectForKey:element_id];
EXPECT_NSEQ(expected_id,
ExecuteJavaScriptWithFormat(
NSString* script = [NSString
stringWithFormat:
@"var elements=document.getElementsByTagName('input');"
"var element=document.getElementById('%@');"
"var next = __gCrWeb.suggestion.getNextElementInTabOrder("
" element, elements);"
"next ? next.id : 'null';",
element_id))
element_id];
EXPECT_NSEQ(expected_id, ExecuteJavaScript(script))
<< "Wrong when selecting next element of element with element id "
<< base::SysNSStringToUTF8(element_id);
}
EXPECT_NSEQ(@YES,
ExecuteJavaScriptWithFormat(
ExecuteJavaScript(
@"var elements=document.getElementsByTagName('input');"
"var element=document.getElementsByTagName('a')[0];"
"var next = __gCrWeb.suggestion.getNextElementInTabOrder("
......@@ -116,11 +115,12 @@ TEST_F(JsSuggestionManagerTest, SelectElementInTabOrder) {
// If the expected next element is null, the focus is not moved.
expected_id = element_id;
}
EXPECT_NSEQ(expected_id, ExecuteJavaScriptWithFormat(
NSString* script = [NSString stringWithFormat:
@"document.getElementById('%@').focus();"
"__gCrWeb.suggestion.selectNextElement();"
"document.activeElement.id",
element_id))
element_id];
EXPECT_NSEQ(expected_id, ExecuteJavaScript(script))
<< "Wrong when selecting next element with active element "
<< base::SysNSStringToUTF8(element_id);
}
......@@ -128,10 +128,11 @@ TEST_F(JsSuggestionManagerTest, SelectElementInTabOrder) {
for (NSString* element_id : next_expected_ids) {
// If the expected next element is null, there is no next element.
BOOL expected = ![next_expected_ids[element_id] isEqualToString:@"null"];
EXPECT_NSEQ(@(expected), ExecuteJavaScriptWithFormat(
NSString* script = [NSString stringWithFormat:
@"document.getElementById('%@').focus();"
"__gCrWeb.suggestion.hasNextElement()",
element_id))
element_id];
EXPECT_NSEQ(@(expected), ExecuteJavaScript(script))
<< "Wrong when checking hasNextElement() for "
<< base::SysNSStringToUTF8(element_id);
}
......@@ -155,20 +156,20 @@ TEST_F(JsSuggestionManagerTest, SelectElementInTabOrder) {
for (NSString* element_id : prev_expected_ids) {
NSString* expected_id = [prev_expected_ids objectForKey:element_id];
EXPECT_NSEQ(
expected_id,
ExecuteJavaScriptWithFormat(
NSString* script = [NSString
stringWithFormat:
@"var elements=document.getElementsByTagName('input');"
"var element=document.getElementById('%@');"
"var prev = __gCrWeb.suggestion.getPreviousElementInTabOrder("
" element, elements);"
"prev ? prev.id : 'null';",
element_id))
element_id];
EXPECT_NSEQ(expected_id, ExecuteJavaScript(script))
<< "Wrong when selecting prev element of element with element id "
<< base::SysNSStringToUTF8(element_id);
}
EXPECT_NSEQ(
@YES, ExecuteJavaScriptWithFormat(
@YES, ExecuteJavaScript(
@"var elements=document.getElementsByTagName('input');"
"var element=document.getElementsByTagName('a')[0];"
"var prev = __gCrWeb.suggestion.getPreviousElementInTabOrder("
......@@ -182,11 +183,13 @@ TEST_F(JsSuggestionManagerTest, SelectElementInTabOrder) {
// If the expected previous element is null, the focus is not moved.
expected_id = element_id;
}
EXPECT_NSEQ(expected_id, ExecuteJavaScriptWithFormat(
NSString* script =
[NSString stringWithFormat:
@"document.getElementById('%@').focus();"
"__gCrWeb.suggestion.selectPreviousElement();"
"document.activeElement.id",
element_id))
element_id];
EXPECT_NSEQ(expected_id, ExecuteJavaScript(script))
<< "Wrong when selecting previous element with active element "
<< base::SysNSStringToUTF8(element_id);
}
......@@ -194,10 +197,12 @@ TEST_F(JsSuggestionManagerTest, SelectElementInTabOrder) {
for (NSString* element_id : prev_expected_ids) {
// If the expected next element is null, there is no next element.
BOOL expected = ![prev_expected_ids[element_id] isEqualToString:@"null"];
EXPECT_NSEQ(@(expected), ExecuteJavaScriptWithFormat(
NSString* script =
[NSString stringWithFormat:
@"document.getElementById('%@').focus();"
"__gCrWeb.suggestion.hasPreviousElement()",
element_id))
element_id];
EXPECT_NSEQ(@(expected), ExecuteJavaScript(script))
<< "Wrong when checking hasPreviousElement() for "
<< base::SysNSStringToUTF8(element_id);
}
......@@ -210,9 +215,7 @@ TEST_F(JsSuggestionManagerTest, SequentialNavigation) {
"<input type='email' name='email'/>"
"</form></body></html>");
[manager_
executeJavaScript:@"document.getElementsByName('firstname')[0].focus()"
completionHandler:nil];
ExecuteJavaScript(@"document.getElementsByName('firstname')[0].focus()");
[manager_ selectNextElement];
EXPECT_NSEQ(@"lastname", GetActiveElementName());
__block BOOL block_was_called = NO;
......@@ -240,12 +243,8 @@ void JsSuggestionManagerTest::SequentialNavigationSkipCheck(NSString* attribute,
"<input type='text' name='lastname'/>"
"</form></body></html>",
attribute]);
[manager_
executeJavaScript:@"document.getElementsByName('firstname')[0].focus()"
completionHandler:nil];
NSString* const kActiveElementNameJS = @"document.activeElement.name";
EXPECT_NSEQ(@"firstname",
web::test::ExecuteJavaScript(manager_, kActiveElementNameJS));
ExecuteJavaScript(@"document.getElementsByName('firstname')[0].focus()");
EXPECT_NSEQ(@"firstname", GetActiveElementName());
[manager_ selectNextElement];
NSString* activeElementNameJS = GetActiveElementName();
if (shouldSkip)
......
......@@ -133,6 +133,7 @@ js_compile_bundle("chrome_bundle_all_frames") {
closure_entry_point = "__crWeb.chromeBundleAllFrames"
sources = [
"//components/autofill/ios/browser/resources/autofill_controller.js",
"//components/autofill/ios/browser/resources/suggestion_controller.js",
"//components/autofill/ios/form_util/resources/fill.js",
"//components/autofill/ios/form_util/resources/form.js",
"//components/autofill/ios/form_util/resources/form_handlers.js",
......
......@@ -11,3 +11,4 @@ goog.require('__crWeb.fill');
goog.require('__crWeb.form');
goog.require('__crWeb.formHandlers');
goog.require('__crWeb.print');
goog.require('__crWeb.suggestion');
......@@ -424,6 +424,7 @@ js_compile_bundle("web_view_bundle") {
closure_entry_point = "__crWeb.webViewBundle"
sources = [
"//components/autofill/ios/browser/resources/autofill_controller.js",
"//components/autofill/ios/browser/resources/suggestion_controller.js",
"//components/autofill/ios/form_util/resources/fill.js",
"//components/autofill/ios/form_util/resources/form.js",
"//components/autofill/ios/form_util/resources/form_handlers.js",
......
......@@ -376,8 +376,6 @@ showUnmaskPromptForCard:(const autofill::CreditCard&)creditCard
inFrame:(web::WebFrame*)frame {
DCHECK_EQ(_webState, webState);
[_JSSuggestionManager inject];
NSString* nsFormName = base::SysUTF8ToNSString(params.form_name);
NSString* nsFieldName = base::SysUTF8ToNSString(params.field_name);
NSString* nsFieldIdentifier =
......
......@@ -10,3 +10,4 @@ goog.require('__crWeb.fill');
goog.require('__crWeb.form');
goog.require('__crWeb.formHandlers');
goog.require('__crWeb.passwords');
goog.require('__crWeb.suggestion');
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