OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h" | 5 #include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/string_split.h" | 10 #include "base/string_split.h" |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 const GURL& source_url, | 126 const GURL& source_url, |
127 const content::SSLStatus& ssl_status, | 127 const content::SSLStatus& ssl_status, |
128 const base::Callback<void(const FormStructure*)>& callback) | 128 const base::Callback<void(const FormStructure*)>& callback) |
129 : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())), | 129 : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())), |
130 contents_(contents), | 130 contents_(contents), |
131 form_structure_(form), | 131 form_structure_(form), |
132 source_url_(source_url), | 132 source_url_(source_url), |
133 ssl_status_(ssl_status), | 133 ssl_status_(ssl_status), |
134 callback_(callback), | 134 callback_(callback), |
135 wallet_client_(profile_->GetRequestContext()), | 135 wallet_client_(profile_->GetRequestContext()), |
136 refresh_wallet_items_in_progress_(false), | |
137 refresh_wallet_items_queued_(false), | |
138 had_wallet_error_(false), | |
136 ALLOW_THIS_IN_INITIALIZER_LIST(suggested_email_(this)), | 139 ALLOW_THIS_IN_INITIALIZER_LIST(suggested_email_(this)), |
137 ALLOW_THIS_IN_INITIALIZER_LIST(suggested_cc_(this)), | 140 ALLOW_THIS_IN_INITIALIZER_LIST(suggested_cc_(this)), |
138 ALLOW_THIS_IN_INITIALIZER_LIST(suggested_billing_(this)), | 141 ALLOW_THIS_IN_INITIALIZER_LIST(suggested_billing_(this)), |
139 ALLOW_THIS_IN_INITIALIZER_LIST(suggested_shipping_(this)), | 142 ALLOW_THIS_IN_INITIALIZER_LIST(suggested_shipping_(this)), |
140 popup_controller_(NULL), | 143 popup_controller_(NULL), |
141 section_showing_popup_(SECTION_BILLING) { | 144 section_showing_popup_(SECTION_BILLING) { |
142 // TODO(estade): |this| should observe PersonalDataManager. | 145 // TODO(estade): |this| should observe PersonalDataManager. |
143 // TODO(estade): remove duplicates from |form|? | 146 // TODO(estade): remove duplicates from |form|? |
144 | 147 |
145 content::NavigationEntry* entry = contents->GetController().GetActiveEntry(); | 148 content::NavigationEntry* entry = contents->GetController().GetActiveEntry(); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
216 &requested_shipping_fields_); | 219 &requested_shipping_fields_); |
217 | 220 |
218 GenerateSuggestionsModels(); | 221 GenerateSuggestionsModels(); |
219 | 222 |
220 // TODO(estade): don't show the dialog if the site didn't specify the right | 223 // TODO(estade): don't show the dialog if the site didn't specify the right |
221 // fields. First we must figure out what the "right" fields are. | 224 // fields. First we must figure out what the "right" fields are. |
222 view_.reset(AutofillDialogView::Create(this)); | 225 view_.reset(AutofillDialogView::Create(this)); |
223 view_->Show(); | 226 view_->Show(); |
224 | 227 |
225 // Request sugar info after the view is showing to simplify code for now. | 228 // Request sugar info after the view is showing to simplify code for now. |
226 wallet_client_.GetWalletItems(this); | 229 ScheduleRefreshWalletItems(); |
227 } | 230 } |
228 | 231 |
229 void AutofillDialogControllerImpl::Hide() { | 232 void AutofillDialogControllerImpl::Hide() { |
230 if (view_) | 233 if (view_) |
231 view_->Hide(); | 234 view_->Hide(); |
232 } | 235 } |
233 | 236 |
234 //////////////////////////////////////////////////////////////////////////////// | 237 //////////////////////////////////////////////////////////////////////////////// |
235 // AutofillDialogController implementation. | 238 // AutofillDialogController implementation. |
236 | 239 |
(...skipping 16 matching lines...) Expand all Loading... | |
253 } | 256 } |
254 | 257 |
255 string16 AutofillDialogControllerImpl::CancelButtonText() const { | 258 string16 AutofillDialogControllerImpl::CancelButtonText() const { |
256 return l10n_util::GetStringUTF16(IDS_CANCEL); | 259 return l10n_util::GetStringUTF16(IDS_CANCEL); |
257 } | 260 } |
258 | 261 |
259 string16 AutofillDialogControllerImpl::ConfirmButtonText() const { | 262 string16 AutofillDialogControllerImpl::ConfirmButtonText() const { |
260 return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON); | 263 return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON); |
261 } | 264 } |
262 | 265 |
263 string16 AutofillDialogControllerImpl::SignInText() const { | |
264 // TODO(abodenha): real strings and l10n. | |
265 return string16(ASCIIToUTF16("Sign in to use Google Wallet")); | |
266 } | |
267 | |
268 string16 AutofillDialogControllerImpl::CancelSignInText() const { | 266 string16 AutofillDialogControllerImpl::CancelSignInText() const { |
269 // TODO(abodenha): real strings and l10n. | 267 // TODO(abodenha): real strings and l10n. |
270 return string16(ASCIIToUTF16("Don't sign in.")); | 268 return ASCIIToUTF16("Don't sign in."); |
269 } | |
270 | |
271 string16 AutofillDialogControllerImpl::SaveLocallyText() const { | |
272 return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX); | |
273 } | |
274 | |
275 string16 AutofillDialogControllerImpl::ProgressBarText() const { | |
276 return l10n_util::GetStringUTF16( | |
277 IDS_AUTOFILL_DIALOG_AUTOCHECKOUT_PROGRESS_BAR); | |
271 } | 278 } |
272 | 279 |
273 DialogSignedInState AutofillDialogControllerImpl::SignedInState() const { | 280 DialogSignedInState AutofillDialogControllerImpl::SignedInState() const { |
274 if (!wallet_items_) | 281 if (!wallet_items_) |
275 return REQUIRES_RESPONSE; | 282 return REQUIRES_RESPONSE; |
276 | 283 |
277 if (HasRequiredAction(wallet::GAIA_AUTH)) | 284 if (HasRequiredAction(wallet::GAIA_AUTH)) |
278 return REQUIRES_SIGN_IN; | 285 return REQUIRES_SIGN_IN; |
279 | 286 |
280 if (HasRequiredAction(wallet::PASSIVE_GAIA_AUTH)) | 287 if (HasRequiredAction(wallet::PASSIVE_GAIA_AUTH)) |
281 return REQUIRES_PASSIVE_SIGN_IN; | 288 return REQUIRES_PASSIVE_SIGN_IN; |
282 | 289 |
283 return SIGNED_IN; | 290 return SIGNED_IN; |
284 } | 291 } |
285 | 292 |
286 string16 AutofillDialogControllerImpl::SaveLocallyText() const { | 293 bool AutofillDialogControllerImpl::CanPayWithWallet() const { |
287 return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX); | 294 return !had_wallet_error_; |
288 } | 295 } |
289 | 296 |
290 string16 AutofillDialogControllerImpl::ProgressBarText() const { | 297 string16 AutofillDialogControllerImpl::AccountChooserText() const { |
291 return l10n_util::GetStringUTF16( | 298 if (!CanPayWithWallet()) |
292 IDS_AUTOFILL_DIALOG_AUTOCHECKOUT_PROGRESS_BAR); | 299 return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PAY_WITHOUT_WALLET); |
300 | |
301 // TODO(dbeam): real strings and l10n. | |
302 const DialogSignedInState& state = SignedInState(); | |
303 return state != SIGNED_IN ? ASCIIToUTF16("Sign in to use Google Wallet") : | |
304 ASCIIToUTF16("user@example.com"); | |
293 } | 305 } |
294 | 306 |
307 bool AutofillDialogControllerImpl::AccountChooserEnabled() const { | |
308 if (!CanPayWithWallet()) | |
309 return false; | |
310 | |
311 const DialogSignedInState& state = SignedInState(); | |
312 return state != REQUIRES_RESPONSE && state != SIGNED_IN; | |
313 } | |
314 | |
315 | |
Evan Stade
2013/02/07 01:54:42
^H
Dan Beam
2013/02/07 03:26:54
Done.
| |
295 const DetailInputs& AutofillDialogControllerImpl::RequestedFieldsForSection( | 316 const DetailInputs& AutofillDialogControllerImpl::RequestedFieldsForSection( |
296 DialogSection section) const { | 317 DialogSection section) const { |
297 switch (section) { | 318 switch (section) { |
298 case SECTION_EMAIL: | 319 case SECTION_EMAIL: |
299 return requested_email_fields_; | 320 return requested_email_fields_; |
300 case SECTION_CC: | 321 case SECTION_CC: |
301 return requested_cc_fields_; | 322 return requested_cc_fields_; |
302 case SECTION_BILLING: | 323 case SECTION_BILLING: |
303 return requested_billing_fields_; | 324 return requested_billing_fields_; |
304 case SECTION_SHIPPING: | 325 case SECTION_SHIPPING: |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
547 l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECURITY_WARNING)); | 568 l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECURITY_WARNING)); |
548 } | 569 } |
549 | 570 |
550 if (!invoked_from_same_origin_) { | 571 if (!invoked_from_same_origin_) { |
551 return DialogNotification( | 572 return DialogNotification( |
552 DialogNotification::SECURITY_WARNING, | 573 DialogNotification::SECURITY_WARNING, |
553 l10n_util::GetStringFUTF16( | 574 l10n_util::GetStringFUTF16( |
554 IDS_AUTOFILL_DIALOG_SITE_WARNING, UTF8ToUTF16(source_url_.host()))); | 575 IDS_AUTOFILL_DIALOG_SITE_WARNING, UTF8ToUTF16(source_url_.host()))); |
555 } | 576 } |
556 | 577 |
578 if (!CanPayWithWallet()) { | |
579 // TODO(dbeam): pass along the Wallet error or remove from the translation. | |
580 return DialogNotification( | |
581 DialogNotification::WALLET_ERROR, | |
582 l10n_util::GetStringFUTF16( | |
583 IDS_AUTOFILL_DIALOG_COMPLETE_WITHOUT_WALLET, | |
584 ASCIIToUTF16("[Wallet-Error]."))); | |
585 } | |
586 | |
557 return DialogNotification(); | 587 return DialogNotification(); |
558 } | 588 } |
559 | 589 |
560 void AutofillDialogControllerImpl::StartSignInFlow() { | 590 void AutofillDialogControllerImpl::StartSignInFlow() { |
561 DCHECK(registrar_.IsEmpty()); | 591 DCHECK(registrar_.IsEmpty()); |
562 | 592 |
563 content::Source<content::NavigationController> source( | 593 content::Source<content::NavigationController> source(&view_->ShowSignIn()); |
564 &view_->ShowSignIn()); | |
565 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source); | 594 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source); |
566 } | 595 } |
567 | 596 |
568 void AutofillDialogControllerImpl::EndSignInFlow() { | 597 void AutofillDialogControllerImpl::EndSignInFlow() { |
569 DCHECK(!registrar_.IsEmpty()); | 598 DCHECK(!registrar_.IsEmpty()); |
570 registrar_.RemoveAll(); | 599 registrar_.RemoveAll(); |
571 view_->HideSignIn(); | 600 view_->HideSignIn(); |
572 } | 601 } |
573 | 602 |
574 Profile* AutofillDialogControllerImpl::profile() { | 603 Profile* AutofillDialogControllerImpl::profile() { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
626 | 655 |
627 void AutofillDialogControllerImpl::Observe( | 656 void AutofillDialogControllerImpl::Observe( |
628 int type, | 657 int type, |
629 const content::NotificationSource& source, | 658 const content::NotificationSource& source, |
630 const content::NotificationDetails& details) { | 659 const content::NotificationDetails& details) { |
631 DCHECK_EQ(type, content::NOTIFICATION_NAV_ENTRY_COMMITTED); | 660 DCHECK_EQ(type, content::NOTIFICATION_NAV_ENTRY_COMMITTED); |
632 content::LoadCommittedDetails* load_details = | 661 content::LoadCommittedDetails* load_details = |
633 content::Details<content::LoadCommittedDetails>(details).ptr(); | 662 content::Details<content::LoadCommittedDetails>(details).ptr(); |
634 if (wallet::IsSignInContinueUrl(load_details->entry->GetVirtualURL())) { | 663 if (wallet::IsSignInContinueUrl(load_details->entry->GetVirtualURL())) { |
635 EndSignInFlow(); | 664 EndSignInFlow(); |
636 // TODO(dbeam): the fetcher can't handle being called multiple times. | 665 ScheduleRefreshWalletItems(); |
637 // Address this soon as we will be re-fetching wallet items after every | |
638 // required action is resolved. | |
639 wallet_client_.GetWalletItems(this); | |
640 } | 666 } |
641 } | 667 } |
642 | 668 |
643 //////////////////////////////////////////////////////////////////////////////// | 669 //////////////////////////////////////////////////////////////////////////////// |
644 // SuggestionsMenuModelDelegate | 670 // SuggestionsMenuModelDelegate |
645 | 671 |
646 void AutofillDialogControllerImpl::SuggestionItemSelected( | 672 void AutofillDialogControllerImpl::SuggestionItemSelected( |
647 const SuggestionsMenuModel& model) { | 673 const SuggestionsMenuModel& model) { |
648 DialogSection section = SectionForSuggestionsMenuModel(model); | 674 DialogSection section = SectionForSuggestionsMenuModel(model); |
649 section_editing_state_[section] = false; | 675 section_editing_state_[section] = false; |
(...skipping 14 matching lines...) Expand all Loading... | |
664 } | 690 } |
665 | 691 |
666 void AutofillDialogControllerImpl::OnDidEscrowSensitiveInformation( | 692 void AutofillDialogControllerImpl::OnDidEscrowSensitiveInformation( |
667 const std::string& escrow_handle) { | 693 const std::string& escrow_handle) { |
668 NOTIMPLEMENTED() << " escrow_handle=" << escrow_handle; | 694 NOTIMPLEMENTED() << " escrow_handle=" << escrow_handle; |
669 } | 695 } |
670 | 696 |
671 void AutofillDialogControllerImpl::OnDidGetFullWallet( | 697 void AutofillDialogControllerImpl::OnDidGetFullWallet( |
672 scoped_ptr<wallet::FullWallet> full_wallet) { | 698 scoped_ptr<wallet::FullWallet> full_wallet) { |
673 NOTIMPLEMENTED(); | 699 NOTIMPLEMENTED(); |
700 WalletRequestCompleted(true); | |
674 } | 701 } |
675 | 702 |
676 void AutofillDialogControllerImpl::OnDidGetWalletItems( | 703 void AutofillDialogControllerImpl::OnDidGetWalletItems( |
677 scoped_ptr<wallet::WalletItems> wallet_items) { | 704 scoped_ptr<wallet::WalletItems> wallet_items) { |
705 bool items_changed = !wallet_items_ || *wallet_items != *wallet_items_; | |
678 wallet_items_ = wallet_items.Pass(); | 706 wallet_items_ = wallet_items.Pass(); |
679 view_->UpdateAccountChooser(); | 707 WalletRequestCompleted(true); |
680 view_->UpdateNotificationArea(); | 708 |
709 if (items_changed) { | |
710 view_->UpdateAccountChooser(); | |
711 view_->UpdateNotificationArea(); | |
712 } | |
681 } | 713 } |
682 | 714 |
683 void AutofillDialogControllerImpl::OnDidSaveAddress( | 715 void AutofillDialogControllerImpl::OnDidSaveAddress( |
684 const std::string& address_id) { | 716 const std::string& address_id) { |
685 NOTIMPLEMENTED() << " address_id=" << address_id; | 717 NOTIMPLEMENTED() << " address_id=" << address_id; |
718 WalletRequestCompleted(true); | |
686 } | 719 } |
687 | 720 |
688 void AutofillDialogControllerImpl::OnDidSaveInstrument( | 721 void AutofillDialogControllerImpl::OnDidSaveInstrument( |
689 const std::string& instrument_id) { | 722 const std::string& instrument_id) { |
690 NOTIMPLEMENTED() << " instrument_id=" << instrument_id; | 723 NOTIMPLEMENTED() << " instrument_id=" << instrument_id; |
724 WalletRequestCompleted(true); | |
691 } | 725 } |
692 | 726 |
693 void AutofillDialogControllerImpl::OnDidSaveInstrumentAndAddress( | 727 void AutofillDialogControllerImpl::OnDidSaveInstrumentAndAddress( |
694 const std::string& instrument_id, const std::string& address_id) { | 728 const std::string& instrument_id, const std::string& address_id) { |
695 NOTIMPLEMENTED() << " instrument_id=" << instrument_id | 729 NOTIMPLEMENTED() << " instrument_id=" << instrument_id |
696 << ", address_id=" << address_id; | 730 << ", address_id=" << address_id; |
731 WalletRequestCompleted(true); | |
697 } | 732 } |
698 | 733 |
699 void AutofillDialogControllerImpl::OnDidSendAutocheckoutStatus() { | 734 void AutofillDialogControllerImpl::OnDidSendAutocheckoutStatus() { |
700 NOTIMPLEMENTED(); | 735 NOTIMPLEMENTED(); |
736 WalletRequestCompleted(true); | |
701 } | 737 } |
702 | 738 |
703 void AutofillDialogControllerImpl::OnWalletError() { | 739 void AutofillDialogControllerImpl::OnWalletError() { |
704 NOTIMPLEMENTED(); | 740 WalletRequestCompleted(false); |
705 wallet_items_.reset(); | |
706 } | 741 } |
707 | 742 |
708 void AutofillDialogControllerImpl::OnMalformedResponse() { | 743 void AutofillDialogControllerImpl::OnMalformedResponse() { |
709 NOTIMPLEMENTED(); | 744 WalletRequestCompleted(false); |
710 wallet_items_.reset(); | |
711 } | 745 } |
712 | 746 |
713 void AutofillDialogControllerImpl::OnNetworkError(int response_code) { | 747 void AutofillDialogControllerImpl::OnNetworkError(int response_code) { |
714 NOTIMPLEMENTED() << " response_code=" << response_code; | 748 WalletRequestCompleted(false); |
715 wallet_items_.reset(); | |
716 } | 749 } |
717 | 750 |
718 //////////////////////////////////////////////////////////////////////////////// | 751 //////////////////////////////////////////////////////////////////////////////// |
719 | 752 |
720 bool AutofillDialogControllerImpl::HandleKeyPressEventInInput( | 753 bool AutofillDialogControllerImpl::HandleKeyPressEventInInput( |
721 const content::NativeWebKeyboardEvent& event) { | 754 const content::NativeWebKeyboardEvent& event) { |
722 if (popup_controller_) | 755 if (popup_controller_) |
723 return popup_controller_->HandleKeyPressEvent(event); | 756 return popup_controller_->HandleKeyPressEvent(event); |
724 | 757 |
725 return false; | 758 return false; |
(...skipping 21 matching lines...) Expand all Loading... | |
747 bool AutofillDialogControllerImpl::HasRequiredAction( | 780 bool AutofillDialogControllerImpl::HasRequiredAction( |
748 wallet::RequiredAction action) const { | 781 wallet::RequiredAction action) const { |
749 if (!wallet_items_) | 782 if (!wallet_items_) |
750 return false; | 783 return false; |
751 | 784 |
752 const std::vector<wallet::RequiredAction>& actions = | 785 const std::vector<wallet::RequiredAction>& actions = |
753 wallet_items_->required_actions(); | 786 wallet_items_->required_actions(); |
754 return std::find(actions.begin(), actions.end(), action) != actions.end(); | 787 return std::find(actions.begin(), actions.end(), action) != actions.end(); |
755 } | 788 } |
756 | 789 |
790 void AutofillDialogControllerImpl::ScheduleRefreshWalletItems() { | |
791 if (!CanPayWithWallet()) | |
792 return; | |
793 | |
794 if (refresh_wallet_items_in_progress_) { | |
795 refresh_wallet_items_queued_ = true; | |
796 return; | |
797 } | |
798 | |
799 wallet_client_.GetWalletItems(this); | |
800 refresh_wallet_items_queued_ = false; | |
801 refresh_wallet_items_in_progress_ = true; | |
Evan Stade
2013/02/07 01:54:42
is refresh_wallet_items_in_progress_ something tha
Dan Beam
2013/02/07 03:26:54
yes, Done.
| |
802 } | |
803 | |
804 void AutofillDialogControllerImpl::WalletRequestCompleted(bool success) { | |
805 // |wallet_client_| only handles 1 request at a time, so this can be safely | |
806 // set to false every time regardless of which type of request completed. | |
807 refresh_wallet_items_in_progress_ = false; | |
808 | |
809 if (!success) { | |
810 had_wallet_error_ = true; | |
811 wallet_items_.reset(); | |
812 view_->UpdateAccountChooser(); | |
813 view_->UpdateNotificationArea(); | |
814 return; | |
815 } | |
816 | |
817 if (refresh_wallet_items_queued_) | |
818 ScheduleRefreshWalletItems(); | |
819 } | |
820 | |
757 void AutofillDialogControllerImpl::GenerateSuggestionsModels() { | 821 void AutofillDialogControllerImpl::GenerateSuggestionsModels() { |
758 PersonalDataManager* manager = GetManager(); | 822 PersonalDataManager* manager = GetManager(); |
759 const std::vector<CreditCard*>& cards = manager->credit_cards(); | 823 const std::vector<CreditCard*>& cards = manager->credit_cards(); |
760 for (size_t i = 0; i < cards.size(); ++i) { | 824 for (size_t i = 0; i < cards.size(); ++i) { |
761 suggested_cc_.AddKeyedItem(cards[i]->guid(), cards[i]->Label()); | 825 suggested_cc_.AddKeyedItem(cards[i]->guid(), cards[i]->Label()); |
762 } | 826 } |
763 // TODO(estade): real strings and i18n. | 827 // TODO(estade): real strings and i18n. |
764 suggested_cc_.AddKeyedItem("", ASCIIToUTF16("Enter new card")); | 828 suggested_cc_.AddKeyedItem("", ASCIIToUTF16("Enter new card")); |
765 | 829 |
766 const std::vector<AutofillProfile*>& profiles = manager->GetProfiles(); | 830 const std::vector<AutofillProfile*>& profiles = manager->GetProfiles(); |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
933 } | 997 } |
934 | 998 |
935 void AutofillDialogControllerImpl::HidePopup() { | 999 void AutofillDialogControllerImpl::HidePopup() { |
936 if (popup_controller_) { | 1000 if (popup_controller_) { |
937 popup_controller_->Hide(); | 1001 popup_controller_->Hide(); |
938 ControllerDestroyed(); | 1002 ControllerDestroyed(); |
939 } | 1003 } |
940 } | 1004 } |
941 | 1005 |
942 } // namespace autofill | 1006 } // namespace autofill |
OLD | NEW |