FLEXWebViewController.m 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. //
  2. // FLEXWebViewController.m
  3. // Flipboard
  4. //
  5. // Created by Ryan Olson on 6/10/14.
  6. // Copyright (c) 2014 Flipboard. All rights reserved.
  7. //
  8. #import "FLEXWebViewController.h"
  9. #import "FLEXUtility.h"
  10. #import <WebKit/WebKit.h>
  11. @interface FLEXWebViewController () <WKNavigationDelegate>
  12. @property (nonatomic) WKWebView *webView;
  13. @property (nonatomic) NSString *originalText;
  14. @end
  15. @implementation FLEXWebViewController
  16. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
  17. {
  18. self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  19. if (self) {
  20. WKWebViewConfiguration *configuration = [WKWebViewConfiguration new];
  21. configuration.dataDetectorTypes = UIDataDetectorTypeLink;
  22. self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
  23. self.webView.navigationDelegate = self;
  24. }
  25. return self;
  26. }
  27. - (id)initWithText:(NSString *)text
  28. {
  29. self = [self initWithNibName:nil bundle:nil];
  30. if (self) {
  31. self.originalText = text;
  32. NSString *htmlString = [NSString stringWithFormat:@"<head><meta name='viewport' content='initial-scale=1.0'></head><body><pre>%@</pre></body>", [FLEXUtility stringByEscapingHTMLEntitiesInString:text]];
  33. [self.webView loadHTMLString:htmlString baseURL:nil];
  34. }
  35. return self;
  36. }
  37. - (id)initWithURL:(NSURL *)url
  38. {
  39. self = [self initWithNibName:nil bundle:nil];
  40. if (self) {
  41. NSURLRequest *request = [NSURLRequest requestWithURL:url];
  42. [self.webView loadRequest:request];
  43. }
  44. return self;
  45. }
  46. - (void)dealloc
  47. {
  48. // WKWebView's delegate is assigned so we need to clear it manually.
  49. if (_webView.navigationDelegate == self) {
  50. _webView.navigationDelegate = nil;
  51. }
  52. }
  53. - (void)viewDidLoad
  54. {
  55. [super viewDidLoad];
  56. [self.view addSubview:self.webView];
  57. self.webView.frame = self.view.bounds;
  58. self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  59. if (self.originalText.length > 0) {
  60. self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Copy" style:UIBarButtonItemStylePlain target:self action:@selector(copyButtonTapped:)];
  61. }
  62. }
  63. - (void)copyButtonTapped:(id)sender
  64. {
  65. [UIPasteboard.generalPasteboard setString:self.originalText];
  66. }
  67. #pragma mark - WKWebView Delegate
  68. - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
  69. {
  70. WKNavigationActionPolicy policy = WKNavigationActionPolicyCancel;
  71. if (navigationAction.navigationType == WKNavigationTypeOther) {
  72. // Allow the initial load
  73. policy = WKNavigationActionPolicyAllow;
  74. } else {
  75. // For clicked links, push another web view controller onto the navigation stack so that hitting the back button works as expected.
  76. // Don't allow the current web view to handle the navigation.
  77. NSURLRequest *request = navigationAction.request;
  78. FLEXWebViewController *webVC = [[[self class] alloc] initWithURL:[request URL]];
  79. webVC.title = [[request URL] absoluteString];
  80. [self.navigationController pushViewController:webVC animated:YES];
  81. }
  82. decisionHandler(policy);
  83. }
  84. #pragma mark - Class Helpers
  85. + (BOOL)supportsPathExtension:(NSString *)extension
  86. {
  87. BOOL supported = NO;
  88. NSSet<NSString *> *supportedExtensions = [self webViewSupportedPathExtensions];
  89. if ([supportedExtensions containsObject:[extension lowercaseString]]) {
  90. supported = YES;
  91. }
  92. return supported;
  93. }
  94. + (NSSet<NSString *> *)webViewSupportedPathExtensions
  95. {
  96. static NSSet<NSString *> *pathExtensions = nil;
  97. static dispatch_once_t onceToken;
  98. dispatch_once(&onceToken, ^{
  99. // Note that this is not exhaustive, but all these extensions should work well in the web view.
  100. // See https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html#//apple_ref/doc/uid/TP40006482-SW7
  101. pathExtensions = [NSSet<NSString *> setWithArray:@[@"jpg", @"jpeg", @"png", @"gif", @"pdf", @"svg", @"tiff", @"3gp", @"3gpp", @"3g2",
  102. @"3gp2", @"aiff", @"aif", @"aifc", @"cdda", @"amr", @"mp3", @"swa", @"mp4", @"mpeg",
  103. @"mpg", @"mp3", @"wav", @"bwf", @"m4a", @"m4b", @"m4p", @"mov", @"qt", @"mqv", @"m4v"]];
  104. });
  105. return pathExtensions;
  106. }
  107. @end