Index: trunk/ICeCoffEE/ICeCoffEE/APEMain.m
===================================================================
--- trunk/ICeCoffEE/ICeCoffEE/APEMain.m	(revision 442)
+++ trunk/ICeCoffEE/ICeCoffEE/APEMain.m	(revision 443)
@@ -160,8 +160,9 @@
     }
 
-    ICCF_PatchMethod("WebHTMLView", "ICeCoffEEWebKit", "ICeCoffEEWebKitSuper", "mouseUp:") &&
+    objc_getClass("WebCoreFrameBridge") != NULL /* require Safari 3 */ &&
+	ICCF_PatchMethod("WebHTMLView", "ICeCoffEEWebKit", "ICeCoffEEWebKitSuper", "mouseUp:") &&
         ICCF_PatchMethod("WebHTMLView", "ICeCoffEEWebKit", "ICeCoffEEWebKitSuper", "mouseDown:") &&
         ICCF_PatchMethod("WebHTMLView", "ICeCoffEEWebKit", "ICeCoffEEWebKitSuper", "menuForEvent:");
-        ICapeprintf("ICeCoffEE APE: loaded in WebHTMLView for WebKit/Safari\n");
+        ICapeprintf("ICeCoffEE APE: loaded in WebHTMLView for WebKit/Safari 3\n");
     
     if (shouldLoadInNSTextView) {
Index: trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebKit.m
===================================================================
--- trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebKit.m	(revision 442)
+++ trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebKit.m	(revision 443)
@@ -8,28 +8,30 @@
 
 #import "ICeCoffEEWebKit.h"
+#import "ICeCoffEEWebPolicyDelegate.h"
+#import "ICeCoffEEParser.h"
+#import "ICeCoffEETrigger.h"
+#import <WebKit/WebKit.h>
 #import <unistd.h>
 
+// XXX WebCoreFrameBridge is going away
+// (see <http://trac.webkit.org/projects/webkit/changeset/30712>)
 // WebCoreBridge, from WebCoreBridge.h (Safari 2)
 // Web(Core)FrameBridge, from WebCoreFrameBridge.h (Safari 3)
 @interface WebCoreBridge : NSObject
 
-// can only use setMarkedText:selectedRange: if WebHTMLView is editable
-// or, should we move to DOM-based accessors, i.e. "setMarkDOMRange"?
-- (void)selectNSRange:(NSRange)range;
+// XXX move to DOM-based accessors
+- (DOMRange *)convertNSRangeToDOMRange:(NSRange)range;
+- (NSString *)stringForRange:(DOMRange *)range;
 
 @end
 
-// from WebKit, private -- XXX maybe I'm better off going back the other way, relying on public methods in the bridge?
+// XXX WebHTMLView is going away
 @interface WebHTMLView : NSObject
 
-- (NSString *)selectedString;
 - (NSRect)selectionRect;
-- (NSRect)_selectionRect; // Safari 2, supported in Safari 3 only for use with Mail
-- (NSRange)selectedRange; // XXX same as selectedNSRange in WebCoreFrameBridge.h?
-- (void)deselectAll;
+- (DOMRange *)_documentRange;
 
-- (WebCoreBridge *)_bridge; /* WebFrameBridge in Safari 3 (see above) */
-
-- (NSDictionary *)elementAtPoint:(NSPoint)point;
+- (WebView *)_webView;
+- (WebCoreBridge *)_bridge; // WebFrameBridge in Safari 3 (see above)
 
 @end
@@ -44,6 +46,6 @@
 
 static NSEvent *downEvent = nil;
-static NSString *selectedString = nil;
-static NSRange selectedRange;
+static id /* (WebPolicyDelegate) */ policyDelegate;
+static id /* DOMRange */ selectedRange;
 
 - (void)mouseDown:(NSEvent *)e;
@@ -51,11 +53,18 @@
     [downEvent release]; downEvent = nil;
     if (ICCF_enabled && ICCF_prefs.commandClickEnabled && ICCF_EventIsCommandMouseDown(e)) {
-	if ([self respondsToSelector: @selector(selectedRange)]) {
+	if ([self respondsToSelector: @selector(_webView)]) {
+	    WebView *webView = [(WebHTMLView *)self _webView];
+	    
 	    // save selection: it may be deselected on super mouseDown
-	    selectedRange = [(WebHTMLView *)self selectedRange];
+	    selectedRange = [[webView selectedDOMRange] retain];
+	    
+	    // stop any URL launching from happening
+	    if ([webView isEditable]) {
+		policyDelegate = [[webView policyDelegate] retain];
+		[webView setPolicyDelegate: [ICeCoffEEWebPolicyDelegate sharedDelegate]];
+	    }
+	    
+	    downEvent = [e retain];
 	}
-	[selectedString release]; selectedString = nil;
-	selectedString = [[(WebHTMLView *)self selectedString] retain];
-        downEvent = [e retain];
     }
     [super mouseDown: e];
@@ -65,57 +74,95 @@
 {
     [super mouseUp: e];
-    if (downEvent != nil) {
-        NSPoint downPt = [downEvent locationInWindow];
-        NSPoint upPt = [e locationInWindow];
-        if (abs(downPt.x - upPt.x) > kICHysteresisPixels && abs(downPt.y - upPt.y) > kICHysteresisPixels)
-            return;
 
-        @try {
-            NSPoint viewClickPt = [self convertPoint: downPt fromView: nil];
-            NSDictionary *elementDict = [(WebHTMLView *)self elementAtPoint: viewClickPt];
-            WebCoreBridge *bridge = [(WebHTMLView *)self _bridge];
-            ICLog(@"elementDict: %@", elementDict);
-            NSAssert([elementDict count] != 0, @"Internal error: Got empty element dictionary from WebHTMLView");
-            if ([elementDict objectForKey: @"WebElementLinkURL"] != nil) {
-                ICLog(@"got a link");
-                return; // don't activate on links
-            }
-	    if (selectedString == nil || [selectedString length] == 0) {
-		ICLog(@"no selected string");
+    if (downEvent == nil)
+	return;
+    
+    WebView *webView = [(WebHTMLView *)self _webView];
+    BOOL isEditable = [webView isEditable];
+
+    if (isEditable) {
+	[webView setPolicyDelegate: policyDelegate];
+	[policyDelegate release]; policyDelegate = nil;
+    }
+
+    NSPoint downPt = [downEvent locationInWindow];
+    NSPoint upPt = [e locationInWindow];
+    if (abs(downPt.x - upPt.x) > kICHysteresisPixels && abs(downPt.y - upPt.y) > kICHysteresisPixels)
+	return;
+
+    @try {
+	if (!isEditable)
+	    [webView setEditable: YES];
+
+	NSPoint viewClickPt = [webView convertPoint: downPt fromView: nil];
+	NSDictionary *elementDict = [webView elementAtPoint: viewClickPt];
+	NSLog(@"elementDict: %@", elementDict);
+	NSAssert([elementDict count] != 0, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select"));
+
+	WebCoreBridge *bridge = [(WebHTMLView *)self _bridge];
+
+	id link = [elementDict objectForKey: @"WebElementLinkURL"];
+	NSString *url = [link isKindOfClass: [NSURL class]] ? [link absoluteString] : nil;
+
+	ICCF_StartIC();
+	
+	id /* DOMRange */ domRange = nil;
+	
+	if (url != nil) {
+	    ICLog(@"got a link");
+	    if (!isEditable) {
+		ICCF_StopIC();
 		return;
 	    }
-	    ICCF_StartIC();
-	    BOOL canSetSelection = [bridge respondsToSelector: @selector(selectNSRange:)];
-	    if (canSetSelection) {
-		// may have become deselected in mouseDown
-		[bridge selectNSRange: selectedRange];
+	    // XXX handle existing selection
+	    domRange = [webView selectedDOMRange];
+	    [domRange selectNode: [elementDict objectForKey:@"WebElementDOMNode"]];
+	    [webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
+	} else {
+	    // may have become deselected in mouseDown
+	    [webView setSelectedDOMRange: selectedRange affinity: NSSelectionAffinityDownstream];
+	    
+	    // XXX at some point, characterIndexForPoint: wasn't implemented, so this will fail
+	    NSRange range = [ICeCoffEETrigger rangeForEvent: downEvent onTarget: (NSView<NSTextInput> *)self];
+
+	    // XXX limit to a reasonable size
+	    // NSRange fetchRange = [bridge convertDOMRangeToNSRange: [(WebHTMLView *)self _documentRange]];
+	    NSString *s = [bridge stringForRange: [(WebHTMLView *)self _documentRange]];
+	
+	    if (range.length == 0) {
+		range.length = 1;
+		range = ICCF_URLEnclosingRange(s, range);
+		domRange = [bridge convertNSRangeToDOMRange: range];
+		[webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
+	    } else {
+		domRange = [bridge convertNSRangeToDOMRange: range];
 	    }
-	    if (ICCF_LaunchURL(selectedString, ICCF_KeyboardAction(downEvent)) && ICCF_prefs.textBlinkEnabled && canSetSelection) {
-		int i;
-		NSRect selectionRect;
-		if ([self respondsToSelector: @selector(selectionRect)])
-		    selectionRect = [(WebHTMLView *)self selectionRect];
-		else
-		    selectionRect = [(WebHTMLView *)self _selectionRect];
-		ICLog(@"selectedRange %@ selectionRect %@ textBlinkCount %d", NSStringFromRange(selectedRange), NSStringFromRect(selectionRect), ICCF_prefs.textBlinkCount);
-		for (i = 0 ; i < ICCF_prefs.textBlinkCount ; i++) {
-		    [(WebHTMLView *)self deselectAll];
-		    [self setNeedsDisplayInRect: selectionRect];
-		    [self display];
-		    usleep(kICBlinkDelayUsecs);
-		    [bridge selectNSRange: selectedRange];
-		    [self setNeedsDisplayInRect: selectionRect];
-		    [self display];
-		    usleep(kICBlinkDelayUsecs);
-		}
+	    
+	    url = [s substringWithRange: range];
+	}	
+	
+	if (ICCF_LaunchURL(url, ICCF_KeyboardAction(downEvent)) && ICCF_prefs.textBlinkEnabled && domRange != nil) {
+	    NSRect selectionRect = [(WebHTMLView *)self selectionRect];
+	    for (int i = 0 ; i < ICCF_prefs.textBlinkCount ; i++) {
+		[webView setSelectedDOMRange: nil affinity: NSSelectionAffinityDownstream];
+		[self setNeedsDisplayInRect: selectionRect];
+		[self display];
+		usleep(kICBlinkDelayUsecs);
+		[webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
+		[self setNeedsDisplayInRect: selectionRect];
+		[self display];
+		usleep(kICBlinkDelayUsecs);
 	    }
-        } @catch (NSException *e) {
-	    ICCF_HandleException(e, downEvent);
-	} @finally {
-	    [downEvent release]; downEvent = nil;
 	}
+    } @catch (NSException *e) {
+	ICCF_HandleException(e, downEvent);
+    } @finally {
+	[selectedRange release]; selectedRange = nil;
+	[downEvent release]; downEvent = nil;
+	if (!isEditable)
+	    [webView setEditable: NO];
+    }
 
-        ICCF_StopIC();
-    }        
+    ICCF_StopIC();
 }
 
Index: trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebPolicyDelegate.h
===================================================================
--- trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebPolicyDelegate.h	(revision 443)
+++ trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebPolicyDelegate.h	(revision 443)
@@ -0,0 +1,18 @@
+//
+//  ICeCoffEEWebPolicyDelegate.h
+//  ICeCoffEE
+//
+//  Created by Nicholas Riley on 3/6/08.
+//  Copyright 2008 Nicholas Riley. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface ICeCoffEEWebPolicyDelegate : NSObject {
+
+}
+
++ (ICeCoffEEWebPolicyDelegate *)sharedDelegate;
+
+@end
Index: trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebPolicyDelegate.m
===================================================================
--- trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebPolicyDelegate.m	(revision 443)
+++ trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEWebPolicyDelegate.m	(revision 443)
@@ -0,0 +1,36 @@
+//
+//  ICeCoffEEWebPolicyDelegate.m
+//  ICeCoffEE
+//
+//  Created by Nicholas Riley on 3/6/08.
+//  Copyright 2008 Nicholas Riley. All rights reserved.
+//
+
+#import "ICeCoffEEWebPolicyDelegate.h"
+#import <WebKit/WebKit.h>
+
+@implementation ICeCoffEEWebPolicyDelegate
+
++ (ICeCoffEEWebPolicyDelegate *)sharedDelegate;
+{
+    static ICeCoffEEWebPolicyDelegate *sharedDelegate = nil;
+    
+    if (sharedDelegate == nil)
+	sharedDelegate = [[self alloc] init];
+    
+    return sharedDelegate;
+}
+
+@end
+
+@implementation ICeCoffEEWebPolicyDelegate (WebPolicyDelegate)
+
+- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation
+							   request:(NSURLRequest *)request
+							     frame:(WebFrame *)frame
+						  decisionListener:(id<WebPolicyDecisionListener>)listener;
+{
+    [listener ignore];
+}
+
+@end
