Commit 16da6daf authored by Vadym Doroshenko's avatar Vadym Doroshenko Committed by Commit Bot

Inject password_controller with WKWebView injection mechanism.

Now password_controller.js is injected by adding it to call of __gCrWeb.findPasswordForms().
It has performance drawbacks since __gCrWeb.findPasswordForms() could be called multiple times.
This CL makes injection of password_controller.js with WKWebView injection.

Also this CL updates the header comment in password_controller.js with up-to-date information.

Bug: 828824, 418827
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: I4036e3279e0c3a32301795b46630c49801679106
Reviewed-on: https://chromium-review.googlesource.com/995534
Commit-Queue: Vadym Doroshenko <dvadym@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548496}
parent 55ada278
......@@ -6,16 +6,14 @@
#define IOS_CHROME_BROWSER_PASSWORDS_JS_PASSWORD_MANAGER_H_
#include "base/ios/block_types.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, password_controller.js, which contains password
// form parsing and autofill functions. It will be evaluated on a page that
// is known to have at least one password form (see hasPasswordField_ in
// password_controller.js) It returns contents of those password forms and also
// registers functions that are later used to autofill them.
@interface JsPasswordManager : CRWJSInjectionManager
@interface JsPasswordManager : NSObject
// Finds any password forms on the web page.
// |completionHandler| is then called with the JSON string result (which can
......@@ -48,6 +46,12 @@
password:(NSString*)password
completionHandler:(void (^)(BOOL))completionHandler;
// Designated initializer. |receiver| should not be nil.
- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
#endif // IOS_CHROME_BROWSER_PASSWORDS_JS_PASSWORD_MANAGER_H_
......@@ -22,32 +22,39 @@ NSString* JSONEscape(NSString* JSONString) {
}
} // namespace
@interface JsPasswordManager ()
// Injects a script that does two things:
// 1. Injects password controller JavaScript in the page.
// 2. Extracts the _submitted_ password form data from the DOM on the page.
// The result is returned in |completionHandler|.
// |completionHandler| cannot be nil.
- (void)evaluateExtraScript:(NSString*)script
completionHandler:(void (^)(NSString*))completionHandler;
@end
@implementation JsPasswordManager {
// The injection receiver used to evaluate JavaScript.
CRWJSInjectionReceiver* _receiver;
}
@implementation JsPasswordManager
- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver {
DCHECK(receiver);
self = [super init];
if (self) {
_receiver = receiver;
}
return self;
}
- (void)findPasswordFormsWithCompletionHandler:
(void (^)(NSString*))completionHandler {
DCHECK(completionHandler);
[self evaluateExtraScript:@"__gCrWeb.findPasswordForms()"
completionHandler:completionHandler];
[_receiver executeJavaScript:@"__gCrWeb.passwords.findPasswordForms()"
completionHandler:^(id result, NSError*) {
completionHandler(base::mac::ObjCCastStrict<NSString>(result));
}];
}
- (void)extractForm:(NSString*)formName
completionHandler:(void (^)(NSString*))completionHandler {
DCHECK(completionHandler);
NSString* extra =
[NSString stringWithFormat:@"__gCrWeb.getPasswordFormDataAsString(%@)",
NSString* extra = [NSString
stringWithFormat:@"__gCrWeb.passwords.getPasswordFormDataAsString(%@)",
JSONEscape(formName)];
[self evaluateExtraScript:extra completionHandler:completionHandler];
[_receiver executeJavaScript:extra
completionHandler:^(id result, NSError*) {
completionHandler(base::mac::ObjCCastStrict<NSString>(result));
}];
}
- (void)fillPasswordForm:(NSString*)JSONString
......@@ -56,30 +63,13 @@ NSString* JSONEscape(NSString* JSONString) {
completionHandler:(void (^)(BOOL))completionHandler {
DCHECK(completionHandler);
NSString* script = [NSString
stringWithFormat:@"__gCrWeb.fillPasswordForm(%@, %@, %@)", JSONString,
JSONEscape(username), JSONEscape(password)];
[self executeJavaScript:script completionHandler:^(id result, NSError*) {
stringWithFormat:@"__gCrWeb.passwords.fillPasswordForm(%@, %@, %@)",
JSONString, JSONEscape(username), JSONEscape(password)];
[_receiver executeJavaScript:script
completionHandler:^(id result, NSError*) {
completionHandler([result isEqual:@YES]);
}];
}
#pragma mark -
#pragma mark ProtectedMethods
- (NSString*)scriptPath {
return @"password_controller";
}
#pragma mark -
#pragma mark Private
- (void)evaluateExtraScript:(NSString*)script
completionHandler:(void (^)(NSString*))completionHandler {
DCHECK(completionHandler);
NSString* JS = [[self injectionContent] stringByAppendingString:script];
[self executeJavaScript:JS completionHandler:^(id result, NSError*) {
completionHandler(base::mac::ObjCCastStrict<NSString>(result));
}];
}
@end
......@@ -268,7 +268,7 @@ bool GetPageURLAndCheckTrustLevel(web::WebState* web_state, GURL* page_url) {
std::unique_ptr<PasswordManagerDriver> passwordManagerDriver_;
std::unique_ptr<CredentialManager> credentialManager_;
__weak JsPasswordManager* passwordJsManager_;
JsPasswordManager* passwordJsManager_;
AccountSelectFillData fillData_;
......@@ -327,12 +327,11 @@ bool GetPageURLAndCheckTrustLevel(web::WebState* web_state, GURL* page_url) {
passwordManager_.reset(new PasswordManager(passwordManagerClient_.get()));
passwordManagerDriver_.reset(new IOSChromePasswordManagerDriver(self));
passwordJsManager_ = base::mac::ObjCCastStrict<JsPasswordManager>(
[webState_->GetJSInjectionReceiver()
instanceOfClass:[JsPasswordManager class]]);
webStateObserverBridge_ =
std::make_unique<web::WebStateObserverBridge>(self);
webState_->AddObserver(webStateObserverBridge_.get());
passwordJsManager_ = [[JsPasswordManager alloc]
initWithReceiver:webState_->GetJSInjectionReceiver()];
sentRequestToStore_ = NO;
if (base::FeatureList::IsEnabled(features::kCredentialManager)) {
......
......@@ -22,10 +22,8 @@ class PasswordControllerJsTest
: public web::WebJsTest<web::WebTestWithWebState> {
public:
PasswordControllerJsTest()
: web::WebJsTest<web::WebTestWithWebState>(@[
@"chrome_bundle_all_frames", @"chrome_bundle_main_frame",
@"password_controller"
]) {}
: web::WebJsTest<web::WebTestWithWebState>(
@[ @"chrome_bundle_all_frames", @"chrome_bundle_main_frame" ]) {}
};
// IDs used in the Username and Password <input> elements.
......@@ -77,10 +75,11 @@ TEST_F(PasswordControllerJsTest,
NSString* const username = @"john.doe@gmail.com";
NSString* const password = @"super!secret";
LoadHtmlAndInject(GAIASignInForm(formAction, username, YES));
EXPECT_NSEQ(@YES, ExecuteJavaScriptWithFormat(
@"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%@')",
GAIASignInFormData(formAction), username, password,
formAction));
EXPECT_NSEQ(
@YES,
ExecuteJavaScriptWithFormat(
@"__gCrWeb.passwords.fillPasswordForm(%@, '%@', '%@', '%@')",
GAIASignInFormData(formAction), username, password, formAction));
// Verifies that the sign-in form has been filled with username/password.
ExecuteJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value",
@[ kEmailInputID, kPasswordInputID ],
......@@ -97,10 +96,11 @@ TEST_F(PasswordControllerJsTest,
NSString* const username2 = @"jean.dubois@gmail.com";
NSString* const password = @"super!secret";
LoadHtmlAndInject(GAIASignInForm(formAction, username1, YES));
EXPECT_NSEQ(@NO, ExecuteJavaScriptWithFormat(
@"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%@')",
GAIASignInFormData(formAction), username2, password,
formAction));
EXPECT_NSEQ(
@NO,
ExecuteJavaScriptWithFormat(
@"__gCrWeb.passwords.fillPasswordForm(%@, '%@', '%@', '%@')",
GAIASignInFormData(formAction), username2, password, formAction));
// Verifies that the sign-in form has not been filled.
ExecuteJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value",
@[ kEmailInputID, kPasswordInputID ],
......@@ -117,10 +117,11 @@ TEST_F(PasswordControllerJsTest,
NSString* const username2 = @"jane.doe@gmail.com";
NSString* const password = @"super!secret";
LoadHtmlAndInject(GAIASignInForm(formAction, username1, NO));
EXPECT_NSEQ(@YES, ExecuteJavaScriptWithFormat(
@"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%@')",
GAIASignInFormData(formAction), username2, password,
formAction));
EXPECT_NSEQ(
@YES,
ExecuteJavaScriptWithFormat(
@"__gCrWeb.passwords.fillPasswordForm(%@, '%@', '%@', '%@')",
GAIASignInFormData(formAction), username2, password, formAction));
// Verifies that the sign-in form has been filled with the new username
// and password.
ExecuteJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value",
......@@ -154,8 +155,8 @@ TEST_F(PasswordControllerJsTest,
@"\"max_length\":524288,\"is_checkable\":false,\"value\":\"\","
@"\"label\":\"Password:\"}]}]",
base_url.c_str()];
EXPECT_NSEQ(result,
ExecuteJavaScriptWithFormat(@"__gCrWeb.findPasswordForms()"));
EXPECT_NSEQ(result, ExecuteJavaScriptWithFormat(
@"__gCrWeb.passwords.findPasswordForms()"));
};
// Check that multiple password forms are identified and serialized correctly.
......@@ -198,8 +199,8 @@ TEST_F(PasswordControllerJsTest,
@"\"label\":\"Password:\"}]}]",
base_url.c_str(), base_url.c_str()];
EXPECT_NSEQ(result,
ExecuteJavaScriptWithFormat(@"__gCrWeb.findPasswordForms()"));
EXPECT_NSEQ(result, ExecuteJavaScriptWithFormat(
@"__gCrWeb.passwords.findPasswordForms()"));
};
// Test serializing of password forms.
......@@ -231,7 +232,8 @@ TEST_F(PasswordControllerJsTest, GetPasswordFormData) {
EXPECT_NSEQ(
result,
ExecuteJavaScriptWithFormat(
@"__gCrWeb.stringify(__gCrWeb.getPasswordFormData(%@))", parameter));
@"__gCrWeb.stringify(__gCrWeb.passwords.getPasswordFormData(%@))",
parameter));
};
// Check that if a form action is not set then the action is parsed to the
......@@ -258,8 +260,8 @@ TEST_F(PasswordControllerJsTest, FormActionIsNotSet) {
@"autocomplete\":true,\"is_focusable\":true,\"max_length\":524288,"
@"\"is_checkable\":false,\"value\":\"\",\"label\":\"Password:\"}]}]",
base_url.c_str(), base_url.c_str()];
EXPECT_NSEQ(result,
ExecuteJavaScriptWithFormat(@"__gCrWeb.findPasswordForms()"));
EXPECT_NSEQ(result, ExecuteJavaScriptWithFormat(
@"__gCrWeb.passwords.findPasswordForms()"));
};
// Checks that a touchend event from a button which contains in a password form
......@@ -274,9 +276,9 @@ TEST_F(PasswordControllerJsTest, TouchendAsSubmissionIndicator) {
"</form>"
"</body></html>");
// Call __gCrWeb.findPasswordForms in order to set an event handler on the
// button touchend event.
ExecuteJavaScriptWithFormat(@"__gCrWeb.findPasswordForms()");
// Call __gCrWeb.passwords.findPasswordForms in order to set an event handler
// on the button touchend event.
ExecuteJavaScriptWithFormat(@"__gCrWeb.passwords.findPasswordForms()");
// Replace __gCrWeb.message.invokeOnHost with mock method for checking of call
// arguments.
......@@ -348,7 +350,7 @@ TEST_F(PasswordControllerJsTest, OriginsAreDifferentInPathes) {
page_origin.c_str(), form_fill_data_origin.c_str()];
EXPECT_NSEQ(@YES,
ExecuteJavaScriptWithFormat(
@"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%s')",
@"__gCrWeb.passwords.fillPasswordForm(%@, '%@', '%@', '%s')",
form_fill_data, username, password, page_origin.c_str()));
// Verifies that the sign-in form has been filled with username/password.
ExecuteJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value",
......
......@@ -1127,6 +1127,11 @@ TEST_F(PasswordControllerTestSimple, SaveOnNonHTMLLandingPage) {
TestChromeBrowserState::Builder builder;
std::unique_ptr<TestChromeBrowserState> browser_state(builder.Build());
MockWebState web_state;
id mock_js_injection_receiver =
[OCMockObject mockForClass:[CRWJSInjectionReceiver class]];
[[mock_js_injection_receiver expect] executeJavaScript:[OCMArg any]
completionHandler:[OCMArg any]];
web_state.SetJSInjectionReceiver(mock_js_injection_receiver);
ON_CALL(web_state, GetBrowserState())
.WillByDefault(testing::Return(browser_state.get()));
......
......@@ -2,45 +2,48 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file adheres to closure-compiler conventions in order to enable
// compilation with ADVANCED_OPTIMIZATIONS. See http://goo.gl/FwOgy
//
// Installs password management functions on the |__gCrWeb| object.
//
// Finds all password forms in the current document and extracts
// their attributes and elements using the same logic as
// third_party/WebKit/Source/WebCore/html/HTMLFormElement.cpp
//
// Returns a JSON string representing an array of objects,
// where each object represents a password form with the discovered
// elements and their values.
//
// The search for password form fields follows the same algorithm
// as the WebKit implementation, see http://goo.gl/4hwh6
/**
* @fileoverview Installs Passwords management functions on the __gCrWeb object.
*
* It scans the DOM, extracting and storing password forms and returns a JSON
* string representing an array of objects, each of which represents an Passord
* form with information about a form to be filled and/or submitted and it can
* be translated to struct FormData for further processing.
*/
goog.provide('__crWeb.passwords');
/* Beginning of anonymous object. */
(function() {
// Only install the password management functions once.
if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
/**
/**
* Namespace for this file. It depends on |__gCrWeb| having already been
* injected.
*/
__gCrWeb.passwords = {};
__gCrWeb['passwords'] = __gCrWeb.passwords;
/**
* Finds all password forms in the window and returns form data as a JSON
* string.
* @return {string} Form data as a JSON string.
*/
__gCrWeb['findPasswordForms'] = function() {
__gCrWeb.passwords['findPasswordForms'] = function() {
var formDataList = [];
if (hasPasswordField_(window)) {
getPasswordFormDataList_(formDataList, window);
}
return __gCrWeb.stringify(formDataList);
};
};
/** Returns true if the supplied window or any frames inside contain an input
/** Returns true if the supplied window or any frames inside contain an input
* field of type 'password'.
* @private
* @param {Window} win Whether the supplied window or any frames inside
* contain an input field of type 'password'.
* @return {boolean}
*/
var hasPasswordField_ = function(win) {
var hasPasswordField_ = function(win) {
var doc = win.document;
// We may will not be allowed to read the 'document' property from a frame
......@@ -54,15 +57,15 @@ if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
}
return getSameOriginFrames_(win).some(hasPasswordField_);
};
};
/**
/**
* Returns the contentWindow of all iframes that are from the the same origin
* as the containing window.
* @param {Window} win The window in which to look for frames.
* @return {Array.<Window>} Array of the same-origin frames found.
*/
var getSameOriginFrames_ = function(win) {
var getSameOriginFrames_ = function(win) {
var frames = win.document.getElementsByTagName('iframe');
var result = [];
for (var i = 0; i < frames.length; i++) {
......@@ -72,102 +75,108 @@ if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
}
}
return result;
};
};
/**
/**
* If |form| has no submit elements and exactly 1 button that button
* is assumed to be a submit button. This function adds onSubmitButtonClick_
* as a handler for touchend event of this button. Touchend event is used as
* a proxy for onclick event because onclick handling might be prevented by
* the site JavaScript.
*/
var addSubmitButtonTouchEndHandler_ = function(form) {
if (form.querySelector('input[type=submit]')) return;
var addSubmitButtonTouchEndHandler_ = function(form) {
if (form.querySelector('input[type=submit]'))
return;
// Try to find buttons of type submit at first.
var buttons = form.querySelectorAll('button[type="submit"]');
if (buttons.length == 0) {
// Try to check all buttons. If there is only one button, assume that this
// is the submit button.
buttons = form.querySelectorAll('button');
if (buttons.length != 1) return;
if (buttons.length != 1)
return;
}
for (var i = 0; i < buttons.length; ++i)
buttons[0].addEventListener('touchend', onSubmitButtonTouchEnd_);
};
};
/**
/**
* Click handler for the submit button. It sends to the host
* form.submitButtonClick command.
*/
var onSubmitButtonTouchEnd_ = function(evt) {
var onSubmitButtonTouchEnd_ = function(evt) {
var form = evt.currentTarget.form;
var formData = __gCrWeb.getPasswordFormData(form);
if (!formData) return;
var formData = __gCrWeb.passwords.getPasswordFormData(form);
if (!formData)
return;
formData['command'] = 'passwordForm.submitButtonClick';
__gCrWeb.message.invokeOnHost(formData);
};
};
/**
/**
* Returns the element from |inputs| which has the field identifier equal to
* |identifier| and null if there is no such element.
* @param {Array.<HTMLInputElement>} inputs
* @param {string} identifier
* @return {HTMLInputElement}
*/
var findInputByFieldIdentifier_ = function(inputs, identifier) {
var findInputByFieldIdentifier_ = function(inputs, identifier) {
for (var i = 0; i < inputs.length; ++i) {
if (identifier == __gCrWeb.form.getFieldIdentifier(inputs[i])) {
return inputs[i];
}
}
return null;
};
};
/**
/**
* Returns the password form with the given |identifier| as a JSON string
* from the frame |win| and all its same-origin subframes.
* @param {Window} win The window in which to look for forms.
* @param {string} identifier The name of the form to extract.
* @return {HTMLFormElement} The password form.
*/
var getPasswordFormElement_ = function(win, identifier) {
var getPasswordFormElement_ = function(win, identifier) {
var el = win.__gCrWeb.form.getFormElementFromIdentifier(identifier);
if (el) return el;
if (el)
return el;
var frames = getSameOriginFrames_(win);
for (var i = 0; i < frames.length; ++i) {
el = getPasswordFormElement_(frames[i], identifier);
if (el) return el;
if (el)
return el;
}
return null;
};
};
/**
/**
* Returns an array of input elements in a form.
* @param {HTMLFormElement} form A form element for which the input elements
* are returned.
* @return {Array<HTMLInputElement>}
*/
var getFormInputElements_ = function(form) {
return __gCrWeb.form.getFormControlElements(form).filter(function(
element) {
var getFormInputElements_ = function(form) {
return __gCrWeb.form.getFormControlElements(form).filter(function(element) {
return element.tagName === 'INPUT';
});
};
};
/**
/**
* Returns the password form with the given |identifier| as a JSON string.
* @param {string} identifier The identifier of the form to extract.
* @return {string} The password form.
*/
__gCrWeb['getPasswordFormDataAsString'] = function(identifier) {
__gCrWeb.passwords['getPasswordFormDataAsString'] = function(identifier) {
var el = getPasswordFormElement_(window, identifier);
if (!el) return '{}';
var formData = __gCrWeb.getPasswordFormData(el);
if (!formData) return '{}';
if (!el)
return '{}';
var formData = __gCrWeb.passwords.getPasswordFormData(el);
if (!formData)
return '{}';
return __gCrWeb.stringify(formData);
};
};
/**
/**
* Finds the form described by |formData| and fills in the
* username and password values.
*
......@@ -180,7 +189,7 @@ if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
* @param {string=} opt_normalizedOrigin The origin URL to compare to.
* @return {boolean} Whether a form field has been filled.
*/
__gCrWeb['fillPasswordForm'] = function(
__gCrWeb.passwords['fillPasswordForm'] = function(
formData, username, password, opt_normalizedOrigin) {
var normalizedOrigin = opt_normalizedOrigin ||
__gCrWeb.common.removeQueryAndReferenceFromURL(window.location.href);
......@@ -190,9 +199,9 @@ if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
}
return fillPasswordFormWithData_(
formData, username, password, window, opt_normalizedOrigin);
};
};
/**
/**
* Given a description of a form (origin, action and input fields),
* finds that form on the page and fills in the specified username
* and password.
......@@ -204,7 +213,7 @@ if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
* @param {string=} opt_normalizedOrigin The origin URL to compare to.
* @return {boolean} Whether a form field has been filled.
*/
var fillPasswordFormWithData_ = function(
var fillPasswordFormWithData_ = function(
formData, username, password, win, opt_normalizedOrigin) {
var doc = win.document;
var forms = doc.forms;
......@@ -212,14 +221,15 @@ if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
for (var i = 0; i < forms.length; i++) {
var form = forms[i];
var normalizedFormAction = opt_normalizedOrigin ||
__gCrWeb.fill.getCanonicalActionForForm(form);
if (formData.action != normalizedFormAction) continue;
var normalizedFormAction =
opt_normalizedOrigin || __gCrWeb.fill.getCanonicalActionForForm(form);
if (formData.action != normalizedFormAction)
continue;
var inputs = getFormInputElements_(form);
var usernameInput =
findInputByFieldIdentifier_(inputs, formData.fields[0].name);
if (usernameInput == null ||
!__gCrWeb.common.isTextField(usernameInput) || usernameInput.disabled)
if (usernameInput == null || !__gCrWeb.common.isTextField(usernameInput) ||
usernameInput.disabled)
continue;
var passwordInput =
findInputByFieldIdentifier_(inputs, formData.fields[1].name);
......@@ -258,9 +268,9 @@ if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
}
return filled;
};
};
/**
/**
* Finds all forms with passwords in the supplied window or frame and appends
* JS objects containing the form data to |formDataList|.
* @param {!Array.<Object>} formDataList A list that this function populates
......@@ -268,11 +278,11 @@ if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
* @param {Window} win A window (or frame) in which the function should
* look for password forms.
*/
var getPasswordFormDataList_ = function(formDataList, win) {
var getPasswordFormDataList_ = function(formDataList, win) {
var doc = win.document;
var forms = doc.forms;
for (var i = 0; i < forms.length; i++) {
var formData = __gCrWeb.getPasswordFormData(forms[i]);
var formData = __gCrWeb.passwords.getPasswordFormData(forms[i]);
if (formData) {
formDataList.push(formData);
addSubmitButtonTouchEndHandler_(forms[i]);
......@@ -284,19 +294,20 @@ if (__gCrWeb && !__gCrWeb['fillPasswordForm']) {
for (var i = 0; i < frames.length; i++) {
getPasswordFormDataList_(formDataList, frames[i]);
}
};
};
/**
/**
* Returns a JS object containing the data from |formElement|.
* @param {HTMLFormElement} formElement An HTML Form element.
* @return {Object} Object of data from formElement.
*/
__gCrWeb.getPasswordFormData = function(formElement) {
__gCrWeb.passwords.getPasswordFormData = function(formElement) {
var extractMask = __gCrWeb.fill.EXTRACT_MASK_VALUE;
var formData = {}
var formData = {};
var ok = __gCrWeb.fill.webFormElementToFormData(
window, formElement, null /* formControlElement */,
extractMask, formData, null /* field */);
window, formElement, null /* formControlElement */, extractMask, formData,
null /* field */);
return ok ? formData : null;
};
}
};
}()); // End of anonymous object
......@@ -121,6 +121,7 @@ js_compile_bundle("chrome_bundle_main_frame") {
sources = [
"//components/autofill/ios/browser/resources/autofill_controller.js",
"//components/autofill/ios/fill/resources/fill.js",
"//ios/chrome/browser/passwords/resources/password_controller.js",
"resources/chrome_bundle_main_frame.js",
"resources/print.js",
]
......
......@@ -7,4 +7,5 @@ goog.provide('__crWeb.chromeBundleMainFrame');
goog.require('__crWeb.autofill');
goog.require('__crWeb.fill');
goog.require('__crWeb.passwords');
goog.require('__crWeb.print');
......@@ -313,6 +313,7 @@ js_compile_bundle("web_view_bundle") {
"//components/autofill/ios/browser/resources/autofill_controller.js",
"//components/autofill/ios/fill/resources/fill.js",
"//components/autofill/ios/fill/resources/form.js",
"//ios/chrome/browser/passwords/resources/password_controller.js",
"resources/web_view_bundle.js",
]
}
......
......@@ -8,3 +8,4 @@ goog.provide('__crWeb.webViewBundle');
goog.require('__crWeb.autofill');
goog.require('__crWeb.fill');
goog.require('__crWeb.form');
goog.require('__crWeb.passwords');
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