From 7a0f0794aa24f15474c1f04f13412e0a0da7e96f Mon Sep 17 00:00:00 2001 From: Tim Oliver <me@timoliver.com.au> Date: Wed, 6 Apr 2016 20:49:52 +0800 Subject: [PATCH] Added items class and gesture recognisers. --- TOWebViewController/TOWebHistoryitem.h | 45 ++++++++++ TOWebViewController/TOWebHistoryitem.m | 71 ++++++++++++++++ TOWebViewController/TOWebViewController.h | 8 ++ TOWebViewController/TOWebViewController.m | 85 +++++++++++++++++-- .../project.pbxproj | 14 +++ 5 files changed, 216 insertions(+), 7 deletions(-) create mode 100644 TOWebViewController/TOWebHistoryitem.h create mode 100644 TOWebViewController/TOWebHistoryitem.m diff --git a/TOWebViewController/TOWebHistoryitem.h b/TOWebViewController/TOWebHistoryitem.h new file mode 100644 index 0000000..1224f8d --- /dev/null +++ b/TOWebViewController/TOWebHistoryitem.h @@ -0,0 +1,45 @@ +// +// TOWebHistoryitem.h +// +// Copyright 2016 Timothy Oliver. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import <Foundation/Foundation.h> + +/** + `TOWebHistoryitem` represents a page in the history of pages navigated in this session +*/ +@interface TOWebHistoryitem : NSObject + +/** + The string from the <title> tag of this particular page + */ +@property (nonatomic,readonly) NSString *title; + +/** + The URL of this web page + */ +@property (nonatomic,readonly) NSURL *URL; + +/** + Class instantiation method + */ +- (instancetype)initWithTitle:(NSString *)title URL:(NSURL *)URL; + +@end diff --git a/TOWebViewController/TOWebHistoryitem.m b/TOWebViewController/TOWebHistoryitem.m new file mode 100644 index 0000000..1524fa9 --- /dev/null +++ b/TOWebViewController/TOWebHistoryitem.m @@ -0,0 +1,71 @@ +// +// TOWebHistoryitem.m +// +// Copyright 2016 Timothy Oliver. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#import "TOWebHistoryitem.h" + +@interface TOWebHistoryitem () + +@property (nonatomic,copy,readwrite) NSString *title; +@property (nonatomic,copy,readwrite) NSURL *URL; + +@end + +@implementation TOWebHistoryitem + +- (instancetype)initWithTitle:(NSString *)title URL:(NSURL *)URL +{ + if (self = [super init]) { + _title = title; + _URL = URL; + } + + return self; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[TOWebHistoryitem class]]) { + return NO; + } + + if ([self.title isEqualToString:[object title]] == NO) { + return NO; + } + + if ([self.URL isEqual:[object URL]] == NO) { + return NO; + } + + return YES; +} + +- (NSUInteger)hash +{ + return self.title.hash ^ self.URL.hash; +} + +@end diff --git a/TOWebViewController/TOWebViewController.h b/TOWebViewController/TOWebViewController.h index e6a9a43..e6a414a 100755 --- a/TOWebViewController/TOWebViewController.h +++ b/TOWebViewController/TOWebViewController.h @@ -156,6 +156,14 @@ */ @property (nonatomic,assign) BOOL hideWebViewBoundaries; +/** + When set to YES, this disables the popup menus that appear when the user + taps and holds on the back or forward buttons. + + Default value is NO. + */ +@property (nonatomic,assign) BOOL historyPopupsDisabled; + /** When the view controller is being presented as a modal popup, this block will be automatically performed right after the view controller is dismissed. diff --git a/TOWebViewController/TOWebViewController.m b/TOWebViewController/TOWebViewController.m index 45ba341..4c1c6f4 100755 --- a/TOWebViewController/TOWebViewController.m +++ b/TOWebViewController/TOWebViewController.m @@ -102,6 +102,14 @@ @interface TOWebViewController () <UIActionSheetDelegate, @property (nonatomic,strong) UIBarButtonItem *actionButton; /* Shows the UIActivityViewController */ @property (nonatomic,strong) UIBarButtonItem *doneButton; /* The 'Done' button for modal contorllers */ +/* Back and Forward Button Gesture Recognizers */ +@property (nonatomic,strong) UILongPressGestureRecognizer *backButtonLongPressGestureRecognizer; +@property (nonatomic,strong) UILongPressGestureRecognizer *forwardButtonLongPressGestureRecognizer; + +/* History tracking */ +@property (nonatomic,strong) NSMutableArray *backHistoryItems; +@property (nonatomic,strong) NSMutableArray *forwardHistoryItems; + /* Load Progress Manager */ @property (nonatomic,strong) NJKWebViewProgress *progressManager; @@ -116,6 +124,7 @@ @interface TOWebViewController () <UIActionSheetDelegate, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" @property (nonatomic,strong) UIPopoverController *sharingPopoverController; +@property (nonatomic,strong) UIPopoverController *historyPopoverController; #pragma GCC diagnostic pop /* See if we need to revert the toolbar to 'hidden' when we pop off a navigation controller. */ @@ -134,6 +143,7 @@ - (NSURL *)cleanURL:(NSURL *)url; /* Init and configure various sections of the controller */ - (void)setUpNavigationButtons; +- (void)setUpNavigationButtonGestureRecognizers; /* Review the current state of the web view and update the UI controls in the nav bar to match it */ - (void)refreshButtonsState; @@ -147,6 +157,9 @@ - (void)reloadStopButtonTapped:(id)sender; - (void)actionButtonTapped:(id)sender; - (void)doneButtonTapped:(id)sender; +/* Gesture Recognizer Callbacks */ +- (void)longPressGestureRecognized:(UILongPressGestureRecognizer *)gestureRecognizer; + /* Event handlers for items in the 'action' popup */ - (void)copyURLToClipboard; - (void)openInBrowser; @@ -274,8 +287,9 @@ - (void)loadView //only load the buttons if we need to - if (self.navigationButtonsHidden == NO) + if (self.navigationButtonsHidden == NO) { [self setUpNavigationButtons]; + } } - (void)setUpNavigationButtons @@ -315,6 +329,34 @@ - (void)setUpNavigationButtons } } +- (void)setUpNavigationButtonGestureRecognizers +{ + if (self.navigationButtonsHidden || self.historyPopupsDisabled) { + return; + } + + if (self.backButtonLongPressGestureRecognizer && self.forwardButtonLongPressGestureRecognizer) { + return; + } + + if (self.backButtonLongPressGestureRecognizer == nil) { + self.backButtonLongPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognized:)]; + } + UIView *backButtonView = [self.backButton valueForKey:@"view"]; + if (backButtonView.gestureRecognizers.count == 0) { + [backButtonView addGestureRecognizer:self.backButtonLongPressGestureRecognizer]; + } + + if (self.forwardButtonLongPressGestureRecognizer == nil) { + self.forwardButtonLongPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognized:)]; + } + + UIView *forwardButtonView = [self.forwardButton valueForKey:@"view"]; + if (forwardButtonView.gestureRecognizers.count == 0) { + [forwardButtonView addGestureRecognizer:self.forwardButtonLongPressGestureRecognizer]; + } +} + - (void)viewDidLoad { [super viewDidLoad]; @@ -348,6 +390,11 @@ - (void)viewDidLoad self.doneButton.tintColor = self.buttonTintColor; } + + if (self.historyPopupsDisabled == NO) { + self.backHistoryItems = [NSMutableArray array]; + self.forwardHistoryItems = [NSMutableArray array]; + } } #pragma mark - View Presentation/Dismissal - @@ -387,6 +434,8 @@ - (void)viewDidAppear:(BOOL)animated [self.urlRequest setURL:self.url]; [self.webView loadRequest:self.urlRequest]; } + + [self setUpNavigationButtonGestureRecognizers]; } - (void)viewWillDisappear:(BOOL)animated @@ -578,7 +627,6 @@ - (void)layoutButtonsForCurrentSizeClass } self.toolbarItems = items; - return; } @@ -779,6 +827,23 @@ - (void)setApplicationLeftBarButtonItems:(NSArray *)applicationLeftBarButtonItem [self refreshButtonsState]; } +- (void)setHistoryPopupsDisabled:(BOOL)disableHistoryPopups +{ + if (self.historyPopupsDisabled == disableHistoryPopups) { + return; + } + + _historyPopupsDisabled = disableHistoryPopups; + + if (_historyPopupsDisabled == YES) { + [self.backButtonLongPressGestureRecognizer.view removeGestureRecognizer:self.backButtonLongPressGestureRecognizer]; + [self.forwardButtonLongPressGestureRecognizer.view removeGestureRecognizer:self.forwardButtonLongPressGestureRecognizer]; + } + else { + [self setUpNavigationButtonGestureRecognizers]; + } +} + #pragma mark - #pragma mark WebView Delegate - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType @@ -823,11 +888,10 @@ -(void)webViewProgress:(NJKWebViewProgress *)webViewProgress updateProgress:(flo if (interactive || complete) { //see if we can set the proper page title yet - if (self.showPageTitles) { - NSString *title = [self.webView stringByEvaluatingJavaScriptFromString:@"document.title"]; - - if (title.length) - self.title = title; + NSString *title = [self.webView stringByEvaluatingJavaScriptFromString:@"document.title"]; + + if (title.length && self.showPageTitles) { + self.title = title; } //if we're matching the view BG to the web view, update the background colour now @@ -1176,6 +1240,13 @@ - (void)openTwitterDialog #pragma clang diagnostic pop } +- (void)longPressGestureRecognized:(UILongPressGestureRecognizer *)gestureRecognizer +{ + if (gestureRecognizer.state != UIGestureRecognizerStateBegan) { + return; + } +} + #pragma mark - #pragma mark UIWebView Attrbutes - (UIView *)webViewContentView diff --git a/TOWebViewControllerExample.xcodeproj/project.pbxproj b/TOWebViewControllerExample.xcodeproj/project.pbxproj index 32ae57d..b56c2ad 100644 --- a/TOWebViewControllerExample.xcodeproj/project.pbxproj +++ b/TOWebViewControllerExample.xcodeproj/project.pbxproj @@ -11,6 +11,11 @@ 227C55F91750F1F800FC3411 /* TOAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 225014F21737B87600DF6D7E /* TOAppDelegate.m */; }; 227C55FA1750F1F900FC3411 /* TOViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 225014F41737B87600DF6D7E /* TOViewController.m */; }; 227C55FB1750F20700FC3411 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 225014FE1737B8A200DF6D7E /* main.m */; }; + 227D20A91CB52411008F641B /* TOWebHistoryitem.h in Headers */ = {isa = PBXBuildFile; fileRef = 227D20A71CB52411008F641B /* TOWebHistoryitem.h */; }; + 227D20AA1CB52411008F641B /* TOWebHistoryitem.m in Sources */ = {isa = PBXBuildFile; fileRef = 227D20A81CB52411008F641B /* TOWebHistoryitem.m */; }; + 227D20AB1CB52411008F641B /* TOWebHistoryitem.m in Sources */ = {isa = PBXBuildFile; fileRef = 227D20A81CB52411008F641B /* TOWebHistoryitem.m */; }; + 227D20AC1CB52411008F641B /* TOWebHistoryitem.m in Sources */ = {isa = PBXBuildFile; fileRef = 227D20A81CB52411008F641B /* TOWebHistoryitem.m */; }; + 227D20AD1CB52411008F641B /* TOWebHistoryitem.m in Sources */ = {isa = PBXBuildFile; fileRef = 227D20A81CB52411008F641B /* TOWebHistoryitem.m */; }; 2282AEEC1B2E473900BD92FC /* TOWebViewControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2282AEEB1B2E473900BD92FC /* TOWebViewControllerTests.m */; }; 2282E1D41C266D5600D53AB1 /* TOActivityChrome.m in Sources */ = {isa = PBXBuildFile; fileRef = 22AC285618E9920B006DB0E9 /* TOActivityChrome.m */; }; 2282E1D51C266D5600D53AB1 /* TOViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 225014F41737B87600DF6D7E /* TOViewController.m */; }; @@ -93,6 +98,8 @@ 225014FF1737B8A200DF6D7E /* DefaultExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "DefaultExample-Info.plist"; path = "Example/DefaultExample-Info.plist"; sourceTree = SOURCE_ROOT; }; 225015001737B8A200DF6D7E /* TOWebViewControllerExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "TOWebViewControllerExample-Prefix.pch"; path = "Example/TOWebViewControllerExample-Prefix.pch"; sourceTree = SOURCE_ROOT; }; 227B3CEE1BAECF95009AC60E /* LaunchImages.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = LaunchImages.xcassets; path = Example/LaunchImages.xcassets; sourceTree = SOURCE_ROOT; }; + 227D20A71CB52411008F641B /* TOWebHistoryitem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOWebHistoryitem.h; sourceTree = "<group>"; }; + 227D20A81CB52411008F641B /* TOWebHistoryitem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOWebHistoryitem.m; sourceTree = "<group>"; }; 2282AEE71B2E473900BD92FC /* TOWebViewControllerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TOWebViewControllerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 2282AEEA1B2E473900BD92FC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 2282AEEB1B2E473900BD92FC /* TOWebViewControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TOWebViewControllerTests.m; sourceTree = "<group>"; }; @@ -382,6 +389,8 @@ 221CE5EC18EEFC84002D89F5 /* Localizations */, 22F922591753B15E0034FEF6 /* TOWebViewController.h */, 22F9225A1753B15E0034FEF6 /* TOWebViewController.m */, + 227D20A71CB52411008F641B /* TOWebHistoryitem.h */, + 227D20A81CB52411008F641B /* TOWebHistoryitem.m */, 22AC285218E98FE1006DB0E9 /* TOActivitySafari.h */, 22AC285318E98FE1006DB0E9 /* TOActivitySafari.m */, 22AC285518E9920B006DB0E9 /* TOActivityChrome.h */, @@ -453,6 +462,7 @@ buildActionMask = 2147483647; files = ( D2A653D71C7E872600566F54 /* NJKWebViewProgressView.h in Headers */, + 227D20A91CB52411008F641B /* TOWebHistoryitem.h in Headers */, D2A653DA1C7E873700566F54 /* TOActivitySafari.h in Headers */, D2A653E51C7EAAF900566F54 /* TOWebViewController.h in Headers */, D2A653DC1C7E873700566F54 /* TOActivityChrome.h in Headers */, @@ -634,6 +644,7 @@ buildActionMask = 2147483647; files = ( 2282AEEC1B2E473900BD92FC /* TOWebViewControllerTests.m in Sources */, + 227D20AC1CB52411008F641B /* TOWebHistoryitem.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -652,6 +663,7 @@ 2282E1D91C266D5600D53AB1 /* TOActivitySafari.m in Sources */, 2282E1DA1C266D5600D53AB1 /* main.m in Sources */, 2282E1DB1C266D5600D53AB1 /* TOWebViewController.m in Sources */, + 227D20AB1CB52411008F641B /* TOWebHistoryitem.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -664,6 +676,7 @@ 227C55FA1750F1F900FC3411 /* TOViewController.m in Sources */, 22CB13C518E8158000B948D8 /* UIImage+TOWebViewControllerIcons.m in Sources */, 227C55F91750F1F800FC3411 /* TOAppDelegate.m in Sources */, + 227D20AA1CB52411008F641B /* TOWebHistoryitem.m in Sources */, 22AC285418E98FE1006DB0E9 /* TOActivitySafari.m in Sources */, 227C55FB1750F20700FC3411 /* main.m in Sources */, 2282E2001C27138600D53AB1 /* NJKWebViewProgressView.m in Sources */, @@ -677,6 +690,7 @@ files = ( D2A653E11C7E873F00566F54 /* OnePasswordExtension.m in Sources */, D2A653E41C7E874500566F54 /* TOWebViewController+1Password.m in Sources */, + 227D20AD1CB52411008F641B /* TOWebHistoryitem.m in Sources */, D2A653D91C7E872E00566F54 /* TOWebViewController.m in Sources */, D2A653D51C7E871C00566F54 /* NJKWebViewProgress.m in Sources */, D2A653D81C7E872B00566F54 /* NJKWebViewProgressView.m in Sources */,