1// Copyright 2019 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "ios/chrome/browser/ui/dialogs/overlay_java_script_dialog_presenter.h" 6 7#include "base/bind.h" 8#include "base/metrics/histogram_macros.h" 9#import "base/strings/sys_string_conversions.h" 10#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h" 11#import "ios/chrome/browser/overlays/public/overlay_request.h" 12#import "ios/chrome/browser/overlays/public/overlay_request_queue.h" 13#import "ios/chrome/browser/overlays/public/overlay_response.h" 14#import "ios/chrome/browser/overlays/public/web_content_area/java_script_dialog_overlay.h" 15#import "ios/chrome/browser/ui/dialogs/java_script_dialog_blocking_state.h" 16#include "ios/chrome/browser/ui/dialogs/java_script_dialog_metrics.h" 17#import "ios/web/public/web_state.h" 18 19#if !defined(__has_feature) || !__has_feature(objc_arc) 20#error "This file requires ARC support." 21#endif 22 23using java_script_dialog_overlays::JavaScriptDialogRequest; 24using java_script_dialog_overlays::JavaScriptDialogResponse; 25 26namespace { 27// Completion callback for JavaScript dialog overlays. 28void HandleJavaScriptDialogResponse(web::DialogClosedCallback callback, 29 web::WebState::Getter web_state_getter, 30 OverlayResponse* response) { 31 // Notify the blocking state that the dialog was shown. 32 web::WebState* web_state = web_state_getter.Run(); 33 JavaScriptDialogBlockingState* blocking_state = 34 web_state ? JavaScriptDialogBlockingState::FromWebState(web_state) 35 : nullptr; 36 if (blocking_state) 37 blocking_state->JavaScriptDialogWasShown(); 38 39 JavaScriptDialogResponse* dialog_response = 40 response ? response->GetInfo<JavaScriptDialogResponse>() : nullptr; 41 if (!dialog_response) { 42 // A null response is used if the dialog was not closed by user interaction. 43 // This occurs either for navigation or because of WebState closures. 44 IOSJavaScriptDialogDismissalCause cause = 45 web_state ? IOSJavaScriptDialogDismissalCause::kNavigation 46 : IOSJavaScriptDialogDismissalCause::kClosure; 47 RecordDialogDismissalCause(cause); 48 std::move(callback).Run(/*success=*/false, /*user_input=*/nil); 49 return; 50 } 51 52 // Update the blocking state if the suppression action was selected. 53 JavaScriptDialogResponse::Action action = dialog_response->action(); 54 if (blocking_state && 55 action == JavaScriptDialogResponse::Action::kBlockDialogs) { 56 blocking_state->JavaScriptDialogBlockingOptionSelected(); 57 } 58 59 RecordDialogDismissalCause(IOSJavaScriptDialogDismissalCause::kUser); 60 bool confirmed = action == JavaScriptDialogResponse::Action::kConfirm; 61 NSString* user_input = confirmed ? dialog_response->user_input() : nil; 62 std::move(callback).Run(confirmed, user_input); 63} 64} // namespace 65 66OverlayJavaScriptDialogPresenter::OverlayJavaScriptDialogPresenter() = default; 67 68OverlayJavaScriptDialogPresenter::OverlayJavaScriptDialogPresenter( 69 OverlayJavaScriptDialogPresenter&& other) = default; 70 71OverlayJavaScriptDialogPresenter& OverlayJavaScriptDialogPresenter::operator=( 72 OverlayJavaScriptDialogPresenter&& other) = default; 73 74OverlayJavaScriptDialogPresenter::~OverlayJavaScriptDialogPresenter() = default; 75 76void OverlayJavaScriptDialogPresenter::RunJavaScriptDialog( 77 web::WebState* web_state, 78 const GURL& origin_url, 79 web::JavaScriptDialogType dialog_type, 80 NSString* message_text, 81 NSString* default_prompt_text, 82 web::DialogClosedCallback callback) { 83 JavaScriptDialogBlockingState::CreateForWebState(web_state); 84 if (JavaScriptDialogBlockingState::FromWebState(web_state)->blocked()) { 85 // Block the dialog if needed. 86 RecordDialogDismissalCause(IOSJavaScriptDialogDismissalCause::kBlocked); 87 std::move(callback).Run(NO, nil); 88 return; 89 } 90 91 bool from_main_frame_origin = 92 origin_url.GetOrigin() == web_state->GetLastCommittedURL().GetOrigin(); 93 std::unique_ptr<OverlayRequest> request = 94 OverlayRequest::CreateWithConfig<JavaScriptDialogRequest>( 95 dialog_type, web_state, origin_url, from_main_frame_origin, 96 message_text, default_prompt_text); 97 request->GetCallbackManager()->AddCompletionCallback( 98 base::BindOnce(&HandleJavaScriptDialogResponse, std::move(callback), 99 web_state->CreateDefaultGetter())); 100 OverlayRequestQueue::FromWebState(web_state, OverlayModality::kWebContentArea) 101 ->AddRequest(std::move(request)); 102} 103 104void OverlayJavaScriptDialogPresenter::CancelDialogs(web::WebState* web_state) { 105 OverlayRequestQueue::FromWebState(web_state, OverlayModality::kWebContentArea) 106 ->CancelAllRequests(); 107} 108