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