X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/652006e71924180e66acb0312ac26eea62eca870..5df7ecfbd8ada3b6bd104d4508c7b7e551f3278a:/UICaboodle/BrowserView.mm diff --git a/UICaboodle/BrowserView.mm b/UICaboodle/BrowserView.mm index e446d605..d1450671 100644 --- a/UICaboodle/BrowserView.mm +++ b/UICaboodle/BrowserView.mm @@ -27,6 +27,25 @@ extern NSString * const kCAFilterNearest; #include "substrate.h" #define ForSaurik 0 +#define DefaultTimeout_ 120.0 + +#define ShowInternals 0 +#define LogBrowser 0 +#define LogMessages 0 + +#define lprintf(args...) fprintf(stderr, args) + +// WebThreadLocked {{{ +struct WebThreadLocked { + _finline WebThreadLocked() { + WebThreadLock(); + } + + _finline ~WebThreadLocked() { + WebThreadUnlock(); + } +}; +// }}} template static inline void CYRelease(Type_ &value) { @@ -40,6 +59,7 @@ float CYScrollViewDecelerationRateNormal; @interface WebView (Apple) - (void) _setLayoutInterval:(float)interval; +- (void) _setAllowsMessaging:(BOOL)allows; @end @interface WebPreferences (Apple) @@ -85,18 +105,28 @@ float CYScrollViewDecelerationRateNormal; - (BOOL) respondsToSelector:(SEL)sel { if ([super respondsToSelector:sel]) return YES; + // XXX: WebThreadCreateNSInvocation returns nil - //fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel)); + +#if ShowInternals + fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel)); +#endif + return delegate_ == nil ? NO : [delegate_ respondsToSelector:sel]; } - (NSMethodSignature *) methodSignatureForSelector:(SEL)sel { if (NSMethodSignature *method = [super methodSignatureForSelector:sel]) return method; - //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel)); + +#if ShowInternals + fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel)); +#endif + if (delegate_ != nil) if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel]) return sig; + // XXX: I fucking hate Apple so very very bad return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } @@ -197,6 +227,10 @@ enum CYWebPolicyDecision { @implementation CYWebView : UIWebView +#if ShowInternals +#include "UICaboodle/UCInternal.h" +#endif + - (id) initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame]) != nil) { } return self; @@ -220,6 +254,21 @@ enum CYWebPolicyDecision { return created; }*/ +// webView:addMessageToConsole: (X.Xx) {{{ +static void $UIWebViewWebViewDelegate$webView$addMessageToConsole$(UIWebViewWebViewDelegate *self, SEL sel, WebView *view, NSDictionary *message) { + UIWebView *uiWebView(MSHookIvar(self, "uiWebView")); + if ([uiWebView respondsToSelector:@selector(webView:addMessageToConsole:)]) + [uiWebView webView:view addMessageToConsole:message]; +} + +- (void) webView:(WebView *)view addMessageToConsole:(NSDictionary *)message { + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webView:addMessageToConsole:)]) + [delegate webView:view addMessageToConsole:message]; + if ([UIWebView instancesRespondToSelector:@selector(webView:addMessageToConsole:)]) + [super webView:view addMessageToConsole:message]; +} +// }}} // webView:decidePolicyForNavigationAction:request:frame:decisionListener: (2.0+) {{{ - (void) webView:(WebView *)view decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { id delegate([self delegate]); @@ -335,8 +384,10 @@ static NSURLRequest *$UIWebViewWebViewDelegate$webView$resource$willSendRequest$ - (void) webView:(WebView *)view runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { id delegate([self delegate]); if ([UIWebView instancesRespondToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:)]) - // XXX: check delegate - if ([delegate webView:view shouldRunJavaScriptAlertPanelWithMessage:message initiatedByFrame:frame]) + if ( + ![delegate respondsToSelector:@selector(webView:shouldRunJavaScriptAlertPanelWithMessage:initiatedByFrame:)] || + [delegate webView:view shouldRunJavaScriptAlertPanelWithMessage:message initiatedByFrame:frame] + ) [super webView:view runJavaScriptAlertPanelWithMessage:message initiatedByFrame:frame]; } // }}} @@ -344,8 +395,10 @@ static NSURLRequest *$UIWebViewWebViewDelegate$webView$resource$willSendRequest$ - (BOOL) webView:(WebView *)view runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { id delegate([self delegate]); if ([UIWebView instancesRespondToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:)]) - // XXX: check delegate - if ([delegate webView:view shouldRunJavaScriptConfirmPanelWithMessage:message initiatedByFrame:frame]) + if ( + ![delegate respondsToSelector:@selector(webView:shouldRunJavaScriptConfirmPanelWithMessage:initiatedByFrame:)] || + [delegate webView:view shouldRunJavaScriptConfirmPanelWithMessage:message initiatedByFrame:frame] + ) return [super webView:view runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:frame]; return NO; } @@ -354,8 +407,10 @@ static NSURLRequest *$UIWebViewWebViewDelegate$webView$resource$willSendRequest$ - (NSString *) webView:(WebView *)view runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)text initiatedByFrame:(WebFrame *)frame { id delegate([self delegate]); if ([UIWebView instancesRespondToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:)]) - // XXX: check delegate - if ([delegate webView:view shouldRunJavaScriptTextInputPanelWithPrompt:prompt defaultText:text initiatedByFrame:frame]) + if ( + ![delegate respondsToSelector:@selector(webView:shouldRunJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:)] || + [delegate webView:view shouldRunJavaScriptTextInputPanelWithPrompt:prompt defaultText:text initiatedByFrame:frame] + ) return [super webView:view runJavaScriptTextInputPanelWithPrompt:prompt defaultText:text initiatedByFrame:frame]; return nil; } @@ -376,8 +431,17 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se } // }}} +- (void) _updateViewSettings { + [super _updateViewSettings]; + + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webViewUpdateViewSettings:)]) + [delegate webViewUpdateViewSettings:self]; +} + + (void) initialize { if (Class $UIWebViewWebViewDelegate = objc_getClass("UIWebViewWebViewDelegate")) { + class_addMethod($UIWebViewWebViewDelegate, @selector(webView:addMessageToConsole:), (IMP) &$UIWebViewWebViewDelegate$webView$addMessageToConsole$, "v16@0:4@8@12"); class_addMethod($UIWebViewWebViewDelegate, @selector(webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:), (IMP) &$UIWebViewWebViewDelegate$webView$decidePolicyForNewWindowAction$request$newFrameName$decisionListener$, "v28@0:4@8@12@16@20@24"); class_addMethod($UIWebViewWebViewDelegate, @selector(webView:didClearWindowObject:forFrame:), (IMP) &$UIWebViewWebViewDelegate$webView$didClearWindowObject$forFrame$, "v20@0:4@8@12@16"); class_addMethod($UIWebViewWebViewDelegate, @selector(webView:didReceiveTitle:forFrame:), (IMP) &$UIWebViewWebViewDelegate$webView$didReceiveTitle$forFrame$, "v20@0:4@8@12@16"); @@ -388,11 +452,6 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se @end -#define ShowInternals 0 -#define LogBrowser 0 - -#define lprintf(args...) fprintf(stderr, args) - @implementation BrowserController #if ShowInternals @@ -421,24 +480,14 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se if (challenge_ != nil) [challenge_ release]; - if (request_ != nil) - [request_ release]; - - //NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - - if (custom_ != nil) - [custom_ release]; - if (style_ != nil) - [style_ release]; - - if (function_ != nil) - [function_ release]; if (closer_ != nil) [closer_ release]; if (title_ != nil) [title_ release]; + if ([loading_ count] != 0) + [delegate_ releaseNetworkActivityIndicator]; [loading_ release]; [reloaditem_ release]; @@ -449,11 +498,21 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se [super dealloc]; } +- (void) setURL:(NSURL *)url { + _assert(request_ == nil); + + request_ = [NSURLRequest + requestWithURL:url + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:DefaultTimeout_ + ]; +} + - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy { [self loadRequest:[NSURLRequest requestWithURL:url cachePolicy:policy - timeoutInterval:120.0 + timeoutInterval:DefaultTimeout_ ]]; } @@ -468,15 +527,19 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se error_ = false; - WebThreadLock(); + WebThreadLocked lock; [webview_ loadRequest:request]; - WebThreadUnlock(); } -- (void) reloadURL { +- (void) reloadURLWithCache:(BOOL)cache { if (request_ == nil) return; + NSMutableURLRequest *request([request_ mutableCopy]); + [request setCachePolicy:(cache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData)]; + + request_ = request; + if ([request_ HTTPBody] == nil && [request_ HTTPBodyStream] == nil) [self loadRequest:request_]; else { @@ -485,7 +548,9 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se message:nil delegate:self cancelButtonTitle:UCLocalize("CANCEL") - otherButtonTitles:UCLocalize("SUBMIT"), nil + otherButtonTitles: + UCLocalize("SUBMIT"), + nil ] autorelease]; [alert setContext:@"submit"]; @@ -493,54 +558,34 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se } } -- (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { - if (custom_ != nil) - [custom_ autorelease]; - if (button == nil) - custom_ = nil; - else - custom_ = [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain]; +- (void) reloadURL { + [self reloadURLWithCache:YES]; +} - if (style_ != nil) - [style_ autorelease]; - if (style == nil) - style_ = nil; - else - style_ = [style retain]; +- (void) reloadData { + [super reloadData]; + [self reloadURLWithCache:YES]; +} - if (function_ != nil) - [function_ autorelease]; - if (function == nil) - function_ = nil; - else - function_ = [function retain]; +- (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { + custom_ = button; + style_ = style; + function_ = function; - [self applyRightButton]; + [self performSelectorOnMainThread:@selector(applyRightButton) withObject:nil waitUntilDone:NO]; } - (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { - if (custom_ != nil) - [custom_ autorelease]; - if (button == nil) - custom_ = nil; - else - custom_ = [button retain]; + custom_ = button; + style_ = style; + function_ = function; - if (style_ != nil) - [style_ autorelease]; - if (style == nil) - style_ = nil; - else - style_ = [style retain]; - - if (function_ != nil) - [function_ autorelease]; - if (function == nil) - function_ = nil; - else - function_ = [function retain]; + [self performSelectorOnMainThread:@selector(applyRightButton) withObject:nil waitUntilDone:NO]; +} - [self applyRightButton]; +- (void) removeButton { + custom_ = [NSNull null]; + [self performSelectorOnMainThread:@selector(applyRightButton) withObject:nil waitUntilDone:NO]; } - (void) setPopupHook:(id)function { @@ -552,9 +597,36 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se closer_ = [function retain]; } +- (void) scrollToBottomAnimated:(NSNumber *)animated { + CGSize size([scroller_ contentSize]); + CGPoint offset([scroller_ contentOffset]); + CGRect frame([scroller_ frame]); + + if (size.height - offset.y < frame.size.height + 20.f) { + CGRect rect = {{0, size.height-1}, {size.width, 1}}; + [scroller_ scrollRectToVisible:rect animated:[animated boolValue]]; + } +} + +- (void) _setViewportWidth { + [[webview_ _documentView] setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10]; +} + - (void) setViewportWidth:(float)width { width_ = width != 0 ? width : [[self class] defaultWidth]; - [[webview_ _documentView] setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10]; + [self _setViewportWidth]; +} + +- (void) _setViewportWidthOnMainThread:(NSNumber *)width { + [self setViewportWidth:[width floatValue]]; +} + +- (void) setViewportWidthOnMainThread:(float)width { + [self performSelectorOnMainThread:@selector(_setViewportWidthOnMainThread:) withObject:[NSNumber numberWithFloat:width] waitUntilDone:NO]; +} + +- (void) webViewUpdateViewSettings:(UIWebView *)view { + [self _setViewportWidth]; } - (void) _openMailToURL:(NSURL *)url { @@ -565,6 +637,18 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se return true; } +- (bool) allowsNavigationAction { + return allowsNavigationAction_; +} + +- (void) setAllowsNavigationAction:(bool)value { + allowsNavigationAction_ = value; +} + +- (void) setAllowsNavigationActionByNumber:(NSNumber *)value { + [self setAllowsNavigationAction:[value boolValue]]; +} + - (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame { [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]]; [self _didFinishLoading]; @@ -582,41 +666,11 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se } } -// CYWebViewDelegate {{{ -- (void) webView:(WebView *)view decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { -#if LogBrowser - NSLog(@"decidePolicyForNavigationAction:%@ request:%@ frame:%@", action, request, frame); -#endif - - if ([frame parentFrame] == nil) { - if (!error_) { - if (request_ != nil) - [request_ autorelease]; - if (request == nil) - request_ = nil; - else - request_ = [request retain]; - } - } -} - -- (void) webView:(WebView *)view decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)frame decisionListener:(id)listener { -#if LogBrowser - NSLog(@"decidePolicyForNewWindowAction:%@ request:%@ newFrameName:%@", action, request, frame); -#endif - +- (void) pushRequest:(NSURLRequest *)request asPop:(bool)pop { NSURL *url([request URL]); - if (url == nil) - return; - - if ([frame isEqualToString:@"_open"]) - [delegate_ openURL:url]; - - NSString *scheme([[url scheme] lowercaseString]); - if ([scheme isEqualToString:@"mailto"]) - [self _openMailToURL:url]; - CYViewController *page([delegate_ pageForURL:url hasTag:NULL]); + // XXX: filter to internal usage? + CYViewController *page([delegate_ pageForURL:url forExternal:NO]); if (page == nil) { BrowserController *browser([[[class_ alloc] init] autorelease]); @@ -626,18 +680,16 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se [page setDelegate:delegate_]; - if (![frame isEqualToString:@"_popup"]) { + if (!pop) { [[self navigationItem] setTitle:title_]; [[self navigationController] pushViewController:page animated:YES]; } else { - UCNavigationController *navigation([[[UCNavigationController alloc] init] autorelease]); + UCNavigationController *navigation([[[UCNavigationController alloc] initWithRootViewController:page] autorelease]); [navigation setHook:indirect_]; [navigation setDelegate:delegate_]; - [navigation setViewControllers:[NSArray arrayWithObject:page]]; - [[page navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CLOSE") style:UIBarButtonItemStylePlain @@ -647,6 +699,53 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se [[self navigationController] presentModalViewController:navigation animated:YES]; } +} + +// CYWebViewDelegate {{{ +- (void) webView:(WebView *)view addMessageToConsole:(NSDictionary *)message { +#if LogMessages + NSLog(@"addMessageToConsole:%@", message); +#endif +} + +- (void) webView:(WebView *)view decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { +#if LogBrowser + NSLog(@"decidePolicyForNavigationAction:%@ request:%@ frame:%@", action, request, frame); +#endif + + if ([frame parentFrame] == nil) { + if (!error_) { + NSURL *url(request == nil ? nil : [request URL]); + + if (request_ == nil || [self allowsNavigationAction] || [[request_ URL] isEqual:url]) + request_ = request; + else { + if (url != nil) + [self pushRequest:request asPop:NO]; + [listener ignore]; + } + } + } +} + +- (void) webView:(WebView *)view decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)frame decisionListener:(id)listener { +#if LogBrowser + NSLog(@"decidePolicyForNewWindowAction:%@ request:%@ newFrameName:%@", action, request, frame); +#endif + + NSURL *url([request URL]); + if (url == nil) + return; + + if ([frame isEqualToString:@"_open"]) + [delegate_ openURL:url]; + else { + NSString *scheme([[url scheme] lowercaseString]); + if ([scheme isEqualToString:@"mailto"]) + [self _openMailToURL:url]; + else + [self pushRequest:request asPop:[frame isEqualToString:@"_popup"]]; + } [listener ignore]; } @@ -670,6 +769,13 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se [self _didFailWithError:error forFrame:frame]; } +// XXX: factor this out somewhere +- (UIColor *) groupTableViewBackgroundColor { + UIDevice *device([UIDevice currentDevice]); + bool iPad([device respondsToSelector:@selector(userInterfaceIdiom)] && [device userInterfaceIdiom] == UIUserInterfaceIdiomPad); + return iPad ? [UIColor colorWithRed:0.821 green:0.834 blue:0.860 alpha:1] : [UIColor groupTableViewBackgroundColor]; +} + - (void) webView:(WebView *)view didFinishLoadForFrame:(WebFrame *)frame { [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]]; @@ -679,7 +785,7 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se for (DOMHTMLBodyElement *body in (id) bodies) { DOMCSSStyleDeclaration *style([document getComputedStyle:body pseudoElement:nil]); - bool colored(false); + UIColor *uic([self groupTableViewBackgroundColor]); if (DOMCSSPrimitiveValue *color = static_cast([style getPropertyCSSValue:@"background-color"])) { if ([color primitiveType] == DOM_CSS_RGBCOLOR) { @@ -690,10 +796,8 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se float blue([[rgb blue] getFloatValue:DOM_CSS_NUMBER]); float alpha([[rgb alpha] getFloatValue:DOM_CSS_NUMBER]); - UIColor *uic(nil); - if (red == 0xc7 && green == 0xce && blue == 0xd5) - uic = [UIColor groupTableViewBackgroundColor]; + uic = [UIColor pinStripeColor]; else if (alpha != 0) uic = [UIColor colorWithRed:(red / 255) @@ -701,16 +805,10 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se blue:(blue / 255) alpha:alpha ]; - - if (uic != nil) { - colored = true; - [scroller_ setBackgroundColor:uic]; - } } } - if (!colored) - [scroller_ setBackgroundColor:[UIColor groupTableViewBackgroundColor]]; + [scroller_ setBackgroundColor:uic]; break; } } @@ -734,11 +832,13 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se if ([frame parentFrame] == nil) { CYRelease(title_); - CYRelease(custom_); - CYRelease(style_); - CYRelease(function_); + custom_ = nil; + style_ = nil; + function_ = nil; CYRelease(closer_); + [self setHidesNavigationBar:NO]; + // XXX: do we still need to do this? [[self navigationItem] setTitle:nil]; } @@ -815,19 +915,12 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se [alert dismissWithClickedButtonIndex:-1 animated:YES]; } else if ([context isEqualToString:@"submit"]) { - switch (button) { - case 1: - break; - - case 2: - if (request_ != nil) { - WebThreadLock(); - [webview_ loadRequest:request_]; - WebThreadUnlock(); - } - break; - - _nodefault + if (button == [alert cancelButtonIndex]) { + } else if (button == [alert firstOtherButtonIndex]) { + if (request_ != nil) { + WebThreadLocked lock; + [webview_ loadRequest:request_]; + } } [alert dismissWithClickedButtonIndex:-1 animated:YES]; @@ -845,8 +938,8 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se } - (UIBarButtonItem *) customButton { - return [[[UIBarButtonItem alloc] - initWithTitle:custom_ + return custom_ == [NSNull null] ? nil : [[[UIBarButtonItem alloc] + initWithTitle:static_cast(custom_.operator NSObject *()) style:[self rightButtonStyle] target:self action:@selector(customButtonClicked) @@ -861,21 +954,43 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se [[self navigationItem] setTitle:UCLocalize("LOADING")]; } +- (void) layoutRightButton { + [[loadingitem_ view] addSubview:indicator_]; + [[loadingitem_ view] bringSubviewToFront:indicator_]; +} + - (void) applyRightButton { if ([self isLoading]) { [[self navigationItem] setRightBarButtonItem:loadingitem_ animated:YES]; - // XXX: why do we do this again here? (if we don't, just remove indicator_) - [[loadingitem_ view] addSubview:indicator_]; + [self performSelector:@selector(layoutRightButton) withObject:nil afterDelay:0]; + + [indicator_ startAnimating]; [self applyLoadingTitle]; - } else if (custom_ != nil) { - [[self navigationItem] setRightBarButtonItem:[self customButton] animated:YES]; } else { - [[self navigationItem] setRightBarButtonItem:[self rightButton] animated:YES]; + [indicator_ stopAnimating]; + + [[self navigationItem] setRightBarButtonItem:( + custom_ != nil ? [self customButton] : [self rightButton] + ) animated:YES]; } } +- (void) didStartLoading { + // Overridden in subclasses. +} + - (void) _didStartLoading { [self applyRightButton]; + + if ([loading_ count] != 1) + return; + + [delegate_ retainNetworkActivityIndicator]; + [self didStartLoading]; +} + +- (void) didFinishLoading { + // Overridden in subclasses. } - (void) _didFinishLoading { @@ -883,10 +998,10 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se return; [self applyRightButton]; + [[self navigationItem] setTitle:title_]; - // XXX: wtf? - if (![self isLoading]) - [[self navigationItem] setTitle:title_]; + [delegate_ releaseNetworkActivityIndicator]; + [self didFinishLoading]; } - (bool) isLoading { @@ -895,6 +1010,8 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se - (id) initWithWidth:(float)width ofClass:(Class)_class { if ((self = [super init]) != nil) { + allowsNavigationAction_ = true; + class_ = _class; loading_ = [[NSMutableSet alloc] initWithCapacity:5]; @@ -917,6 +1034,8 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se [document setTileSize:CGSizeMake(320, 500)]; [document setBackgroundColor:[UIColor clearColor]]; + + // XXX: this is terribly (too?) expensive [document setDrawsBackground:NO]; WebView *webview([document webView]); @@ -931,6 +1050,13 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se [preferences setCacheModel:WebCacheModelDocumentBrowser]; [preferences setOfflineWebApplicationCacheEnabled:YES]; +#if LogMessages + if ([document respondsToSelector:@selector(setAllowsMessaging:)]) + [document setAllowsMessaging:YES]; + if ([webview respondsToSelector:@selector(_setAllowsMessaging:)]) + [webview _setAllowsMessaging:YES]; +#endif + if ([webview_ respondsToSelector:@selector(_scrollView)]) { scroller_ = [webview_ _scrollView]; @@ -958,7 +1084,7 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se } [scroller_ setFixedBackgroundPattern:YES]; - [scroller_ setBackgroundColor:[UIColor groupTableViewBackgroundColor]]; + [scroller_ setBackgroundColor:[self groupTableViewBackgroundColor]]; [scroller_ setClipsSubviews:YES]; [scroller_ setBounces:YES]; @@ -981,11 +1107,8 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se action:@selector(reloadButtonClicked) ]; - CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite]; - indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(15, 5, indsize.width, indsize.height)]; - [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite]; - [indicator_ startAnimation]; - [[loadingitem_ view] addSubview:indicator_]; + indicator_ = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; + [indicator_ setFrame:CGRectMake(15, 5, [indicator_ frame].size.width, [indicator_ frame].size.height)]; [webview_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)]; [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; @@ -1000,13 +1123,19 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se return [self initWithWidth:0]; } +- (id) initWithURL:(NSURL *)url { + if ((self = [self init]) != nil) { + [self setURL:url]; + } return self; +} + - (void) didDismissModalViewController { if (closer_ != nil) [self callFunction:closer_]; } - (void) callFunction:(WebScriptObject *)function { - WebThreadLock(); + WebThreadLocked lock; WebView *webview([[webview_ _documentView] webView]); WebFrame *frame([webview mainFrame]); @@ -1039,12 +1168,10 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se settings->setJavaScriptCanOpenWindowsAutomatically(no);*/ [preferences setJavaScriptCanOpenWindowsAutomatically:maybe]; - - WebThreadUnlock(); } - (void) reloadButtonClicked { - [self reloadURL]; + [self reloadURLWithCache:YES]; } - (void) _customButtonClicked { @@ -1064,4 +1191,99 @@ static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *se return 980; } +- (void) setNavigationBarStyle:(NSString *)name { + UIBarStyle style; + if ([name isEqualToString:@"Black"]) + style = UIBarStyleBlack; + else + style = UIBarStyleDefault; + + [[[self navigationController] navigationBar] setBarStyle:style]; +} + +- (void) setNavigationBarTintColor:(UIColor *)color { + [[[self navigationController] navigationBar] setTintColor:color]; +} + +- (void) setHidesBackButton:(bool)value { + [[self navigationItem] setHidesBackButton:value]; +} + +- (void) setHidesBackButtonByNumber:(NSNumber *)value { + [self setHidesBackButton:[value boolValue]]; +} + +- (void) dispatchEvent:(NSString *)event { + WebThreadLocked lock; + + NSString *script([NSString stringWithFormat:@ + "(function() {" + "var event = this.document.createEvent('Events');" + "event.initEvent('%@', false, false);" + "this.document.dispatchEvent(event);" + "})();" + , event]); + + NSMutableArray *frames([NSMutableArray arrayWithObjects: + [[[webview_ _documentView] webView] mainFrame] + , nil]); + + while (WebFrame *frame = [frames lastObject]) { + WebScriptObject *object([frame windowObject]); + [object evaluateWebScript:script]; + [frames removeLastObject]; + [frames addObjectsFromArray:[frame childFrames]]; + } +} + +- (bool) hidesNavigationBar { + return hidesNavigationBar_; +} + +- (void) _setHidesNavigationBar:(bool)value animated:(bool)animated { + if (visible_) + [[self navigationController] setNavigationBarHidden:(value && [self hidesNavigationBar]) animated:animated]; +} + +- (void) setHidesNavigationBar:(bool)value { + if (hidesNavigationBar_ != value) { + hidesNavigationBar_ = value; + [self _setHidesNavigationBar:YES animated:YES]; + } +} + +- (void) setHidesNavigationBarByNumber:(NSNumber *)value { + [self setHidesNavigationBar:[value boolValue]]; +} + +- (void) viewWillAppear:(BOOL)animated { + visible_ = true; + + if ([self hidesNavigationBar]) + [self _setHidesNavigationBar:YES animated:animated]; + + [self dispatchEvent:@"CydiaViewWillAppear"]; + [super viewWillAppear:animated]; +} + +- (void) viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [self dispatchEvent:@"CydiaViewDidAppear"]; +} + +- (void) viewWillDisappear:(BOOL)animated { + [self dispatchEvent:@"CydiaViewWillDisappear"]; + [super viewWillDisappear:animated]; + + if ([self hidesNavigationBar]) + [self _setHidesNavigationBar:NO animated:animated]; + + visible_ = false; +} + +- (void) viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + [self dispatchEvent:@"CydiaViewDidDisappear"]; +} + @end