OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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/dialog_presenter.h" |
| 6 |
| 7 #include <deque> |
| 8 #include <map> |
| 9 |
| 10 #import "base/ios/block_types.h" |
| 11 #import "base/ios/weak_nsobject.h" |
| 12 #include "base/logging.h" |
| 13 #import "base/mac/scoped_nsobject.h" |
| 14 #include "base/strings/sys_string_conversions.h" |
| 15 #include "components/strings/grit/components_strings.h" |
| 16 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h" |
| 17 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h" |
| 18 #import "ios/chrome/browser/ui/alert_coordinator/input_alert_coordinator.h" |
| 19 #import "ios/chrome/browser/ui/dialogs/javascript_dialog_blocking_util.h" |
| 20 #import "ios/chrome/browser/ui/dialogs/nsurl_protection_space_util.h" |
| 21 #include "ios/chrome/browser/ui/ui_util.h" |
| 22 #include "ios/chrome/grit/ios_strings.h" |
| 23 #include "ios/web/public/web_state/web_state.h" |
| 24 #include "ui/base/l10n/l10n_util.h" |
| 25 #include "url/gurl.h" |
| 26 |
| 27 // Externed accessibility identifier. |
| 28 NSString* const kJavaScriptDialogTextFieldAccessibiltyIdentifier = |
| 29 @"JavaScriptDialogTextFieldAccessibiltyIdentifier"; |
| 30 |
| 31 namespace { |
| 32 // The hostname to use for JavaScript alerts when there is no valid hostname in |
| 33 // the URL passed to |+localizedTitleForJavaScriptAlertFromPage:type:|. |
| 34 const char kAboutNullHostname[] = "about:null"; |
| 35 } // namespace |
| 36 |
| 37 @interface DialogPresenter () { |
| 38 // Backing objects for properties of the same name. |
| 39 base::WeakNSProtocol<id<DialogPresenterDelegate>> _delegate; |
| 40 base::WeakNSObject<UIViewController> _viewController; |
| 41 // Queue of WebStates which correspond to the keys in |
| 42 // |_dialogCoordinatorsForWebStates|. |
| 43 std::deque<web::WebState*> _queuedWebStates; |
| 44 // A map associating queued webStates with their coordinators. |
| 45 std::map<web::WebState*, base::scoped_nsobject<AlertCoordinator>> |
| 46 _dialogCoordinatorsForWebStates; |
| 47 web::WebState* _presentedDialogWebState; |
| 48 base::scoped_nsobject<AlertCoordinator> _presentedDialogCoordinator; |
| 49 base::scoped_nsobject<ActionSheetCoordinator> |
| 50 _blockingConfirmationCoordinator; |
| 51 } |
| 52 |
| 53 // The delegate passed on initialization. |
| 54 @property(nonatomic, readonly) id<DialogPresenterDelegate> delegate; |
| 55 |
| 56 // The presenting view controller passed on initialization. |
| 57 @property(nonatomic, readonly) UIViewController* viewController; |
| 58 |
| 59 // Whether a modal dialog is currently being shown. |
| 60 @property(nonatomic, readonly, getter=isShowingDialog) BOOL showingDialog; |
| 61 |
| 62 // The webState for |presentedDialog|. |
| 63 @property(nonatomic) web::WebState* presentedDialogWebState; |
| 64 |
| 65 // The dialog that's currently being shown, if any. |
| 66 @property(nonatomic, retain) AlertCoordinator* presentedDialogCoordinator; |
| 67 |
| 68 // The JavaScript dialog blocking confirmation action sheet being shown, if any. |
| 69 @property(nonatomic, retain) AlertCoordinator* blockingConfirmationCoordinator; |
| 70 |
| 71 // Adds |context| and |coordinator| to the queue. If a dialog is not already |
| 72 // being shown, |coordinator| will be presented. Otherwise, |coordinator| will |
| 73 // be displayed once the previously shown dialog is dismissed. |
| 74 - (void)addDialogCoordinator:(AlertCoordinator*)coordinator |
| 75 forWebState:(web::WebState*)webState; |
| 76 |
| 77 // Shows the dialog associated with the next context in |contextQueue|. |
| 78 - (void)showNextDialog; |
| 79 |
| 80 // Called when a button in |coordinator| is tapped. |
| 81 - (void)buttonWasTappedForCoordinator:(AlertCoordinator*)coordinator; |
| 82 |
| 83 // Adds buttons to |alertCoordinator|. A confirmation button with |label| as |
| 84 // the text will be added for |confirmAction|, and a cancel button will be added |
| 85 // for |cancelAction|. |
| 86 - (void)setUpAlertCoordinator:(AlertCoordinator*)alertCoordinator |
| 87 confirmAction:(ProceduralBlock)confirmAction |
| 88 cancelAction:(ProceduralBlock)cancelAction |
| 89 OKLabel:(NSString*)label; |
| 90 |
| 91 // Sets up the JavaScript dialog blocking option for |alertCoordinator|. |
| 92 // Overrides |alertCoordinator|'s |startAction| to call |
| 93 // JavaScriptDialogWasShown(). Depending on the value of |
| 94 // ShouldShowDialogBlockingOption() for |webState|, optionally adds a button to |
| 95 // |alertCoordinator| allowing for the blocking of future dialogs. In addition |
| 96 // to blocking dialogs for the WebState, the added button will call |
| 97 // |alertCoordinator|'s |cancelAction|. |
| 98 - (void)setUpBlockingOptionForCoordinator:(AlertCoordinator*)alertCoordinator |
| 99 webState:(web::WebState*)webState; |
| 100 |
| 101 // The block to use for the JavaScript dialog blocking option for |coordinator|. |
| 102 - (ProceduralBlock)blockingActionForCoordinator:(AlertCoordinator*)coordinator; |
| 103 |
| 104 @end |
| 105 |
| 106 @implementation DialogPresenter |
| 107 |
| 108 @synthesize active = _active; |
| 109 |
| 110 - (instancetype)initWithDelegate:(id<DialogPresenterDelegate>)delegate |
| 111 presentingViewController:(UIViewController*)viewController { |
| 112 if ((self = [super init])) { |
| 113 DCHECK(delegate); |
| 114 DCHECK(viewController); |
| 115 _delegate.reset(delegate); |
| 116 _viewController.reset(viewController); |
| 117 } |
| 118 return self; |
| 119 } |
| 120 |
| 121 #pragma mark - Accessors |
| 122 |
| 123 - (void)setActive:(BOOL)active { |
| 124 if (_active != active) { |
| 125 _active = active; |
| 126 [self tryToPresent]; |
| 127 } |
| 128 } |
| 129 |
| 130 - (id<DialogPresenterDelegate>)delegate { |
| 131 return _delegate; |
| 132 } |
| 133 |
| 134 - (UIViewController*)viewController { |
| 135 return _viewController; |
| 136 } |
| 137 |
| 138 - (BOOL)isShowingDialog { |
| 139 DCHECK_EQ(self.presentedDialogWebState != nullptr, |
| 140 self.presentedDialogCoordinator != nil); |
| 141 return self.presentedDialogCoordinator != nil; |
| 142 } |
| 143 |
| 144 - (web::WebState*)presentedDialogWebState { |
| 145 return _presentedDialogWebState; |
| 146 } |
| 147 |
| 148 - (void)setPresentedDialogWebState:(web::WebState*)presentedDialogWebState { |
| 149 _presentedDialogWebState = presentedDialogWebState; |
| 150 } |
| 151 |
| 152 - (AlertCoordinator*)presentedDialogCoordinator { |
| 153 return _presentedDialogCoordinator; |
| 154 } |
| 155 |
| 156 - (void)setPresentedDialogCoordinator: |
| 157 (AlertCoordinator*)presentedDialogCoordinator { |
| 158 _presentedDialogCoordinator.reset([presentedDialogCoordinator retain]); |
| 159 } |
| 160 |
| 161 - (ActionSheetCoordinator*)blockingConfirmationCoordinator { |
| 162 return _blockingConfirmationCoordinator; |
| 163 } |
| 164 |
| 165 - (void)setBlockingConfirmationCoordinator: |
| 166 (ActionSheetCoordinator*)blockingConfirmationActionSheetCoordinator { |
| 167 _blockingConfirmationCoordinator.reset( |
| 168 [blockingConfirmationActionSheetCoordinator retain]); |
| 169 } |
| 170 |
| 171 #pragma mark - Public |
| 172 |
| 173 - (void)runJavaScriptAlertPanelWithMessage:(NSString*)message |
| 174 requestURL:(const GURL&)requestURL |
| 175 webState:(web::WebState*)webState |
| 176 completionHandler:(void (^)(void))completionHandler { |
| 177 NSString* title = |
| 178 [DialogPresenter localizedTitleForJavaScriptAlertFromPage:requestURL]; |
| 179 AlertCoordinator* alertCoordinator = [[[AlertCoordinator alloc] |
| 180 initWithBaseViewController:self.viewController |
| 181 title:title |
| 182 message:message] autorelease]; |
| 183 |
| 184 // Handler. |
| 185 base::WeakNSObject<DialogPresenter> weakSelf(self); |
| 186 base::WeakNSObject<AlertCoordinator> weakCoordinator(alertCoordinator); |
| 187 ProceduralBlock OKHandler = ^{ |
| 188 if (completionHandler) |
| 189 completionHandler(); |
| 190 [weakSelf buttonWasTappedForCoordinator:weakCoordinator]; |
| 191 }; |
| 192 |
| 193 // Add button. |
| 194 [alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_OK) |
| 195 action:OKHandler |
| 196 style:UIAlertActionStyleDefault]; |
| 197 |
| 198 // Add cancel handler. |
| 199 alertCoordinator.cancelAction = completionHandler; |
| 200 alertCoordinator.noInteractionAction = completionHandler; |
| 201 |
| 202 // Blocking option setup. |
| 203 [self setUpBlockingOptionForCoordinator:alertCoordinator webState:webState]; |
| 204 |
| 205 [self addDialogCoordinator:alertCoordinator forWebState:webState]; |
| 206 } |
| 207 |
| 208 - (void)runJavaScriptConfirmPanelWithMessage:(NSString*)message |
| 209 requestURL:(const GURL&)requestURL |
| 210 webState:(web::WebState*)webState |
| 211 completionHandler: |
| 212 (void (^)(BOOL isConfirmed))completionHandler { |
| 213 NSString* title = |
| 214 [DialogPresenter localizedTitleForJavaScriptAlertFromPage:requestURL]; |
| 215 AlertCoordinator* alertCoordinator = [[[AlertCoordinator alloc] |
| 216 initWithBaseViewController:self.viewController |
| 217 title:title |
| 218 message:message] autorelease]; |
| 219 |
| 220 // Actions. |
| 221 ProceduralBlock confirmAction = ^{ |
| 222 if (completionHandler) |
| 223 completionHandler(YES); |
| 224 }; |
| 225 |
| 226 ProceduralBlock cancelAction = ^{ |
| 227 if (completionHandler) |
| 228 completionHandler(NO); |
| 229 }; |
| 230 |
| 231 // Coordinator Setup. |
| 232 NSString* OKLabel = l10n_util::GetNSString(IDS_OK); |
| 233 [self setUpAlertCoordinator:alertCoordinator |
| 234 confirmAction:confirmAction |
| 235 cancelAction:cancelAction |
| 236 OKLabel:OKLabel]; |
| 237 |
| 238 // Blocking option setup. |
| 239 [self setUpBlockingOptionForCoordinator:alertCoordinator webState:webState]; |
| 240 |
| 241 [self addDialogCoordinator:alertCoordinator forWebState:webState]; |
| 242 } |
| 243 |
| 244 - (void)runJavaScriptTextInputPanelWithPrompt:(NSString*)message |
| 245 defaultText:(NSString*)defaultText |
| 246 requestURL:(const GURL&)requestURL |
| 247 webState:(web::WebState*)webState |
| 248 completionHandler: |
| 249 (void (^)(NSString* input))completionHandler { |
| 250 NSString* title = |
| 251 [DialogPresenter localizedTitleForJavaScriptAlertFromPage:requestURL]; |
| 252 InputAlertCoordinator* alertCoordinator = [[[InputAlertCoordinator alloc] |
| 253 initWithBaseViewController:self.viewController |
| 254 title:title |
| 255 message:message] autorelease]; |
| 256 |
| 257 // Actions. |
| 258 base::WeakNSObject<InputAlertCoordinator> weakCoordinator(alertCoordinator); |
| 259 ProceduralBlock confirmAction = ^{ |
| 260 if (completionHandler) { |
| 261 NSString* textInput = [weakCoordinator textFields].firstObject.text; |
| 262 completionHandler(textInput ? textInput : @""); |
| 263 } |
| 264 }; |
| 265 |
| 266 ProceduralBlock cancelAction = ^{ |
| 267 if (completionHandler) |
| 268 completionHandler(nil); |
| 269 }; |
| 270 |
| 271 // Coordinator Setup. |
| 272 NSString* OKLabel = l10n_util::GetNSString(IDS_OK); |
| 273 [self setUpAlertCoordinator:alertCoordinator |
| 274 confirmAction:confirmAction |
| 275 cancelAction:cancelAction |
| 276 OKLabel:OKLabel]; |
| 277 |
| 278 // Blocking option setup. |
| 279 [self setUpBlockingOptionForCoordinator:alertCoordinator webState:webState]; |
| 280 |
| 281 // Add text field. |
| 282 [alertCoordinator |
| 283 addTextFieldWithConfigurationHandler:^(UITextField* textField) { |
| 284 textField.text = defaultText; |
| 285 textField.accessibilityIdentifier = |
| 286 kJavaScriptDialogTextFieldAccessibiltyIdentifier; |
| 287 }]; |
| 288 |
| 289 [self addDialogCoordinator:alertCoordinator forWebState:webState]; |
| 290 } |
| 291 |
| 292 - (void)runAuthDialogForProtectionSpace:(NSURLProtectionSpace*)protectionSpace |
| 293 proposedCredential:(NSURLCredential*)credential |
| 294 webState:(web::WebState*)webState |
| 295 completionHandler:(void (^)(NSString* user, |
| 296 NSString* password))handler { |
| 297 NSString* title = l10n_util::GetNSStringWithFixup(IDS_LOGIN_DIALOG_TITLE); |
| 298 NSString* message = |
| 299 ios_internal::nsurlprotectionspace_util::MessageForHTTPAuth( |
| 300 protectionSpace); |
| 301 |
| 302 InputAlertCoordinator* alertCoordinator = [[[InputAlertCoordinator alloc] |
| 303 initWithBaseViewController:self.viewController |
| 304 title:title |
| 305 message:message] autorelease]; |
| 306 |
| 307 // Actions. |
| 308 base::WeakNSObject<InputAlertCoordinator> weakCoordinator(alertCoordinator); |
| 309 ProceduralBlock confirmAction = ^{ |
| 310 if (handler) { |
| 311 NSString* username = [[weakCoordinator textFields] objectAtIndex:0].text; |
| 312 NSString* password = [[weakCoordinator textFields] objectAtIndex:1].text; |
| 313 handler(username, password); |
| 314 } |
| 315 }; |
| 316 |
| 317 ProceduralBlock cancelAction = ^{ |
| 318 if (handler) |
| 319 handler(nil, nil); |
| 320 }; |
| 321 |
| 322 // Coordinator Setup. |
| 323 NSString* OKLabel = |
| 324 l10n_util::GetNSStringWithFixup(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL); |
| 325 [self setUpAlertCoordinator:alertCoordinator |
| 326 confirmAction:confirmAction |
| 327 cancelAction:cancelAction |
| 328 OKLabel:OKLabel]; |
| 329 |
| 330 // Add text fields. |
| 331 NSString* username = credential.user ? credential.user : @""; |
| 332 [alertCoordinator |
| 333 addTextFieldWithConfigurationHandler:^(UITextField* textField) { |
| 334 textField.text = username; |
| 335 textField.placeholder = l10n_util::GetNSString( |
| 336 IDS_IOS_HTTP_LOGIN_DIALOG_USERNAME_PLACEHOLDER); |
| 337 }]; |
| 338 [alertCoordinator |
| 339 addTextFieldWithConfigurationHandler:^(UITextField* textField) { |
| 340 textField.placeholder = l10n_util::GetNSString( |
| 341 IDS_IOS_HTTP_LOGIN_DIALOG_PASSWORD_PLACEHOLDER); |
| 342 textField.secureTextEntry = YES; |
| 343 }]; |
| 344 |
| 345 [self addDialogCoordinator:alertCoordinator forWebState:webState]; |
| 346 } |
| 347 |
| 348 - (void)cancelDialogForWebState:(web::WebState*)webState { |
| 349 DCHECK_NE(webState, self.presentedDialogWebState); |
| 350 AlertCoordinator* dialogToCancel = _dialogCoordinatorsForWebStates[webState]; |
| 351 if (dialogToCancel) { |
| 352 auto it = |
| 353 std::find(_queuedWebStates.begin(), _queuedWebStates.end(), webState); |
| 354 DCHECK(it != _queuedWebStates.end()); |
| 355 _queuedWebStates.erase(it); |
| 356 [dialogToCancel executeCancelHandler]; |
| 357 [dialogToCancel stop]; |
| 358 _dialogCoordinatorsForWebStates.erase(webState); |
| 359 } |
| 360 } |
| 361 |
| 362 - (void)cancelAllDialogs { |
| 363 [self.presentedDialogCoordinator executeCancelHandler]; |
| 364 [self.presentedDialogCoordinator stop]; |
| 365 self.presentedDialogCoordinator = nil; |
| 366 self.presentedDialogWebState = nil; |
| 367 while (!_queuedWebStates.empty()) { |
| 368 [self cancelDialogForWebState:_queuedWebStates.front()]; |
| 369 } |
| 370 } |
| 371 |
| 372 - (void)tryToPresent { |
| 373 // Don't try to present if a JavaScript dialog blocking confirmation sheet is |
| 374 // displayed. |
| 375 if (self.blockingConfirmationCoordinator) |
| 376 return; |
| 377 // The active TabModel can't be changed while a JavaScript dialog is shown. |
| 378 DCHECK(!self.showingDialog); |
| 379 if (_active && !_queuedWebStates.empty() && !self.delegate.presenting) |
| 380 [self showNextDialog]; |
| 381 } |
| 382 |
| 383 + (NSString*)localizedTitleForJavaScriptAlertFromPage:(const GURL&)pageURL { |
| 384 NSString* hostname = base::SysUTF8ToNSString(pageURL.host()); |
| 385 if (!hostname.length) |
| 386 hostname = base::SysUTF8ToNSString(kAboutNullHostname); |
| 387 return l10n_util::GetNSStringF(IDS_JAVASCRIPT_MESSAGEBOX_TITLE, |
| 388 base::SysNSStringToUTF16(hostname)); |
| 389 } |
| 390 |
| 391 #pragma mark - Private methods. |
| 392 |
| 393 - (void)addDialogCoordinator:(AlertCoordinator*)coordinator |
| 394 forWebState:(web::WebState*)webState { |
| 395 DCHECK(coordinator); |
| 396 DCHECK(webState); |
| 397 DCHECK_NE(webState, self.presentedDialogWebState); |
| 398 DCHECK(!_dialogCoordinatorsForWebStates[webState]); |
| 399 _queuedWebStates.push_back(webState); |
| 400 _dialogCoordinatorsForWebStates[webState] = |
| 401 base::scoped_nsobject<AlertCoordinator>([coordinator retain]); |
| 402 |
| 403 if (self.active && !self.showingDialog && !self.delegate.presenting) |
| 404 [self showNextDialog]; |
| 405 } |
| 406 |
| 407 - (void)showNextDialog { |
| 408 DCHECK(self.active); |
| 409 DCHECK(!self.showingDialog); |
| 410 DCHECK(!_queuedWebStates.empty()); |
| 411 // Update properties and remove context and the dialog from queue. |
| 412 self.presentedDialogWebState = _queuedWebStates.front(); |
| 413 _queuedWebStates.pop_front(); |
| 414 self.presentedDialogCoordinator = |
| 415 _dialogCoordinatorsForWebStates[self.presentedDialogWebState]; |
| 416 _dialogCoordinatorsForWebStates.erase(self.presentedDialogWebState); |
| 417 // Notify the delegate and display the dialog. |
| 418 [self.delegate dialogPresenter:self |
| 419 willShowDialogForWebState:self.presentedDialogWebState]; |
| 420 [self.presentedDialogCoordinator start]; |
| 421 } |
| 422 |
| 423 - (void)buttonWasTappedForCoordinator:(AlertCoordinator*)coordinator { |
| 424 if (coordinator != self.presentedDialogCoordinator) |
| 425 return; |
| 426 self.presentedDialogWebState = nil; |
| 427 self.presentedDialogCoordinator = nil; |
| 428 self.blockingConfirmationCoordinator = nil; |
| 429 if (!_queuedWebStates.empty() && !self.delegate.presenting) |
| 430 [self showNextDialog]; |
| 431 } |
| 432 |
| 433 - (void)setUpAlertCoordinator:(AlertCoordinator*)alertCoordinator |
| 434 confirmAction:(ProceduralBlock)confirmAction |
| 435 cancelAction:(ProceduralBlock)cancelAction |
| 436 OKLabel:(NSString*)label { |
| 437 // Handlers. |
| 438 base::WeakNSObject<DialogPresenter> weakSelf(self); |
| 439 base::WeakNSObject<AlertCoordinator> weakCoordinator(alertCoordinator); |
| 440 |
| 441 ProceduralBlock confirmHandler = ^{ |
| 442 if (confirmAction) |
| 443 confirmAction(); |
| 444 [weakSelf buttonWasTappedForCoordinator:weakCoordinator]; |
| 445 }; |
| 446 |
| 447 ProceduralBlock cancelHandler = ^{ |
| 448 if (cancelAction) |
| 449 cancelAction(); |
| 450 [weakSelf buttonWasTappedForCoordinator:weakCoordinator]; |
| 451 }; |
| 452 |
| 453 // Add buttons. |
| 454 [alertCoordinator addItemWithTitle:label |
| 455 action:confirmHandler |
| 456 style:UIAlertActionStyleDefault]; |
| 457 [alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL) |
| 458 action:cancelHandler |
| 459 style:UIAlertActionStyleCancel]; |
| 460 |
| 461 // Add cancel handler. |
| 462 alertCoordinator.cancelAction = cancelAction; |
| 463 alertCoordinator.noInteractionAction = cancelAction; |
| 464 } |
| 465 |
| 466 - (void)setUpBlockingOptionForCoordinator:(AlertCoordinator*)alertCoordinator |
| 467 webState:(web::WebState*)webState { |
| 468 DCHECK(alertCoordinator); |
| 469 DCHECK(webState); |
| 470 |
| 471 // Set up the start action. |
| 472 base::WeakNSObject<DialogPresenter> weakSelf(self); |
| 473 base::WeakNSObject<AlertCoordinator> weakCoordinator(alertCoordinator); |
| 474 ProceduralBlock originalStartAction = alertCoordinator.startAction; |
| 475 alertCoordinator.startAction = ^{ |
| 476 if (originalStartAction) |
| 477 originalStartAction(); |
| 478 JavaScriptDialogWasShown(webState); |
| 479 }; |
| 480 |
| 481 // Early return if a blocking option should not be added. |
| 482 if (!ShouldShowDialogBlockingOption(webState)) |
| 483 return; |
| 484 |
| 485 ProceduralBlock blockingAction = |
| 486 [self blockingActionForCoordinator:alertCoordinator]; |
| 487 NSString* blockingOptionTitle = |
| 488 l10n_util::GetNSString(IDS_IOS_JAVA_SCRIPT_DIALOG_BLOCKING_BUTTON_TEXT); |
| 489 [alertCoordinator addItemWithTitle:blockingOptionTitle |
| 490 action:blockingAction |
| 491 style:UIAlertActionStyleDefault]; |
| 492 } |
| 493 |
| 494 - (ProceduralBlock)blockingActionForCoordinator:(AlertCoordinator*)coordinator { |
| 495 base::WeakNSObject<DialogPresenter> weakSelf(self); |
| 496 base::WeakNSObject<AlertCoordinator> weakCoordinator(coordinator); |
| 497 base::WeakNSObject<UIViewController> weakBaseViewController( |
| 498 coordinator.baseViewController); |
| 499 ProceduralBlock cancelAction = coordinator.cancelAction; |
| 500 return [[^{ |
| 501 // Create the confirmation coordinator. Use an action sheet on iPhone and |
| 502 // an alert on iPhone. |
| 503 NSString* confirmMessage = |
| 504 l10n_util::GetNSString(IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION); |
| 505 AlertCoordinator* confirmationCoordinator = |
| 506 IsIPadIdiom() |
| 507 ? [[[AlertCoordinator alloc] |
| 508 initWithBaseViewController:weakBaseViewController |
| 509 title:nil |
| 510 message:confirmMessage] autorelease] |
| 511 : [[[ActionSheetCoordinator alloc] |
| 512 initWithBaseViewController:weakBaseViewController |
| 513 title:nil |
| 514 message:confirmMessage |
| 515 rect:CGRectZero |
| 516 view:nil] autorelease]; |
| 517 // Set up button actions. |
| 518 ProceduralBlock confirmHandler = ^{ |
| 519 if (cancelAction) |
| 520 cancelAction(); |
| 521 base::scoped_nsobject<DialogPresenter> strongSelf([weakSelf retain]); |
| 522 if (!strongSelf) |
| 523 return; |
| 524 DialogBlockingOptionSelected([strongSelf presentedDialogWebState]); |
| 525 [strongSelf buttonWasTappedForCoordinator:weakCoordinator]; |
| 526 }; |
| 527 ProceduralBlock cancelHandler = ^{ |
| 528 if (cancelAction) |
| 529 cancelAction(); |
| 530 [weakSelf buttonWasTappedForCoordinator:weakCoordinator]; |
| 531 }; |
| 532 NSString* blockingOptionTitle = |
| 533 l10n_util::GetNSString(IDS_IOS_JAVA_SCRIPT_DIALOG_BLOCKING_BUTTON_TEXT); |
| 534 [confirmationCoordinator addItemWithTitle:blockingOptionTitle |
| 535 action:confirmHandler |
| 536 style:UIAlertActionStyleDestructive]; |
| 537 [confirmationCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL) |
| 538 action:cancelHandler |
| 539 style:UIAlertActionStyleCancel]; |
| 540 [weakSelf setBlockingConfirmationCoordinator:confirmationCoordinator]; |
| 541 [[weakSelf blockingConfirmationCoordinator] start]; |
| 542 } copy] autorelease]; |
| 543 } |
| 544 |
| 545 @end |
OLD | NEW |