]> git.saurik.com Git - cydia.git/blame - UICaboodle/BrowserView.mm
Changed the package preferences controller to use UITableView rather than the private...
[cydia.git] / UICaboodle / BrowserView.mm
CommitLineData
3cb572d2
JF
1#include <UICaboodle/BrowserView.h>
2#include <UICaboodle/UCLocalize.h>
61b13cae
JF
3
4#import <QuartzCore/CALayer.h>
5// XXX: fix the minimum requirement
6extern NSString * const kCAFilterNearest;
bde2d79b 7
9d7f5e2d 8#include <WebCore/WebCoreThread.h>
4825688a 9#include <WebKit/WebPreferences-WebPrivate.h>
9d7f5e2d 10
61b13cae
JF
11#include "substrate.h"
12
13bb1e92 13#define ForSaurik 0
017b2b71 14
d3bef7bc
JF
15static bool Wildcat_;
16
5d8f1006
JF
17static CFArrayRef (*$GSSystemCopyCapability)(CFStringRef);
18static CFArrayRef (*$GSSystemGetCapability)(CFStringRef);
d4f84362
JF
19static Class $UIFormAssistant;
20static Class $UIWebBrowserView;
5d8f1006 21
61b13cae
JF
22@interface NSString (UIKit)
23- (NSString *) stringByAddingPercentEscapes;
24@end
25
04700693 26/* Indirect Delegate {{{ */
9d7f5e2d 27@interface IndirectDelegate : NSObject {
04700693
JF
28 _transient volatile id delegate_;
29}
30
31- (void) setDelegate:(id)delegate;
32- (id) initWithDelegate:(id)delegate;
33@end
34
35@implementation IndirectDelegate
36
37- (void) setDelegate:(id)delegate {
38 delegate_ = delegate;
39}
40
41- (id) initWithDelegate:(id)delegate {
42 delegate_ = delegate;
43 return self;
44}
45
9d7f5e2d
JF
46- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
47 if (delegate_ != nil)
48 return [delegate_ webView:sender didClearWindowObject:window forFrame:frame];
49}
50
51- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
52 if (delegate_ != nil)
53 return [delegate_ webView:sender didCommitLoadForFrame:frame];
54}
55
56- (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
57 if (delegate_ != nil)
58 return [delegate_ webView:sender didFailLoadWithError:error forFrame:frame];
59}
60
61- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
62 if (delegate_ != nil)
63 return [delegate_ webView:sender didFailProvisionalLoadWithError:error forFrame:frame];
64}
65
66- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
67 if (delegate_ != nil)
68 return [delegate_ webView:sender didFinishLoadForFrame:frame];
69}
70
71- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
72 if (delegate_ != nil)
73 return [delegate_ webView:sender didReceiveTitle:title forFrame:frame];
74}
75
76- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
77 if (delegate_ != nil)
78 return [delegate_ webView:sender didStartProvisionalLoadForFrame:frame];
79}
80
81- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
82 if (delegate_ != nil)
83 return [delegate_ webView:sender resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:source];
84}
85
86- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
87 if (delegate_ != nil)
88 return [delegate_ webView:sender resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:source];
89 return nil;
90}
91
92- (IMP) methodForSelector:(SEL)sel {
93 if (IMP method = [super methodForSelector:sel])
94 return method;
95 fprintf(stderr, "methodForSelector:[%s] == NULL\n", sel_getName(sel));
96 return NULL;
97}
98
04700693 99- (BOOL) respondsToSelector:(SEL)sel {
9d7f5e2d
JF
100 if ([super respondsToSelector:sel])
101 return YES;
102 // XXX: WebThreadCreateNSInvocation returns nil
103 //fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel));
104 return delegate_ == nil ? NO : [delegate_ respondsToSelector:sel];
04700693
JF
105}
106
107- (NSMethodSignature *) methodSignatureForSelector:(SEL)sel {
9d7f5e2d
JF
108 if (NSMethodSignature *method = [super methodSignatureForSelector:sel])
109 return method;
110 //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel));
04700693
JF
111 if (delegate_ != nil)
112 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
113 return sig;
114 // XXX: I fucking hate Apple so very very bad
115 return [NSMethodSignature signatureWithObjCTypes:"v@:"];
116}
117
118- (void) forwardInvocation:(NSInvocation *)inv {
119 SEL sel = [inv selector];
120 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
121 [inv invokeWithTarget:delegate_];
122}
123
124@end
125/* }}} */
126
61b13cae 127@interface WebView (UICaboodle)
bde2d79b
JF
128- (void) setScriptDebugDelegate:(id)delegate;
129- (void) _setFormDelegate:(id)delegate;
130- (void) _setUIKitDelegate:(id)delegate;
131- (void) setWebMailDelegate:(id)delegate;
132- (void) _setLayoutInterval:(float)interval;
133@end
134
61b13cae 135@implementation WebScriptObject (UICaboodle)
9d7f5e2d
JF
136
137- (unsigned) count {
138 id length([self valueForKey:@"length"]);
139 if ([length respondsToSelector:@selector(intValue)])
140 return [length intValue];
141 else
142 return 0;
143}
144
145- (id) objectAtIndex:(unsigned)index {
146 return [self webScriptValueAtIndex:index];
147}
148
149@end
150
161c1078 151@interface BrowserView : UIView {
3c83edee
RP
152@private
153 UIWebDocumentView *documentView;
154}
155@property (nonatomic, retain) UIWebDocumentView *documentView;
156@end
157
161c1078 158@implementation BrowserView
3c83edee
RP
159
160@synthesize documentView;
161
162- (void)dealloc {
163 [documentView release];
164 [super dealloc];
165}
166
167- (void)layoutSubviews {
168 [super layoutSubviews];
169 if ([documentView respondsToSelector:@selector(setMinimumSize:)])
170 [documentView setMinimumSize:documentView.bounds.size];
171}
172
173@end
174
13bb1e92 175#define ShowInternals 0
9ae52960 176#define LogBrowser 1
4825688a
JF
177
178#define lprintf(args...) fprintf(stderr, args)
179
161c1078 180@implementation BrowserController
bde2d79b 181
5a5c1e4b 182#if ShowInternals
4825688a 183#include "UICaboodle/UCInternal.h"
bde2d79b
JF
184#endif
185
4825688a 186+ (void) _initialize {
9ae52960 187 //[WebView enableWebThread];
4825688a
JF
188
189 WebPreferences *preferences([WebPreferences standardPreferences]);
190 [preferences setCacheModel:WebCacheModelDocumentBrowser];
191 [preferences setOfflineWebApplicationCacheEnabled:YES];
192
193 [WebPreferences _setInitialDefaultTextEncodingToSystemEncoding];
5d8f1006
JF
194
195 $GSSystemCopyCapability = reinterpret_cast<CFArrayRef (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemCopyCapability"));
196 $GSSystemGetCapability = reinterpret_cast<CFArrayRef (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemGetCapability"));
d4f84362
JF
197 $UIFormAssistant = objc_getClass("UIFormAssistant");
198
199 $UIWebBrowserView = objc_getClass("UIWebBrowserView");
d3bef7bc
JF
200 if ($UIWebBrowserView == nil) {
201 Wildcat_ = false;
d4f84362 202 $UIWebBrowserView = objc_getClass("UIWebDocumentView");
d3bef7bc
JF
203 } else {
204 Wildcat_ = true;
205 }
4825688a
JF
206}
207
bde2d79b 208- (void) dealloc {
1ce016d4 209#if LogBrowser
161c1078 210 NSLog(@"[BrowserController dealloc]");
7b00c562 211#endif
5a5c1e4b 212
bde2d79b
JF
213 if (challenge_ != nil)
214 [challenge_ release];
215
9d7f5e2d
JF
216 WebThreadLock();
217
2fd3803f 218 WebView *webview = [document_ webView];
bde2d79b
JF
219 [webview setFrameLoadDelegate:nil];
220 [webview setResourceLoadDelegate:nil];
221 [webview setUIDelegate:nil];
222 [webview setScriptDebugDelegate:nil];
223 [webview setPolicyDelegate:nil];
224
9d7f5e2d 225 /* XXX: these are set by UIWebDocumentView
4825688a 226 [webview setDownloadDelegate:nil];
bde2d79b
JF
227 [webview _setFormDelegate:nil];
228 [webview _setUIKitDelegate:nil];
9d7f5e2d
JF
229 [webview setEditingDelegate:nil];*/
230
231 /* XXX: no one sets this, ever
232 [webview setWebMailDelegate:nil];*/
bde2d79b 233
2fd3803f
JF
234 [document_ setDelegate:nil];
235 [document_ setGestureDelegate:nil];
d4f84362 236
2fd3803f
JF
237 if ([document_ respondsToSelector:@selector(setFormEditingDelegate:)])
238 [document_ setFormEditingDelegate:nil];
d4f84362 239
2fd3803f 240 [document_ setInteractionDelegate:nil];
bde2d79b 241
9d7f5e2d
JF
242 [indirect_ setDelegate:nil];
243
bde2d79b
JF
244 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
245
246 [webview close];
247
248#if RecycleWebViews
2fd3803f
JF
249 [document_ removeFromSuperview];
250 [Documents_ addObject:[document_ autorelease]];
bde2d79b 251#else
2fd3803f 252 [document_ release];
bde2d79b
JF
253#endif
254
bde2d79b
JF
255 [indirect_ release];
256
9d7f5e2d
JF
257 WebThreadUnlock();
258
bde2d79b
JF
259 [scroller_ setDelegate:nil];
260
261 if (button_ != nil)
262 [button_ release];
263 if (style_ != nil)
264 [style_ release];
265 if (function_ != nil)
266 [function_ release];
9d7f5e2d
JF
267 if (finish_ != nil)
268 [finish_ release];
1ce016d4
JF
269 if (closer_ != nil)
270 [closer_ release];
9d7f5e2d
JF
271 if (special_ != nil)
272 [special_ release];
bde2d79b
JF
273
274 [scroller_ release];
275 [indicator_ release];
276 if (confirm_ != nil)
277 [confirm_ release];
0fc560b6
JF
278 if (sensitive_ != nil)
279 [sensitive_ release];
bde2d79b
JF
280 if (title_ != nil)
281 [title_ release];
c8e3b4b3
GP
282 if (reloaditem_ != nil)
283 [reloaditem_ release];
284 if (loadingitem_ != nil)
285 [loadingitem_ release];
286
bde2d79b
JF
287 [super dealloc];
288}
289
290- (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
291 [self loadRequest:[NSURLRequest
292 requestWithURL:url
293 cachePolicy:policy
daf7f6e2 294 timeoutInterval:120.0
bde2d79b
JF
295 ]];
296}
297
298- (void) loadURL:(NSURL *)url {
299 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
300}
301
bde2d79b
JF
302- (void) loadRequest:(NSURLRequest *)request {
303 pushed_ = true;
f4772bd1 304 error_ = false;
9d7f5e2d
JF
305
306 WebThreadLock();
2fd3803f 307 [document_ loadRequest:request];
9d7f5e2d 308 WebThreadUnlock();
bde2d79b
JF
309}
310
311- (void) reloadURL {
bde2d79b
JF
312 if (request_ == nil)
313 return;
314
315 if ([request_ HTTPBody] == nil && [request_ HTTPBodyStream] == nil)
f4772bd1 316 [self loadRequest:request_];
bde2d79b
JF
317 else {
318 UIActionSheet *sheet = [[[UIActionSheet alloc]
61b13cae
JF
319 initWithTitle:UCLocalize("RESUBMIT_FORM")
320 buttons:[NSArray arrayWithObjects:UCLocalize("CANCEL"), UCLocalize("SUBMIT"), nil]
bde2d79b
JF
321 defaultButtonIndex:0
322 delegate:self
323 context:@"submit"
324 ] autorelease];
325
d3bef7bc
JF
326 [sheet setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
327
bde2d79b
JF
328 [sheet setNumberOfRows:1];
329 [sheet popupAlertAnimated:YES];
330 }
331}
332
333- (WebView *) webView {
2fd3803f 334 return [document_ webView];
bde2d79b
JF
335}
336
5a5c1e4b 337- (UIWebDocumentView *) documentView {
2fd3803f 338 return document_;
5a5c1e4b
JF
339}
340
9d7f5e2d
JF
341/* XXX: WebThreadLock? */
342- (void) _fixScroller:(CGRect)bounds {
9ae52960 343 float extra;
d4f84362
JF
344
345 if (!editing_ || $UIFormAssistant == nil)
dcc55b8b
JF
346 extra = 0;
347 else {
d4f84362 348 UIFormAssistant *assistant([$UIFormAssistant sharedFormAssistant]);
dcc55b8b 349 CGRect peripheral([assistant peripheralFrame]);
1ce016d4 350#if LogBrowser
dcc55b8b 351 NSLog(@"per:%f", peripheral.size.height);
5889429e 352#endif
dcc55b8b
JF
353 extra = peripheral.size.height;
354 }
355
356 CGRect subrect([scroller_ frame]);
357 subrect.size.height -= extra;
dcc55b8b 358
d4f84362
JF
359 if ([scroller_ respondsToSelector:@selector(setScrollerIndicatorSubrect:)])
360 [scroller_ setScrollerIndicatorSubrect:subrect];
361
2fd3803f 362 [document_ setValue:[NSValue valueWithSize:NSMakeSize(subrect.size.width, subrect.size.height)] forGestureAttribute:UIGestureAttributeVisibleSize];
5889429e 363
dcc55b8b
JF
364 CGSize size(size_);
365 size.height += extra;
366 [scroller_ setContentSize:size];
5889429e 367
d4f84362
JF
368 if ([scroller_ respondsToSelector:@selector(releaseRubberBandIfNecessary)])
369 [scroller_ releaseRubberBandIfNecessary];
dcc55b8b
JF
370}
371
9d7f5e2d 372- (void) fixScroller {
2fd3803f 373 CGRect bounds([document_ documentBounds]);
e9fde613 374#if TrackResize
9d7f5e2d
JF
375 NSLog(@"_fs:(%f,%f+%f,%f)", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
376#endif
377 [self _fixScroller:bounds];
378}
379
bde2d79b 380- (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
dcc55b8b 381 size_ = frame.size;
e9fde613 382#if TrackResize
5889429e
JF
383 NSLog(@"dsf:(%f,%f+%f,%f)", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
384#endif
9d7f5e2d 385 [self _fixScroller:frame];
bde2d79b
JF
386}
387
388- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
389 [self view:sender didSetFrame:frame];
390}
391
9ae52960 392- (void) pushPage:(UCViewController *)page {
bde2d79b 393 [page setDelegate:delegate_];
9ae52960
GP
394 [[self navigationItem] setTitle:title_];
395 [[self navigationController] pushViewController:page animated:YES];
bde2d79b
JF
396}
397
a55054a2
JF
398- (void) _pushPage {
399 if (pushed_)
400 return;
9d7f5e2d 401 // WTR: [self autorelease];
a55054a2 402 pushed_ = true;
9ae52960 403 [[self navigationController] pushViewController:self animated:YES];
a55054a2
JF
404}
405
9ae52960 406- (void) swapPage:(UCViewController *)page {
5889429e 407 [page setDelegate:delegate_];
9ae52960
GP
408 if (pushed_) [[self navigationController] popViewControllerAnimated:NO];
409
410 [[self navigationController] pushViewController:page animated:NO];
5889429e
JF
411}
412
b8de369a 413- (BOOL) getSpecial:(NSURL *)url swap:(BOOL)swap {
1ce016d4 414#if LogBrowser
a55054a2
JF
415 NSLog(@"getSpecial:%@", url);
416#endif
417
9ae52960 418 if (UCViewController *page = [delegate_ pageForURL:url hasTag:NULL]) {
b8de369a
JF
419 if (swap)
420 [self swapPage:page];
421 else
422 [self pushPage:page];
61b13cae
JF
423
424 return true;
425 } else
426 return false;
bde2d79b
JF
427}
428
4825688a
JF
429- (void) formAssistant:(id)sender didBeginEditingFormNode:(id)node {
430}
431
432- (void) formAssistant:(id)sender didEndEditingFormNode:(id)node {
433 [self fixScroller];
434}
435
5a5c1e4b 436- (void) webViewShow:(WebView *)sender {
5b2d5cf3 437 /* XXX: this is where I cry myself to sleep */
5a5c1e4b
JF
438}
439
7b00c562
JF
440- (bool) _allowJavaScriptPanel {
441 return true;
442}
443
0fc560b6 444- (bool) allowSensitiveRequests {
61b13cae 445 return [self _allowJavaScriptPanel];
0fc560b6
JF
446}
447
448- (void) _promptForSensitive:(NSMutableArray *)array {
449 NSString *name([array objectAtIndex:0]);
450
451 UIActionSheet *sheet = [[[UIActionSheet alloc]
452 initWithTitle:nil
61b13cae 453 buttons:[NSArray arrayWithObjects:UCLocalize("YES"), UCLocalize("NO"), nil]
0fc560b6
JF
454 defaultButtonIndex:0
455 delegate:indirect_
456 context:@"sensitive"
457 ] autorelease];
458
d3bef7bc
JF
459 [sheet setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
460
0fc560b6
JF
461 NSString *host(@"XXX");
462
463 [sheet setNumberOfRows:1];
464 [sheet setBodyText:[NSString stringWithFormat:@"The website at %@ is requesting your phone's %@. This is almost certainly for product licensing purposes. Will you allow this?", host, name]];
465 [sheet popupAlertAnimated:YES];
466
467 NSRunLoop *loop([NSRunLoop currentRunLoop]);
468 NSDate *future([NSDate distantFuture]);
469
470 while (sensitive_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
471
472 NSNumber *sensitive([sensitive_ autorelease]);
473 sensitive_ = nil;
474
475 [self autorelease];
476 [array replaceObjectAtIndex:0 withObject:sensitive];
477}
478
479- (bool) promptForSensitive:(NSString *)name {
480 if (![self allowSensitiveRequests])
481 return false;
482
483 NSMutableArray *array([NSMutableArray arrayWithCapacity:1]);
484 [array addObject:name];
485
486 [self performSelectorOnMainThread:@selector(_promptForSensitive:) withObject:array waitUntilDone:YES];
487 return [[array lastObject] boolValue];
488}
489
bde2d79b 490- (void) webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
263b91b4 491 if (![self _allowJavaScriptPanel])
7b00c562 492 return;
b452841e 493 [self retain];
b456f1c9 494
bde2d79b
JF
495 UIActionSheet *sheet = [[[UIActionSheet alloc]
496 initWithTitle:nil
61b13cae 497 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), nil]
bde2d79b
JF
498 defaultButtonIndex:0
499 delegate:self
500 context:@"alert"
501 ] autorelease];
502
d3bef7bc
JF
503 [sheet setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
504
bde2d79b
JF
505 [sheet setBodyText:message];
506 [sheet popupAlertAnimated:YES];
507}
508
509- (BOOL) webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
7b00c562
JF
510 if (![self _allowJavaScriptPanel])
511 return NO;
b452841e 512 [self retain];
7b00c562 513
bde2d79b
JF
514 UIActionSheet *sheet = [[[UIActionSheet alloc]
515 initWithTitle:nil
61b13cae 516 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), UCLocalize("CANCEL"), nil]
bde2d79b 517 defaultButtonIndex:0
b456f1c9 518 delegate:indirect_
bde2d79b
JF
519 context:@"confirm"
520 ] autorelease];
521
d3bef7bc
JF
522 [sheet setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
523
bde2d79b
JF
524 [sheet setNumberOfRows:1];
525 [sheet setBodyText:message];
526 [sheet popupAlertAnimated:YES];
527
528 NSRunLoop *loop([NSRunLoop currentRunLoop]);
529 NSDate *future([NSDate distantFuture]);
530
531 while (confirm_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
532
533 NSNumber *confirm([confirm_ autorelease]);
534 confirm_ = nil;
b452841e
JF
535
536 [self autorelease];
bde2d79b
JF
537 return [confirm boolValue];
538}
539
7b00c562
JF
540- (void) setAutoPopup:(BOOL)popup {
541 popup_ = popup;
542}
543
9d7f5e2d
JF
544- (void) setSpecial:(id)function {
545 if (special_ != nil)
546 [special_ autorelease];
547 special_ = function == nil ? nil : [function retain];
1ce016d4
JF
548}
549
bde2d79b
JF
550- (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
551 if (button_ != nil)
552 [button_ autorelease];
553 button_ = button == nil ? nil : [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain];
554
555 if (style_ != nil)
556 [style_ autorelease];
557 style_ = style == nil ? nil : [style retain];
558
559 if (function_ != nil)
560 [function_ autorelease];
561 function_ = function == nil ? nil : [function retain];
1ce016d4 562
161c1078 563 [self applyRightButton];
bde2d79b
JF
564}
565
566- (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
567 if (button_ != nil)
568 [button_ autorelease];
569 button_ = button == nil ? nil : [button retain];
570
571 if (style_ != nil)
572 [style_ autorelease];
573 style_ = style == nil ? nil : [style retain];
574
575 if (function_ != nil)
576 [function_ autorelease];
577 function_ = function == nil ? nil : [function retain];
1ce016d4 578
161c1078 579 [self applyRightButton];
bde2d79b 580}
bde2d79b 581
9d7f5e2d
JF
582- (void) setFinishHook:(id)function {
583 if (finish_ != nil)
584 [finish_ autorelease];
585 finish_ = function == nil ? nil : [function retain];
586}
587
588- (void) setPopupHook:(id)function {
589 if (closer_ != nil)
590 [closer_ autorelease];
591 closer_ = function == nil ? nil : [function retain];
592}
593
61b13cae 594- (void) _openMailToURL:(NSURL *)url {
61b13cae 595 [UIApp openURL:url];// asPanel:YES];
61b13cae
JF
596}
597
dcc55b8b
JF
598- (void) webView:(WebView *)sender willBeginEditingFormElement:(id)element {
599 editing_ = true;
600}
601
602- (void) webView:(WebView *)sender didBeginEditingFormElement:(id)element {
9d7f5e2d 603 [self fixScroller];
dcc55b8b
JF
604}
605
606- (void) webViewDidEndEditingFormElements:(WebView *)sender {
607 editing_ = false;
9d7f5e2d 608 [self fixScroller];
dcc55b8b
JF
609}
610
04700693 611- (void) webViewClose:(WebView *)sender {
9ae52960 612 [self close];
04700693
JF
613}
614
7afcea1c 615- (void) close {
9ae52960 616 [[self navigationController] dismissModalViewControllerAnimated:YES];
7afcea1c
JF
617}
618
bde2d79b 619- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
bde2d79b
JF
620}
621
622- (void) webView:(WebView *)sender unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame {
623 NSLog(@"err:%@", error);
624}
625
626- (void) webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id<WebPolicyDecisionListener>)listener {
1ce016d4 627#if LogBrowser
5a5c1e4b 628 NSLog(@"nwa:%@", name);
7b00c562 629#endif
5a5c1e4b 630
bde2d79b 631 if (NSURL *url = [request URL]) {
04700693 632 if (name == nil) unknown: {
b8de369a 633 if (![self getSpecial:url swap:NO]) {
04700693
JF
634 NSString *scheme([[url scheme] lowercaseString]);
635 if ([scheme isEqualToString:@"mailto"])
61b13cae 636 [self _openMailToURL:url];
04700693
JF
637 else goto use;
638 }
639 } else if ([name isEqualToString:@"_open"])
bde2d79b 640 [delegate_ openURL:url];
04700693 641 else if ([name isEqualToString:@"_popup"]) {
3ac7a20a
JF
642 NSString *scheme([[url scheme] lowercaseString]);
643 if ([scheme isEqualToString:@"mailto"])
61b13cae 644 [self _openMailToURL:url];
3ac7a20a 645 else {
9ae52960
GP
646 UCNavigationController *navigation([[[UCNavigationController alloc] init] autorelease]);
647 [navigation setHook:indirect_];
04700693 648
9ae52960 649 UCViewController *page([delegate_ pageForURL:url hasTag:NULL]);
3ac7a20a
JF
650 if (page == nil) {
651 /* XXX: call createWebViewWithRequest instead? */
5a5c1e4b 652
161c1078 653 BrowserController *browser([[[class_ alloc] init] autorelease]);
3ac7a20a
JF
654 [browser loadURL:url];
655 page = browser;
656 }
bde2d79b 657
9ae52960 658 [navigation setDelegate:delegate_];
3ac7a20a 659 [page setDelegate:delegate_];
0a7e5478 660
9ae52960
GP
661 [navigation setViewControllers:[NSArray arrayWithObject:page]];
662 UIBarButtonItem *closeItem = [[UIBarButtonItem alloc]
663 initWithTitle:UCLocalize("CLOSE")
664 style:UIBarButtonItemStylePlain
665 target:page
666 action:@selector(close)
667 ];
668 [[page navigationItem] setLeftBarButtonItem:closeItem];
669 [closeItem release];
670
671 [[self navigationController] presentModalViewController:navigation animated:YES];
3ac7a20a 672 }
04700693 673 } else goto unknown;
bde2d79b
JF
674
675 [listener ignore];
676 } else use:
677 [listener use];
678}
679
5889429e 680- (void) webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
bde2d79b
JF
681 if ([WebView canShowMIMEType:type])
682 [listener use];
683 else {
684 // XXX: handle more mime types!
685 [listener ignore];
5889429e 686
2fd3803f 687 WebView *webview([document_ webView]);
5889429e 688 if (frame == [webview mainFrame])
bde2d79b
JF
689 [UIApp openURL:[request URL]];
690 }
691}
692
693- (void) webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
694 if (request == nil) ignore: {
695 [listener ignore];
696 return;
697 }
698
699 NSURL *url([request URL]);
5d8f1006 700 NSString *host([url host]);
bde2d79b
JF
701
702 if (url == nil) use: {
f4772bd1 703 if (!error_ && [frame parentFrame] == nil) {
bde2d79b
JF
704 if (request_ != nil)
705 [request_ autorelease];
706 request_ = [request retain];
1ce016d4 707#if LogBrowser
bde2d79b 708 NSLog(@"dpn:%@", request_);
04700693 709#endif
bde2d79b
JF
710 }
711
712 [listener use];
5889429e 713
2fd3803f 714 WebView *webview([document_ webView]);
5889429e
JF
715 if (frame == [webview mainFrame])
716 [self _pushPage];
bde2d79b
JF
717 return;
718 }
1ce016d4 719#if LogBrowser
bde2d79b
JF
720 else NSLog(@"nav:%@:%@", url, [action description]);
721#endif
722
9d7f5e2d
JF
723 const NSArray *capability;
724
5d8f1006
JF
725 if ($GSSystemCopyCapability != NULL) {
726 capability = reinterpret_cast<const NSArray *>((*$GSSystemCopyCapability)(kGSDisplayIdentifiersCapability));
727 capability = [capability autorelease];
728 } else if ($GSSystemGetCapability != NULL) {
729 capability = reinterpret_cast<const NSArray *>((*$GSSystemGetCapability)(kGSDisplayIdentifiersCapability));
730 } else
731 capability = nil;
732
733 NSURL *open(nil);
bde2d79b 734
9d7f5e2d 735 if (capability != nil && (
5d8f1006
JF
736 [url isGoogleMapsURL] && [capability containsObject:@"com.apple.Maps"] && (open = [url mapsURL]) != nil||
737 [host hasSuffix:@"youtube.com"] && [capability containsObject:@"com.apple.youtube"] && (open = [url youTubeURL]) != nil ||
738 [url respondsToSelector:@selector(phobosURL)] && (open = [url phobosURL]) != nil
9d7f5e2d 739 )) {
5d8f1006 740 url = open;
bde2d79b
JF
741 open:
742 [UIApp openURL:url];
743 goto ignore;
744 }
745
746 int store(_not(int));
747 if (NSURL *itms = [url itmsURL:&store]) {
1ce016d4 748#if LogBrowser
bde2d79b 749 NSLog(@"itms#%@#%u#%@", url, store, itms);
7b00c562
JF
750#endif
751
9d7f5e2d 752 if (capability != nil && (
bde2d79b
JF
753 store == 1 && [capability containsObject:@"com.apple.MobileStore"] ||
754 store == 2 && [capability containsObject:@"com.apple.AppStore"]
9d7f5e2d 755 )) {
bde2d79b
JF
756 url = itms;
757 goto open;
758 }
759 }
760
761 NSString *scheme([[url scheme] lowercaseString]);
762
763 if ([scheme isEqualToString:@"tel"]) {
764 // XXX: intelligence
765 goto open;
766 }
767
768 if ([scheme isEqualToString:@"mailto"]) {
61b13cae 769 [self _openMailToURL:url];
bde2d79b
JF
770 goto ignore;
771 }
772
b8de369a 773 if ([self getSpecial:url swap:YES])
bde2d79b
JF
774 goto ignore;
775 else if ([WebView _canHandleRequest:request])
776 goto use;
777 else if ([url isSpringboardHandledURL])
778 goto open;
779 else
780 goto use;
781}
782
783- (void) webView:(WebView *)sender setStatusText:(NSString *)text {
784 //lprintf("Status:%s\n", [text UTF8String]);
785}
786
bde2d79b
JF
787- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
788 NSString *context([sheet context]);
789
b456f1c9
JF
790 if ([context isEqualToString:@"alert"]) {
791 [self autorelease];
bde2d79b 792 [sheet dismiss];
b456f1c9 793 } else if ([context isEqualToString:@"confirm"]) {
bde2d79b
JF
794 switch (button) {
795 case 1:
796 confirm_ = [NSNumber numberWithBool:YES];
797 break;
798
799 case 2:
800 confirm_ = [NSNumber numberWithBool:NO];
801 break;
802 }
803
0fc560b6
JF
804 [sheet dismiss];
805 } else if ([context isEqualToString:@"sensitive"]) {
806 switch (button) {
807 case 1:
808 sensitive_ = [NSNumber numberWithBool:YES];
809 break;
810
811 case 2:
812 sensitive_ = [NSNumber numberWithBool:NO];
813 break;
814 }
815
bde2d79b
JF
816 [sheet dismiss];
817 } else if ([context isEqualToString:@"challenge"]) {
818 id<NSURLAuthenticationChallengeSender> sender([challenge_ sender]);
819
820 switch (button) {
821 case 1: {
822 NSString *username([[sheet textFieldAtIndex:0] text]);
823 NSString *password([[sheet textFieldAtIndex:1] text]);
824
825 NSURLCredential *credential([NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]);
826
827 [sender useCredential:credential forAuthenticationChallenge:challenge_];
828 } break;
829
830 case 2:
831 [sender cancelAuthenticationChallenge:challenge_];
832 break;
833
6981ccdf 834 _nodefault
bde2d79b
JF
835 }
836
837 [challenge_ release];
838 challenge_ = nil;
839
840 [sheet dismiss];
841 } else if ([context isEqualToString:@"submit"]) {
842 switch (button) {
843 case 1:
844 break;
845
846 case 2:
9d7f5e2d
JF
847 if (request_ != nil) {
848 WebThreadLock();
2fd3803f 849 [document_ loadRequest:request_];
9d7f5e2d
JF
850 WebThreadUnlock();
851 }
bde2d79b
JF
852 break;
853
6981ccdf 854 _nodefault
bde2d79b
JF
855 }
856
857 [sheet dismiss];
858 }
859}
860
861- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
862 challenge_ = [challenge retain];
863
864 NSURLProtectionSpace *space([challenge protectionSpace]);
865 NSString *realm([space realm]);
866 if (realm == nil)
867 realm = @"";
868
869 UIActionSheet *sheet = [[[UIActionSheet alloc]
870 initWithTitle:realm
61b13cae 871 buttons:[NSArray arrayWithObjects:UCLocalize("LOGIN"), UCLocalize("CANCEL"), nil]
bde2d79b
JF
872 defaultButtonIndex:0
873 delegate:self
874 context:@"challenge"
875 ] autorelease];
876
d3bef7bc
JF
877 [sheet setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
878
bde2d79b
JF
879 [sheet setNumberOfRows:1];
880
61b13cae
JF
881 [sheet addTextFieldWithValue:@"" label:UCLocalize("USERNAME")];
882 [sheet addTextFieldWithValue:@"" label:UCLocalize("PASSWORD")];
bde2d79b
JF
883
884 UITextField *username([sheet textFieldAtIndex:0]); {
885 UITextInputTraits *traits([username textInputTraits]);
886 [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
887 [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
888 [traits setKeyboardType:UIKeyboardTypeASCIICapable];
889 [traits setReturnKeyType:UIReturnKeyNext];
890 }
891
892 UITextField *password([sheet textFieldAtIndex:1]); {
893 UITextInputTraits *traits([password textInputTraits]);
894 [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
895 [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
896 [traits setKeyboardType:UIKeyboardTypeASCIICapable];
897 // XXX: UIReturnKeyDone
898 [traits setReturnKeyType:UIReturnKeyNext];
899 [traits setSecureTextEntry:YES];
900 }
901
902 [sheet popupAlertAnimated:YES];
903}
904
905- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
61b13cae 906 return request;
bde2d79b
JF
907}
908
5a5c1e4b 909- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features {
7b00c562 910//- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request userGesture:(BOOL)gesture {
1ce016d4 911#if LogBrowser
7b00c562
JF
912 NSLog(@"cwv:%@ (%@): %@", request, title_, features == nil ? @"{}" : [features description]);
913 //NSLog(@"cwv:%@ (%@): %@", request, title_, gesture ? @"Yes" : @"No");
5a5c1e4b 914#endif
bde2d79b 915
7b00c562 916 NSNumber *value([features objectForKey:@"width"]);
5889429e 917 float width(value == nil ? 0 : [value floatValue]);
7b00c562 918
9ae52960 919 UCNavigationController *navigation(!popup_ ? [self navigationController] : [[[UCNavigationController alloc] init] autorelease]);
7b00c562
JF
920
921 /* XXX: deal with cydia:// pages */
161c1078 922 BrowserController *browser([[[class_ alloc] initWithWidth:width] autorelease]);
7b00c562 923
b456f1c9 924 if (features != nil && popup_) {
9ae52960
GP
925 [navigation setDelegate:delegate_];
926 [navigation setHook:indirect_];
7b00c562
JF
927 [browser setDelegate:delegate_];
928
929 [browser loadRequest:request];
a55054a2 930
9ae52960
GP
931 [navigation setViewControllers:[NSArray arrayWithObject:browser]];
932 UIBarButtonItem *closeItem = [[UIBarButtonItem alloc]
933 initWithTitle:UCLocalize("CLOSE")
934 style:UIBarButtonItemStylePlain
935 target:browser
936 action:@selector(close)
937 ];
938 [[browser navigationItem] setLeftBarButtonItem:closeItem];
939 [closeItem release];
940
941 [[self navigationController] presentModalViewController:navigation animated:YES];
942 } /*else if (request == nil) {
943 [[self navigationItem] setTitle:title_];
a55054a2
JF
944 [browser setDelegate:delegate_];
945 [browser retain];
9ae52960 946 }*/ else {
a55054a2
JF
947 [self pushPage:browser];
948 [browser loadRequest:request];
949 }
950
bde2d79b
JF
951 return [browser webView];
952}
953
954- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
5a5c1e4b 955 return [self webView:sender createWebViewWithRequest:request windowFeatures:nil];
7b00c562 956 //return [self webView:sender createWebViewWithRequest:request userGesture:YES];
bde2d79b
JF
957}
958
959- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
960 if ([frame parentFrame] != nil)
961 return;
962
963 title_ = [title retain];
9ae52960 964 [[self navigationItem] setTitle:title_];
bde2d79b
JF
965}
966
967- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
017b2b71
JF
968 /*if ([loading_ count] == 0)
969 [self retain];*/
b452841e 970 [loading_ addObject:[NSValue valueWithNonretainedObject:frame]];
bde2d79b 971
9d7f5e2d 972 if ([frame parentFrame] == nil) {
2fd3803f 973 [document_ resignFirstResponder];
5889429e 974
9d7f5e2d 975 reloading_ = false;
bde2d79b 976
9d7f5e2d
JF
977 if (title_ != nil) {
978 [title_ release];
979 title_ = nil;
980 }
bde2d79b 981
9d7f5e2d
JF
982 if (button_ != nil) {
983 [button_ release];
984 button_ = nil;
985 }
bde2d79b 986
9d7f5e2d
JF
987 if (style_ != nil) {
988 [style_ release];
989 style_ = nil;
990 }
bde2d79b 991
9d7f5e2d
JF
992 if (function_ != nil) {
993 [function_ release];
994 function_ = nil;
995 }
bde2d79b 996
9d7f5e2d
JF
997 if (finish_ != nil) {
998 [finish_ release];
999 finish_ = nil;
1000 }
1ce016d4 1001
9d7f5e2d
JF
1002 if (closer_ != nil) {
1003 [closer_ release];
1004 closer_ = nil;
1005 }
1006
1007 if (special_ != nil) {
1008 [special_ release];
1009 special_ = nil;
1010 }
bde2d79b 1011
9ae52960 1012 [[self navigationItem] setTitle:title_];
9d7f5e2d 1013
daf7f6e2
JF
1014 if (Wildcat_) {
1015 CGRect webrect = [scroller_ bounds];
1016 webrect.size.height = 1;
2fd3803f 1017 [document_ setFrame:webrect];
daf7f6e2 1018 }
d4f84362
JF
1019
1020 if ([scroller_ respondsToSelector:@selector(scrollPointVisibleAtTopLeft:)])
1021 [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
1022 else
1023 [scroller_ scrollRectToVisible:CGRectZero animated:NO];
9d7f5e2d
JF
1024
1025 if ([scroller_ respondsToSelector:@selector(setZoomScale:duration:)])
1026 [scroller_ setZoomScale:1 duration:0];
f4cd7e8b
JF
1027 else if ([scroller_ respondsToSelector:@selector(_setZoomScale:duration:)])
1028 [scroller_ _setZoomScale:1 duration:0];
1029 /*else if ([scroller_ respondsToSelector:@selector(setZoomScale:animated:)])
1030 [scroller_ setZoomScale:1 animated:NO];*/
daf7f6e2
JF
1031
1032 if (!Wildcat_) {
1033 CGRect webrect = [scroller_ bounds];
1034 webrect.size.height = 0;
2fd3803f 1035 [document_ setFrame:webrect];
daf7f6e2 1036 }
9d7f5e2d
JF
1037 }
1038
161c1078 1039 [self _startLoading];
bde2d79b
JF
1040}
1041
c8e3b4b3
GP
1042- (UINavigationButtonStyle) rightButtonStyle {
1043 if (style_ == nil) normal:
1044 return UINavigationButtonStyleNormal;
1045 else if ([style_ isEqualToString:@"Normal"])
1046 return UINavigationButtonStyleNormal;
1047 else if ([style_ isEqualToString:@"Back"])
1048 return UINavigationButtonStyleBack;
1049 else if ([style_ isEqualToString:@"Highlighted"])
1050 return UINavigationButtonStyleHighlighted;
1051 else if ([style_ isEqualToString:@"Destructive"])
1052 return UINavigationButtonStyleDestructive;
1053 else goto normal;
1054}
1055
1056- (UIBarButtonItem *) customButton {
1057 UIBarButtonItem *customItem = [[UIBarButtonItem alloc]
1058 initWithTitle:button_
1059 style:[self rightButtonStyle]
1060 target:self
1061 action:@selector(customButtonClicked)
1062 ];
1063
1064 return [customItem autorelease];
1065}
1066
b36becfc
GP
1067- (void) applyLoadingTitle {
1068 [[self navigationItem] setTitle:UCLocalize("LOADING")];
1069}
1070
161c1078
GP
1071- (void) applyRightButton {
1072 if ([self isLoading]) {
c8e3b4b3 1073 [[self navigationItem] setRightBarButtonItem:loadingitem_ animated:YES];
766b71dd 1074 [[loadingitem_ view] addSubview:indicator_];
b36becfc 1075 [self applyLoadingTitle];
c8e3b4b3
GP
1076 } else if (button_) {
1077 [[self navigationItem] setRightBarButtonItem:[self customButton] animated:YES];
161c1078 1078 } else {
c8e3b4b3 1079 [[self navigationItem] setRightBarButtonItem:reloaditem_ animated:YES];
161c1078
GP
1080 }
1081}
1082
1083- (void) _startLoading {
1084 [self applyRightButton];
1085}
9ae52960 1086
bde2d79b 1087- (void) _finishLoading {
b452841e 1088 size_t count([loading_ count]);
017b2b71
JF
1089 /*if (count == 0)
1090 [self autorelease];*/
b452841e 1091 if (reloading_ || count != 0)
9d7f5e2d
JF
1092 return;
1093 if (finish_ != nil)
1094 [self callFunction:finish_];
9ae52960 1095
161c1078 1096 [self applyRightButton];
6e8f1574 1097 if (![self isLoading]) [[self navigationItem] setTitle:title_];
bde2d79b
JF
1098}
1099
1ce016d4 1100- (bool) isLoading {
9d7f5e2d 1101 return [loading_ count] != 0;
bde2d79b
JF
1102}
1103
bde2d79b 1104- (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
2fd3803f 1105 return [document_ webView:sender shouldScrollToPoint:point forFrame:frame];
bde2d79b
JF
1106}
1107
1108- (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
2fd3803f 1109 return [document_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
bde2d79b
JF
1110}
1111
1112- (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
2fd3803f 1113 return [document_ webView:sender needsScrollNotifications:notifications forFrame:frame];
bde2d79b
JF
1114}
1115
1116- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
10c3a9c1 1117 [self _pushPage];
2fd3803f 1118 return [document_ webView:sender didCommitLoadForFrame:frame];
bde2d79b
JF
1119}
1120
1121- (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
2fd3803f 1122 return [document_ webView:sender didReceiveDocTypeForFrame:frame];
bde2d79b
JF
1123}
1124
1125- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
b452841e 1126 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
9d7f5e2d 1127 [self _finishLoading];
bde2d79b 1128
9d7f5e2d 1129 if ([frame parentFrame] == nil) {
bde2d79b
JF
1130 if (DOMDocument *document = [frame DOMDocument])
1131 if (DOMNodeList<NSFastEnumeration> *bodies = [document getElementsByTagName:@"body"])
1132 for (DOMHTMLBodyElement *body in bodies) {
1133 DOMCSSStyleDeclaration *style([document getComputedStyle:body pseudoElement:nil]);
1134
1135 bool colored(false);
1136
1137 if (DOMCSSPrimitiveValue *color = static_cast<DOMCSSPrimitiveValue *>([style getPropertyCSSValue:@"background-color"])) {
f4772bd1
JF
1138 if ([color primitiveType] == DOM_CSS_RGBCOLOR) {
1139 DOMRGBColor *rgb([color getRGBColorValue]);
1140
1141 float red([[rgb red] getFloatValue:DOM_CSS_NUMBER]);
1142 float green([[rgb green] getFloatValue:DOM_CSS_NUMBER]);
1143 float blue([[rgb blue] getFloatValue:DOM_CSS_NUMBER]);
1144 float alpha([[rgb alpha] getFloatValue:DOM_CSS_NUMBER]);
1145
1146 UIColor *uic(nil);
1147
1148 if (red == 0xc7 && green == 0xce && blue == 0xd5)
1149 uic = [UIColor pinStripeColor];
1150 else if (alpha != 0)
1151 uic = [UIColor
1152 colorWithRed:(red / 255)
1153 green:(green / 255)
1154 blue:(blue / 255)
1155 alpha:alpha
1156 ];
1157
1158 if (uic != nil) {
1159 colored = true;
1160 [scroller_ setBackgroundColor:uic];
1161 }
bde2d79b
JF
1162 }
1163 }
1164
1165 if (!colored)
1166 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1167 break;
1168 }
1169 }
1170
2fd3803f 1171 return [document_ webView:sender didFinishLoadForFrame:frame];
bde2d79b
JF
1172}
1173
9d7f5e2d 1174- (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame {
017b2b71
JF
1175 _trace();
1176 /*if ([frame parentFrame] == nil)
1177 [self autorelease];*/
9d7f5e2d 1178
b452841e 1179 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
bde2d79b
JF
1180 [self _finishLoading];
1181
b452841e
JF
1182 if (reloading_)
1183 return;
1184
9d7f5e2d
JF
1185 if ([frame parentFrame] == nil) {
1186 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
1187 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
1188 [[error localizedDescription] stringByAddingPercentEscapes]
1189 ]]];
1190
1191 error_ = true;
1192 }
1193}
f4772bd1 1194
9d7f5e2d
JF
1195- (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1196 [self _didFailWithError:error forFrame:frame];
2fd3803f
JF
1197 if ([document_ respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)])
1198 [document_ webView:sender didFailLoadWithError:error forFrame:frame];
9d7f5e2d
JF
1199}
1200
1201- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1202 [self _didFailWithError:error forFrame:frame];
bde2d79b
JF
1203}
1204
1205- (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary {
1ce016d4 1206#if LogBrowser || ForSaurik
bde2d79b
JF
1207 lprintf("Console:%s\n", [[dictionary description] UTF8String]);
1208#endif
1209}
1210
d4f84362
JF
1211- (void) webView:(WebView *)sender didReceiveMessage:(NSDictionary *)dictionary {
1212#if LogBrowser || ForSaurik
1213 lprintf("Console:%s\n", [[dictionary description] UTF8String]);
1214#endif
2fd3803f
JF
1215 if ([document_ respondsToSelector:@selector(webView:didReceiveMessage:)])
1216 [document_ webView:sender didReceiveMessage:dictionary];
d4f84362
JF
1217}
1218
1219- (void) webView:(id)sender willCloseFrame:(id)frame {
2fd3803f
JF
1220 if ([document_ respondsToSelector:@selector(webView:willCloseFrame:)])
1221 [document_ webView:sender willCloseFrame:frame];
d4f84362
JF
1222}
1223
1224- (void) webView:(id)sender didFinishDocumentLoadForFrame:(id)frame {
2fd3803f
JF
1225 if ([document_ respondsToSelector:@selector(webView:didFinishDocumentLoadForFrame:)])
1226 [document_ webView:sender didFinishDocumentLoadForFrame:frame];
d4f84362
JF
1227}
1228
1229- (void) webView:(id)sender didFirstLayoutInFrame:(id)frame {
2fd3803f
JF
1230 if ([document_ respondsToSelector:@selector(webView:didFirstLayoutInFrame:)])
1231 [document_ webView:sender didFirstLayoutInFrame:frame];
d4f84362
JF
1232}
1233
1234- (void) webViewFormEditedStatusHasChanged:(id)changed {
2fd3803f
JF
1235 if ([document_ respondsToSelector:@selector(webViewFormEditedStatusHasChanged:)])
1236 [document_ webViewFormEditedStatusHasChanged:changed];
d4f84362
JF
1237}
1238
1239- (void) webView:(id)sender formStateDidFocusNode:(id)formState {
2fd3803f
JF
1240 if ([document_ respondsToSelector:@selector(webView:formStateDidFocusNode:)])
1241 [document_ webView:sender formStateDidFocusNode:formState];
d4f84362
JF
1242}
1243
1244- (void) webView:(id)sender formStateDidBlurNode:(id)formState {
2fd3803f
JF
1245 if ([document_ respondsToSelector:@selector(webView:formStateDidBlurNode:)])
1246 [document_ webView:sender formStateDidBlurNode:formState];
d4f84362
JF
1247}
1248
9d7f5e2d
JF
1249/* XXX: fix this stupid include file
1250- (void) webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)database {
1251 [origin setQuota:0x500000];
1252}*/
1253
d4f84362 1254- (void) webViewDidLayout:(id)sender {
2fd3803f 1255 [document_ webViewDidLayout:sender];
d4f84362
JF
1256}
1257
1258- (void) webView:(id)sender didFirstVisuallyNonEmptyLayoutInFrame:(id)frame {
2fd3803f 1259 [document_ webView:sender didFirstVisuallyNonEmptyLayoutInFrame:frame];
d4f84362
JF
1260}
1261
1262- (void) webView:(id)sender saveStateToHistoryItem:(id)item forFrame:(id)frame {
2fd3803f 1263 [document_ webView:sender saveStateToHistoryItem:item forFrame:frame];
d4f84362
JF
1264}
1265
1266- (void) webView:(id)sender restoreStateFromHistoryItem:(id)item forFrame:(id)frame force:(BOOL)force {
2fd3803f 1267 [document_ webView:sender restoreStateFromHistoryItem:item forFrame:frame force:force];
d4f84362
JF
1268}
1269
1270- (void) webView:(id)sender attachRootLayer:(id)layer {
2fd3803f 1271 [document_ webView:sender attachRootLayer:layer];
d4f84362
JF
1272}
1273
1274- (id) webView:(id)sender plugInViewWithArguments:(id)arguments fromPlugInPackage:(id)package {
2fd3803f 1275 return [document_ webView:sender plugInViewWithArguments:arguments fromPlugInPackage:package];
d4f84362
JF
1276}
1277
1278- (void) webView:(id)sender willShowFullScreenForPlugInView:(id)view {
2fd3803f 1279 [document_ webView:sender willShowFullScreenForPlugInView:view];
d4f84362
JF
1280}
1281
1282- (void) webView:(id)sender didHideFullScreenForPlugInView:(id)view {
2fd3803f 1283 [document_ webView:sender didHideFullScreenForPlugInView:view];
d4f84362
JF
1284}
1285
1286- (void) webView:(id)sender willAddPlugInView:(id)view {
2fd3803f 1287 [document_ webView:sender willAddPlugInView:view];
d4f84362
JF
1288}
1289
1290- (void) webView:(id)sender didObserveDeferredContentChange:(int)change forFrame:(id)frame {
2fd3803f 1291 [document_ webView:sender didObserveDeferredContentChange:change forFrame:frame];
d4f84362
JF
1292}
1293
1294- (void) webViewDidPreventDefaultForEvent:(id)sender {
2fd3803f 1295 [document_ webViewDidPreventDefaultForEvent:sender];
d4f84362
JF
1296}
1297
9d7f5e2d 1298- (void) _setTileDrawingEnabled:(BOOL)enabled {
2fd3803f 1299 //[document_ setTileDrawingEnabled:enabled];
9d7f5e2d
JF
1300}
1301
dcc55b8b 1302- (void) setViewportWidth:(float)width {
0a523b5a 1303 width_ = width != 0 ? width : [[self class] defaultWidth];
2fd3803f 1304 [document_ setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
dcc55b8b
JF
1305}
1306
9d7f5e2d
JF
1307- (void) willStartGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1308 [self _setTileDrawingEnabled:NO];
1309}
1310
1311- (void) didFinishGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1312 [self _setTileDrawingEnabled:YES];
2fd3803f 1313 [document_ redrawScaledDocument];
9d7f5e2d
JF
1314}
1315
1316- (void) scrollerWillStartDragging:(UIScroller *)scroller {
1317 [self _setTileDrawingEnabled:NO];
1318}
1319
1320- (void) scrollerDidEndDragging:(UIScroller *)scroller willSmoothScroll:(BOOL)smooth {
1321 [self _setTileDrawingEnabled:YES];
1322}
1323
1324- (void) scrollerDidEndDragging:(UIScroller *)scroller {
1325 [self _setTileDrawingEnabled:YES];
1326}
1327
9ae52960
GP
1328- (id) initWithWidth:(float)width ofClass:(Class)_class {
1329 if ((self = [super init]) != nil) {
85021801 1330 class_ = _class;
9d7f5e2d 1331 loading_ = [[NSMutableSet alloc] initWithCapacity:3];
7b00c562 1332 popup_ = false;
bde2d79b 1333
161c1078 1334 BrowserView *actualView = [[BrowserView alloc] initWithFrame:CGRectZero];
3c83edee
RP
1335 [self setView:actualView];
1336
9ae52960 1337 struct CGRect bounds = [[self view] bounds];
bde2d79b 1338
d3bef7bc 1339 scroller_ = [[objc_getClass(Wildcat_ ? "UIScrollView" : "UIScroller") alloc] initWithFrame:bounds];
9ae52960 1340 [[self view] addSubview:scroller_];
bde2d79b 1341
bde2d79b
JF
1342 [scroller_ setFixedBackgroundPattern:YES];
1343 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1344
1345 [scroller_ setScrollingEnabled:YES];
bde2d79b 1346 [scroller_ setClipsSubviews:YES];
d4f84362 1347
d3bef7bc 1348 if (!Wildcat_)
d4f84362 1349 [scroller_ setAllowsRubberBanding:YES];
9d7f5e2d 1350
bde2d79b 1351 [scroller_ setDelegate:self];
9d7f5e2d 1352 [scroller_ setBounces:YES];
d4f84362 1353
d3bef7bc 1354 if (!Wildcat_) {
d4f84362
JF
1355 [scroller_ setScrollHysteresis:8];
1356 [scroller_ setThumbDetectionEnabled:NO];
1357 [scroller_ setDirectionalScrolling:YES];
d3bef7bc 1358 //[scroller_ setScrollDecelerationFactor:0.99]; /* 0.989324 */
d4f84362
JF
1359 [scroller_ setEventMode:YES];
1360 }
1361
d3bef7bc
JF
1362 if (Wildcat_) {
1363 UIScrollView *scroller((UIScrollView *)scroller_);
1364 //[scroller setDirectionalLockEnabled:NO];
1365 [scroller setDelaysContentTouches:NO];
1366 //[scroller setScrollsToTop:NO];
1367 //[scroller setCanCancelContentTouches:NO];
1368 }
1369
9d7f5e2d 1370 [scroller_ setShowBackgroundShadow:NO]; /* YES */
d4f84362
JF
1371 //[scroller_ setAllowsRubberBanding:YES]; /* Vertical */
1372
d3bef7bc 1373 if (!Wildcat_)
d4f84362 1374 [scroller_ setAdjustForContentSizeChange:YES]; /* NO */
bde2d79b
JF
1375
1376 CGRect webrect = [scroller_ bounds];
1377 webrect.size.height = 0;
1378
1379 WebView *webview;
1380
9d7f5e2d
JF
1381 WebThreadLock();
1382
bde2d79b 1383#if RecycleWebViews
2fd3803f
JF
1384 document_ = [Documents_ lastObject];
1385 if (document_ != nil) {
1386 document_ = [document_ retain];
1387 webview = [document_ webView];
bde2d79b 1388 [Documents_ removeLastObject];
2fd3803f 1389 [document_ setFrame:webrect];
bde2d79b
JF
1390 } else {
1391#else
1392 if (true) {
1393#endif
2fd3803f
JF
1394 document_ = [[$UIWebBrowserView alloc] initWithFrame:webrect];
1395 webview = [document_ webView];
bde2d79b
JF
1396
1397 // XXX: this is terribly (too?) expensive
2fd3803f 1398 //[document_ setDrawsBackground:NO];
bde2d79b
JF
1399 [webview setPreferencesIdentifier:@"Cydia"];
1400
2fd3803f 1401 [document_ setTileSize:CGSizeMake(webrect.size.width, 500)];
bde2d79b 1402
2fd3803f
JF
1403 if ([document_ respondsToSelector:@selector(enableReachability)])
1404 [document_ enableReachability];
1405 if ([document_ respondsToSelector:@selector(setAllowsMessaging:)])
1406 [document_ setAllowsMessaging:YES];
1407 if ([document_ respondsToSelector:@selector(useSelectionAssistantWithMode:)])
1408 [document_ useSelectionAssistantWithMode:0];
4825688a 1409
2fd3803f
JF
1410 [document_ setTilingEnabled:YES];
1411 [document_ setDrawsGrid:NO];
1412 [document_ setLogsTilingChanges:NO];
1413 [document_ setTileMinificationFilter:kCAFilterNearest];
4825688a 1414
2fd3803f 1415 if ([document_ respondsToSelector:@selector(setDataDetectorTypes:)])
9d7f5e2d 1416 /* XXX: abstractify */
2fd3803f 1417 [document_ setDataDetectorTypes:0x80000000];
9d7f5e2d 1418 else
2fd3803f 1419 [document_ setDetectsPhoneNumbers:NO];
4825688a 1420
2fd3803f 1421 [document_ setAutoresizes:YES];
bde2d79b 1422
2fd3803f
JF
1423 [document_ setMinimumScale:0.25f forDocumentTypes:0x10];
1424 [document_ setMaximumScale:5.00f forDocumentTypes:0x10];
1425 [document_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x10];
1426 //[document_ setViewportSize:CGSizeMake(980, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
bde2d79b 1427
2fd3803f 1428 [document_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x2];
bde2d79b 1429
2fd3803f
JF
1430 [document_ setMinimumScale:1.00f forDocumentTypes:0x8];
1431 [document_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x8];
1432 [document_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x8];
bde2d79b 1433
2fd3803f 1434 [document_ _setDocumentType:0x4];
bde2d79b 1435
2fd3803f
JF
1436 if ([document_ respondsToSelector:@selector(setZoomsFocusedFormControl:)])
1437 [document_ setZoomsFocusedFormControl:YES];
1438 [document_ setContentsPosition:7];
1439 [document_ setEnabledGestures:0xa];
1440 [document_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeIsZoomRubberBandEnabled];
1441 [document_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeUpdatesScroller];
bde2d79b 1442
2fd3803f
JF
1443 [document_ setSmoothsFonts:YES];
1444 [document_ setAllowsImageSheet:YES];
bde2d79b 1445 [webview _setUsesLoaderCache:YES];
7b00c562
JF
1446
1447 [webview setGroupName:@"CydiaGroup"];
4825688a
JF
1448
1449 WebPreferences *preferences([webview preferences]);
1450
9d7f5e2d
JF
1451 if ([webview respondsToSelector:@selector(_setLayoutInterval:)])
1452 [webview _setLayoutInterval:0];
4825688a
JF
1453 else
1454 [preferences _setLayoutInterval:0];
bde2d79b 1455 }
3c83edee
RP
1456
1457 actualView.documentView = document_;
1458 [actualView release];
bde2d79b 1459
dcc55b8b 1460 [self setViewportWidth:width];
7b00c562 1461
2fd3803f
JF
1462 [document_ setDelegate:self];
1463 [document_ setGestureDelegate:self];
d4f84362 1464
2fd3803f
JF
1465 if ([document_ respondsToSelector:@selector(setFormEditingDelegate:)])
1466 [document_ setFormEditingDelegate:self];
d4f84362 1467
2fd3803f 1468 [document_ setInteractionDelegate:self];
dcc55b8b 1469
2fd3803f 1470 [scroller_ addSubview:document_];
bde2d79b
JF
1471
1472 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
1473
bde2d79b
JF
1474 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
1475
9d7f5e2d 1476 [webview setFrameLoadDelegate:indirect_];
4825688a 1477 [webview setPolicyDelegate:indirect_];
bde2d79b 1478 [webview setResourceLoadDelegate:indirect_];
9d7f5e2d 1479 [webview setUIDelegate:indirect_];
4825688a
JF
1480
1481 /* XXX: do not turn this on under penalty of extreme pain */
1482 [webview setScriptDebugDelegate:nil];
9d7f5e2d
JF
1483
1484 WebThreadUnlock();
1485
1486 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite];
9ae52960 1487 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(15, 5, indsize.width, indsize.height)];
9d7f5e2d 1488 [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite];
9ae52960 1489 [indicator_ startAnimation];
c8e3b4b3
GP
1490
1491 reloaditem_ = [[UIBarButtonItem alloc]
1492 initWithTitle:UCLocalize("RELOAD")
1493 style:[self rightButtonStyle]
1494 target:self
1495 action:@selector(reloadButtonClicked)
1496 ];
1497
1498 loadingitem_ = [[UIBarButtonItem alloc]
1499 initWithTitle:@" "
1500 style:UIBarButtonItemStylePlain
1501 target:self
1502 action:@selector(reloadButtonClicked)
1503 ];
1504 [[loadingitem_ view] addSubview:indicator_];
bde2d79b 1505
d3bef7bc
JF
1506 [scroller_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
1507 [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
3c83edee 1508 [document_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
9d7f5e2d 1509
9ae52960 1510 /*UIWebView *test([[[UIWebView alloc] initWithFrame:[[self view] bounds]] autorelease]);
9d7f5e2d 1511 [test loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.saurik.com/"]]];
9ae52960 1512 [[self view] addSubview:test];*/
bde2d79b
JF
1513 } return self;
1514}
1515
9ae52960
GP
1516- (id) initWithWidth:(float)width {
1517 return [self initWithWidth:width ofClass:[self class]];
85021801
JF
1518}
1519
9ae52960
GP
1520- (id) init {
1521 return [self initWithWidth:0];
7b00c562
JF
1522}
1523
9d7f5e2d
JF
1524- (NSString *) stringByEvaluatingJavaScriptFromString:(NSString *)script {
1525 WebThreadLock();
2fd3803f 1526 WebView *webview([document_ webView]);
9d7f5e2d
JF
1527 NSString *string([webview stringByEvaluatingJavaScriptFromString:script]);
1528 WebThreadUnlock();
1529 return string;
bde2d79b
JF
1530}
1531
1ce016d4 1532- (void) callFunction:(WebScriptObject *)function {
9d7f5e2d
JF
1533 WebThreadLock();
1534
2fd3803f 1535 WebView *webview([document_ webView]);
1ce016d4 1536 WebFrame *frame([webview mainFrame]);
bde2d79b 1537
1ce016d4
JF
1538 id _private(MSHookIvar<id>(webview, "_private"));
1539 WebCore::Page *page(_private == nil ? NULL : MSHookIvar<WebCore::Page *>(_private, "page"));
1540 WebCore::Settings *settings(page == NULL ? NULL : page->settings());
bde2d79b 1541
1ce016d4
JF
1542 bool no;
1543 if (settings == NULL)
1544 no = 0;
1545 else {
1546 no = settings->JavaScriptCanOpenWindowsAutomatically();
1547 settings->setJavaScriptCanOpenWindowsAutomatically(true);
bde2d79b 1548 }
1ce016d4 1549
9ae52960 1550 if (UIWindow *window = [[self view] window])
61b13cae
JF
1551 if (UIResponder *responder = [window firstResponder])
1552 [responder resignFirstResponder];
1553
1ce016d4
JF
1554 JSObjectRef object([function JSObject]);
1555 JSGlobalContextRef context([frame globalContext]);
1556 JSObjectCallAsFunction(context, object, NULL, 0, NULL, NULL);
1557
1558 if (settings != NULL)
9d7f5e2d
JF
1559 settings->setJavaScriptCanOpenWindowsAutomatically(no);
1560
1561 WebThreadUnlock();
1ce016d4
JF
1562}
1563
9ae52960 1564- (void) didDismissModalViewController {
1ce016d4
JF
1565 if (closer_ != nil)
1566 [self callFunction:closer_];
1567}
1568
161c1078 1569- (void) reloadButtonClicked {
1ce016d4
JF
1570 reloading_ = true;
1571 [self reloadURL];
1572}
1573
161c1078 1574- (void) customButtonClicked {
9d7f5e2d
JF
1575#if !AlwaysReload
1576 if (function_ != nil)
1ce016d4 1577 [self callFunction:function_];
9d7f5e2d
JF
1578 else
1579#endif
161c1078 1580 [self reloadButtonClicked];
bde2d79b
JF
1581}
1582
bde2d79b
JF
1583- (void) setPageActive:(BOOL)active {
1584 if (!active)
1585 [indicator_ removeFromSuperview];
1586 else
9ae52960 1587 [[[[self navigationItem] rightBarButtonItem] view] addSubview:indicator_];
bde2d79b
JF
1588}
1589
1590- (void) resetViewAnimated:(BOOL)animated {
1591}
1592
1593- (void) setPushed:(bool)pushed {
1594 pushed_ = pushed;
1595}
1596
7b00c562
JF
1597+ (float) defaultWidth {
1598 return 980;
1599}
1600
9ae52960 1601@end