source: trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebKit.m @ 446

Last change on this file since 446 was 446, checked in by Nicholas Riley, 12 years ago

Fixed -[NSCFString characterAtIndex:]: Range or index out of bounds when clicking outside text of Web page.

File size: 5.2 KB
Line 
1//
2//  ICeCoffEEWebKit.m
3//  ICeCoffEE APE
4//
5//  Created by Nicholas Riley on Sun Jan 19 2003.
6//  Copyright (c) 2003 Nicholas Riley. All rights reserved.
7//
8
9#import "ICeCoffEEWebKit.h"
10#import "ICeCoffEEWebPolicyDelegate.h"
11#import "ICeCoffEEParser.h"
12#import "ICeCoffEETrigger.h"
13#import <WebKit/WebKit.h>
14#import <unistd.h>
15
16// XXX WebCoreFrameBridge is going away
17// (see <http://trac.webkit.org/projects/webkit/changeset/30712>)
18// WebCoreBridge, from WebCoreBridge.h (Safari 2)
19// Web(Core)FrameBridge, from WebCoreFrameBridge.h (Safari 3)
20@interface WebCoreBridge : NSObject
21
22// XXX move to DOM-based accessors
23- (DOMRange *)convertNSRangeToDOMRange:(NSRange)range;
24- (NSString *)stringForRange:(DOMRange *)range;
25
26@end
27
28// XXX WebHTMLView is going away
29@interface WebHTMLView : NSObject
30
31- (NSRect)selectionRect;
32- (DOMRange *)_documentRange;
33
34- (WebView *)_webView;
35- (WebCoreBridge *)_bridge; // WebFrameBridge in Safari 3 (see above)
36
37@end
38
39@implementation ICeCoffEEWebKit
40
41- (NSMenu *)menuForEvent:(NSEvent *)e;
42{
43    NSMenu *myMenu = [super menuForEvent: e];
44    return ICCF_MenuForEvent(self, myMenu, e);
45}
46
47static NSEvent *downEvent = nil;
48static id /* (WebPolicyDelegate) */ policyDelegate;
49static id /* DOMRange */ selectedRange;
50
51- (void)mouseDown:(NSEvent *)e;
52{
53    [downEvent release]; downEvent = nil;
54    if (ICCF_enabled && ICCF_prefs.commandClickEnabled && ICCF_EventIsCommandMouseDown(e)) {
55        if ([self respondsToSelector: @selector(_webView)]) {
56            WebView *webView = [(WebHTMLView *)self _webView];
57           
58            // save selection: it may be deselected on super mouseDown
59            selectedRange = [[webView selectedDOMRange] retain];
60           
61            // stop any URL launching from happening
62            if ([webView isEditable]) {
63                policyDelegate = [[webView policyDelegate] retain];
64                [webView setPolicyDelegate: [ICeCoffEEWebPolicyDelegate sharedDelegate]];
65            }
66           
67            downEvent = [e retain];
68        }
69    }
70    [super mouseDown: e];
71}
72
73- (void)mouseUp:(NSEvent *)e;
74{
75    [super mouseUp: e];
76
77    if (downEvent == nil)
78        return;
79   
80    WebView *webView = [(WebHTMLView *)self _webView];
81    BOOL isEditable = [webView isEditable];
82
83    if (isEditable) {
84        [webView setPolicyDelegate: policyDelegate];
85        [policyDelegate release]; policyDelegate = nil;
86    }
87
88    NSPoint downPt = [downEvent locationInWindow];
89    NSPoint upPt = [e locationInWindow];
90    if (abs(downPt.x - upPt.x) > kICHysteresisPixels && abs(downPt.y - upPt.y) > kICHysteresisPixels)
91        return;
92
93    @try {
94        if (!isEditable)
95            [webView setEditable: YES];
96
97        NSPoint viewClickPt = [webView convertPoint: downPt fromView: nil];
98        NSDictionary *elementDict = [webView elementAtPoint: viewClickPt];
99        NSLog(@"elementDict: %@", elementDict);
100        NSAssert([elementDict count] != 0, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select"));
101       
102        WebCoreBridge *bridge = [(WebHTMLView *)self _bridge];
103
104        id link = [elementDict objectForKey: @"WebElementLinkURL"];
105        NSString *url = [link isKindOfClass: [NSURL class]] ? [link absoluteString] : nil;
106
107        ICCF_StartIC();
108       
109        id /* DOMRange */ domRange = nil;
110       
111        if (url != nil) {
112            ICLog(@"got a link");
113            if (!isEditable) {
114                ICCF_StopIC();
115                return;
116            }
117            // XXX handle existing selection
118            domRange = [webView selectedDOMRange];
119            [domRange selectNode: [elementDict objectForKey:@"WebElementDOMNode"]];
120            [webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
121        } else {
122            // may have become deselected in mouseDown
123            [webView setSelectedDOMRange: selectedRange affinity: NSSelectionAffinityDownstream];
124           
125            // XXX at some point, characterIndexForPoint: wasn't implemented, so this will fail
126            NSRange range = [ICeCoffEETrigger rangeForEvent: downEvent onTarget: (NSView<NSTextInput> *)self];
127           
128            NSAssert(range.location != NSNotFound, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select"));
129
130            // XXX limit to a reasonable size
131            // NSRange fetchRange = [bridge convertDOMRangeToNSRange: [(WebHTMLView *)self _documentRange]];
132            NSString *s = [bridge stringForRange: [(WebHTMLView *)self _documentRange]];
133       
134            if (range.length == 0) {
135                range.length = 1;
136                range = ICCF_URLEnclosingRange(s, range);
137                domRange = [bridge convertNSRangeToDOMRange: range];
138                [webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
139            } else {
140                domRange = [bridge convertNSRangeToDOMRange: range];
141            }
142           
143            url = [s substringWithRange: range];
144        }       
145       
146        if (ICCF_LaunchURL(url, ICCF_KeyboardAction(downEvent)) && ICCF_prefs.textBlinkEnabled && domRange != nil) {
147            NSRect selectionRect = [(WebHTMLView *)self selectionRect];
148            for (int i = 0 ; i < ICCF_prefs.textBlinkCount ; i++) {
149                [webView setSelectedDOMRange: nil affinity: NSSelectionAffinityDownstream];
150                [self setNeedsDisplayInRect: selectionRect];
151                [self display];
152                usleep(kICBlinkDelayUsecs);
153                [webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
154                [self setNeedsDisplayInRect: selectionRect];
155                [self display];
156                usleep(kICBlinkDelayUsecs);
157            }
158        }
159    } @catch (NSException *e) {
160        ICCF_HandleException(e, downEvent);
161    } @finally {
162        [selectedRange release]; selectedRange = nil;
163        [downEvent release]; downEvent = nil;
164        if (!isEditable)
165            [webView setEditable: NO];
166    }
167
168    ICCF_StopIC();
169}
170
171@end
Note: See TracBrowser for help on using the repository browser.