]> git.saurik.com Git - cydia.git/blame - UICaboodle/BrowserView.mm
Drastic performance and stability increases.
[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
13@interface NSString (UIKit)
14- (NSString *) stringByAddingPercentEscapes;
15@end
16
04700693 17/* Indirect Delegate {{{ */
9d7f5e2d 18@interface IndirectDelegate : NSObject {
04700693
JF
19 _transient volatile id delegate_;
20}
21
22- (void) setDelegate:(id)delegate;
23- (id) initWithDelegate:(id)delegate;
24@end
25
26@implementation IndirectDelegate
27
28- (void) setDelegate:(id)delegate {
29 delegate_ = delegate;
30}
31
32- (id) initWithDelegate:(id)delegate {
33 delegate_ = delegate;
34 return self;
35}
36
9d7f5e2d
JF
37- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
38 if (delegate_ != nil)
39 return [delegate_ webView:sender didClearWindowObject:window forFrame:frame];
40}
41
42- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
43 if (delegate_ != nil)
44 return [delegate_ webView:sender didCommitLoadForFrame:frame];
45}
46
47- (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
48 if (delegate_ != nil)
49 return [delegate_ webView:sender didFailLoadWithError:error forFrame:frame];
50}
51
52- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
53 if (delegate_ != nil)
54 return [delegate_ webView:sender didFailProvisionalLoadWithError:error forFrame:frame];
55}
56
57- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
58 if (delegate_ != nil)
59 return [delegate_ webView:sender didFinishLoadForFrame:frame];
60}
61
62- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
63 if (delegate_ != nil)
64 return [delegate_ webView:sender didReceiveTitle:title forFrame:frame];
65}
66
67- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
68 if (delegate_ != nil)
69 return [delegate_ webView:sender didStartProvisionalLoadForFrame:frame];
70}
71
72- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
73 if (delegate_ != nil)
74 return [delegate_ webView:sender resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:source];
75}
76
77- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
78 if (delegate_ != nil)
79 return [delegate_ webView:sender resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:source];
80 return nil;
81}
82
83- (IMP) methodForSelector:(SEL)sel {
84 if (IMP method = [super methodForSelector:sel])
85 return method;
86 fprintf(stderr, "methodForSelector:[%s] == NULL\n", sel_getName(sel));
87 return NULL;
88}
89
04700693 90- (BOOL) respondsToSelector:(SEL)sel {
9d7f5e2d
JF
91 if ([super respondsToSelector:sel])
92 return YES;
93 // XXX: WebThreadCreateNSInvocation returns nil
94 //fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel));
95 return delegate_ == nil ? NO : [delegate_ respondsToSelector:sel];
04700693
JF
96}
97
98- (NSMethodSignature *) methodSignatureForSelector:(SEL)sel {
9d7f5e2d
JF
99 if (NSMethodSignature *method = [super methodSignatureForSelector:sel])
100 return method;
101 //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel));
04700693
JF
102 if (delegate_ != nil)
103 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
104 return sig;
105 // XXX: I fucking hate Apple so very very bad
106 return [NSMethodSignature signatureWithObjCTypes:"v@:"];
107}
108
109- (void) forwardInvocation:(NSInvocation *)inv {
110 SEL sel = [inv selector];
111 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
112 [inv invokeWithTarget:delegate_];
113}
114
115@end
116/* }}} */
117
61b13cae 118@interface WebView (UICaboodle)
bde2d79b
JF
119- (void) setScriptDebugDelegate:(id)delegate;
120- (void) _setFormDelegate:(id)delegate;
121- (void) _setUIKitDelegate:(id)delegate;
122- (void) setWebMailDelegate:(id)delegate;
123- (void) _setLayoutInterval:(float)interval;
124@end
125
61b13cae 126@implementation WebScriptObject (UICaboodle)
9d7f5e2d
JF
127
128- (unsigned) count {
129 id length([self valueForKey:@"length"]);
130 if ([length respondsToSelector:@selector(intValue)])
131 return [length intValue];
132 else
133 return 0;
134}
135
136- (id) objectAtIndex:(unsigned)index {
137 return [self webScriptValueAtIndex:index];
138}
139
140@end
141
61b13cae
JF
142#if 0
143/* Mail Composition {{{ */
144@interface MailToView : PopUpView {
145 MailComposeController *controller_;
45f88d41
JF
146}
147
61b13cae
JF
148- (id) initWithView:(UIView *)view delegate:(id)delegate url:(NSURL *)url;
149
45f88d41
JF
150@end
151
61b13cae 152@implementation MailToView
45f88d41
JF
153
154- (void) dealloc {
61b13cae 155 [controller_ release];
45f88d41
JF
156 [super dealloc];
157}
158
61b13cae
JF
159- (void) mailComposeControllerWillAttemptToSend:(MailComposeController *)controller {
160 NSLog(@"will");
45f88d41
JF
161}
162
61b13cae
JF
163- (void) mailComposeControllerDidAttemptToSend:(MailComposeController *)controller mailDelivery:(id)delivery {
164 NSLog(@"did:%@", delivery);
165// [UIApp setStatusBarShowsProgress:NO];
166if ([controller error]){
167NSArray *buttons = [NSArray arrayWithObjects:UCLocalize("OK"), nil];
168UIActionSheet *mailAlertSheet = [[UIActionSheet alloc] initWithTitle:UCLocalize("ERROR") buttons:buttons defaultButtonIndex:0 delegate:self context:self];
169[mailAlertSheet setBodyText:[controller error]];
170[mailAlertSheet popupAlertAnimated:YES];
3ff1504e 171}
3ff1504e
JF
172}
173
61b13cae
JF
174- (void) showError {
175 NSLog(@"%@", [controller_ error]);
176 NSArray *buttons = [NSArray arrayWithObjects:UCLocalize("OK"), nil];
177 UIActionSheet *mailAlertSheet = [[UIActionSheet alloc] initWithTitle:UCLocalize("ERROR") buttons:buttons defaultButtonIndex:0 delegate:self context:self];
178 [mailAlertSheet setBodyText:[controller_ error]];
179 [mailAlertSheet popupAlertAnimated:YES];
3ff1504e
JF
180}
181
61b13cae
JF
182- (void) deliverMessage { _pooled
183 setuid(501);
184 setgid(501);
0fc560b6 185
61b13cae
JF
186 if (![controller_ deliverMessage])
187 [self performSelectorOnMainThread:@selector(showError) withObject:nil waitUntilDone:NO];
0fc560b6
JF
188}
189
61b13cae
JF
190- (void) mailComposeControllerCompositionFinished:(MailComposeController *)controller {
191 if ([controller_ needsDelivery])
192 [NSThread detachNewThreadSelector:@selector(deliverMessage) toTarget:self withObject:nil];
45f88d41 193 else
61b13cae 194 [self cancel];
45f88d41
JF
195}
196
61b13cae
JF
197- (id) initWithView:(UIView *)view delegate:(id)delegate url:(NSURL *)url {
198 if ((self = [super initWithView:view delegate:delegate]) != nil) {
199 controller_ = [[MailComposeController alloc] initForContentSize:[overlay_ bounds].size];
200 [controller_ setDelegate:self];
201 [controller_ initializeUI];
202 [controller_ setupForURL:url];
7b00c562 203
61b13cae
JF
204 UIView *view([controller_ view]);
205 [overlay_ addSubview:view];
206 } return self;
9d7f5e2d
JF
207}
208
45f88d41
JF
209@end
210/* }}} */
61b13cae 211#endif
45f88d41 212
4825688a
JF
213#define ShowInternals 0
214#define LogBrowser 0
215
216#define lprintf(args...) fprintf(stderr, args)
217
bde2d79b
JF
218@implementation BrowserView
219
5a5c1e4b 220#if ShowInternals
4825688a 221#include "UICaboodle/UCInternal.h"
bde2d79b
JF
222#endif
223
4825688a
JF
224+ (void) _initialize {
225 NSLog(@"INITIALIZING");
226 [WebView enableWebThread];
227
228 WebPreferences *preferences([WebPreferences standardPreferences]);
229 [preferences setCacheModel:WebCacheModelDocumentBrowser];
230 [preferences setOfflineWebApplicationCacheEnabled:YES];
231
232 [WebPreferences _setInitialDefaultTextEncodingToSystemEncoding];
233}
234
bde2d79b 235- (void) dealloc {
1ce016d4 236#if LogBrowser
7b00c562
JF
237 NSLog(@"[BrowserView dealloc]");
238#endif
5a5c1e4b 239
bde2d79b
JF
240 if (challenge_ != nil)
241 [challenge_ release];
242
9d7f5e2d
JF
243 WebThreadLock();
244
bde2d79b
JF
245 WebView *webview = [webview_ webView];
246 [webview setFrameLoadDelegate:nil];
247 [webview setResourceLoadDelegate:nil];
248 [webview setUIDelegate:nil];
249 [webview setScriptDebugDelegate:nil];
250 [webview setPolicyDelegate:nil];
251
9d7f5e2d 252 /* XXX: these are set by UIWebDocumentView
4825688a 253 [webview setDownloadDelegate:nil];
bde2d79b
JF
254 [webview _setFormDelegate:nil];
255 [webview _setUIKitDelegate:nil];
9d7f5e2d
JF
256 [webview setEditingDelegate:nil];*/
257
258 /* XXX: no one sets this, ever
259 [webview setWebMailDelegate:nil];*/
bde2d79b
JF
260
261 [webview_ setDelegate:nil];
262 [webview_ setGestureDelegate:nil];
dcc55b8b
JF
263 [webview_ setFormEditingDelegate:nil];
264 [webview_ setInteractionDelegate:nil];
bde2d79b 265
9d7f5e2d
JF
266 [indirect_ setDelegate:nil];
267
bde2d79b
JF
268 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
269
270 [webview close];
271
272#if RecycleWebViews
273 [webview_ removeFromSuperview];
274 [Documents_ addObject:[webview_ autorelease]];
275#else
276 [webview_ release];
277#endif
278
bde2d79b
JF
279 [indirect_ release];
280
9d7f5e2d
JF
281 WebThreadUnlock();
282
bde2d79b
JF
283 [scroller_ setDelegate:nil];
284
285 if (button_ != nil)
286 [button_ release];
287 if (style_ != nil)
288 [style_ release];
289 if (function_ != nil)
290 [function_ release];
9d7f5e2d
JF
291 if (finish_ != nil)
292 [finish_ release];
1ce016d4
JF
293 if (closer_ != nil)
294 [closer_ release];
9d7f5e2d
JF
295 if (special_ != nil)
296 [special_ release];
bde2d79b
JF
297
298 [scroller_ release];
299 [indicator_ release];
300 if (confirm_ != nil)
301 [confirm_ release];
0fc560b6
JF
302 if (sensitive_ != nil)
303 [sensitive_ release];
bde2d79b
JF
304 if (title_ != nil)
305 [title_ release];
306 [super dealloc];
307}
308
309- (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
310 [self loadRequest:[NSURLRequest
311 requestWithURL:url
312 cachePolicy:policy
313 timeoutInterval:30.0
314 ]];
315}
316
317- (void) loadURL:(NSURL *)url {
318 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
319}
320
bde2d79b
JF
321- (void) loadRequest:(NSURLRequest *)request {
322 pushed_ = true;
f4772bd1 323 error_ = false;
9d7f5e2d
JF
324
325 WebThreadLock();
bde2d79b 326 [webview_ loadRequest:request];
9d7f5e2d 327 WebThreadUnlock();
bde2d79b
JF
328}
329
330- (void) reloadURL {
bde2d79b
JF
331 if (request_ == nil)
332 return;
333
334 if ([request_ HTTPBody] == nil && [request_ HTTPBodyStream] == nil)
f4772bd1 335 [self loadRequest:request_];
bde2d79b
JF
336 else {
337 UIActionSheet *sheet = [[[UIActionSheet alloc]
61b13cae
JF
338 initWithTitle:UCLocalize("RESUBMIT_FORM")
339 buttons:[NSArray arrayWithObjects:UCLocalize("CANCEL"), UCLocalize("SUBMIT"), nil]
bde2d79b
JF
340 defaultButtonIndex:0
341 delegate:self
342 context:@"submit"
343 ] autorelease];
344
345 [sheet setNumberOfRows:1];
346 [sheet popupAlertAnimated:YES];
347 }
348}
349
350- (WebView *) webView {
351 return [webview_ webView];
352}
353
5a5c1e4b
JF
354- (UIWebDocumentView *) documentView {
355 return webview_;
356}
357
9d7f5e2d
JF
358/* XXX: WebThreadLock? */
359- (void) _fixScroller:(CGRect)bounds {
dcc55b8b
JF
360 float extra;
361 if (!editing_)
362 extra = 0;
363 else {
364 UIFormAssistant *assistant([UIFormAssistant sharedFormAssistant]);
365 CGRect peripheral([assistant peripheralFrame]);
1ce016d4 366#if LogBrowser
dcc55b8b 367 NSLog(@"per:%f", peripheral.size.height);
5889429e 368#endif
dcc55b8b
JF
369 extra = peripheral.size.height;
370 }
371
372 CGRect subrect([scroller_ frame]);
373 subrect.size.height -= extra;
374 [scroller_ setScrollerIndicatorSubrect:subrect];
375
5889429e
JF
376 NSSize visible(NSMakeSize(subrect.size.width, subrect.size.height));
377 [webview_ setValue:[NSValue valueWithSize:visible] forGestureAttribute:UIGestureAttributeVisibleSize];
378
dcc55b8b
JF
379 CGSize size(size_);
380 size.height += extra;
381 [scroller_ setContentSize:size];
5889429e
JF
382
383 [scroller_ releaseRubberBandIfNecessary];
dcc55b8b
JF
384}
385
9d7f5e2d
JF
386- (void) fixScroller {
387 CGRect bounds([webview_ documentBounds]);
e9fde613 388#if TrackResize
9d7f5e2d
JF
389 NSLog(@"_fs:(%f,%f+%f,%f)", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
390#endif
391 [self _fixScroller:bounds];
392}
393
bde2d79b 394- (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
dcc55b8b 395 size_ = frame.size;
e9fde613 396#if TrackResize
5889429e
JF
397 NSLog(@"dsf:(%f,%f+%f,%f)", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
398#endif
9d7f5e2d 399 [self _fixScroller:frame];
bde2d79b
JF
400}
401
402- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
403 [self view:sender didSetFrame:frame];
404}
405
406- (void) pushPage:(RVPage *)page {
bde2d79b 407 [page setDelegate:delegate_];
2517c95f 408 [self setBackButtonTitle:title_];
5a5c1e4b 409 [book_ pushPage:page];
bde2d79b
JF
410}
411
a55054a2
JF
412- (void) _pushPage {
413 if (pushed_)
414 return;
9d7f5e2d 415 // WTR: [self autorelease];
a55054a2
JF
416 pushed_ = true;
417 [book_ pushPage:self];
418}
419
5889429e
JF
420- (void) swapPage:(RVPage *)page {
421 [page setDelegate:delegate_];
422 if (pushed_)
423 [book_ swapPage:page];
424 else
425 [book_ pushPage:page];
426}
427
b8de369a 428- (BOOL) getSpecial:(NSURL *)url swap:(BOOL)swap {
1ce016d4 429#if LogBrowser
a55054a2
JF
430 NSLog(@"getSpecial:%@", url);
431#endif
432
61b13cae 433 if (RVPage *page = [delegate_ pageForURL:url hasTag:NULL]) {
b8de369a
JF
434 if (swap)
435 [self swapPage:page];
436 else
437 [self pushPage:page];
61b13cae
JF
438
439 return true;
440 } else
441 return false;
bde2d79b
JF
442}
443
4825688a
JF
444- (void) formAssistant:(id)sender didBeginEditingFormNode:(id)node {
445}
446
447- (void) formAssistant:(id)sender didEndEditingFormNode:(id)node {
448 [self fixScroller];
449}
450
5a5c1e4b 451- (void) webViewShow:(WebView *)sender {
5b2d5cf3 452 /* XXX: this is where I cry myself to sleep */
5a5c1e4b
JF
453}
454
7b00c562
JF
455- (bool) _allowJavaScriptPanel {
456 return true;
457}
458
0fc560b6 459- (bool) allowSensitiveRequests {
61b13cae 460 return [self _allowJavaScriptPanel];
0fc560b6
JF
461}
462
463- (void) _promptForSensitive:(NSMutableArray *)array {
464 NSString *name([array objectAtIndex:0]);
465
466 UIActionSheet *sheet = [[[UIActionSheet alloc]
467 initWithTitle:nil
61b13cae 468 buttons:[NSArray arrayWithObjects:UCLocalize("YES"), UCLocalize("NO"), nil]
0fc560b6
JF
469 defaultButtonIndex:0
470 delegate:indirect_
471 context:@"sensitive"
472 ] autorelease];
473
474 NSString *host(@"XXX");
475
476 [sheet setNumberOfRows:1];
477 [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]];
478 [sheet popupAlertAnimated:YES];
479
480 NSRunLoop *loop([NSRunLoop currentRunLoop]);
481 NSDate *future([NSDate distantFuture]);
482
483 while (sensitive_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
484
485 NSNumber *sensitive([sensitive_ autorelease]);
486 sensitive_ = nil;
487
488 [self autorelease];
489 [array replaceObjectAtIndex:0 withObject:sensitive];
490}
491
492- (bool) promptForSensitive:(NSString *)name {
493 if (![self allowSensitiveRequests])
494 return false;
495
496 NSMutableArray *array([NSMutableArray arrayWithCapacity:1]);
497 [array addObject:name];
498
499 [self performSelectorOnMainThread:@selector(_promptForSensitive:) withObject:array waitUntilDone:YES];
500 return [[array lastObject] boolValue];
501}
502
bde2d79b 503- (void) webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
263b91b4 504 if (![self _allowJavaScriptPanel])
7b00c562 505 return;
b452841e 506 [self retain];
b456f1c9 507
bde2d79b
JF
508 UIActionSheet *sheet = [[[UIActionSheet alloc]
509 initWithTitle:nil
61b13cae 510 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), nil]
bde2d79b
JF
511 defaultButtonIndex:0
512 delegate:self
513 context:@"alert"
514 ] autorelease];
515
516 [sheet setBodyText:message];
517 [sheet popupAlertAnimated:YES];
518}
519
520- (BOOL) webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
7b00c562
JF
521 if (![self _allowJavaScriptPanel])
522 return NO;
b452841e 523 [self retain];
7b00c562 524
bde2d79b
JF
525 UIActionSheet *sheet = [[[UIActionSheet alloc]
526 initWithTitle:nil
61b13cae 527 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), UCLocalize("CANCEL"), nil]
bde2d79b 528 defaultButtonIndex:0
b456f1c9 529 delegate:indirect_
bde2d79b
JF
530 context:@"confirm"
531 ] autorelease];
532
533 [sheet setNumberOfRows:1];
534 [sheet setBodyText:message];
535 [sheet popupAlertAnimated:YES];
536
537 NSRunLoop *loop([NSRunLoop currentRunLoop]);
538 NSDate *future([NSDate distantFuture]);
539
540 while (confirm_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
541
542 NSNumber *confirm([confirm_ autorelease]);
543 confirm_ = nil;
b452841e
JF
544
545 [self autorelease];
bde2d79b
JF
546 return [confirm boolValue];
547}
548
7b00c562
JF
549- (void) setAutoPopup:(BOOL)popup {
550 popup_ = popup;
551}
552
9d7f5e2d
JF
553- (void) setSpecial:(id)function {
554 if (special_ != nil)
555 [special_ autorelease];
556 special_ = function == nil ? nil : [function retain];
1ce016d4
JF
557}
558
bde2d79b
JF
559- (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
560 if (button_ != nil)
561 [button_ autorelease];
562 button_ = button == nil ? nil : [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain];
563
564 if (style_ != nil)
565 [style_ autorelease];
566 style_ = style == nil ? nil : [style retain];
567
568 if (function_ != nil)
569 [function_ autorelease];
570 function_ = function == nil ? nil : [function retain];
1ce016d4
JF
571
572 [self reloadButtons];
bde2d79b
JF
573}
574
575- (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
576 if (button_ != nil)
577 [button_ autorelease];
578 button_ = button == nil ? nil : [button retain];
579
580 if (style_ != nil)
581 [style_ autorelease];
582 style_ = style == nil ? nil : [style retain];
583
584 if (function_ != nil)
585 [function_ autorelease];
586 function_ = function == nil ? nil : [function retain];
1ce016d4
JF
587
588 [self reloadButtons];
bde2d79b 589}
bde2d79b 590
9d7f5e2d
JF
591- (void) setFinishHook:(id)function {
592 if (finish_ != nil)
593 [finish_ autorelease];
594 finish_ = function == nil ? nil : [function retain];
595}
596
597- (void) setPopupHook:(id)function {
598 if (closer_ != nil)
599 [closer_ autorelease];
600 closer_ = function == nil ? nil : [function retain];
601}
602
61b13cae
JF
603- (void) _openMailToURL:(NSURL *)url {
604// XXX: this makes me sad
605#if 0
606 [[[MailToView alloc] initWithView:underlay_ delegate:self url:url] autorelease];
607#else
608 [UIApp openURL:url];// asPanel:YES];
609#endif
610}
611
dcc55b8b
JF
612- (void) webView:(WebView *)sender willBeginEditingFormElement:(id)element {
613 editing_ = true;
614}
615
616- (void) webView:(WebView *)sender didBeginEditingFormElement:(id)element {
9d7f5e2d 617 [self fixScroller];
dcc55b8b
JF
618}
619
620- (void) webViewDidEndEditingFormElements:(WebView *)sender {
621 editing_ = false;
9d7f5e2d 622 [self fixScroller];
dcc55b8b
JF
623}
624
04700693
JF
625- (void) webViewClose:(WebView *)sender {
626 [book_ close];
627}
628
7afcea1c
JF
629- (void) close {
630 [book_ close];
631}
632
bde2d79b 633- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
bde2d79b
JF
634}
635
636- (void) webView:(WebView *)sender unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame {
637 NSLog(@"err:%@", error);
638}
639
640- (void) webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id<WebPolicyDecisionListener>)listener {
1ce016d4 641#if LogBrowser
5a5c1e4b 642 NSLog(@"nwa:%@", name);
7b00c562 643#endif
5a5c1e4b 644
bde2d79b 645 if (NSURL *url = [request URL]) {
04700693 646 if (name == nil) unknown: {
b8de369a 647 if (![self getSpecial:url swap:NO]) {
04700693
JF
648 NSString *scheme([[url scheme] lowercaseString]);
649 if ([scheme isEqualToString:@"mailto"])
61b13cae 650 [self _openMailToURL:url];
04700693
JF
651 else goto use;
652 }
653 } else if ([name isEqualToString:@"_open"])
bde2d79b 654 [delegate_ openURL:url];
04700693 655 else if ([name isEqualToString:@"_popup"]) {
3ac7a20a
JF
656 NSString *scheme([[url scheme] lowercaseString]);
657 if ([scheme isEqualToString:@"mailto"])
61b13cae 658 [self _openMailToURL:url];
3ac7a20a
JF
659 else {
660 RVBook *book([[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]);
661 [book setHook:indirect_];
04700693 662
3ac7a20a
JF
663 RVPage *page([delegate_ pageForURL:url hasTag:NULL]);
664 if (page == nil) {
665 /* XXX: call createWebViewWithRequest instead? */
5a5c1e4b 666
3ac7a20a 667 [self setBackButtonTitle:title_];
5a5c1e4b 668
85021801 669 BrowserView *browser([[[class_ alloc] initWithBook:book] autorelease]);
3ac7a20a
JF
670 [browser loadURL:url];
671 page = browser;
672 }
bde2d79b 673
3ac7a20a
JF
674 [book setDelegate:delegate_];
675 [page setDelegate:delegate_];
0a7e5478 676
3ac7a20a
JF
677 [book setPage:page];
678 [book_ pushBook:book];
679 }
04700693 680 } else goto unknown;
bde2d79b
JF
681
682 [listener ignore];
683 } else use:
684 [listener use];
685}
686
5889429e 687- (void) webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
bde2d79b
JF
688 if ([WebView canShowMIMEType:type])
689 [listener use];
690 else {
691 // XXX: handle more mime types!
692 [listener ignore];
5889429e
JF
693
694 WebView *webview([webview_ webView]);
695 if (frame == [webview mainFrame])
bde2d79b
JF
696 [UIApp openURL:[request URL]];
697 }
698}
699
700- (void) webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
701 if (request == nil) ignore: {
702 [listener ignore];
703 return;
704 }
705
706 NSURL *url([request URL]);
707
708 if (url == nil) use: {
f4772bd1 709 if (!error_ && [frame parentFrame] == nil) {
bde2d79b
JF
710 if (request_ != nil)
711 [request_ autorelease];
712 request_ = [request retain];
1ce016d4 713#if LogBrowser
bde2d79b 714 NSLog(@"dpn:%@", request_);
04700693 715#endif
bde2d79b
JF
716 }
717
718 [listener use];
5889429e
JF
719
720 WebView *webview([webview_ webView]);
721 if (frame == [webview mainFrame])
722 [self _pushPage];
bde2d79b
JF
723 return;
724 }
1ce016d4 725#if LogBrowser
bde2d79b
JF
726 else NSLog(@"nav:%@:%@", url, [action description]);
727#endif
728
9d7f5e2d
JF
729 const NSArray *capability;
730
731#if 0 // XXX:3:GSSystemCopyCapability
732 capability = reinterpret_cast<const NSArray *>(GSSystemGetCapability(kGSDisplayIdentifiersCapability));
733#else
734 capability = nil;
735#endif
bde2d79b 736
9d7f5e2d 737 if (capability != nil && (
bde2d79b
JF
738 [capability containsObject:@"com.apple.Maps"] && [url mapsURL] ||
739 [capability containsObject:@"com.apple.youtube"] && [url youTubeURL]
9d7f5e2d 740 )) {
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
834 default:
835 _assert(false);
836 }
837
838 [challenge_ release];
839 challenge_ = nil;
840
841 [sheet dismiss];
842 } else if ([context isEqualToString:@"submit"]) {
843 switch (button) {
844 case 1:
845 break;
846
847 case 2:
9d7f5e2d
JF
848 if (request_ != nil) {
849 WebThreadLock();
bde2d79b 850 [webview_ loadRequest:request_];
9d7f5e2d
JF
851 WebThreadUnlock();
852 }
bde2d79b
JF
853 break;
854
855 default:
856 _assert(false);
857 }
858
859 [sheet dismiss];
860 }
861}
862
863- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
864 challenge_ = [challenge retain];
865
866 NSURLProtectionSpace *space([challenge protectionSpace]);
867 NSString *realm([space realm]);
868 if (realm == nil)
869 realm = @"";
870
871 UIActionSheet *sheet = [[[UIActionSheet alloc]
872 initWithTitle:realm
61b13cae 873 buttons:[NSArray arrayWithObjects:UCLocalize("LOGIN"), UCLocalize("CANCEL"), nil]
bde2d79b
JF
874 defaultButtonIndex:0
875 delegate:self
876 context:@"challenge"
877 ] autorelease];
878
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
JF
918
919 RVBook *book(!popup_ ? book_ : [[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]);
920
921 /* XXX: deal with cydia:// pages */
85021801 922 BrowserView *browser([[[class_ alloc] initWithBook:book forWidth:width] autorelease]);
7b00c562 923
b456f1c9 924 if (features != nil && popup_) {
7b00c562 925 [book setDelegate:delegate_];
1ce016d4 926 [book setHook:indirect_];
7b00c562
JF
927 [browser setDelegate:delegate_];
928
929 [browser loadRequest:request];
a55054a2 930
7b00c562
JF
931 [book setPage:browser];
932 [book_ pushBook:book];
933 } else if (request == nil) {
a55054a2
JF
934 [self setBackButtonTitle:title_];
935 [browser setDelegate:delegate_];
936 [browser retain];
937 } else {
938 [self pushPage:browser];
939 [browser loadRequest:request];
940 }
941
bde2d79b
JF
942 return [browser webView];
943}
944
945- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
5a5c1e4b 946 return [self webView:sender createWebViewWithRequest:request windowFeatures:nil];
7b00c562 947 //return [self webView:sender createWebViewWithRequest:request userGesture:YES];
bde2d79b
JF
948}
949
950- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
951 if ([frame parentFrame] != nil)
952 return;
953
954 title_ = [title retain];
955 [book_ reloadTitleForPage:self];
956}
957
958- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
b452841e
JF
959 if ([loading_ count] == 0)
960 [self retain];
961 [loading_ addObject:[NSValue valueWithNonretainedObject:frame]];
bde2d79b 962
9d7f5e2d
JF
963 if ([frame parentFrame] == nil) {
964 [webview_ resignFirstResponder];
5889429e 965
9d7f5e2d 966 reloading_ = false;
bde2d79b 967
9d7f5e2d
JF
968 if (title_ != nil) {
969 [title_ release];
970 title_ = nil;
971 }
bde2d79b 972
9d7f5e2d
JF
973 if (button_ != nil) {
974 [button_ release];
975 button_ = nil;
976 }
bde2d79b 977
9d7f5e2d
JF
978 if (style_ != nil) {
979 [style_ release];
980 style_ = nil;
981 }
bde2d79b 982
9d7f5e2d
JF
983 if (function_ != nil) {
984 [function_ release];
985 function_ = nil;
986 }
bde2d79b 987
9d7f5e2d
JF
988 if (finish_ != nil) {
989 [finish_ release];
990 finish_ = nil;
991 }
1ce016d4 992
9d7f5e2d
JF
993 if (closer_ != nil) {
994 [closer_ release];
995 closer_ = nil;
996 }
997
998 if (special_ != nil) {
999 [special_ release];
1000 special_ = nil;
1001 }
bde2d79b 1002
9d7f5e2d
JF
1003 [book_ reloadTitleForPage:self];
1004
1005 [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
1006
1007 if ([scroller_ respondsToSelector:@selector(setZoomScale:duration:)])
1008 [scroller_ setZoomScale:1 duration:0];
f4cd7e8b
JF
1009 else if ([scroller_ respondsToSelector:@selector(_setZoomScale:duration:)])
1010 [scroller_ _setZoomScale:1 duration:0];
1011 /*else if ([scroller_ respondsToSelector:@selector(setZoomScale:animated:)])
1012 [scroller_ setZoomScale:1 animated:NO];*/
bde2d79b 1013
9d7f5e2d
JF
1014 CGRect webrect = [scroller_ bounds];
1015 webrect.size.height = 0;
1016 [webview_ setFrame:webrect];
1017 }
1018
1019 [self reloadButtons];
bde2d79b
JF
1020}
1021
1022- (void) _finishLoading {
b452841e
JF
1023 size_t count([loading_ count]);
1024 if (count == 0)
1025 [self autorelease];
1026 if (reloading_ || count != 0)
9d7f5e2d
JF
1027 return;
1028 if (finish_ != nil)
1029 [self callFunction:finish_];
1030 [self reloadButtons];
bde2d79b
JF
1031}
1032
1ce016d4 1033- (bool) isLoading {
9d7f5e2d 1034 return [loading_ count] != 0;
bde2d79b
JF
1035}
1036
1037- (void) reloadButtons {
1ce016d4 1038 if ([self isLoading])
bde2d79b
JF
1039 [indicator_ startAnimation];
1040 else
1041 [indicator_ stopAnimation];
1042 [super reloadButtons];
1043}
1044
1045- (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
1046 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
1047}
1048
1049- (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
1050 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
1051}
1052
1053- (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
1054 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
1055}
1056
1057- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
10c3a9c1 1058 [self _pushPage];
bde2d79b
JF
1059 return [webview_ webView:sender didCommitLoadForFrame:frame];
1060}
1061
1062- (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
1063 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
1064}
1065
1066- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
b452841e 1067 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
9d7f5e2d 1068 [self _finishLoading];
bde2d79b 1069
9d7f5e2d 1070 if ([frame parentFrame] == nil) {
bde2d79b
JF
1071 if (DOMDocument *document = [frame DOMDocument])
1072 if (DOMNodeList<NSFastEnumeration> *bodies = [document getElementsByTagName:@"body"])
1073 for (DOMHTMLBodyElement *body in bodies) {
1074 DOMCSSStyleDeclaration *style([document getComputedStyle:body pseudoElement:nil]);
1075
1076 bool colored(false);
1077
1078 if (DOMCSSPrimitiveValue *color = static_cast<DOMCSSPrimitiveValue *>([style getPropertyCSSValue:@"background-color"])) {
f4772bd1
JF
1079 if ([color primitiveType] == DOM_CSS_RGBCOLOR) {
1080 DOMRGBColor *rgb([color getRGBColorValue]);
1081
1082 float red([[rgb red] getFloatValue:DOM_CSS_NUMBER]);
1083 float green([[rgb green] getFloatValue:DOM_CSS_NUMBER]);
1084 float blue([[rgb blue] getFloatValue:DOM_CSS_NUMBER]);
1085 float alpha([[rgb alpha] getFloatValue:DOM_CSS_NUMBER]);
1086
1087 UIColor *uic(nil);
1088
1089 if (red == 0xc7 && green == 0xce && blue == 0xd5)
1090 uic = [UIColor pinStripeColor];
1091 else if (alpha != 0)
1092 uic = [UIColor
1093 colorWithRed:(red / 255)
1094 green:(green / 255)
1095 blue:(blue / 255)
1096 alpha:alpha
1097 ];
1098
1099 if (uic != nil) {
1100 colored = true;
1101 [scroller_ setBackgroundColor:uic];
1102 }
bde2d79b
JF
1103 }
1104 }
1105
1106 if (!colored)
1107 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1108 break;
1109 }
1110 }
1111
1112 return [webview_ webView:sender didFinishLoadForFrame:frame];
1113}
1114
9d7f5e2d 1115- (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame {
b452841e
JF
1116 if ([frame parentFrame] == nil)
1117 [self autorelease];
9d7f5e2d 1118
b452841e 1119 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
bde2d79b
JF
1120 [self _finishLoading];
1121
b452841e
JF
1122 if (reloading_)
1123 return;
1124
9d7f5e2d
JF
1125 if ([frame parentFrame] == nil) {
1126 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
1127 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
1128 [[error localizedDescription] stringByAddingPercentEscapes]
1129 ]]];
1130
1131 error_ = true;
1132 }
1133}
f4772bd1 1134
9d7f5e2d
JF
1135- (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1136 [self _didFailWithError:error forFrame:frame];
1137}
1138
1139- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1140 [self _didFailWithError:error forFrame:frame];
bde2d79b
JF
1141}
1142
1143- (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary {
1ce016d4 1144#if LogBrowser || ForSaurik
bde2d79b
JF
1145 lprintf("Console:%s\n", [[dictionary description] UTF8String]);
1146#endif
1147}
1148
9d7f5e2d
JF
1149/* XXX: fix this stupid include file
1150- (void) webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)database {
1151 [origin setQuota:0x500000];
1152}*/
1153
1154- (void) _setTileDrawingEnabled:(BOOL)enabled {
1155 //[webview_ setTileDrawingEnabled:enabled];
1156}
1157
dcc55b8b 1158- (void) setViewportWidth:(float)width {
5889429e 1159 width_ = width ? width != 0 : [[self class] defaultWidth];
dcc55b8b
JF
1160 [webview_ setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
1161}
1162
9d7f5e2d
JF
1163- (void) willStartGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1164 [self _setTileDrawingEnabled:NO];
1165}
1166
1167- (void) didFinishGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1168 [self _setTileDrawingEnabled:YES];
1169 [webview_ redrawScaledDocument];
1170}
1171
1172- (void) scrollerWillStartDragging:(UIScroller *)scroller {
1173 [self _setTileDrawingEnabled:NO];
1174}
1175
1176- (void) scrollerDidEndDragging:(UIScroller *)scroller willSmoothScroll:(BOOL)smooth {
1177 [self _setTileDrawingEnabled:YES];
1178}
1179
1180- (void) scrollerDidEndDragging:(UIScroller *)scroller {
1181 [self _setTileDrawingEnabled:YES];
1182}
1183
85021801 1184- (id) initWithBook:(RVBook *)book forWidth:(float)width ofClass:(Class)_class {
bde2d79b 1185 if ((self = [super initWithBook:book]) != nil) {
85021801 1186 class_ = _class;
9d7f5e2d 1187 loading_ = [[NSMutableSet alloc] initWithCapacity:3];
7b00c562 1188 popup_ = false;
bde2d79b
JF
1189
1190 struct CGRect bounds = [self bounds];
1191
1192 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
1193 [self addSubview:scroller_];
1194
bde2d79b
JF
1195 [scroller_ setFixedBackgroundPattern:YES];
1196 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1197
1198 [scroller_ setScrollingEnabled:YES];
bde2d79b
JF
1199 [scroller_ setClipsSubviews:YES];
1200 [scroller_ setAllowsRubberBanding:YES];
9d7f5e2d 1201
bde2d79b 1202 [scroller_ setDelegate:self];
9d7f5e2d
JF
1203 [scroller_ setBounces:YES];
1204 [scroller_ setScrollHysteresis:8];
1205 [scroller_ setThumbDetectionEnabled:NO];
1206 [scroller_ setDirectionalScrolling:YES];
1207 [scroller_ setScrollDecelerationFactor:0.99]; /* 0.989324 */
1208 [scroller_ setEventMode:YES];
1209 [scroller_ setShowBackgroundShadow:NO]; /* YES */
1210 [scroller_ setAllowsRubberBanding:YES]; /* Vertical */
1211 [scroller_ setAdjustForContentSizeChange:YES]; /* NO */
bde2d79b
JF
1212
1213 CGRect webrect = [scroller_ bounds];
1214 webrect.size.height = 0;
1215
1216 WebView *webview;
1217
9d7f5e2d
JF
1218 WebThreadLock();
1219
bde2d79b
JF
1220#if RecycleWebViews
1221 webview_ = [Documents_ lastObject];
1222 if (webview_ != nil) {
1223 webview_ = [webview_ retain];
1224 webview = [webview_ webView];
1225 [Documents_ removeLastObject];
1226 [webview_ setFrame:webrect];
1227 } else {
1228#else
1229 if (true) {
1230#endif
1231 webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect];
1232 webview = [webview_ webView];
1233
1234 // XXX: this is terribly (too?) expensive
1235 //[webview_ setDrawsBackground:NO];
1236 [webview setPreferencesIdentifier:@"Cydia"];
1237
1238 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
1239
4825688a
JF
1240 if ([webview_ respondsToSelector:@selector(enableReachability)])
1241 [webview_ enableReachability];
1242
bde2d79b
JF
1243 [webview_ setAllowsMessaging:YES];
1244
4825688a
JF
1245 if ([webview_ respondsToSelector:@selector(useSelectionAssistantWithMode:)])
1246 [webview_ useSelectionAssistantWithMode:0];
1247
bde2d79b
JF
1248 [webview_ setTilingEnabled:YES];
1249 [webview_ setDrawsGrid:NO];
1250 [webview_ setLogsTilingChanges:NO];
1251 [webview_ setTileMinificationFilter:kCAFilterNearest];
4825688a 1252
9d7f5e2d
JF
1253 if ([webview_ respondsToSelector:@selector(setDataDetectorTypes:)])
1254 /* XXX: abstractify */
1255 [webview_ setDataDetectorTypes:0x80000000];
1256 else
1257 [webview_ setDetectsPhoneNumbers:NO];
4825688a 1258
bde2d79b
JF
1259 [webview_ setAutoresizes:YES];
1260
1261 [webview_ setMinimumScale:0.25f forDocumentTypes:0x10];
7b00c562 1262 [webview_ setMaximumScale:5.00f forDocumentTypes:0x10];
bde2d79b 1263 [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x10];
7b00c562 1264 //[webview_ setViewportSize:CGSizeMake(980, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
bde2d79b
JF
1265
1266 [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x2];
1267
7b00c562 1268 [webview_ setMinimumScale:1.00f forDocumentTypes:0x8];
bde2d79b
JF
1269 [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x8];
1270 [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x8];
1271
1272 [webview_ _setDocumentType:0x4];
1273
9d7f5e2d
JF
1274 if ([webview_ respondsToSelector:@selector(UIWebDocumentView:)])
1275 [webview_ setZoomsFocusedFormControl:YES];
bde2d79b
JF
1276 [webview_ setContentsPosition:7];
1277 [webview_ setEnabledGestures:0xa];
1278 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeIsZoomRubberBandEnabled];
1279 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeUpdatesScroller];
1280
1281 [webview_ setSmoothsFonts:YES];
7b00c562 1282 [webview_ setAllowsImageSheet:YES];
bde2d79b 1283 [webview _setUsesLoaderCache:YES];
7b00c562
JF
1284
1285 [webview setGroupName:@"CydiaGroup"];
4825688a
JF
1286
1287 WebPreferences *preferences([webview preferences]);
1288
9d7f5e2d
JF
1289 if ([webview respondsToSelector:@selector(_setLayoutInterval:)])
1290 [webview _setLayoutInterval:0];
4825688a
JF
1291 else
1292 [preferences _setLayoutInterval:0];
bde2d79b
JF
1293 }
1294
dcc55b8b 1295 [self setViewportWidth:width];
7b00c562 1296
bde2d79b
JF
1297 [webview_ setDelegate:self];
1298 [webview_ setGestureDelegate:self];
dcc55b8b
JF
1299 [webview_ setFormEditingDelegate:self];
1300 [webview_ setInteractionDelegate:self];
1301
bde2d79b
JF
1302 [scroller_ addSubview:webview_];
1303
1304 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
1305
bde2d79b
JF
1306 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
1307
9d7f5e2d 1308 [webview setFrameLoadDelegate:indirect_];
4825688a 1309 [webview setPolicyDelegate:indirect_];
bde2d79b 1310 [webview setResourceLoadDelegate:indirect_];
9d7f5e2d 1311 [webview setUIDelegate:indirect_];
4825688a
JF
1312
1313 /* XXX: do not turn this on under penalty of extreme pain */
1314 [webview setScriptDebugDelegate:nil];
9d7f5e2d
JF
1315
1316 WebThreadUnlock();
1317
1318 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite];
1319 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)];
1320 [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite];
bde2d79b
JF
1321
1322 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
1323 [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
9d7f5e2d
JF
1324
1325 /*UIWebView *test([[[UIWebView alloc] initWithFrame:[self bounds]] autorelease]);
1326 [test loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.saurik.com/"]]];
1327 [self addSubview:test];*/
bde2d79b
JF
1328 } return self;
1329}
1330
85021801
JF
1331- (id) initWithBook:(RVBook *)book forWidth:(float)width {
1332 return [self initWithBook:book forWidth:width ofClass:[self class]];
1333}
1334
7b00c562 1335- (id) initWithBook:(RVBook *)book {
5889429e 1336 return [self initWithBook:book forWidth:0];
7b00c562
JF
1337}
1338
9d7f5e2d
JF
1339- (NSString *) stringByEvaluatingJavaScriptFromString:(NSString *)script {
1340 WebThreadLock();
1341 WebView *webview([webview_ webView]);
1342 NSString *string([webview stringByEvaluatingJavaScriptFromString:script]);
1343 WebThreadUnlock();
1344 return string;
bde2d79b
JF
1345}
1346
1ce016d4 1347- (void) callFunction:(WebScriptObject *)function {
9d7f5e2d
JF
1348 WebThreadLock();
1349
1ce016d4
JF
1350 WebView *webview([webview_ webView]);
1351 WebFrame *frame([webview mainFrame]);
bde2d79b 1352
1ce016d4
JF
1353 id _private(MSHookIvar<id>(webview, "_private"));
1354 WebCore::Page *page(_private == nil ? NULL : MSHookIvar<WebCore::Page *>(_private, "page"));
1355 WebCore::Settings *settings(page == NULL ? NULL : page->settings());
bde2d79b 1356
1ce016d4
JF
1357 bool no;
1358 if (settings == NULL)
1359 no = 0;
1360 else {
1361 no = settings->JavaScriptCanOpenWindowsAutomatically();
1362 settings->setJavaScriptCanOpenWindowsAutomatically(true);
bde2d79b 1363 }
1ce016d4 1364
61b13cae
JF
1365 if (UIWindow *window = [self window])
1366 if (UIResponder *responder = [window firstResponder])
1367 [responder resignFirstResponder];
1368
1ce016d4
JF
1369 JSObjectRef object([function JSObject]);
1370 JSGlobalContextRef context([frame globalContext]);
1371 JSObjectCallAsFunction(context, object, NULL, 0, NULL, NULL);
1372
1373 if (settings != NULL)
9d7f5e2d
JF
1374 settings->setJavaScriptCanOpenWindowsAutomatically(no);
1375
1376 WebThreadUnlock();
1ce016d4
JF
1377}
1378
1379- (void) didCloseBook:(RVBook *)book {
1380 if (closer_ != nil)
1381 [self callFunction:closer_];
1382}
1383
1384- (void) __rightButtonClicked {
1385 reloading_ = true;
1386 [self reloadURL];
1387}
1388
1389- (void) _rightButtonClicked {
9d7f5e2d
JF
1390#if !AlwaysReload
1391 if (function_ != nil)
1ce016d4 1392 [self callFunction:function_];
9d7f5e2d
JF
1393 else
1394#endif
1395 [self __rightButtonClicked];
bde2d79b
JF
1396}
1397
1398- (id) _rightButtonTitle {
61b13cae 1399 return UCLocalize("RELOAD");
bde2d79b
JF
1400}
1401
1402- (id) rightButtonTitle {
1ce016d4 1403 return [self isLoading] ? @"" : button_ != nil ? button_ : [self _rightButtonTitle];
bde2d79b
JF
1404}
1405
1406- (UINavigationButtonStyle) rightButtonStyle {
1407 if (style_ == nil) normal:
1408 return UINavigationButtonStyleNormal;
1409 else if ([style_ isEqualToString:@"Normal"])
1410 return UINavigationButtonStyleNormal;
1411 else if ([style_ isEqualToString:@"Back"])
1412 return UINavigationButtonStyleBack;
1413 else if ([style_ isEqualToString:@"Highlighted"])
1414 return UINavigationButtonStyleHighlighted;
1415 else if ([style_ isEqualToString:@"Destructive"])
1416 return UINavigationButtonStyleDestructive;
1417 else goto normal;
1418}
1419
1420- (NSString *) title {
61b13cae 1421 return title_ == nil ? UCLocalize("LOADING") : title_;
bde2d79b
JF
1422}
1423
1424- (NSString *) backButtonTitle {
61b13cae 1425 return UCLocalize("BROWSER");
bde2d79b
JF
1426}
1427
1428- (void) setPageActive:(BOOL)active {
1429 if (!active)
1430 [indicator_ removeFromSuperview];
1431 else
1432 [[book_ navigationBar] addSubview:indicator_];
1433}
1434
1435- (void) resetViewAnimated:(BOOL)animated {
1436}
1437
1438- (void) setPushed:(bool)pushed {
1439 pushed_ = pushed;
1440}
1441
7b00c562
JF
1442+ (float) defaultWidth {
1443 return 980;
1444}
1445
bde2d79b 1446@end