blob: 41edcd0e5ff9b84991d08bf78a8467242251cc58 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "components/autofill/ios/browser/js_suggestion_manager.h"
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/check.h"
#include "base/format_macros.h"
#include "base/json/string_escape.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
#import "components/autofill/ios/browser/autofill_util.h"
#include "ios/web/public/js_messaging/web_frame.h"
#include "ios/web/public/js_messaging/web_frames_manager.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation JsSuggestionManager {
// The injection receiver used to evaluate JavaScript.
__weak CRWJSInjectionReceiver* _receiver;
web::WebFramesManager* _webFramesManager;
}
- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver {
DCHECK(receiver);
self = [super init];
if (self) {
_receiver = receiver;
}
return self;
}
- (void)setWebFramesManager:(web::WebFramesManager*)framesManager {
_webFramesManager = framesManager;
}
#pragma mark -
#pragma mark ProtectedMethods
- (void)selectNextElementInFrameWithID:(NSString*)frameID {
[self selectNextElementInFrameWithID:frameID afterForm:@"" field:@""];
}
- (void)selectNextElementInFrameWithID:(NSString*)frameID
afterForm:(NSString*)formName
field:(NSString*)fieldName {
std::vector<base::Value> parameters;
parameters.push_back(base::Value(base::SysNSStringToUTF8(formName)));
parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName)));
autofill::ExecuteJavaScriptFunction(
"suggestion.selectNextElement", parameters,
[self frameWithFrameID:frameID], autofill::JavaScriptResultCallback());
}
- (void)selectPreviousElementInFrameWithID:(NSString*)frameID {
[self selectPreviousElementInFrameWithID:frameID beforeForm:@"" field:@""];
}
- (void)selectPreviousElementInFrameWithID:(NSString*)frameID
beforeForm:(NSString*)formName
field:(NSString*)fieldName {
std::vector<base::Value> parameters;
parameters.push_back(base::Value(base::SysNSStringToUTF8(formName)));
parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName)));
autofill::ExecuteJavaScriptFunction(
"suggestion.selectPreviousElement", parameters,
[self frameWithFrameID:frameID], autofill::JavaScriptResultCallback());
}
- (void)fetchPreviousAndNextElementsPresenceInFrameWithID:(NSString*)frameID
completionHandler:
(void (^)(BOOL,
BOOL))completionHandler {
[self fetchPreviousAndNextElementsPresenceInFrameWithID:frameID
forForm:@""
field:@""
completionHandler:completionHandler];
}
- (void)fetchPreviousAndNextElementsPresenceInFrameWithID:(NSString*)frameID
forForm:(NSString*)formName
field:(NSString*)fieldName
completionHandler:
(void (^)(BOOL,
BOOL))completionHandler {
DCHECK(completionHandler);
std::vector<base::Value> parameters;
parameters.push_back(base::Value(base::SysNSStringToUTF8(formName)));
parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName)));
autofill::ExecuteJavaScriptFunction(
"suggestion.hasPreviousNextElements", parameters,
[self frameWithFrameID:frameID],
autofill::CreateStringCallback(^(NSString* result) {
// 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.
NSArray* components = [result componentsSeparatedByString:@","];
if (components.count != 2) {
completionHandler(NO, NO);
return;
}
DCHECK([components[0] isEqualToString:@"true"] ||
[components[0] isEqualToString:@"false"]);
BOOL hasPreviousElement = [components[0] isEqualToString:@"true"];
DCHECK([components[1] isEqualToString:@"true"] ||
[components[1] isEqualToString:@"false"]);
BOOL hasNextElement = [components[1] isEqualToString:@"true"];
completionHandler(hasPreviousElement, hasNextElement);
}));
}
- (void)closeKeyboardForFrameWithID:(NSString*)frameID {
std::vector<base::Value> parameters;
autofill::ExecuteJavaScriptFunction(
"suggestion.blurActiveElement", parameters,
[self frameWithFrameID:frameID], autofill::JavaScriptResultCallback());
}
- (web::WebFrame*)frameWithFrameID:(NSString*)frameID {
DCHECK(_webFramesManager);
return _webFramesManager->GetFrameWithId(base::SysNSStringToUTF8(frameID));
}
@end