Fixed:
authorcblu <cblu@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Aug 2004 22:12:12 +0000 (22:12 +0000)
committercblu <cblu@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Aug 2004 22:12:12 +0000 (22:12 +0000)
<rdar://problem/3699498> Context menu for editable WebViews should provide items like Cut and Paste
<rdar://problem/3781535> REGRESSION (Mail): no context menu after ctrl-clicking a misspelled word

        Reviewed by kocienda.

        * English.lproj/Localizable.strings:
        * WebView.subproj/WebDefaultContextMenuDelegate.m:
        (-[WebDefaultUIDelegate menuItemWithTag:]): updated to handle new menu items
        (-[WebDefaultUIDelegate contextMenuItemsForElement:]): renamed from webView:contextMenuItemsForElement:defaultMenuItems:
        (-[WebDefaultUIDelegate editingContextMenuItemsForElement:]): new
        (-[WebDefaultUIDelegate webView:contextMenuItemsForElement:defaultMenuItems:]): moved, now call contextMenuItemsForElement: or editingContextMenuItemsForElement:
        * WebView.subproj/WebDefaultUIDelegate.h:
        * WebView.subproj/WebHTMLView.m:
        (-[WebHTMLView _isSelectionMisspelled]): new
        (-[WebHTMLView _guessesForMisspelledSelection]): new
        (-[WebHTMLView _changeSpellingFromMenu:]): new
        (-[WebHTMLView _ignoreSpellingFromMenu:]): new
        (-[WebHTMLView _learnSpellingFromMenu:]): new
        * WebView.subproj/WebHTMLViewPrivate.h:
        * WebView.subproj/WebUIDelegate.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@7424 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKit/ChangeLog
WebKit/English.lproj/Localizable.strings
WebKit/WebView.subproj/WebDefaultContextMenuDelegate.m
WebKit/WebView.subproj/WebDefaultUIDelegate.h
WebKit/WebView.subproj/WebHTMLView.m
WebKit/WebView.subproj/WebHTMLViewPrivate.h
WebKit/WebView.subproj/WebUIDelegate.h

index a09916c..dd934c5 100644 (file)
@@ -1,3 +1,27 @@
+2004-08-31  Chris Blumenberg  <cblu@apple.com>
+
+       Fixed: 
+       <rdar://problem/3699498> Context menu for editable WebViews should provide items like Cut and Paste
+       <rdar://problem/3781535> REGRESSION (Mail): no context menu after ctrl-clicking a misspelled word
+
+        Reviewed by kocienda.
+
+        * English.lproj/Localizable.strings:
+        * WebView.subproj/WebDefaultContextMenuDelegate.m:
+        (-[WebDefaultUIDelegate menuItemWithTag:]): updated to handle new menu items
+        (-[WebDefaultUIDelegate contextMenuItemsForElement:]): renamed from webView:contextMenuItemsForElement:defaultMenuItems:
+        (-[WebDefaultUIDelegate editingContextMenuItemsForElement:]): new
+        (-[WebDefaultUIDelegate webView:contextMenuItemsForElement:defaultMenuItems:]): moved, now call contextMenuItemsForElement: or editingContextMenuItemsForElement:
+        * WebView.subproj/WebDefaultUIDelegate.h:
+        * WebView.subproj/WebHTMLView.m:
+        (-[WebHTMLView _isSelectionMisspelled]): new
+        (-[WebHTMLView _guessesForMisspelledSelection]): new
+        (-[WebHTMLView _changeSpellingFromMenu:]): new
+        (-[WebHTMLView _ignoreSpellingFromMenu:]): new
+        (-[WebHTMLView _learnSpellingFromMenu:]): new
+        * WebView.subproj/WebHTMLViewPrivate.h:
+        * WebView.subproj/WebUIDelegate.h:
+
 2004-08-31  Darin Adler  <darin@apple.com>
 
         - fixed B&I build failure
index 38e1138..11e81fc 100644 (file)
Binary files a/WebKit/English.lproj/Localizable.strings and b/WebKit/English.lproj/Localizable.strings differ
index 27f9a03..cfbd127 100644 (file)
@@ -12,6 +12,7 @@
 #import <WebKit/WebDefaultUIDelegate.h>
 #import <WebKit/WebDOMOperations.h>
 #import <WebKit/WebFramePrivate.h>
+#import <WebKit/WebHTMLViewPrivate.h>
 #import <WebKit/WebLocalizableStrings.h>
 #import <WebKit/WebNSPasteboardExtras.h>
 #import <WebKit/WebFrameView.h>
@@ -29,8 +30,7 @@
 
 - (NSMenuItem *)menuItemWithTag:(int)tag
 {
-    NSMenuItem *menuItem = [[NSMenuItem alloc] init];
-    [menuItem setTarget:self];
+    NSMenuItem *menuItem = [[[NSMenuItem alloc] init] autorelease];
     [menuItem setTag:tag];
     
     NSString *title;
         case WebMenuItemTagOpenLinkInNewWindow:
             title = UI_STRING("Open Link in New Window", "Open in New Window context menu item");
             action = @selector(openLinkInNewWindow:);
+            [menuItem setTarget:self];
             break;
         case WebMenuItemTagDownloadLinkToDisk:
             title = UI_STRING("Download Linked File", "Download Linked File context menu item");
             action = @selector(downloadLinkToDisk:);
+            [menuItem setTarget:self];
             break;
         case WebMenuItemTagCopyLinkToClipboard:
             title = UI_STRING("Copy Link", "Copy Link context menu item");
             action = @selector(copyLinkToClipboard:);
+            [menuItem setTarget:self];
             break;
         case WebMenuItemTagOpenImageInNewWindow:
             title = UI_STRING("Open Image in New Window", "Open Image in New Window context menu item");
             action = @selector(openImageInNewWindow:);
+            [menuItem setTarget:self];
             break;
         case WebMenuItemTagDownloadImageToDisk:
             title = UI_STRING("Download Image", "Download Image context menu item");
             action = @selector(downloadImageToDisk:);
+            [menuItem setTarget:self];
             break;
         case WebMenuItemTagCopyImageToClipboard:
             title = UI_STRING("Copy Image", "Copy Image context menu item");
             action = @selector(copyImageToClipboard:);
+            [menuItem setTarget:self];
             break;
         case WebMenuItemTagOpenFrameInNewWindow:
             title = UI_STRING("Open Frame in New Window", "Open Frame in New Window context menu item");
             action = @selector(openFrameInNewWindow:);
+            [menuItem setTarget:self];
             break;
         case WebMenuItemTagCopy:
             title = UI_STRING("Copy", "Copy context menu item");
             action = @selector(copy:);
-            [menuItem setTarget:nil];
             break;
         case WebMenuItemTagGoBack:
             title = UI_STRING("Back", "Back context menu item");
             action = @selector(goBack:);
-            [menuItem setTarget:nil];
             break;
         case WebMenuItemTagGoForward:
             title = UI_STRING("Forward", "Forward context menu item");
             action = @selector(goForward:);
-            [menuItem setTarget:nil];
             break;
         case WebMenuItemTagStop:
             title = UI_STRING("Stop", "Stop context menu item");
             action = @selector(stopLoading:);
-            [menuItem setTarget:nil];
             break;
         case WebMenuItemTagReload:
             title = UI_STRING("Reload", "Reload context menu item");
             action = @selector(reload:);
-            [menuItem setTarget:nil];
+            break;
+        case WebMenuItemTagCut:
+            title = UI_STRING("Cut", "Cut context menu item");
+            action = @selector(cut:);
+            break;
+        case WebMenuItemTagPaste:
+            title = UI_STRING("Paste", "Paste context menu item");
+            action = @selector(paste:);
+            break;
+        case WebMenuItemTagSpellingGuess:
+            action = @selector(_changeSpellingFromMenu:);
+            break;
+        case WebMenuItemTagNoGuessesFound:
+            title = UI_STRING("No Guesses Found", "No Guesses Found context menu item");
+            break;
+        case WebMenuItemTagIgnoreSpelling:
+            title = UI_STRING("Ignore Spelling", "Ignore Spelling context menu item");
+            action = @selector(_ignoreSpellingFromMenu:);
+            break;
+        case WebMenuItemTagLearnSpelling:
+            title = UI_STRING("Learn Spelling", "Learn Spelling context menu item");
+            action = @selector(_learnSpellingFromMenu:);
             break;
         default:
-            [menuItem release];
             return nil;
     }
 
-    [menuItem setTitle:title];
+    if (title != nil) {
+        [menuItem setTitle:title];
+    }
     [menuItem setAction:action];
     
-    return [menuItem autorelease];
+    return menuItem;
 }
 
-- (NSArray *)webView: (WebView *)wv contextMenuItemsForElement: (NSDictionary *)element  defaultMenuItems: (NSArray *)defaultMenuItems
+- (NSArray *)contextMenuItemsForElement:(NSDictionary *)element
 {
     NSMutableArray *menuItems = [NSMutableArray array];
     
         if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
             [menuItems addObject:[self menuItemWithTag:WebMenuItemTagCopy]];
         } else {
+            WebFrame *webFrame = [element objectForKey:WebElementFrameKey];
+            WebView *wv = [webFrame webView];
             if ([wv canGoBack]) {
                 [menuItems addObject:[self menuItemWithTag:WebMenuItemTagGoBack]];
             }
                 [menuItems addObject:[self menuItemWithTag:WebMenuItemTagReload]];
             }
             
-            WebFrame *webFrame = [element objectForKey:WebElementFrameKey];
             if (webFrame != [wv mainFrame]) {
                 [menuItems addObject:[self menuItemWithTag:WebMenuItemTagOpenFrameInNewWindow]];
             }
     return menuItems;
 }
 
+- (NSArray *)editingContextMenuItemsForElement:(NSDictionary *)element
+{
+    NSMenuItem *item;
+    NSMutableArray *menuItems = [NSMutableArray array];
+    WebHTMLView *HTMLView = (WebHTMLView *)[[[element objectForKey:WebElementFrameKey] frameView] documentView];
+    ASSERT([HTMLView isKindOfClass:[WebHTMLView class]]);
+    
+    // Add spelling related context menu items.
+    if ([HTMLView _isSelectionMisspelled]) {
+        NSArray *guesses = [HTMLView _guessesForMisspelledSelection];
+        unsigned count = [guesses count];
+        if (count > 0) {
+            NSEnumerator *enumerator = [guesses objectEnumerator];
+            NSString *guess;
+            while ((guess = [enumerator nextObject]) != nil) {
+                item = [self menuItemWithTag:WebMenuItemTagSpellingGuess];
+                [item setTitle:guess];
+                [menuItems addObject:item];
+            }
+        } else {
+            [menuItems addObject:[self menuItemWithTag:WebMenuItemTagNoGuessesFound]];
+        }
+        [menuItems addObject:[NSMenuItem separatorItem]];
+        [menuItems addObject:[self menuItemWithTag:WebMenuItemTagIgnoreSpelling]];
+        [menuItems addObject:[self menuItemWithTag:WebMenuItemTagLearnSpelling]];
+        [menuItems addObject:[NSMenuItem separatorItem]];
+    }
+    
+    // Load the standard NSTextView context menu nib.
+    if (defaultMenu == nil) {
+        static NSNib *textViewMenuNib = nil;
+        if (textViewMenuNib == nil) {
+            textViewMenuNib = [[NSNib alloc] initWithNibNamed:@"NSTextViewContextMenu" bundle:[NSBundle bundleForClass:[NSTextView class]]];
+        }
+        [textViewMenuNib instantiateNibWithOwner:self topLevelObjects:nil];
+    }
+    
+    // Add tags to the menu items because this is what the WebUIDelegate expects.
+    NSEnumerator *enumerator = [[defaultMenu itemArray] objectEnumerator];
+    while ((item = [enumerator nextObject]) != nil) {
+        item = [item copy];
+        SEL action = [item action];
+        int tag;
+        if (action == @selector(cut:)) {
+            tag = WebMenuItemTagCut;
+        } else if (action == @selector(copy:)) {
+            tag = WebMenuItemTagCopy;
+        } else if (action == @selector(paste:)) {
+            tag = WebMenuItemTagPaste;
+        } else {
+            tag = WebMenuItemTagOther;
+        }
+        [item setTag:tag];
+        [menuItems addObject:item];
+        [item release];
+    }
+    
+    return menuItems;
+}
+
+- (NSArray *)webView:(WebView *)wv contextMenuItemsForElement:(NSDictionary *)element  defaultMenuItems:(NSArray *)defaultMenuItems
+{
+    WebHTMLView *HTMLView = (WebHTMLView *)[[[element objectForKey:WebElementFrameKey] frameView] documentView];
+    if ([HTMLView isKindOfClass:[WebHTMLView class]] && [HTMLView _isEditable]) {
+        return [self editingContextMenuItemsForElement:element];
+    } else {
+        return [self contextMenuItemsForElement:element];
+    }
+}
+
 - (void)openNewWindowWithURL:(NSURL *)URL element:(NSDictionary *)element
 {
     WebFrame *webFrame = [element objectForKey:WebElementFrameKey];
index bdd2968..7993877 100644 (file)
@@ -8,5 +8,8 @@
 #import <Foundation/Foundation.h>
 
 @interface WebDefaultUIDelegate : NSObject
+{
+    IBOutlet NSMenu *defaultMenu;
+}
 + (WebDefaultUIDelegate *)sharedUIDelegate;
 @end
index 5039bc3..a60b3aa 100644 (file)
@@ -148,6 +148,10 @@ static BOOL forceRealHitTest = NO;
 - (DOMDocumentFragment *)_documentFromRange:(NSRange)range document:(DOMDocument *)document documentAttributes:(NSDictionary *)dict subresources:(NSArray **)subresources;
 @end
 
+@interface NSSpellChecker(CurrentlyPrivateForTextView)
+- (void)learnWord:(NSString *)word;
+@end
+
 static WebElementOrTextFilter *elementOrTextFilterInstance = nil;
 
 // Handles the complete: text command
@@ -1123,6 +1127,46 @@ static WebHTMLView *lastHitView = nil;
     return [[self _webView] isEditable] || [[self _bridge] isSelectionEditable];
 }
 
+- (BOOL)_isSelectionMisspelled
+{
+    NSString *selectedString = [self selectedString];
+    unsigned length = [selectedString length];
+    if (length == 0) {
+        return NO;
+    }
+    NSRange range = [[NSSpellChecker sharedSpellChecker] checkSpellingOfString:selectedString
+                                                                    startingAt:0
+                                                                      language:@""
+                                                                          wrap:NO
+                                                        inSpellDocumentWithTag:[[self _webView] spellCheckerDocumentTag]
+                                                                     wordCount:NULL];
+    return range.length == length;
+}
+
+- (NSArray *)_guessesForMisspelledSelection
+{
+    ASSERT([[self selectedString] length] != 0);
+    return [[NSSpellChecker sharedSpellChecker] guessesForWord:[self selectedString]];
+}
+
+- (void)_changeSpellingFromMenu:(id)sender
+{
+    ASSERT([[self selectedString] length] != 0);
+    [[self _bridge] replaceSelectionWithText:[sender title] selectReplacement:YES];
+}
+
+- (void)_ignoreSpellingFromMenu:(id)sender
+{
+    ASSERT([[self selectedString] length] != 0);
+    [[NSSpellChecker sharedSpellChecker] ignoreWord:[self selectedString] inSpellDocumentWithTag:[[self _webView] spellCheckerDocumentTag]];
+}
+
+- (void)_learnSpellingFromMenu:(id)sender
+{
+    ASSERT([[self selectedString] length] != 0);
+    [[NSSpellChecker sharedSpellChecker] learnWord:[self selectedString]];
+}
+
 @end
 
 @implementation NSView (WebHTMLViewPrivate)
index bfedc99..3b62839 100644 (file)
@@ -62,4 +62,7 @@
 - (BOOL)_hasSelectionOrInsertionPoint;
 - (BOOL)_isEditable;
 
+- (BOOL)_isSelectionMisspelled;
+- (NSArray *)_guessesForMisspelledSelection;
+
 @end
index 6116c30..75ae1f0 100644 (file)
@@ -27,7 +27,14 @@ enum {
     WebMenuItemTagGoBack,
     WebMenuItemTagGoForward,
     WebMenuItemTagStop,
-    WebMenuItemTagReload
+    WebMenuItemTagReload,
+    WebMenuItemTagCut,
+    WebMenuItemTagPaste,
+    WebMenuItemTagSpellingGuess,
+    WebMenuItemTagNoGuessesFound,
+    WebMenuItemTagIgnoreSpelling,
+    WebMenuItemTagLearnSpelling,
+    WebMenuItemTagOther
 };
 
 /*!