#include "iPhonePrivate.h"
+#include "CyteKit/IndirectDelegate.h"
#include "CyteKit/Localize.h"
#include "CyteKit/WebViewController.h"
#include "CyteKit/PerlCompatibleRegEx.hpp"
#include <WebCore/WebCoreThread.h>
-#include <WebKit/WebKitErrors.h>
-#include <WebKit/WebPreferences.h>
+#import <WebKit/WebKitErrors.h>
+#import <WebKit/WebPreferences.h>
#include <WebKit/DOMCSSPrimitiveValue.h>
#include <WebKit/DOMCSSStyleDeclaration.h>
- (void) _setAllowsMessaging:(BOOL)allows;
@end
-@interface WebPreferences (Apple)
-+ (void) _setInitialDefaultTextEncodingToSystemEncoding;
-- (void) _setLayoutInterval:(NSInteger)interval;
-- (void) setOfflineWebApplicationCacheEnabled:(BOOL)enabled;
-@end
+@implementation WebFrame (Cydia)
-/* Indirect Delegate {{{ */
-@interface IndirectDelegate : NSObject {
- _transient volatile id delegate_;
+- (NSString *) description {
+ return [NSString stringWithFormat:@"<%s: %p, %@>", class_getName([self class]), self, [[[([self provisionalDataSource] ?: [self dataSource]) request] URL] absoluteString]];
}
-- (void) setDelegate:(id)delegate;
-- (id) initWithDelegate:(id)delegate;
@end
+/* Indirect Delegate {{{ */
@implementation IndirectDelegate
- (void) setDelegate:(id)delegate {
CYScrollViewDecelerationRateNormal = 0.998;
}
+- (bool) retainsNetworkActivityIndicator {
+ return true;
+}
+
+- (void) releaseNetworkActivityIndicator {
+ if ([loading_ count] != 0) {
+ [loading_ removeAllObjects];
+
+ if ([self retainsNetworkActivityIndicator])
+ [delegate_ releaseNetworkActivityIndicator];
+ }
+}
+
- (void) dealloc {
#if LogBrowser
NSLog(@"[CyteWebViewController dealloc]");
#endif
- if ([loading_ count] != 0)
- [delegate_ releaseNetworkActivityIndicator];
+ [self releaseNetworkActivityIndicator];
[super dealloc];
}
+- (NSString *) description {
+ return [NSString stringWithFormat:@"<%s: %p, %@>", class_getName([self class]), self, [[request_ URL] absoluteString]];
+}
+
- (CyteWebView *) webView {
return (CyteWebView *) [self view];
}
return url;
}
-- (NSURLRequest *) requestWithURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
- return [NSURLRequest
+- (NSURLRequest *) requestWithURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy referrer:(NSString *)referrer {
+ NSMutableURLRequest *request([NSMutableURLRequest
requestWithURL:[self URLWithURL:url]
cachePolicy:policy
timeoutInterval:DefaultTimeout_
- ];
+ ]);
+
+ [request setValue:referrer forHTTPHeaderField:@"Referer"];
+
+ return request;
}
-- (void) setURL:(NSURL *)url {
+- (void) setRequest:(NSURLRequest *)request {
_assert(request_ == nil);
- request_ = [self requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
+ request_ = request;
+}
+
+- (void) setURL:(NSURL *)url {
+ [self setURL:url withReferrer:nil];
+}
+
+- (void) setURL:(NSURL *)url withReferrer:(NSString *)referrer {
+ [self setRequest:[self requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy referrer:referrer]];
}
- (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
- [self loadRequest:[self requestWithURL:url cachePolicy:policy]];
+ [self loadRequest:[self requestWithURL:url cachePolicy:policy referrer:nil]];
}
- (void) loadURL:(NSURL *)url {
}
- (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame {
- [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
+ NSValue *object([NSValue valueWithNonretainedObject:frame]);
+ if (![loading_ containsObject:object])
+ return;
+ [loading_ removeObject:object];
+
[self _didFinishLoading];
if ([[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled)
return;
if ([[error domain] isEqualToString:WebKitErrorDomain] && [error code] == WebKitErrorFrameLoadInterruptedByPolicyChange) {
- request_ = stage2_;
- stage1_ = nil;
- stage2_ = nil;
+ request_ = nil;
return;
}
}
}
-- (void) pushRequest:(NSURLRequest *)request asPop:(bool)pop {
+- (void) pushRequest:(NSURLRequest *)request forAction:(NSDictionary *)action asPop:(bool)pop {
+ WebFrame *frame(nil);
+ if (NSDictionary *WebActionElement = [action objectForKey:@"WebActionElementKey"])
+ frame = [WebActionElement objectForKey:@"WebElementFrame"];
+ if (frame == nil)
+ frame = [[[[self webView] _documentView] webView] mainFrame];
+
+ WebDataSource *source([frame provisionalDataSource] ?: [frame dataSource]);
+ NSString *referrer([request valueForHTTPHeaderField:@"Referer"] ?: [[[source request] URL] absoluteString]);
+
NSURL *url([request URL]);
// XXX: filter to internal usage?
- CyteViewController *page([delegate_ pageForURL:url forExternal:NO]);
+ CyteViewController *page([delegate_ pageForURL:url forExternal:NO withReferrer:referrer]);
if (page == nil) {
CyteWebViewController *browser([[[class_ alloc] init] autorelease]);
- [browser loadRequest:request];
+ [browser setRequest:request];
page = browser;
}
- (void) webView:(WebView *)view decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
#if LogBrowser
- NSLog(@"decidePolicyForNavigationAction:%@ request:%@ frame:%@", action, request, frame);
+ NSLog(@"decidePolicyForNavigationAction:%@ request:%@ %@ frame:%@", action, request, [request allHTTPHeaderFields], frame);
#endif
if ([frame parentFrame] == nil) {
if (request_ != nil && ![[request_ URL] isEqual:url] && ![self allowsNavigationAction]) {
if (url != nil)
- [self pushRequest:request asPop:NO];
+ [self pushRequest:request forAction:action asPop:NO];
[listener ignore];
}
}
- (void) webView:(WebView *)view didDecidePolicy:(CYWebPolicyDecision)decision forNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame {
if ([frame parentFrame] == nil)
if (decision == CYWebPolicyDecisionUse)
- if (!error_) {
- stage1_ = request_;
+ if (!error_)
request_ = request;
- }
}
-- (void) webView:(WebView *)view decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
+- (void) webView:(WebView *)view decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id<WebPolicyDecisionListener>)listener {
#if LogBrowser
- NSLog(@"decidePolicyForNewWindowAction:%@ request:%@ newFrameName:%@", action, request, frame);
+ NSLog(@"decidePolicyForNewWindowAction:%@ request:%@ %@ newFrameName:%@", action, request, [request allHTTPHeaderFields], name);
#endif
NSURL *url([request URL]);
if (url == nil)
return;
- if ([frame isEqualToString:@"_open"])
+ if ([name 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"]];
+ [self pushRequest:request forAction:action asPop:[name isEqualToString:@"_popup"]];
}
[listener ignore];
- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
}
+- (void) webView:(WebView *)view didCommitLoadForFrame:(WebFrame *)frame {
+#if LogBrowser
+ NSLog(@"didCommitLoadForFrame:%@", frame);
+#endif
+
+ if ([frame parentFrame] == nil) {
+ loaded_ = true;
+ }
+}
+
- (void) webView:(WebView *)view didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
#if LogBrowser
NSLog(@"didFailLoadWithError:%@ forFrame:%@", error, frame);
}
- (void) webView:(WebView *)view didFinishLoadForFrame:(WebFrame *)frame {
- [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
+ NSValue *object([NSValue valueWithNonretainedObject:frame]);
+ if (![loading_ containsObject:object])
+ return;
+ [loading_ removeObject:object];
if ([frame parentFrame] == nil) {
- stage1_ = nil;
- stage2_ = nil;
-
if (DOMDocument *document = [frame DOMDocument])
if (DOMNodeList<NSFastEnumeration> *bodies = [document getElementsByTagName:@"body"])
for (DOMHTMLBodyElement *body in (id) bodies) {
allowsNavigationAction_ = true;
- stage2_ = stage1_;
- stage1_ = nil;
-
[self setHidesNavigationBar:NO];
+ [self setScrollAlwaysBounceVertical:true];
+ [self setScrollIndicatorStyle:UIScrollViewIndicatorStyleDefault];
// XXX: do we still need to do this?
[[self navigationItem] setTitle:nil];
// }}}
- (void) close {
- [[self navigationController] dismissModalViewControllerAnimated:YES];
+ [[[self navigationController] parentViewController] dismissModalViewControllerAnimated:YES];
}
- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button {
if ([loading_ count] != 1)
return;
- [delegate_ retainNetworkActivityIndicator];
+ if ([self retainsNetworkActivityIndicator])
+ [delegate_ retainNetworkActivityIndicator];
+
[self didStartLoading];
}
[self applyRightButton];
[[self navigationItem] setTitle:title_];
- [delegate_ releaseNetworkActivityIndicator];
+ if ([self retainsNetworkActivityIndicator])
+ [delegate_ releaseNetworkActivityIndicator];
+
[self didFinishLoading];
}
} return self;
}
+- (NSString *) applicationNameForUserAgent {
+ return nil;
+}
+
- (void) loadView {
CGRect bounds([[UIScreen mainScreen] applicationFrame]);
[preferences setJavaScriptCanOpenWindowsAutomatically:YES];
[preferences setOfflineWebApplicationCacheEnabled:YES];
+ if (NSString *agent = [self applicationNameForUserAgent])
+ [webview setApplicationNameForUserAgent:agent];
+
if ([webview respondsToSelector:@selector(setShouldUpdateWhileOffscreen:)])
[webview setShouldUpdateWhileOffscreen:NO];
[self setViewportWidth:width_];
UITableView *table([[[UITableView alloc] initWithFrame:[webview_ bounds] style:UITableViewStyleGrouped] autorelease]);
+ [table setScrollsToTop:NO];
[webview_ insertSubview:table atIndex:0];
[table setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
webview_ = nil;
scroller_ = nil;
+ [self releaseNetworkActivityIndicator];
+
[super releaseSubviews];
}
} return self;
}
+- (id) initWithRequest:(NSURLRequest *)request {
+ if ((self = [self init]) != nil) {
+ [self setRequest:request];
+ } return self;
+}
+
- (void) callFunction:(WebScriptObject *)function {
WebThreadLocked lock;
[self setHidesNavigationBar:[value boolValue]];
}
+- (void) setScrollAlwaysBounceVertical:(bool)value {
+ if ([webview_ respondsToSelector:@selector(_scrollView)]) {
+ UIScrollView *scroller([webview_ _scrollView]);
+ [scroller setAlwaysBounceVertical:value];
+ } else if ([webview_ respondsToSelector:@selector(_scroller)]) {
+ //UIScroller *scroller([webview_ _scroller]);
+ // XXX: I am sad here.
+ } else return;
+}
+
+- (void) setScrollAlwaysBounceVerticalNumber:(NSNumber *)value {
+ [self setScrollAlwaysBounceVertical:[value boolValue]];
+}
+
+- (void) setScrollIndicatorStyle:(UIScrollViewIndicatorStyle)style {
+ if ([webview_ respondsToSelector:@selector(_scrollView)]) {
+ UIScrollView *scroller([webview_ _scrollView]);
+ [scroller setIndicatorStyle:style];
+ } else if ([webview_ respondsToSelector:@selector(_scroller)]) {
+ UIScroller *scroller([webview_ _scroller]);
+ [scroller setScrollerIndicatorStyle:style];
+ } else return;
+}
+
+- (void) setScrollIndicatorStyleWithName:(NSString *)style {
+ UIScrollViewIndicatorStyle value;
+
+ if (false);
+ else if ([style isEqualToString:@"default"])
+ value = UIScrollViewIndicatorStyleDefault;
+ else if ([style isEqualToString:@"black"])
+ value = UIScrollViewIndicatorStyleBlack;
+ else if ([style isEqualToString:@"white"])
+ value = UIScrollViewIndicatorStyleWhite;
+ else return;
+
+ [self setScrollIndicatorStyle:value];
+}
+
- (void) viewWillAppear:(BOOL)animated {
visible_ = true;
if ([self hidesNavigationBar])
[self _setHidesNavigationBar:YES animated:animated];
+ // XXX: why isn't this evern called automatically?
+ [[self webView] setNeedsLayout];
+
[self dispatchEvent:@"CydiaViewWillAppear"];
[super viewWillAppear:animated];
}