]> git.saurik.com Git - cydia.git/blob - UICaboodle/BrowserView.mm
Totally reimplemented BrowserController in terms of UIWebView.
[cydia.git] / UICaboodle / BrowserView.mm
1 #include <UIKit/UIKit.h>
2 #include "iPhonePrivate.h"
3
4 #include "UCPlatform.h"
5
6 #include <UICaboodle/BrowserView.h>
7 #include <UICaboodle/UCLocalize.h>
8
9 //#include <QuartzCore/CALayer.h>
10 // XXX: fix the minimum requirement
11 extern NSString * const kCAFilterNearest;
12
13 #include <WebCore/WebCoreThread.h>
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>
26
27 #include "substrate.h"
28
29 #define ForSaurik 0
30
31 template <typename Type_>
32 static inline void CYRelease(Type_ &value) {
33 if (value != nil) {
34 [value release];
35 value = nil;
36 }
37 }
38
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
48
49 /* Indirect Delegate {{{ */
50 @interface IndirectDelegate : NSObject <
51 HookProtocol
52 > {
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
71 - (void) didDismissModalViewController {
72 if (delegate_ != nil)
73 return [delegate_ didDismissModalViewController];
74 }
75
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
83 - (BOOL) respondsToSelector:(SEL)sel {
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];
89 }
90
91 - (NSMethodSignature *) methodSignatureForSelector:(SEL)sel {
92 if (NSMethodSignature *method = [super methodSignatureForSelector:sel])
93 return method;
94 //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel));
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
111 @implementation WebScriptObject (UICaboodle)
112
113 - (NSUInteger) count {
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
127 // CYWebPolicyDecision* {{{
128 enum 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_;
140 }
141
142 - (id) initWithListener:(id<WebPolicyDecisionListener>)listener;
143
144 - (CYWebPolicyDecision) decision;
145 - (bool) decided;
146 - (bool) decide;
147
148 @end
149
150 @implementation CYWebPolicyDecisionMediator
151
152 - (id) initWithListener:(id<WebPolicyDecisionListener>)listener {
153 if ((self = [super init]) != nil) {
154 listener_ = listener;
155 } return self;
156 }
157
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;
182 }
183
184 - (void) ignore {
185 decision_ = CYWebPolicyDecisionIgnore;
186 }
187
188 - (void) use {
189 decision_ = CYWebPolicyDecisionUse;
190 }
191
192 @end
193 // }}}
194
195 @implementation CYWebView : UIWebView
196
197 - (id) initWithFrame:(CGRect)frame {
198 if ((self = [super initWithFrame:frame]) != nil) {
199 } return self;
200 }
201
202 - (void) dealloc {
203 [super dealloc];
204 }
205
206 - (id<CYWebViewDelegate>) delegate {
207 return (id<CYWebViewDelegate>) [super delegate];
208 }
209
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 }*/
218
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 }
226
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 }
234
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 }
240
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];
245 }
246
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 }
252
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 }
258
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 }
264
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 }
270
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 }
276
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 }
282
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 }
289
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 }
296
297 - (void) webViewClose:(WebView *)view {
298 [[self delegate] webViewClose:view];
299 if ([super respondsToSelector:@selector(webViewClose:)])
300 [super webViewClose:view];
301 }
302
303 @end
304
305 #define ShowInternals 0
306 #define LogBrowser 1
307
308 #define lprintf(args...) fprintf(stderr, args)
309
310 @implementation BrowserController
311
312 #if ShowInternals
313 #include "UICaboodle/UCInternal.h"
314 #endif
315
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];
328 [indirect_ release];
329
330 if (challenge_ != nil)
331 [challenge_ release];
332
333 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
334
335 if (custom_ != nil)
336 [custom_ release];
337 if (style_ != nil)
338 [style_ release];
339
340 if (function_ != nil)
341 [function_ release];
342 if (closer_ != nil)
343 [closer_ release];
344
345 if (sensitive_ != nil)
346 [sensitive_ release];
347 if (title_ != nil)
348 [title_ release];
349
350 [reloaditem_ release];
351 [loadingitem_ release];
352
353 [indicator_ release];
354
355 [super dealloc];
356 }
357
358 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
359 [self loadRequest:[NSURLRequest
360 requestWithURL:url
361 cachePolicy:policy
362 timeoutInterval:120.0
363 ]];
364 }
365
366 - (void) loadURL:(NSURL *)url {
367 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
368 }
369
370 - (void) loadRequest:(NSURLRequest *)request {
371 error_ = false;
372
373 WebThreadLock();
374 [webview_ loadRequest:request];
375 WebThreadUnlock();
376 }
377
378 - (void) reloadURL {
379 if (request_ == nil)
380 return;
381
382 if ([request_ HTTPBody] == nil && [request_ HTTPBodyStream] == nil)
383 [self loadRequest:request_];
384 else {
385 UIAlertView *alert = [[[UIAlertView alloc]
386 initWithTitle:UCLocalize("RESUBMIT_FORM")
387 message:nil
388 delegate:self
389 cancelButtonTitle:UCLocalize("CANCEL")
390 otherButtonTitles:UCLocalize("SUBMIT"), nil
391 ] autorelease];
392
393 [alert setContext:@"submit"];
394 [alert show];
395 }
396 }
397
398 - (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
399 if (custom_ != nil)
400 [custom_ autorelease];
401 custom_ = button == nil ? nil : [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain];
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];
410
411 [self applyRightButton];
412 }
413
414 - (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
415 if (custom_ != nil)
416 [custom_ autorelease];
417 custom_ = button == nil ? nil : [button retain];
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];
426
427 [self applyRightButton];
428 }
429
430 - (void) setPopupHook:(id)function {
431 if (closer_ != nil)
432 [closer_ autorelease];
433 closer_ = function == nil ? nil : [function retain];
434 }
435
436 - (void) setViewportWidth:(float)width {
437 width_ = width != 0 ? width : [[self class] defaultWidth];
438 [[webview_ _documentView] setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
439 }
440
441 - (void) _openMailToURL:(NSURL *)url {
442 [[UIApplication sharedApplication] openURL:url];// asPanel:YES];
443 }
444
445 - (bool) _allowJavaScriptPanel {
446 return true;
447 }
448
449 - (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame {
450 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
451 [self _didFinishLoading];
452
453 if ([error code] == NSURLErrorCancelled)
454 return;
455
456 if ([frame parentFrame] == nil) {
457 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
458 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
459 [[error localizedDescription] stringByAddingPercentEscapes]
460 ]]];
461
462 error_ = true;
463 }
464 }
465
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
471
472 if (!error_ && [frame parentFrame] == nil) {
473 if (request_ != nil)
474 [request_ autorelease];
475 if (request == nil)
476 request_ = nil;
477 else
478 request_ = [request retain];
479 }
480 }
481
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
486
487 NSURL *url([request URL]);
488 if (url == nil)
489 return;
490
491 if ([frame isEqualToString:@"_open"])
492 [delegate_ openURL:url];
493
494 NSString *scheme([[url scheme] lowercaseString]);
495 if ([scheme isEqualToString:@"mailto"])
496 [self _openMailToURL:url];
497
498 CYViewController *page([delegate_ pageForURL:url hasTag:NULL]);
499
500 if (page == nil) {
501 BrowserController *browser([[[class_ alloc] init] autorelease]);
502 [browser loadRequest:request];
503 page = browser;
504 }
505
506 [page setDelegate:delegate_];
507
508 if (![frame isEqualToString:@"_popup"]) {
509 [[self navigationItem] setTitle:title_];
510
511 [[self navigationController] pushViewController:page animated:YES];
512 } else {
513 UCNavigationController *navigation([[[UCNavigationController alloc] init] autorelease]);
514
515 [navigation setHook:indirect_];
516 [navigation setDelegate:delegate_];
517
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 }
529
530 [listener ignore];
531 }
532
533 - (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
534 }
535
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];
542 }
543
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];
550 }
551
552 - (void) webView:(WebView *)view didFinishLoadForFrame:(WebFrame *)frame {
553 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
554
555 if ([frame parentFrame] == nil) {
556 if (DOMDocument *document = [frame DOMDocument])
557 if (DOMNodeList<NSFastEnumeration> *bodies = [document getElementsByTagName:@"body"])
558 for (DOMHTMLBodyElement *body in (id) bodies) {
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"])) {
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)
575 uic = [UIColor groupTableViewBackgroundColor];
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 }
588 }
589 }
590
591 if (!colored)
592 [scroller_ setBackgroundColor:[UIColor groupTableViewBackgroundColor]];
593 break;
594 }
595 }
596
597 [self _didFinishLoading];
598 }
599
600 - (void) webView:(WebView *)view didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
601 if ([frame parentFrame] != nil)
602 return;
603
604 title_ = [title retain];
605 [[self navigationItem] setTitle:title_];
606 }
607
608 - (void) webView:(WebView *)view didStartProvisionalLoadForFrame:(WebFrame *)frame {
609 [loading_ addObject:[NSValue valueWithNonretainedObject:frame]];
610
611 if ([frame parentFrame] == nil) {
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];
620 }
621
622 [self _didStartLoading];
623 }
624
625 - (NSURLRequest *) webView:(WebView *)view resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source {
626 return request;
627 }
628
629 - (bool) webView:(WebView *)view shouldRunJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
630 return [self _allowJavaScriptPanel];
631 }
632
633 - (bool) webView:(WebView *)view shouldRunJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
634 return [self _allowJavaScriptPanel];
635 }
636
637 - (bool) webView:(WebView *)view shouldRunJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)text initiatedByFrame:(WebFrame *)frame {
638 return [self _allowJavaScriptPanel];
639 }
640
641 - (void) webViewClose:(WebView *)view {
642 [self close];
643 }
644 // }}}
645
646 - (void) close {
647 [[self navigationController] dismissModalViewControllerAnimated:YES];
648 }
649
650 - (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button {
651 NSString *context([alert context]);
652
653 if ([context isEqualToString:@"sensitive"]) {
654 switch (button) {
655 case 1:
656 sensitive_ = [NSNumber numberWithBool:YES];
657 break;
658
659 case 2:
660 sensitive_ = [NSNumber numberWithBool:NO];
661 break;
662 }
663
664 [alert dismissWithClickedButtonIndex:-1 animated:YES];
665 } else if ([context isEqualToString:@"challenge"]) {
666 id<NSURLAuthenticationChallengeSender> sender([challenge_ sender]);
667
668 switch (button) {
669 case 1: {
670 NSString *username([[alert textFieldAtIndex:0] text]);
671 NSString *password([[alert textFieldAtIndex:1] text]);
672
673 NSURLCredential *credential([NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]);
674
675 [sender useCredential:credential forAuthenticationChallenge:challenge_];
676 } break;
677
678 case 2:
679 [sender cancelAuthenticationChallenge:challenge_];
680 break;
681
682 _nodefault
683 }
684
685 [challenge_ release];
686 challenge_ = nil;
687
688 [alert dismissWithClickedButtonIndex:-1 animated:YES];
689 } else if ([context isEqualToString:@"submit"]) {
690 switch (button) {
691 case 1:
692 break;
693
694 case 2:
695 if (request_ != nil) {
696 WebThreadLock();
697 [webview_ loadRequest:request_];
698 WebThreadUnlock();
699 }
700 break;
701
702 _nodefault
703 }
704
705 [alert dismissWithClickedButtonIndex:-1 animated:YES];
706 }
707 }
708
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;
717 }
718
719 - (UIBarButtonItem *) customButton {
720 return [[[UIBarButtonItem alloc]
721 initWithTitle:custom_
722 style:[self rightButtonStyle]
723 target:self
724 action:@selector(customButtonClicked)
725 ] autorelease];
726 }
727
728 - (UIBarButtonItem *) rightButton {
729 return reloaditem_;
730 }
731
732 - (void) applyLoadingTitle {
733 [[self navigationItem] setTitle:UCLocalize("LOADING")];
734 }
735
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 }
747 }
748
749 - (void) _didStartLoading {
750 [self applyRightButton];
751 }
752
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_];
762 }
763
764 - (bool) isLoading {
765 return [loading_ count] != 0;
766 }
767
768 - (id) initWithWidth:(float)width ofClass:(Class)_class {
769 if ((self = [super init]) != nil) {
770 class_ = _class;
771 loading_ = [[NSMutableSet alloc] initWithCapacity:5];
772
773 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
774
775 webview_ = [[[CYWebView alloc] initWithFrame:[[self view] bounds]] autorelease];
776 [webview_ setDelegate:self];
777 [self setView:webview_];
778
779 if ([webview_ respondsToSelector:@selector(setDataDetectorTypes:)])
780 [webview_ setDataDetectorTypes:UIDataDetectorTypeAutomatic];
781 else
782 [webview_ setDetectsPhoneNumbers:NO];
783
784 [webview_ setScalesPageToFit:YES];
785
786 UIWebDocumentView *document([webview_ _documentView]);
787
788 // XXX: I think this improves scrolling; the hardcoded-ness sucks
789 [document setTileSize:CGSizeMake(320, 500)];
790
791 [document setBackgroundColor:[UIColor clearColor]];
792 [document setDrawsBackground:NO];
793
794 WebView *webview([document webView]);
795 WebPreferences *preferences([webview preferences]);
796
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];
802
803 [preferences setCacheModel:WebCacheModelDocumentBrowser];
804 [preferences setOfflineWebApplicationCacheEnabled:YES];
805
806 if ([webview_ respondsToSelector:@selector(_scrollView)]) {
807 scroller_ = [webview_ _scrollView];
808
809 [scroller_ setDirectionalLockEnabled:YES];
810 [scroller_ setDecelerationRate:UIScrollViewDecelerationRateNormal];
811 [scroller_ setDelaysContentTouches:NO];
812
813 [scroller_ setCanCancelContentTouches:YES];
814 } else if ([webview_ respondsToSelector:@selector(_scroller)]) {
815 UIScroller *scroller([webview_ _scroller]);
816 scroller_ = (UIScrollView *) scroller;
817
818 [scroller setDirectionalScrolling:YES];
819 [scroller setScrollDecelerationFactor:UIScrollViewDecelerationRateNormal]; /* 0.989324 */
820 [scroller setScrollHysteresis:0]; /* 8 */
821
822 [scroller setThumbDetectionEnabled:NO];
823
824 // use NO with UIApplicationUseLegacyEvents(YES)
825 [scroller setEventMode:YES];
826
827 // XXX: this is handled by setBounces, right?
828 //[scroller setAllowsRubberBanding:YES];
829 }
830
831 [scroller_ setFixedBackgroundPattern:YES];
832 [scroller_ setBackgroundColor:[UIColor groupTableViewBackgroundColor]];
833 [scroller_ setClipsSubviews:YES];
834
835 [scroller_ setBounces:YES];
836 [scroller_ setScrollingEnabled:YES];
837 [scroller_ setShowBackgroundShadow:NO];
838
839 [self setViewportWidth:width];
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 ];
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];
859 [[loadingitem_ view] addSubview:indicator_];
860
861 [webview_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
862 [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
863 } return self;
864 }
865
866 - (id) initWithWidth:(float)width {
867 return [self initWithWidth:width ofClass:[self class]];
868 }
869
870 - (id) init {
871 return [self initWithWidth:0];
872 }
873
874 - (void) didDismissModalViewController {
875 if (closer_ != nil)
876 [self callFunction:closer_];
877 }
878
879 - (void) callFunction:(WebScriptObject *)function {
880 WebThreadLock();
881
882 WebView *webview([[webview_ _documentView] webView]);
883 WebFrame *frame([webview mainFrame]);
884 WebPreferences *preferences([webview preferences]);
885
886 bool maybe([preferences javaScriptCanOpenWindowsAutomatically]);
887 [preferences setJavaScriptCanOpenWindowsAutomatically:NO];
888
889 /*id _private(MSHookIvar<id>(webview, "_private"));
890 WebCore::Page *page(_private == nil ? NULL : MSHookIvar<WebCore::Page *>(_private, "page"));
891 WebCore::Settings *settings(page == NULL ? NULL : page->settings());
892
893 bool no;
894 if (settings == NULL)
895 no = 0;
896 else {
897 no = settings->JavaScriptCanOpenWindowsAutomatically();
898 settings->setJavaScriptCanOpenWindowsAutomatically(true);
899 }*/
900
901 if (UIWindow *window = [[self view] window])
902 if (UIResponder *responder = [window firstResponder])
903 [responder resignFirstResponder];
904
905 JSObjectRef object([function JSObject]);
906 JSGlobalContextRef context([frame globalContext]);
907 JSObjectCallAsFunction(context, object, NULL, 0, NULL, NULL);
908
909 /*if (settings != NULL)
910 settings->setJavaScriptCanOpenWindowsAutomatically(no);*/
911
912 [preferences setJavaScriptCanOpenWindowsAutomatically:maybe];
913
914 WebThreadUnlock();
915 }
916
917 - (void) reloadButtonClicked {
918 [self reloadURL];
919 }
920
921 - (void) _customButtonClicked {
922 [self reloadButtonClicked];
923 }
924
925 - (void) customButtonClicked {
926 #if !AlwaysReload
927 if (function_ != nil)
928 [self callFunction:function_];
929 else
930 #endif
931 [self _customButtonClicked];
932 }
933
934 + (float) defaultWidth {
935 return 980;
936 }
937
938 @end