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

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

Properly handle form fields and buttons; note WebCoreFrameBridge removal.

File size: 7.0 KB
RevLine 
[66]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"
[443]10#import "ICeCoffEEWebPolicyDelegate.h"
11#import "ICeCoffEEParser.h"
12#import "ICeCoffEETrigger.h"
13#import <WebKit/WebKit.h>
[66]14#import <unistd.h>
15
[455]16// Safari 3.1 and earlier (pre-r31014)
17// eliminated in http://bugs.webkit.org/show_bug.cgi?id=17640
[449]18@interface WebCoreFrameBridge : NSObject
[443]19- (DOMRange *)convertNSRangeToDOMRange:(NSRange)range;
20- (NSString *)stringForRange:(DOMRange *)range;
[66]21@end
22
[443]23// XXX WebHTMLView is going away
[167]24@interface WebHTMLView : NSObject
[66]25
[320]26- (NSRect)selectionRect;
[443]27- (DOMRange *)_documentRange;
[66]28
[443]29- (WebView *)_webView;
[449]30- (WebCoreFrameBridge *)_bridge;
[167]31
[66]32@end
33
[448]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
[66]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;
[443]49static id /* (WebPolicyDelegate) */ policyDelegate;
50static id /* DOMRange */ selectedRange;
[167]51
[66]52- (void)mouseDown:(NSEvent *)e;
53{
[182]54 [downEvent release]; downEvent = nil;
[74]55 if (ICCF_enabled && ICCF_prefs.commandClickEnabled && ICCF_EventIsCommandMouseDown(e)) {
[443]56 if ([self respondsToSelector: @selector(_webView)]) {
57 WebView *webView = [(WebHTMLView *)self _webView];
58
[182]59 // save selection: it may be deselected on super mouseDown
[443]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];
[182]69 }
[66]70 }
71 [super mouseDown: e];
72}
73
74- (void)mouseUp:(NSEvent *)e;
75{
76 [super mouseUp: e];
77
[443]78 if (downEvent == nil)
79 return;
80
81 WebView *webView = [(WebHTMLView *)self _webView];
[455]82 BOOL webViewIsEditable = [webView isEditable];
83 BOOL elementIsEditable = YES; // don't restore
[448]84 BOOL isContinuousSpellCheckingEnabled = NO, isGrammarCheckingEnabled = NO;
[443]85
[455]86 if (webViewIsEditable) {
[443]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 {
[455]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");
[443]106 [webView setEditable: YES];
[448]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 }
[443]116
[448]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
[455]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 }
[443]133
134 id link = [elementDict objectForKey: @"WebElementLinkURL"];
135 NSString *url = [link isKindOfClass: [NSURL class]] ? [link absoluteString] : nil;
[455]136
[443]137 ICCF_StartIC();
138
139 id /* DOMRange */ domRange = nil;
140
141 if (url != nil) {
142 ICLog(@"got a link");
[455]143 if (!elementIsEditable) {
[443]144 ICCF_StopIC();
[436]145 return;
[182]146 }
[443]147 // XXX handle existing selection
148 domRange = [webView selectedDOMRange];
[455]149 [domRange selectNode: clickedNode];
[443]150 [webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
151 } else {
[455]152 if (!elementIsEditable) // may have become deselected in mouseDown
153 [webView setSelectedDOMRange: selectedRange affinity: NSSelectionAffinityDownstream];
[443]154
155 NSRange range = [ICeCoffEETrigger rangeForEvent: downEvent onTarget: (NSView<NSTextInput> *)self];
[446]156 NSAssert(range.location != NSNotFound, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select"));
[443]157
[455]158 WebCoreFrameBridge *bridge = [(WebHTMLView *)self _bridge];
159
[443]160 // XXX limit to a reasonable size
[455]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
[443]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];
[183]174 }
[443]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);
[182]190 }
[436]191 }
[443]192 } @catch (NSException *e) {
193 ICCF_HandleException(e, downEvent);
194 } @finally {
195 [selectedRange release]; selectedRange = nil;
196 [downEvent release]; downEvent = nil;
[455]197 if (!elementIsEditable && !webViewIsEditable) {
[443]198 [webView setEditable: NO];
[448]199 if (isContinuousSpellCheckingEnabled)
200 [webView setContinuousSpellCheckingEnabled: YES];
201 if (isGrammarCheckingEnabled)
202 [webView setGrammarCheckingEnabled: YES];
203 }
[443]204 }
[66]205
[443]206 ICCF_StopIC();
[66]207}
208
209@end
Note: See TracBrowser for help on using the repository browser.