]> git.saurik.com Git - cydia.git/blame - UICaboodle/BrowserView.mm
Redid chpwn's code to match physical formatting guidelines. :(
[cydia.git] / UICaboodle / BrowserView.mm
CommitLineData
1e4922b8
JF
1#include <UIKit/UIKit.h>
2#include "iPhonePrivate.h"
3
4#include "UCPlatform.h"
5
3cb572d2
JF
6#include <UICaboodle/BrowserView.h>
7#include <UICaboodle/UCLocalize.h>
61b13cae 8
1e4922b8 9//#include <QuartzCore/CALayer.h>
61b13cae
JF
10// XXX: fix the minimum requirement
11extern NSString * const kCAFilterNearest;
bde2d79b 12
9d7f5e2d 13#include <WebCore/WebCoreThread.h>
1e4922b8
JF
14
15#include <WebKit/WebPolicyDelegate.h>
16#include <WebKit/WebPreferences.h>
17
18#include <WebKit/DOMCSSPrimitiveValue.h>
19#include <WebKit/DOMCSSStyleDeclaration.h>
20#include <WebKit/DOMDocument.h>
21#include <WebKit/DOMHTMLBodyElement.h>
22#include <WebKit/DOMRGBColor.h>
23
24//#include <WebCore/Page.h>
25//#include <WebCore/Settings.h>
9d7f5e2d 26
61b13cae
JF
27#include "substrate.h"
28
13bb1e92 29#define ForSaurik 0
017b2b71 30
c2292b80
JF
31template <typename Type_>
32static inline void CYRelease(Type_ &value) {
33 if (value != nil) {
34 [value release];
35 value = nil;
36 }
37}
d3bef7bc 38
c2292b80
JF
39@interface WebView (Apple)
40- (void) _setLayoutInterval:(float)interval;
41@end
42
43@interface WebPreferences (Apple)
44+ (void) _setInitialDefaultTextEncodingToSystemEncoding;
45- (void) _setLayoutInterval:(NSInteger)interval;
46- (void) setOfflineWebApplicationCacheEnabled:(BOOL)enabled;
47@end
5d8f1006 48
04700693 49/* Indirect Delegate {{{ */
1e4922b8
JF
50@interface IndirectDelegate : NSObject <
51 HookProtocol
52> {
04700693
JF
53 _transient volatile id delegate_;
54}
55
56- (void) setDelegate:(id)delegate;
57- (id) initWithDelegate:(id)delegate;
58@end
59
60@implementation IndirectDelegate
61
62- (void) setDelegate:(id)delegate {
63 delegate_ = delegate;
64}
65
66- (id) initWithDelegate:(id)delegate {
67 delegate_ = delegate;
68 return self;
69}
70
1e4922b8
JF
71- (void) didDismissModalViewController {
72 if (delegate_ != nil)
73 return [delegate_ didDismissModalViewController];
74}
75
9d7f5e2d
JF
76- (IMP) methodForSelector:(SEL)sel {
77 if (IMP method = [super methodForSelector:sel])
78 return method;
79 fprintf(stderr, "methodForSelector:[%s] == NULL\n", sel_getName(sel));
80 return NULL;
81}
82
04700693 83- (BOOL) respondsToSelector:(SEL)sel {
9d7f5e2d
JF
84 if ([super respondsToSelector:sel])
85 return YES;
86 // XXX: WebThreadCreateNSInvocation returns nil
87 //fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel));
88 return delegate_ == nil ? NO : [delegate_ respondsToSelector:sel];
04700693
JF
89}
90
91- (NSMethodSignature *) methodSignatureForSelector:(SEL)sel {
9d7f5e2d
JF
92 if (NSMethodSignature *method = [super methodSignatureForSelector:sel])
93 return method;
94 //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel));
04700693
JF
95 if (delegate_ != nil)
96 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
97 return sig;
98 // XXX: I fucking hate Apple so very very bad
99 return [NSMethodSignature signatureWithObjCTypes:"v@:"];
100}
101
102- (void) forwardInvocation:(NSInvocation *)inv {
103 SEL sel = [inv selector];
104 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
105 [inv invokeWithTarget:delegate_];
106}
107
108@end
109/* }}} */
110
61b13cae 111@implementation WebScriptObject (UICaboodle)
9d7f5e2d 112
485f16d6 113- (NSUInteger) count {
9d7f5e2d
JF
114 id length([self valueForKey:@"length"]);
115 if ([length respondsToSelector:@selector(intValue)])
116 return [length intValue];
117 else
118 return 0;
119}
120
121- (id) objectAtIndex:(unsigned)index {
122 return [self webScriptValueAtIndex:index];
123}
124
125@end
126
c2292b80
JF
127// CYWebPolicyDecision* {{{
128enum CYWebPolicyDecision {
129 CYWebPolicyDecisionUnknown,
130 CYWebPolicyDecisionDownload,
131 CYWebPolicyDecisionIgnore,
132 CYWebPolicyDecisionUse,
133};
134
135@interface CYWebPolicyDecisionMediator : NSObject <
136 WebPolicyDecisionListener
137> {
138 id<WebPolicyDecisionListener> listener_;
139 CYWebPolicyDecision decision_;
3c83edee 140}
c2292b80
JF
141
142- (id) initWithListener:(id<WebPolicyDecisionListener>)listener;
143
144- (CYWebPolicyDecision) decision;
145- (bool) decided;
146- (bool) decide;
147
3c83edee
RP
148@end
149
c2292b80 150@implementation CYWebPolicyDecisionMediator
3c83edee 151
c2292b80
JF
152- (id) initWithListener:(id<WebPolicyDecisionListener>)listener {
153 if ((self = [super init]) != nil) {
154 listener_ = listener;
155 } return self;
156}
3c83edee 157
c2292b80
JF
158- (CYWebPolicyDecision) decision {
159 return decision_;
160}
161
162- (bool) decided {
163 return decision_ != CYWebPolicyDecisionUnknown;
164}
165
166- (bool) decide {
167 switch (decision_) {
168 case CYWebPolicyDecisionUnknown:
169 default:
170 return false;
171
172 case CYWebPolicyDecisionDownload: [listener_ download]; break;
173 case CYWebPolicyDecisionIgnore: [listener_ ignore]; break;
174 case CYWebPolicyDecisionUse: [listener_ use]; break;
175 }
176
177 return true;
178}
179
180- (void) download {
181 decision_ = CYWebPolicyDecisionDownload;
3c83edee
RP
182}
183
c2292b80
JF
184- (void) ignore {
185 decision_ = CYWebPolicyDecisionIgnore;
186}
187
188- (void) use {
189 decision_ = CYWebPolicyDecisionUse;
3c83edee
RP
190}
191
192@end
c2292b80 193// }}}
3c83edee 194
c2292b80 195@implementation CYWebView : UIWebView
4825688a 196
c2292b80
JF
197- (id) initWithFrame:(CGRect)frame {
198 if ((self = [super initWithFrame:frame]) != nil) {
199 } return self;
200}
4825688a 201
c2292b80
JF
202- (void) dealloc {
203 [super dealloc];
204}
bde2d79b 205
c2292b80
JF
206- (id<CYWebViewDelegate>) delegate {
207 return (id<CYWebViewDelegate>) [super delegate];
208}
bde2d79b 209
c2292b80
JF
210/*- (WebView *) webView:(WebView *)view createWebViewWithRequest:(NSURLRequest *)request {
211 NSLog(@"createWebViewWithRequest:%@", request);
212 WebView *created(nil); // XXX
213 if (created == nil && [super respondsToSelector:@selector(webView:createWebViewWithRequest:)])
214 return [super webView:view createWebViewWithRequest:request];
215 else
216 return created;
217}*/
4825688a 218
c2292b80
JF
219- (void) webView:(WebView *)view decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
220 CYWebPolicyDecisionMediator *mediator([[[CYWebPolicyDecisionMediator alloc] initWithListener:listener] autorelease]);
221 [[self delegate] webView:view decidePolicyForNavigationAction:action request:request frame:frame decisionListener:mediator];
222 if (![mediator decided] && [super respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)])
223 [super webView:view decidePolicyForNavigationAction:action request:request frame:frame decisionListener:mediator];
224 [mediator decide];
225}
4825688a 226
c2292b80
JF
227- (void) webView:(WebView *)view decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
228 CYWebPolicyDecisionMediator *mediator([[[CYWebPolicyDecisionMediator alloc] initWithListener:listener] autorelease]);
229 [[self delegate] webView:view decidePolicyForNewWindowAction:action request:request newFrameName:frame decisionListener:mediator];
230 if (![mediator decided] && [super respondsToSelector:@selector(webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:)])
231 [super webView:view decidePolicyForNewWindowAction:action request:request newFrameName:frame decisionListener:mediator];
232 [mediator decide];
233}
5d8f1006 234
c2292b80
JF
235- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
236 [[self delegate] webView:view didClearWindowObject:window forFrame:frame];
237 if ([super respondsToSelector:@selector(webView:didClearWindowObject:forFrame:)])
238 [super webView:view didClearWindowObject:window forFrame:frame];
239}
d4f84362 240
c2292b80
JF
241- (void) webView:(WebView *)view didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
242 [[self delegate] webView:view didFailLoadWithError:error forFrame:frame];
243 if ([super respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)])
244 [super webView:view didFailLoadWithError:error forFrame:frame];
4825688a
JF
245}
246
c2292b80
JF
247- (void) webView:(WebView *)view didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
248 [[self delegate] webView:view didFailProvisionalLoadWithError:error forFrame:frame];
249 if ([super respondsToSelector:@selector(webView:didFailProvisionalLoadWithError:forFrame:)])
250 [super webView:view didFailProvisionalLoadWithError:error forFrame:frame];
251}
5a5c1e4b 252
c2292b80
JF
253- (void) webView:(WebView *)view didFinishLoadForFrame:(WebFrame *)frame {
254 [[self delegate] webView:view didFinishLoadForFrame:frame];
255 if ([super respondsToSelector:@selector(webView:didFinishLoadForFrame:)])
256 [super webView:view didFinishLoadForFrame:frame];
257}
bde2d79b 258
c2292b80
JF
259- (void) webView:(WebView *)view didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
260 [[self delegate] webView:view didReceiveTitle:title forFrame:frame];
261 if ([super respondsToSelector:@selector(webView:didReceiveTitle:forFrame:)])
262 [super webView:view didReceiveTitle:title forFrame:frame];
263}
9d7f5e2d 264
c2292b80
JF
265- (void) webView:(WebView *)view didStartProvisionalLoadForFrame:(WebFrame *)frame {
266 [[self delegate] webView:view didStartProvisionalLoadForFrame:frame];
267 if ([super respondsToSelector:@selector(webView:didStartProvisionalLoadForFrame:)])
268 [super webView:view didStartProvisionalLoadForFrame:frame];
269}
bde2d79b 270
c2292b80
JF
271- (NSURLRequest *) webView:(WebView *)view resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source {
272 if ([super respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:)])
273 request = [super webView:view resource:identifier willSendRequest:request redirectResponse:response fromDataSource:source];
274 return [[self delegate] webView:view resource:identifier willSendRequest:request redirectResponse:response fromDataSource:source];
275}
9d7f5e2d 276
c2292b80
JF
277- (void) webView:(WebView *)view runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
278 if ([super respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:)])
279 if ([[self delegate] webView:view shouldRunJavaScriptAlertPanelWithMessage:message initiatedByFrame:frame])
280 [super webView:view runJavaScriptAlertPanelWithMessage:message initiatedByFrame:frame];
281}
bde2d79b 282
c2292b80
JF
283- (BOOL) webView:(WebView *)view runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
284 if ([super respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:)])
285 if ([[self delegate] webView:view shouldRunJavaScriptConfirmPanelWithMessage:message initiatedByFrame:frame])
286 return [super webView:view runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:frame];
287 return NO;
288}
d4f84362 289
c2292b80
JF
290- (NSString *) webView:(WebView *)view runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)text initiatedByFrame:(WebFrame *)frame {
291 if ([super respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:)])
292 if ([[self delegate] webView:view shouldRunJavaScriptTextInputPanelWithPrompt:prompt defaultText:text initiatedByFrame:frame])
293 return [super webView:view runJavaScriptTextInputPanelWithPrompt:prompt defaultText:text initiatedByFrame:frame];
294 return nil;
295}
d4f84362 296
c2292b80
JF
297- (void) webViewClose:(WebView *)view {
298 [[self delegate] webViewClose:view];
299 if ([super respondsToSelector:@selector(webViewClose:)])
300 [super webViewClose:view];
301}
bde2d79b 302
c2292b80 303@end
9d7f5e2d 304
c2292b80
JF
305#define ShowInternals 0
306#define LogBrowser 1
bde2d79b 307
c2292b80 308#define lprintf(args...) fprintf(stderr, args)
bde2d79b 309
c2292b80
JF
310@implementation BrowserController
311
312#if ShowInternals
313#include "UICaboodle/UCInternal.h"
bde2d79b
JF
314#endif
315
c2292b80
JF
316+ (void) _initialize {
317 [WebPreferences _setInitialDefaultTextEncodingToSystemEncoding];
318}
319
320- (void) dealloc {
321#if LogBrowser
322 NSLog(@"[BrowserController dealloc]");
323#endif
324
325 [webview_ setDelegate:nil];
326
327 [indirect_ setDelegate:nil];
bde2d79b
JF
328 [indirect_ release];
329
c2292b80
JF
330 if (challenge_ != nil)
331 [challenge_ release];
9d7f5e2d 332
c2292b80 333 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
bde2d79b 334
c2292b80
JF
335 if (custom_ != nil)
336 [custom_ release];
bde2d79b
JF
337 if (style_ != nil)
338 [style_ release];
c2292b80 339
bde2d79b
JF
340 if (function_ != nil)
341 [function_ release];
1ce016d4
JF
342 if (closer_ != nil)
343 [closer_ release];
bde2d79b 344
0fc560b6
JF
345 if (sensitive_ != nil)
346 [sensitive_ release];
bde2d79b
JF
347 if (title_ != nil)
348 [title_ release];
c2292b80
JF
349
350 [reloaditem_ release];
351 [loadingitem_ release];
352
353 [indicator_ release];
f99f86e2 354
bde2d79b
JF
355 [super dealloc];
356}
357
358- (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
359 [self loadRequest:[NSURLRequest
360 requestWithURL:url
361 cachePolicy:policy
daf7f6e2 362 timeoutInterval:120.0
bde2d79b
JF
363 ]];
364}
365
366- (void) loadURL:(NSURL *)url {
367 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
368}
369
bde2d79b 370- (void) loadRequest:(NSURLRequest *)request {
f4772bd1 371 error_ = false;
9d7f5e2d
JF
372
373 WebThreadLock();
c2292b80 374 [webview_ loadRequest:request];
9d7f5e2d 375 WebThreadUnlock();
bde2d79b
JF
376}
377
378- (void) reloadURL {
bde2d79b
JF
379 if (request_ == nil)
380 return;
381
382 if ([request_ HTTPBody] == nil && [request_ HTTPBodyStream] == nil)
f4772bd1 383 [self loadRequest:request_];
bde2d79b 384 else {
afcd8bef 385 UIAlertView *alert = [[[UIAlertView alloc]
61b13cae 386 initWithTitle:UCLocalize("RESUBMIT_FORM")
afcd8bef 387 message:nil
bde2d79b 388 delegate:self
afcd8bef
GP
389 cancelButtonTitle:UCLocalize("CANCEL")
390 otherButtonTitles:UCLocalize("SUBMIT"), nil
bde2d79b 391 ] autorelease];
c2292b80 392
afcd8bef
GP
393 [alert setContext:@"submit"];
394 [alert show];
bde2d79b
JF
395 }
396}
397
bde2d79b 398- (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
c2292b80
JF
399 if (custom_ != nil)
400 [custom_ autorelease];
401 custom_ = button == nil ? nil : [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain];
bde2d79b
JF
402
403 if (style_ != nil)
404 [style_ autorelease];
405 style_ = style == nil ? nil : [style retain];
406
407 if (function_ != nil)
408 [function_ autorelease];
409 function_ = function == nil ? nil : [function retain];
1ce016d4 410
f99f86e2 411 [self applyRightButton];
bde2d79b
JF
412}
413
414- (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
c2292b80
JF
415 if (custom_ != nil)
416 [custom_ autorelease];
417 custom_ = button == nil ? nil : [button retain];
bde2d79b
JF
418
419 if (style_ != nil)
420 [style_ autorelease];
421 style_ = style == nil ? nil : [style retain];
422
423 if (function_ != nil)
424 [function_ autorelease];
425 function_ = function == nil ? nil : [function retain];
1ce016d4 426
f99f86e2 427 [self applyRightButton];
bde2d79b 428}
bde2d79b 429
9d7f5e2d
JF
430- (void) setPopupHook:(id)function {
431 if (closer_ != nil)
432 [closer_ autorelease];
433 closer_ = function == nil ? nil : [function retain];
434}
435
c2292b80
JF
436- (void) setViewportWidth:(float)width {
437 width_ = width != 0 ? width : [[self class] defaultWidth];
438 [[webview_ _documentView] setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
bde2d79b
JF
439}
440
c2292b80
JF
441- (void) _openMailToURL:(NSURL *)url {
442 [[UIApplication sharedApplication] openURL:url];// asPanel:YES];
bde2d79b
JF
443}
444
c2292b80
JF
445- (bool) _allowJavaScriptPanel {
446 return true;
bde2d79b
JF
447}
448
c2292b80
JF
449- (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame {
450 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
451 [self _didFinishLoading];
bde2d79b 452
c2292b80 453 if ([error code] == NSURLErrorCancelled)
bde2d79b
JF
454 return;
455
9d7f5e2d 456 if ([frame parentFrame] == nil) {
c2292b80
JF
457 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
458 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
459 [[error localizedDescription] stringByAddingPercentEscapes]
460 ]]];
bde2d79b 461
c2292b80
JF
462 error_ = true;
463 }
464}
9d7f5e2d 465
c2292b80
JF
466// CYWebViewDelegate {{{
467- (void) webView:(WebView *)view decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
468#if LogBrowser
469 NSLog(@"decidePolicyForNavigationAction:%@ request:%@ frame:%@", action, request, frame);
470#endif
d4f84362 471
c2292b80
JF
472 if (!error_ && [frame parentFrame] == nil) {
473 if (request_ != nil)
474 [request_ autorelease];
475 if (request == nil)
476 request_ = nil;
d4f84362 477 else
c2292b80 478 request_ = [request retain];
9d7f5e2d 479 }
bde2d79b
JF
480}
481
c2292b80
JF
482- (void) webView:(WebView *)view decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
483#if LogBrowser
484 NSLog(@"decidePolicyForNewWindowAction:%@ request:%@ newFrameName:%@", action, request, frame);
485#endif
c8e3b4b3 486
c2292b80
JF
487 NSURL *url([request URL]);
488 if (url == nil)
489 return;
f99f86e2 490
c2292b80
JF
491 if ([frame isEqualToString:@"_open"])
492 [delegate_ openURL:url];
c8e3b4b3 493
c2292b80
JF
494 NSString *scheme([[url scheme] lowercaseString]);
495 if ([scheme isEqualToString:@"mailto"])
496 [self _openMailToURL:url];
3db9f43c 497
c2292b80 498 CYViewController *page([delegate_ pageForURL:url hasTag:NULL]);
b36becfc 499
c2292b80
JF
500 if (page == nil) {
501 BrowserController *browser([[[class_ alloc] init] autorelease]);
502 [browser loadRequest:request];
503 page = browser;
f99f86e2 504 }
161c1078 505
c2292b80 506 [page setDelegate:delegate_];
9ae52960 507
c2292b80
JF
508 if (![frame isEqualToString:@"_popup"]) {
509 [[self navigationItem] setTitle:title_];
9ae52960 510
c2292b80
JF
511 [[self navigationController] pushViewController:page animated:YES];
512 } else {
513 UCNavigationController *navigation([[[UCNavigationController alloc] init] autorelease]);
bde2d79b 514
c2292b80
JF
515 [navigation setHook:indirect_];
516 [navigation setDelegate:delegate_];
bde2d79b 517
c2292b80
JF
518 [navigation setViewControllers:[NSArray arrayWithObject:page]];
519
520 [[page navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
521 initWithTitle:UCLocalize("CLOSE")
522 style:UIBarButtonItemStylePlain
523 target:page
524 action:@selector(close)
525 ] autorelease]];
526
527 [[self navigationController] presentModalViewController:navigation animated:YES];
528 }
bde2d79b 529
c2292b80 530 [listener ignore];
bde2d79b
JF
531}
532
c2292b80 533- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
bde2d79b
JF
534}
535
c2292b80
JF
536- (void) webView:(WebView *)view didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
537#if LogBrowser
538 NSLog(@"didFailLoadWithError:%@ forFrame:%@", error, frame);
539#endif
540
541 [self _didFailWithError:error forFrame:frame];
bde2d79b
JF
542}
543
c2292b80
JF
544- (void) webView:(WebView *)view didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
545#if LogBrowser
546 NSLog(@"didFailProvisionalLoadWithError:%@ forFrame:%@", error, frame);
547#endif
548
549 [self _didFailWithError:error forFrame:frame];
bde2d79b
JF
550}
551
c2292b80 552- (void) webView:(WebView *)view didFinishLoadForFrame:(WebFrame *)frame {
b452841e 553 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
bde2d79b 554
9d7f5e2d 555 if ([frame parentFrame] == nil) {
bde2d79b
JF
556 if (DOMDocument *document = [frame DOMDocument])
557 if (DOMNodeList<NSFastEnumeration> *bodies = [document getElementsByTagName:@"body"])
485f16d6 558 for (DOMHTMLBodyElement *body in (id) bodies) {
bde2d79b
JF
559 DOMCSSStyleDeclaration *style([document getComputedStyle:body pseudoElement:nil]);
560
561 bool colored(false);
562
563 if (DOMCSSPrimitiveValue *color = static_cast<DOMCSSPrimitiveValue *>([style getPropertyCSSValue:@"background-color"])) {
f4772bd1
JF
564 if ([color primitiveType] == DOM_CSS_RGBCOLOR) {
565 DOMRGBColor *rgb([color getRGBColorValue]);
566
567 float red([[rgb red] getFloatValue:DOM_CSS_NUMBER]);
568 float green([[rgb green] getFloatValue:DOM_CSS_NUMBER]);
569 float blue([[rgb blue] getFloatValue:DOM_CSS_NUMBER]);
570 float alpha([[rgb alpha] getFloatValue:DOM_CSS_NUMBER]);
571
572 UIColor *uic(nil);
573
574 if (red == 0xc7 && green == 0xce && blue == 0xd5)
aaa0be19 575 uic = [UIColor groupTableViewBackgroundColor];
f4772bd1
JF
576 else if (alpha != 0)
577 uic = [UIColor
578 colorWithRed:(red / 255)
579 green:(green / 255)
580 blue:(blue / 255)
581 alpha:alpha
582 ];
583
584 if (uic != nil) {
585 colored = true;
586 [scroller_ setBackgroundColor:uic];
587 }
bde2d79b
JF
588 }
589 }
590
591 if (!colored)
aaa0be19 592 [scroller_ setBackgroundColor:[UIColor groupTableViewBackgroundColor]];
bde2d79b
JF
593 break;
594 }
595 }
596
c2292b80 597 [self _didFinishLoading];
bde2d79b
JF
598}
599
c2292b80
JF
600- (void) webView:(WebView *)view didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
601 if ([frame parentFrame] != nil)
602 return;
9d7f5e2d 603
c2292b80
JF
604 title_ = [title retain];
605 [[self navigationItem] setTitle:title_];
606}
bde2d79b 607
c2292b80
JF
608- (void) webView:(WebView *)view didStartProvisionalLoadForFrame:(WebFrame *)frame {
609 [loading_ addObject:[NSValue valueWithNonretainedObject:frame]];
b452841e 610
9d7f5e2d 611 if ([frame parentFrame] == nil) {
c2292b80
JF
612 CYRelease(title_);
613 CYRelease(custom_);
614 CYRelease(style_);
615 CYRelease(function_);
616 CYRelease(closer_);
617
618 // XXX: do we still need to do this?
619 [[self navigationItem] setTitle:nil];
9d7f5e2d 620 }
f4772bd1 621
c2292b80 622 [self _didStartLoading];
9d7f5e2d
JF
623}
624
c2292b80
JF
625- (NSURLRequest *) webView:(WebView *)view resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source {
626 return request;
bde2d79b
JF
627}
628
c2292b80
JF
629- (bool) webView:(WebView *)view shouldRunJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
630 return [self _allowJavaScriptPanel];
bde2d79b
JF
631}
632
c2292b80
JF
633- (bool) webView:(WebView *)view shouldRunJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
634 return [self _allowJavaScriptPanel];
d4f84362
JF
635}
636
c2292b80
JF
637- (bool) webView:(WebView *)view shouldRunJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)text initiatedByFrame:(WebFrame *)frame {
638 return [self _allowJavaScriptPanel];
d4f84362
JF
639}
640
c2292b80
JF
641- (void) webViewClose:(WebView *)view {
642 [self close];
d4f84362 643}
c2292b80 644// }}}
d4f84362 645
c2292b80
JF
646- (void) close {
647 [[self navigationController] dismissModalViewControllerAnimated:YES];
d4f84362
JF
648}
649
c2292b80
JF
650- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button {
651 NSString *context([alert context]);
d4f84362 652
c2292b80
JF
653 if ([context isEqualToString:@"sensitive"]) {
654 switch (button) {
655 case 1:
656 sensitive_ = [NSNumber numberWithBool:YES];
657 break;
d4f84362 658
c2292b80
JF
659 case 2:
660 sensitive_ = [NSNumber numberWithBool:NO];
661 break;
662 }
d4f84362 663
c2292b80
JF
664 [alert dismissWithClickedButtonIndex:-1 animated:YES];
665 } else if ([context isEqualToString:@"challenge"]) {
666 id<NSURLAuthenticationChallengeSender> sender([challenge_ sender]);
9d7f5e2d 667
c2292b80
JF
668 switch (button) {
669 case 1: {
670 NSString *username([[alert textFieldAtIndex:0] text]);
671 NSString *password([[alert textFieldAtIndex:1] text]);
d4f84362 672
c2292b80 673 NSURLCredential *credential([NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]);
d4f84362 674
c2292b80
JF
675 [sender useCredential:credential forAuthenticationChallenge:challenge_];
676 } break;
d4f84362 677
c2292b80
JF
678 case 2:
679 [sender cancelAuthenticationChallenge:challenge_];
680 break;
d4f84362 681
c2292b80
JF
682 _nodefault
683 }
d4f84362 684
c2292b80
JF
685 [challenge_ release];
686 challenge_ = nil;
d4f84362 687
c2292b80
JF
688 [alert dismissWithClickedButtonIndex:-1 animated:YES];
689 } else if ([context isEqualToString:@"submit"]) {
690 switch (button) {
691 case 1:
692 break;
d4f84362 693
c2292b80
JF
694 case 2:
695 if (request_ != nil) {
696 WebThreadLock();
697 [webview_ loadRequest:request_];
698 WebThreadUnlock();
699 }
700 break;
d4f84362 701
c2292b80
JF
702 _nodefault
703 }
d4f84362 704
c2292b80
JF
705 [alert dismissWithClickedButtonIndex:-1 animated:YES];
706 }
d4f84362
JF
707}
708
c2292b80
JF
709- (UIBarButtonItemStyle) rightButtonStyle {
710 if (style_ == nil) normal:
711 return UIBarButtonItemStylePlain;
712 else if ([style_ isEqualToString:@"Normal"])
713 return UIBarButtonItemStylePlain;
714 else if ([style_ isEqualToString:@"Highlighted"])
715 return UIBarButtonItemStyleDone;
716 else goto normal;
d4f84362
JF
717}
718
c2292b80
JF
719- (UIBarButtonItem *) customButton {
720 return [[[UIBarButtonItem alloc]
721 initWithTitle:custom_
722 style:[self rightButtonStyle]
723 target:self
724 action:@selector(customButtonClicked)
725 ] autorelease];
9d7f5e2d
JF
726}
727
c2292b80
JF
728- (UIBarButtonItem *) rightButton {
729 return reloaditem_;
dcc55b8b
JF
730}
731
c2292b80
JF
732- (void) applyLoadingTitle {
733 [[self navigationItem] setTitle:UCLocalize("LOADING")];
9d7f5e2d
JF
734}
735
c2292b80
JF
736- (void) applyRightButton {
737 if ([self isLoading]) {
738 [[self navigationItem] setRightBarButtonItem:loadingitem_ animated:YES];
739 // XXX: why do we do this again here?
740 [[loadingitem_ view] addSubview:indicator_];
741 [self applyLoadingTitle];
742 } else if (custom_ != nil) {
743 [[self navigationItem] setRightBarButtonItem:[self customButton] animated:YES];
744 } else {
745 [[self navigationItem] setRightBarButtonItem:[self rightButton] animated:YES];
746 }
9d7f5e2d
JF
747}
748
c2292b80
JF
749- (void) _didStartLoading {
750 [self applyRightButton];
9d7f5e2d
JF
751}
752
c2292b80
JF
753- (void) _didFinishLoading {
754 if ([loading_ count] != 0)
755 return;
756
757 [self applyRightButton];
758
759 // XXX: wtf?
760 if (![self isLoading])
761 [[self navigationItem] setTitle:title_];
9d7f5e2d
JF
762}
763
c2292b80
JF
764- (bool) isLoading {
765 return [loading_ count] != 0;
9d7f5e2d
JF
766}
767
9ae52960
GP
768- (id) initWithWidth:(float)width ofClass:(Class)_class {
769 if ((self = [super init]) != nil) {
85021801 770 class_ = _class;
c2292b80 771 loading_ = [[NSMutableSet alloc] initWithCapacity:5];
f99f86e2 772
c2292b80 773 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
9d7f5e2d 774
c2292b80
JF
775 webview_ = [[[CYWebView alloc] initWithFrame:[[self view] bounds]] autorelease];
776 [webview_ setDelegate:self];
777 [self setView:webview_];
bde2d79b 778
c2292b80
JF
779 if ([webview_ respondsToSelector:@selector(setDataDetectorTypes:)])
780 [webview_ setDataDetectorTypes:UIDataDetectorTypeAutomatic];
781 else
782 [webview_ setDetectsPhoneNumbers:NO];
bde2d79b 783
c2292b80 784 [webview_ setScalesPageToFit:YES];
bde2d79b 785
c2292b80 786 UIWebDocumentView *document([webview_ _documentView]);
4825688a 787
c2292b80
JF
788 // XXX: I think this improves scrolling; the hardcoded-ness sucks
789 [document setTileSize:CGSizeMake(320, 500)];
4825688a 790
c2292b80
JF
791 [document setBackgroundColor:[UIColor clearColor]];
792 [document setDrawsBackground:NO];
4825688a 793
c2292b80
JF
794 WebView *webview([document webView]);
795 WebPreferences *preferences([webview preferences]);
bde2d79b 796
c2292b80
JF
797 // XXX: I have no clue if I actually /want/ this modification
798 if ([webview respondsToSelector:@selector(_setLayoutInterval:)])
799 [webview _setLayoutInterval:0];
800 else if ([preferences respondsToSelector:@selector(_setLayoutInterval:)])
801 [preferences _setLayoutInterval:0];
bde2d79b 802
c2292b80
JF
803 [preferences setCacheModel:WebCacheModelDocumentBrowser];
804 [preferences setOfflineWebApplicationCacheEnabled:YES];
bde2d79b 805
c2292b80
JF
806 if ([webview_ respondsToSelector:@selector(_scrollView)]) {
807 scroller_ = [webview_ _scrollView];
bde2d79b 808
c2292b80
JF
809 [scroller_ setDirectionalLockEnabled:YES];
810 [scroller_ setDecelerationRate:UIScrollViewDecelerationRateNormal];
811 [scroller_ setDelaysContentTouches:NO];
bde2d79b 812
c2292b80
JF
813 [scroller_ setCanCancelContentTouches:YES];
814 } else if ([webview_ respondsToSelector:@selector(_scroller)]) {
815 UIScroller *scroller([webview_ _scroller]);
816 scroller_ = (UIScrollView *) scroller;
bde2d79b 817
c2292b80
JF
818 [scroller setDirectionalScrolling:YES];
819 [scroller setScrollDecelerationFactor:UIScrollViewDecelerationRateNormal]; /* 0.989324 */
820 [scroller setScrollHysteresis:0]; /* 8 */
7b00c562 821
c2292b80 822 [scroller setThumbDetectionEnabled:NO];
4825688a 823
c2292b80
JF
824 // use NO with UIApplicationUseLegacyEvents(YES)
825 [scroller setEventMode:YES];
4825688a 826
c2292b80
JF
827 // XXX: this is handled by setBounces, right?
828 //[scroller setAllowsRubberBanding:YES];
bde2d79b 829 }
f99f86e2 830
c2292b80
JF
831 [scroller_ setFixedBackgroundPattern:YES];
832 [scroller_ setBackgroundColor:[UIColor groupTableViewBackgroundColor]];
833 [scroller_ setClipsSubviews:YES];
9d7f5e2d 834
c2292b80
JF
835 [scroller_ setBounces:YES];
836 [scroller_ setScrollingEnabled:YES];
837 [scroller_ setShowBackgroundShadow:NO];
9d7f5e2d 838
c2292b80 839 [self setViewportWidth:width];
f99f86e2
JF
840
841 reloaditem_ = [[UIBarButtonItem alloc]
842 initWithTitle:UCLocalize("RELOAD")
843 style:[self rightButtonStyle]
844 target:self
845 action:@selector(reloadButtonClicked)
846 ];
847
848 loadingitem_ = [[UIBarButtonItem alloc]
849 initWithTitle:@" "
850 style:UIBarButtonItemStylePlain
851 target:self
852 action:@selector(reloadButtonClicked)
853 ];
c2292b80
JF
854
855 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite];
856 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(15, 5, indsize.width, indsize.height)];
857 [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite];
858 [indicator_ startAnimation];
f99f86e2 859 [[loadingitem_ view] addSubview:indicator_];
bde2d79b 860
c2292b80 861 [webview_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
d3bef7bc 862 [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
bde2d79b
JF
863 } return self;
864}
865
9ae52960
GP
866- (id) initWithWidth:(float)width {
867 return [self initWithWidth:width ofClass:[self class]];
85021801
JF
868}
869
9ae52960
GP
870- (id) init {
871 return [self initWithWidth:0];
7b00c562
JF
872}
873
c2292b80
JF
874- (void) didDismissModalViewController {
875 if (closer_ != nil)
876 [self callFunction:closer_];
bde2d79b
JF
877}
878
1ce016d4 879- (void) callFunction:(WebScriptObject *)function {
9d7f5e2d
JF
880 WebThreadLock();
881
c2292b80 882 WebView *webview([[webview_ _documentView] webView]);
1ce016d4 883 WebFrame *frame([webview mainFrame]);
1e4922b8
JF
884 WebPreferences *preferences([webview preferences]);
885
886 bool maybe([preferences javaScriptCanOpenWindowsAutomatically]);
887 [preferences setJavaScriptCanOpenWindowsAutomatically:NO];
bde2d79b 888
1e4922b8 889 /*id _private(MSHookIvar<id>(webview, "_private"));
1ce016d4
JF
890 WebCore::Page *page(_private == nil ? NULL : MSHookIvar<WebCore::Page *>(_private, "page"));
891 WebCore::Settings *settings(page == NULL ? NULL : page->settings());
bde2d79b 892
1ce016d4
JF
893 bool no;
894 if (settings == NULL)
895 no = 0;
896 else {
897 no = settings->JavaScriptCanOpenWindowsAutomatically();
898 settings->setJavaScriptCanOpenWindowsAutomatically(true);
1e4922b8 899 }*/
1ce016d4 900
9ae52960 901 if (UIWindow *window = [[self view] window])
61b13cae
JF
902 if (UIResponder *responder = [window firstResponder])
903 [responder resignFirstResponder];
904
1ce016d4
JF
905 JSObjectRef object([function JSObject]);
906 JSGlobalContextRef context([frame globalContext]);
907 JSObjectCallAsFunction(context, object, NULL, 0, NULL, NULL);
908
1e4922b8
JF
909 /*if (settings != NULL)
910 settings->setJavaScriptCanOpenWindowsAutomatically(no);*/
911
912 [preferences setJavaScriptCanOpenWindowsAutomatically:maybe];
9d7f5e2d
JF
913
914 WebThreadUnlock();
1ce016d4
JF
915}
916
161c1078 917- (void) reloadButtonClicked {
1ce016d4
JF
918 [self reloadURL];
919}
920
b98e849f
DH
921- (void) _customButtonClicked {
922 [self reloadButtonClicked];
923}
924
161c1078 925- (void) customButtonClicked {
9d7f5e2d
JF
926#if !AlwaysReload
927 if (function_ != nil)
1ce016d4 928 [self callFunction:function_];
9d7f5e2d
JF
929 else
930#endif
b98e849f 931 [self _customButtonClicked];
bde2d79b
JF
932}
933
7b00c562
JF
934+ (float) defaultWidth {
935 return 980;
936}
937
3db9f43c 938@end