blob: f29d4cb72e4c8df6d6337ead38f49bd8646bd6a4 [file] [log] [blame]
// Copyright 2014 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 "ios/web_view/shell/shell_view_controller.h"
#import <MobileCoreServices/MobileCoreServices.h>
#import "ios/web_view/public/cwv.h"
#import "ios/web_view/public/cwv_html_element.h"
#import "ios/web_view/public/cwv_web_view.h"
#import "ios/web_view/shell/translate_controller.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Externed accessibility identifier.
NSString* const kWebViewShellBackButtonAccessibilityLabel = @"Back";
NSString* const kWebViewShellForwardButtonAccessibilityLabel = @"Forward";
NSString* const kWebViewShellAddressFieldAccessibilityLabel = @"Address field";
NSString* const kWebViewShellJavaScriptDialogTextFieldAccessibiltyIdentifier =
@"WebViewShellJavaScriptDialogTextFieldAccessibiltyIdentifier";
@interface ShellViewController ()<CWVNavigationDelegate,
CWVUIDelegate,
UITextFieldDelegate>
// Container for |webView|.
@property(nonatomic, strong) UIView* containerView;
// Text field used for navigating to URLs.
@property(nonatomic, strong) UITextField* field;
// Toolbar containing navigation buttons and |field|.
@property(nonatomic, strong) UIToolbar* toolbar;
// CWV view which renders the web page.
@property(nonatomic, strong) CWVWebView* webView;
// Handles the translation of the content displayed in |webView|.
@property(nonatomic, strong) TranslateController* translateController;
- (void)back;
- (void)forward;
- (void)stopLoading;
@end
@implementation ShellViewController
@synthesize containerView = _containerView;
@synthesize field = _field;
@synthesize toolbar = _toolbar;
@synthesize webView = _webView;
@synthesize translateController = _translateController;
- (void)viewDidLoad {
[super viewDidLoad];
CGRect bounds = self.view.bounds;
// Set up the toolbar.
self.toolbar = [[UIToolbar alloc] init];
[_toolbar setBarTintColor:[UIColor colorWithRed:0.337
green:0.467
blue:0.988
alpha:1.0]];
[_toolbar setFrame:CGRectMake(0, 20, CGRectGetWidth(bounds), 44)];
[_toolbar setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleBottomMargin];
[self.view addSubview:_toolbar];
// Set up the container view.
self.containerView = [[UIView alloc] init];
[_containerView setFrame:CGRectMake(0, 64, CGRectGetWidth(bounds),
CGRectGetHeight(bounds) - 64)];
[_containerView setBackgroundColor:[UIColor lightGrayColor]];
[_containerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight];
[self.view addSubview:_containerView];
const int kButtonCount = 3;
const CGFloat kButtonSize = 44;
// Text field.
self.field = [[UITextField alloc]
initWithFrame:CGRectMake(kButtonCount * kButtonSize, 6,
CGRectGetWidth([_toolbar frame]) -
kButtonCount * kButtonSize - 10,
31)];
[_field setDelegate:self];
[_field setBackground:[[UIImage imageNamed:@"textfield_background"]
resizableImageWithCapInsets:UIEdgeInsetsMake(
12, 12, 12, 12)]];
[_field setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[_field setKeyboardType:UIKeyboardTypeWebSearch];
[_field setAutocorrectionType:UITextAutocorrectionTypeNo];
[_field setClearButtonMode:UITextFieldViewModeWhileEditing];
[_field setAccessibilityLabel:kWebViewShellAddressFieldAccessibilityLabel];
// Set up the toolbar buttons.
// Back.
UIButton* back = [UIButton buttonWithType:UIButtonTypeCustom];
[back setImage:[UIImage imageNamed:@"toolbar_back"]
forState:UIControlStateNormal];
[back setFrame:CGRectMake(0, 0, kButtonSize, kButtonSize)];
UIEdgeInsets insets = UIEdgeInsetsMake(5, 5, 4, 4);
[back setImageEdgeInsets:insets];
[back setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
[back addTarget:self
action:@selector(back)
forControlEvents:UIControlEventTouchUpInside];
[back setAccessibilityLabel:kWebViewShellBackButtonAccessibilityLabel];
// Forward.
UIButton* forward = [UIButton buttonWithType:UIButtonTypeCustom];
[forward setImage:[UIImage imageNamed:@"toolbar_forward"]
forState:UIControlStateNormal];
[forward setFrame:CGRectMake(kButtonSize, 0, kButtonSize, kButtonSize)];
[forward setImageEdgeInsets:insets];
[forward setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
[forward addTarget:self
action:@selector(forward)
forControlEvents:UIControlEventTouchUpInside];
[forward setAccessibilityLabel:kWebViewShellForwardButtonAccessibilityLabel];
// Stop.
UIButton* stop = [UIButton buttonWithType:UIButtonTypeCustom];
[stop setImage:[UIImage imageNamed:@"toolbar_stop"]
forState:UIControlStateNormal];
[stop setFrame:CGRectMake(2 * kButtonSize, 0, kButtonSize, kButtonSize)];
[stop setImageEdgeInsets:insets];
[stop setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
[stop addTarget:self
action:@selector(stopLoading)
forControlEvents:UIControlEventTouchUpInside];
[_toolbar addSubview:back];
[_toolbar addSubview:forward];
[_toolbar addSubview:stop];
[_toolbar addSubview:_field];
self.webView = [CWV webViewWithFrame:[_containerView bounds]];
_webView.navigationDelegate = self;
_translateController = [[TranslateController alloc] init];
_webView.translationDelegate = _translateController;
[_webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight];
[_containerView addSubview:_webView];
NSURLRequest* request = [NSURLRequest
requestWithURL:[NSURL URLWithString:@"https://www.google.com/"]];
[_webView loadRequest:request];
}
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar {
if (bar == _toolbar) {
return UIBarPositionTopAttached;
}
return UIBarPositionAny;
}
- (void)back {
if ([_webView canGoBack]) {
[_webView goBack];
}
}
- (void)forward {
if ([_webView canGoForward]) {
[_webView goForward];
}
}
- (void)stopLoading {
[_webView stopLoading];
}
- (BOOL)textFieldShouldReturn:(UITextField*)field {
NSURLRequest* request =
[NSURLRequest requestWithURL:[NSURL URLWithString:[field text]]];
[_webView loadRequest:request];
[field resignFirstResponder];
[self updateToolbar];
return YES;
}
- (void)updateToolbar {
// Do not update the URL if the text field is currently being edited.
if ([_field isFirstResponder]) {
return;
}
[_field setText:[[_webView visibleURL] absoluteString]];
}
#pragma mark CWVUIDelegate methods
- (void)webView:(CWVWebView*)webView
runContextMenuWithTitle:(NSString*)menuTitle
forHTMLElement:(CWVHTMLElement*)element
inView:(UIView*)view
userGestureLocation:(CGPoint)location {
if (!element.hyperlink) {
return;
}
UIAlertController* alert = [UIAlertController
alertControllerWithTitle:menuTitle
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alert.popoverPresentationController.sourceView = view;
alert.popoverPresentationController.sourceRect =
CGRectMake(location.x, location.y, 1.0, 1.0);
void (^copyHandler)(UIAlertAction*) = ^(UIAlertAction* action) {
NSDictionary* item = @{
(NSString*)(kUTTypeURL) : element.hyperlink,
(NSString*)(kUTTypeUTF8PlainText) : [[element.hyperlink absoluteString]
dataUsingEncoding:NSUTF8StringEncoding],
};
[[UIPasteboard generalPasteboard] setItems:@[ item ]];
};
[alert addAction:[UIAlertAction actionWithTitle:@"Copy Link"
style:UIAlertActionStyleDefault
handler:copyHandler]];
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)webView:(CWVWebView*)webView
runJavaScriptAlertPanelWithMessage:(NSString*)message
pageURL:(NSURL*)URL
completionHandler:(void (^)(void))handler {
UIAlertController* alert =
[UIAlertController alertControllerWithTitle:nil
message:message
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"Ok"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* action) {
handler();
}]];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)webView:(CWVWebView*)webView
runJavaScriptConfirmPanelWithMessage:(NSString*)message
pageURL:(NSURL*)URL
completionHandler:(void (^)(BOOL))handler {
UIAlertController* alert =
[UIAlertController alertControllerWithTitle:nil
message:message
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"Ok"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* action) {
handler(YES);
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction* action) {
handler(NO);
}]];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)webView:(CWVWebView*)webView
runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt
defaultText:(NSString*)defaultText
pageURL:(NSURL*)URL
completionHandler:(void (^)(NSString*))handler {
UIAlertController* alert =
[UIAlertController alertControllerWithTitle:nil
message:prompt
preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField* textField) {
textField.text = defaultText;
textField.accessibilityIdentifier =
kWebViewShellJavaScriptDialogTextFieldAccessibiltyIdentifier;
}];
__weak UIAlertController* weakAlert = alert;
[alert addAction:[UIAlertAction
actionWithTitle:@"Ok"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* action) {
NSString* textInput =
weakAlert.textFields.firstObject.text;
handler(textInput);
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction* action) {
handler(nil);
}]];
[self presentViewController:alert animated:YES completion:nil];
}
#pragma mark CWVNavigationDelegate methods
- (BOOL)webView:(CWVWebView*)webView
shouldStartLoadWithRequest:(NSURLRequest*)request {
NSLog(@"shouldStartLoadWithRequest");
return YES;
}
- (BOOL)webView:(CWVWebView*)webView
shouldContinueLoadWithResponse:(NSURLResponse*)response {
NSLog(@"shouldContinueLoadWithResponse");
return YES;
}
- (void)webViewDidStartProvisionalNavigation:(CWVWebView*)webView {
NSLog(@"webViewDidStartProvisionalNavigation");
[self updateToolbar];
}
- (void)webViewDidCommitNavigation:(CWVWebView*)webView {
NSLog(@"webViewDidCommitNavigation");
[self updateToolbar];
}
- (void)webView:(CWVWebView*)webView didLoadPageWithSuccess:(BOOL)success {
NSLog(@"webView:didLoadPageWithSuccess");
// TODO(crbug.com/679895): Add some visual indication that the page load has
// finished.
[self updateToolbar];
}
- (void)webViewWebContentProcessDidTerminate:(CWVWebView*)webView {
NSLog(@"webViewWebContentProcessDidTerminate");
}
@end