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

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

Properly handle form fields and buttons; note WebCoreFrameBridge? removal.

File size: 7.0 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// Safari 3.1 and earlier (pre-r31014)
17// eliminated in http://bugs.webkit.org/show_bug.cgi?id=17640
18@interface WebCoreFrameBridge : NSObject
19- (DOMRange *)convertNSRangeToDOMRange:(NSRange)range;
20- (NSString *)stringForRange:(DOMRange *)range;
21@end
22
23// XXX WebHTMLView is going away
24@interface WebHTMLView : NSObject
25
26- (NSRect)selectionRect;
27- (DOMRange *)_documentRange;
28
29- (WebView *)_webView;
30- (WebCoreFrameBridge *)_bridge;
31
32@end
33
34// from WebViewPrivate.h (will become public, part of WebViewEditing)
35@interface WebView (webViewGrammarChecking)
36- (BOOL)isGrammarCheckingEnabled;
37- (void)setGrammarCheckingEnabled:(BOOL)flag;
38@end
39
40@implementation ICeCoffEEWebKit
41
42- (NSMenu *)menuForEvent:(NSEvent *)e;
43{
44    NSMenu *myMenu = [super menuForEvent: e];
45    return ICCF_MenuForEvent(self, myMenu, e);
46}
47
48static NSEvent *downEvent = nil;
49static id /* (WebPolicyDelegate) */ policyDelegate;
50static id /* DOMRange */ selectedRange;
51
52- (void)mouseDown:(NSEvent *)e;
53{
54    [downEvent release]; downEvent = nil;
55    if (ICCF_enabled && ICCF_prefs.commandClickEnabled && ICCF_EventIsCommandMouseDown(e)) {
56        if ([self respondsToSelector: @selector(_webView)]) {
57            WebView *webView = [(WebHTMLView *)self _webView];
58           
59            // save selection: it may be deselected on super mouseDown
60            selectedRange = [[webView selectedDOMRange] retain];
61           
62            // stop any URL launching from happening
63            if ([webView isEditable]) {
64                policyDelegate = [[webView policyDelegate] retain];
65                [webView setPolicyDelegate: [ICeCoffEEWebPolicyDelegate sharedDelegate]];
66            }
67           
68            downEvent = [e retain];
69        }
70    }
71    [super mouseDown: e];
72}
73
74- (void)mouseUp:(NSEvent *)e;
75{
76    [super mouseUp: e];
77
78    if (downEvent == nil)
79        return;
80   
81    WebView *webView = [(WebHTMLView *)self _webView];
82    BOOL webViewIsEditable = [webView isEditable];
83    BOOL elementIsEditable = YES; // don't restore
84    BOOL isContinuousSpellCheckingEnabled = NO, isGrammarCheckingEnabled = NO;
85
86    if (webViewIsEditable) {
87        [webView setPolicyDelegate: policyDelegate];
88        [policyDelegate release]; policyDelegate = nil;
89    }
90
91    NSPoint downPt = [downEvent locationInWindow];
92    NSPoint upPt = [e locationInWindow];
93    if (abs(downPt.x - upPt.x) > kICHysteresisPixels && abs(downPt.y - upPt.y) > kICHysteresisPixels)
94        return;
95
96    @try {
97        NSPoint viewClickPt = [webView convertPoint: downPt fromView: nil];
98        NSDictionary *elementDict = [webView elementAtPoint: viewClickPt];
99        ICLog(@"elementDict: %@", elementDict);
100
101        NSAssert([elementDict count] != 0, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select"));
102
103        elementIsEditable = [[elementDict objectForKey: @"WebElementIsContentEditableKey"] boolValue];
104        if (!elementIsEditable) {
105            NSAssert(!webViewIsEditable, @"Internal error: uneditable element inside editable WebView");
106            [webView setEditable: YES];
107       
108            // don't want spelling/grammar marks to persist when view is made uneditable again
109            if ([webView respondsToSelector: @selector(isContinuousSpellCheckingEnabled)] &&
110                (isContinuousSpellCheckingEnabled = [webView isContinuousSpellCheckingEnabled])) {
111                if ([webView respondsToSelector: @selector(setContinuousSpellCheckingEnabled:)])
112                    [webView setContinuousSpellCheckingEnabled: NO];
113                else
114                    isContinuousSpellCheckingEnabled = NO; // don't restore
115            }
116
117            if ([webView respondsToSelector: @selector(isGrammarCheckingEnabled)] &&
118                (isGrammarCheckingEnabled = [webView isGrammarCheckingEnabled])) {
119                if ([webView respondsToSelector: @selector(setGrammarCheckingEnabled:)])
120                    [webView setGrammarCheckingEnabled: NO];
121                else
122                    isGrammarCheckingEnabled = NO; // don't restore
123            }
124        }
125
126        DOMNode *clickedNode = [elementDict objectForKey: @"WebElementDOMNode"];
127       
128        if (!elementIsEditable && ([clickedNode isKindOfClass: NSClassFromString(@"DOMHTMLInputElement")] ||
129            [clickedNode isKindOfClass: NSClassFromString(@"DOMHTMLFieldSetElement")])) {
130            ICLog(@"got an uneditable form field (e.g., button)");
131            return;
132        }
133
134        id link = [elementDict objectForKey: @"WebElementLinkURL"];
135        NSString *url = [link isKindOfClass: [NSURL class]] ? [link absoluteString] : nil;
136       
137        ICCF_StartIC();
138       
139        id /* DOMRange */ domRange = nil;
140       
141        if (url != nil) {
142            ICLog(@"got a link");
143            if (!elementIsEditable) {
144                ICCF_StopIC();
145                return;
146            }
147            // XXX handle existing selection
148            domRange = [webView selectedDOMRange];
149            [domRange selectNode: clickedNode];
150            [webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
151        } else {
152            if (!elementIsEditable) // may have become deselected in mouseDown
153                [webView setSelectedDOMRange: selectedRange affinity: NSSelectionAffinityDownstream];
154           
155            NSRange range = [ICeCoffEETrigger rangeForEvent: downEvent onTarget: (NSView<NSTextInput> *)self];
156            NSAssert(range.location != NSNotFound, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select"));
157
158            WebCoreFrameBridge *bridge = [(WebHTMLView *)self _bridge];
159
160            // XXX limit to a reasonable size
161            NSString *s;
162            if (elementIsEditable) // for form fields, range will be field-relative rather than document-relative
163                s = [[(NSView<NSTextInput> *)self attributedSubstringFromRange: NSMakeRange(0, UINT_MAX)] string];
164            else // sometimes attributedSubstringFromRange: returns nil
165                s = [bridge stringForRange: [(WebHTMLView *)self _documentRange]];
166           
167            if (range.length == 0) {
168                range.length = 1;
169                range = ICCF_URLEnclosingRange(s, range);
170                domRange = [bridge convertNSRangeToDOMRange: range];
171                [webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
172            } else {
173                domRange = [bridge convertNSRangeToDOMRange: range];
174            }
175           
176            url = [s substringWithRange: range];
177        }       
178       
179        if (ICCF_LaunchURL(url, ICCF_KeyboardAction(downEvent)) && ICCF_prefs.textBlinkEnabled && domRange != nil) {
180            NSRect selectionRect = [(WebHTMLView *)self selectionRect];
181            for (int i = 0 ; i < ICCF_prefs.textBlinkCount ; i++) {
182                [webView setSelectedDOMRange: nil affinity: NSSelectionAffinityDownstream];
183                [self setNeedsDisplayInRect: selectionRect];
184                [self display];
185                usleep(kICBlinkDelayUsecs);
186                [webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
187                [self setNeedsDisplayInRect: selectionRect];
188                [self display];
189                usleep(kICBlinkDelayUsecs);
190            }
191        }
192    } @catch (NSException *e) {
193        ICCF_HandleException(e, downEvent);
194    } @finally {
195        [selectedRange release]; selectedRange = nil;
196        [downEvent release]; downEvent = nil;
197        if (!elementIsEditable && !webViewIsEditable) {
198            [webView setEditable: NO];
199            if (isContinuousSpellCheckingEnabled)
200                [webView setContinuousSpellCheckingEnabled: YES];
201            if (isGrammarCheckingEnabled)
202                [webView setGrammarCheckingEnabled: YES];
203        }
204    }
205
206    ICCF_StopIC();
207}
208
209@end
Note: See TracBrowser for help on using the repository browser.