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