Skip to content

Commit

Permalink
* Convenience methods added to string for opening/loading URLs
Browse files Browse the repository at this point in the history
* Allow URL opener to specify a parent URL, overriding the pattern
  • Loading branch information
joehewitt committed Jul 8, 2009
1 parent 47d434c commit 11f1e74
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 52 deletions.
13 changes: 13 additions & 0 deletions src/NSStringAdditions.m
Expand Up @@ -119,4 +119,17 @@ - (void)openURL {
TTOpenURL(self);
}

- (id)objectValue {
return [[TTAppMap sharedMap] objectForURL:self];
}

- (NSString*)objectURL:(id)object {
if ([object conformsToProtocol:@protocol(TTURLObject)]) {
id<TTURLObject> URLObject = object;
return [URLObject formatURL:self];
} else {
return self;
}
}

@end
94 changes: 59 additions & 35 deletions src/TTAppMap.m
Expand Up @@ -101,18 +101,18 @@ - (TTURLPattern*)matchPattern:(NSURL*)URL {
return _defaultPattern;
}

- (id)objectForURL:(NSURL*)URL outPattern:(TTURLPattern**)outPattern {
TTURLPattern* pattern = [self matchPattern:URL];
if (pattern) {
if (_bindings) {
// XXXjoe Normalize the URL first
NSString* URLString = [URL absoluteString];
UIViewController* controller = [_bindings objectForKey:URLString];
if (controller) {
return controller;
}
- (id)objectForURL:(NSString*)URL theURL:(NSURL*)theURL params:(NSDictionary*)params
outPattern:(TTURLPattern**)outPattern {
if (_bindings) {
// XXXjoe Normalize the URL first
id object = [_bindings objectForKey:URL];
if (object) {
return object;
}
}

TTURLPattern* pattern = [self matchPattern:theURL];
if (pattern) {
id target = nil;
UIViewController* controller = nil;

Expand All @@ -123,13 +123,13 @@ - (id)objectForURL:(NSURL*)URL outPattern:(TTURLPattern**)outPattern {
}

if (pattern.selector) {
controller = [pattern invokeSelectorForTarget:target withURL:URL];
controller = [pattern invoke:target withURL:theURL params:params];
} else if (pattern.targetClass) {
controller = [target init];
}

if (pattern.displayMode == TTDisplayModeShare && controller) {
[self bindObject:controller toURL:[URL absoluteString]];
[self bindObject:controller toURL:URL];
}

[target autorelease];
Expand All @@ -144,10 +144,11 @@ - (id)objectForURL:(NSURL*)URL outPattern:(TTURLPattern**)outPattern {
}

- (UIViewController*)parentControllerForController:(UIViewController*)controller
withPattern:(TTURLPattern*)pattern {
parent:(NSURL*)parentURL {
UIViewController* parentController = nil;
if (pattern.parentURL) {
parentController = [self objectForURL:pattern.parentURL outPattern:nil];
if (parentURL) {
parentController = [self objectForURL:parentURL.absoluteString theURL:parentURL params:nil
outPattern:nil];
}

// If this is the first controller, and it is not a "container", forcibly put
Expand Down Expand Up @@ -192,36 +193,40 @@ - (void)presentController:(UIViewController*)controller
}

- (void)presentController:(UIViewController*)controller forURL:(NSURL*)URL
withPattern:(TTURLPattern*)pattern animated:(BOOL)animated {
parent:(NSString*)parentURL withPattern:(TTURLPattern*)pattern animated:(BOOL)animated {
NSURL* parent = parentURL ? [NSURL URLWithString:parentURL] : pattern.parentURL;
UIViewController* parentController = [self parentControllerForController:controller
withPattern:pattern];
parent:parent];
[self presentController:controller parent:parentController
modal:pattern.displayMode == TTDisplayModeModal animated:animated];
}

- (UIViewController*)openControllerWithURL:(NSString*)URL display:(BOOL)display
animated:(BOOL)animated {
if ([_delegate respondsToSelector:@selector(appMap:shouldOpenURL:)]) {
if ([_delegate appMap:self shouldOpenURL:URL]) {
- (UIViewController*)openControllerWithURL:(NSString*)URL parent:(NSString*)parentURL
params:(NSDictionary*)params display:(BOOL)display animated:(BOOL)animated {
NSURL* theURL = [NSURL URLWithString:URL];

if (display && [_delegate respondsToSelector:@selector(appMap:shouldOpenURL:)]) {
if (![_delegate appMap:self shouldOpenURL:theURL]) {
return nil;
}
}

NSURL* theURL = [NSURL URLWithString:URL];
TTURLPattern* pattern = nil;
UIViewController* controller = [self objectForURL:theURL outPattern:&pattern];
UIViewController* controller = [self objectForURL:URL theURL:theURL params:params
outPattern:&pattern];
if (controller) {
if ([_delegate respondsToSelector:@selector(appMap:wilOpenURL:inViewController:)]) {
[_delegate appMap:self willOpenURL:URL inViewController:controller];
if (display && [_delegate respondsToSelector:@selector(appMap:wilOpenURL:inViewController:)]) {
[_delegate appMap:self willOpenURL:theURL inViewController:controller];
}

controller.appMapURL = URL;
if (display) {
[self presentController:controller forURL:theURL withPattern:pattern animated:animated];
[self presentController:controller forURL:theURL parent:parentURL withPattern:pattern
animated:animated];
}
} else if (_openExternalURLs) {
} else if (display && _openExternalURLs) {
if ([_delegate respondsToSelector:@selector(appMap:wilOpenURL:inViewController:)]) {
[_delegate appMap:self willOpenURL:URL inViewController:nil];
[_delegate appMap:self willOpenURL:theURL inViewController:nil];
}

[[UIApplication sharedApplication] openURL:theURL];
Expand Down Expand Up @@ -255,7 +260,8 @@ - (BOOL)restoreControllersStartingWithURL:(NSString*)startURL {
return NO;
}

UIViewController* controller = [self openControllerWithURL:URL display:YES animated:NO];
UIViewController* controller = [self openControllerWithURL:URL parent:nil params:nil
display:YES animated:NO];
controller.frozenState = state;

if (_persistenceMode == TTAppMapPersistenceModeTop && pathIndex++ == 1) {
Expand Down Expand Up @@ -351,19 +357,37 @@ - (UIViewController*)visibleViewController {
}

- (UIViewController*)openURL:(NSString*)URL {
return [self openURL:URL animated:YES];
return [self openURL:URL parent:nil params:nil animated:YES];
}

- (UIViewController*)openURL:(NSString*)URL params:(NSDictionary*)params {
return [self openURL:URL parent:nil params:params animated:YES];
}

- (UIViewController*)openURL:(NSString*)URL animated:(BOOL)animated {
return [self openURL:URL parent:nil params:nil animated:animated];
}

- (UIViewController*)openURL:(NSString*)URL parent:(NSString*)parentURL animated:(BOOL)animated {
return [self openURL:URL parent:parentURL params:nil animated:animated];
}

- (UIViewController*)openURL:(NSString*)URL params:(NSDictionary*)params animated:(BOOL)animated {
return [self openURL:URL parent:nil params:nil animated:animated];
}

- (UIViewController*)openURL:(NSString*)URL parent:(NSString*)parentURL params:(NSDictionary*)params
animated:(BOOL)animated {
if (!_mainViewController && _persistenceMode && [self restoreControllersStartingWithURL:URL]) {
return _mainViewController;
} else {
return [self openControllerWithURL:URL display:YES animated:animated];
return [self openControllerWithURL:URL parent:parentURL params:params display:YES
animated:animated];
}
}

- (id)objectForURL:(NSString*)URL {
return [self openControllerWithURL:URL display:NO animated:NO];
return [self openControllerWithURL:URL parent:nil params:nil display:NO animated:NO];
}

- (TTDisplayMode)displayModeForURL:(NSString*)URL {
Expand Down Expand Up @@ -460,7 +484,7 @@ - (void)removeBindingForObject:(id)object {
// XXXjoe IMPLEMENT ME
}

- (void)removePersistedControllers {
- (void)resetDefaults {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObjectForKey:@"TTAppMapNavigation"];
[defaults synchronize];
Expand All @@ -484,6 +508,6 @@ - (void)persistController:(UIViewController*)controller path:(NSMutableArray*)pa
///////////////////////////////////////////////////////////////////////////////////////////////////
// global

void TTOpenURL(NSString* URL) {
[[TTAppMap sharedMap] openURL:URL];
UIViewController* TTOpenURL(NSString* URL) {
return [[TTAppMap sharedMap] openURL:URL];
}
2 changes: 1 addition & 1 deletion src/TTURLPattern.h
Expand Up @@ -30,6 +30,6 @@

- (BOOL)matchURL:(NSURL*)URL;

- (id)invokeSelectorForTarget:(id)target withURL:(NSURL*)URL;
- (id)invoke:(id)target withURL:(NSURL*)URL params:(NSDictionary*)params;

@end
13 changes: 8 additions & 5 deletions src/TTURLPattern.m
Expand Up @@ -191,7 +191,6 @@ - (void)deduceSelector {
if (parts.count) {
NSString* selectorName = [[parts componentsJoinedByString:@":"] stringByAppendingString:@":"];
SEL selector = sel_registerName(selectorName.UTF8String);
Class cls = _targetClass ? _targetClass : [_targetObject class];
_selector = selector;
}
}
Expand Down Expand Up @@ -279,7 +278,8 @@ - (BOOL)setArgument:(NSString*)text pattern:(id<TTURLPatternText>)patternText
return NO;
}

- (void)setArgumentsFromURL:(NSURL*)URL forInvocation:(NSInvocation*)invocation {
- (void)setArgumentsFromURL:(NSURL*)URL forInvocation:(NSInvocation*)invocation
params:(NSDictionary*)params {
NSInteger remainingArguments = _argumentCount;

NSArray* pathComponents = URL.path.pathComponents;
Expand All @@ -293,7 +293,7 @@ - (void)setArgumentsFromURL:(NSURL*)URL forInvocation:(NSInvocation*)invocation

NSDictionary* query = [URL.query queryDictionaryUsingEncoding:NSUTF8StringEncoding];
if (query.count) {
NSMutableDictionary* unmatched = nil;
NSMutableDictionary* unmatched = params ? [[params mutableCopy] autorelease] : nil;

for (NSString* name in [query keyEnumerator]) {
id<TTURLPatternText> patternText = [_query objectForKey:name];
Expand Down Expand Up @@ -429,7 +429,7 @@ - (BOOL)matchURL:(NSURL*)URL {
return YES;
}

- (id)invokeSelectorForTarget:(id)target withURL:(NSURL*)URL {
- (id)invoke:(id)target withURL:(NSURL*)URL params:(NSDictionary*)params {
id returnValue = nil;

NSMethodSignature *sig = [target methodSignatureForSelector:self.selector];
Expand All @@ -439,8 +439,11 @@ - (id)invokeSelectorForTarget:(id)target withURL:(NSURL*)URL {
[invocation setSelector:self.selector];
if (self.isUniversal) {
[invocation setArgument:&URL atIndex:2];
if (params) {
[invocation setArgument:&params atIndex:3];
}
} else {
[self setArgumentsFromURL:URL forInvocation:invocation];
[self setArgumentsFromURL:URL forInvocation:invocation params:params];
}
[invocation invoke];

Expand Down
12 changes: 12 additions & 0 deletions src/TTWebController.m
Expand Up @@ -44,6 +44,18 @@ - (id)initWithURL:(NSURL*)URL {
return self;
}

- (id)initWithURL:(NSURL*)URL params:(NSDictionary*)params {
if (self = [super init]) {
NSURLRequest* request = [params objectForKey:@"request"];
if (request) {
[self openRequest:request];
} else {
[self openURL:URL];
}
}
return self;
}

- (id)init {
if (self = [super init]) {
_delegate = nil;
Expand Down
12 changes: 11 additions & 1 deletion src/Three20/NSStringAdditions.h
Expand Up @@ -15,8 +15,18 @@
- (NSString*)stringByRemovingHTMLTags;

/**
* Loads a URL with the string using TTAppMap.
* Opens a URL with the string using TTAppMap.
*/
- (void)openURL;

/**
* Converts the string to an object using TTAppMap.
*/
- (id)objectValue;

/**
* Formats a URL using an object that conforms to the TTURLObject protocol.
*/
- (NSString*)objectURL:(id)object;

@end
21 changes: 16 additions & 5 deletions src/Three20/TTAppMap.h
Expand Up @@ -18,6 +18,12 @@ typedef enum {
TTDisplayModeModal, // new controller is created and displayed modally
} TTDisplayMode;

@protocol TTURLObject

- (NSString*)formatURL:(NSString*)URLFormat;

@end

@interface TTAppMap : NSObject {
id<TTAppMapDelegate> _delegate;
UIWindow* _mainWindow;
Expand Down Expand Up @@ -75,7 +81,12 @@ typedef enum {
* a keyWindow, a UIWindow will be created and displayed.
*/
- (UIViewController*)openURL:(NSString*)URL;
- (UIViewController*)openURL:(NSString*)URL params:(NSDictionary*)params;
- (UIViewController*)openURL:(NSString*)URL animated:(BOOL)animated;
- (UIViewController*)openURL:(NSString*)URL parent:(NSString*)parentURL animated:(BOOL)animated;
- (UIViewController*)openURL:(NSString*)URL params:(NSDictionary*)params animated:(BOOL)animated;
- (UIViewController*)openURL:(NSString*)URL parent:(NSString*)parentURL
params:(NSDictionary*)params animated:(BOOL)animated;

/**
* Gets or creates the object with a pattern that matches the URL.
Expand Down Expand Up @@ -174,9 +185,9 @@ typedef enum {
- (void)removeBindingForObject:(id)object;

/**
* Erases all persisted controller data from preferences.
* Erases all data stored in user defaults.
*/
- (void)removePersistedControllers;
- (void)resetDefaults;

/**
* Persists a controller's state and recursively persists the next controller after it.
Expand All @@ -194,14 +205,14 @@ typedef enum {
/**
* Asks if the URL should be opened and allows the delegate to stop it.
*/
- (BOOL)appMap:(TTAppMap*)appMap shouldOpenURL:(NSString*)URL;
- (BOOL)appMap:(TTAppMap*)appMap shouldOpenURL:(NSURL*)URL;

/**
* The URL is about to be opened in a controller.
*
* If the controller argument is nil, the URL will be opened externally.
*/
- (void)appMap:(TTAppMap*)appMap willOpenURL:(NSString*)URL
- (void)appMap:(TTAppMap*)appMap willOpenURL:(NSURL*)URL
inViewController:(UIViewController*)controller;

@end
Expand All @@ -212,4 +223,4 @@ typedef enum {
/**
* Shortcut for calling [[TTAppMap sharedMap] openURL:]
*/
void TTOpenURL(NSString* URL);
UIViewController* TTOpenURL(NSString* URL);
4 changes: 2 additions & 2 deletions src/Three20/UIViewControllerAdditions.h
Expand Up @@ -52,12 +52,12 @@
*/
- (BOOL)isContainerController;

- (void)persistNavigationPath:(NSMutableArray*)path;

- (void)persistView:(NSMutableDictionary*)state;

- (void)restoreView:(NSDictionary*)state;

- (void)persistNavigationPath:(NSMutableArray*)path;

/**
* Shows a UIAlertView with a message and title.
*
Expand Down
6 changes: 3 additions & 3 deletions src/UIViewControllerAdditions.m
Expand Up @@ -102,13 +102,13 @@ - (BOOL)isContainerController {
return NO;
}

- (void)persistView:(NSMutableDictionary*)state {
- (void)persistNavigationPath:(NSMutableArray*)path {
}

- (void)restoreView:(NSDictionary*)state {
- (void)persistView:(NSMutableDictionary*)state {
}

- (void)persistNavigationPath:(NSMutableArray*)path {
- (void)restoreView:(NSDictionary*)state {
}

- (void)alert:(NSString*)message title:(NSString*)title delegate:(id)delegate {
Expand Down

0 comments on commit 11f1e74

Please sign in to comment.