Revision: 29442
          http://sourceforge.net/p/bibdesk/svn/29442
Author:   hofman
Date:     2025-08-23 16:19:22 +0000 (Sat, 23 Aug 2025)
Log Message:
-----------
Replace text import weview by WKWebView subclass. Use user scripts and message 
handler to handle selection change and link hover. Use subclass to allow 
customizing the context menu, use a trick shadowing a Open Link in New Window 
menu item to allow custom menu items using the link, as this is passed by the 
UI delegate methlod this calls. Allow adding WKDownload objects to download 
manager.

Modified Paths:
--------------
    trunk/bibdesk/BDSKDownloadManager.h
    trunk/bibdesk/BDSKDownloadManager.m
    trunk/bibdesk/BDSKTextImportController.h
    trunk/bibdesk/BDSKTextImportController.m
    trunk/bibdesk/de.lproj/Localizable.strings
    trunk/bibdesk/en.lproj/Localizable.strings
    trunk/bibdesk/fr.lproj/Localizable.strings

Modified: trunk/bibdesk/BDSKDownloadManager.h
===================================================================
--- trunk/bibdesk/BDSKDownloadManager.h 2025-08-21 16:56:15 UTC (rev 29441)
+++ trunk/bibdesk/BDSKDownloadManager.h 2025-08-23 16:19:22 UTC (rev 29442)
@@ -62,6 +62,8 @@
 - (void)cancel:(NSUInteger)uniqueID;
 - (void)remove:(NSUInteger)uniqueID;
 
+- (void)addDownload:(id)download;
+
 @end
 
 #pragma mark -
@@ -71,12 +73,12 @@
     NSURL *URL;
     NSURL *fileURL;
     BDSKDownloadStatus status;
-    NSURLDownload *URLDownload;
+    id download;
 }
 
-- (instancetype)initWithURLDownload:(NSURLDownload *)aDownload;
+- (instancetype)initWithDownload:(id)aDownload URL:(NSURL *)aURL;
 
-@property (nonatomic, readonly) NSURLDownload *URLDownload;
+@property (nonatomic, readonly) id download;
 @property (nonatomic, readonly) NSUInteger uniqueID;
 @property (nonatomic, readonly) NSURL *URL;
 @property (nonatomic, nullable, strong) NSURL *fileURL;
@@ -83,6 +85,8 @@
 @property (nonatomic, nullable, readonly) NSString *fileName;
 @property (nonatomic) BDSKDownloadStatus status;
 
+- (void)cancel;
+
 @end
 
 NS_ASSUME_NONNULL_END

Modified: trunk/bibdesk/BDSKDownloadManager.m
===================================================================
--- trunk/bibdesk/BDSKDownloadManager.m 2025-08-21 16:56:15 UTC (rev 29441)
+++ trunk/bibdesk/BDSKDownloadManager.m 2025-08-23 16:19:22 UTC (rev 29442)
@@ -40,10 +40,25 @@
 #import "BDSKStringConstants.h"
 #import "NSURL_BDSKExtensions.h"
 #import "NSFileManager_BDSKExtensions.h"
+#import <WebKit/WebKit.h>
 
 #define BDSKRemoveFinishedDownloadsKey @"BDSKRemoveFinishedDownloads"
 #define BDSKRemoveFailedDownloadsKey   @"BDSKRemoveFailedDownloads"
 
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 110300
+@protocol WKDownloadDelegate <NSObject>
+@end
+@interface WKDownload : NSObject <NSProgressReporting>
+@property (nonatomic, readonly, nullable) NSURLRequest *originalRequest;
+@property (nonatomic, readonly, weak) WKWebView *webView;
+@property (nonatomic, weak) id <WKDownloadDelegate> delegate;
+- (void)cancel:(void(^)(NSData * resumeData))completionHandler;
+@end
+#endif
+
+@interface BDSKDownloadManager () <WKDownloadDelegate>
+@end
+
 @implementation BDSKDownloadManager
 
 @synthesize downloads;
@@ -80,9 +95,14 @@
    [[NSUserDefaults standardUserDefaults] setBool:flag 
forKey:BDSKRemoveFailedDownloadsKey];
 }
 
-- (BDSKWebDownload *)downloadForURLDownload:(NSURLDownload *)URLDownload {
-    for (BDSKWebDownload *download in downloads) {
-        if ([download URLDownload] == URLDownload)
+- (void)addDownload:(id)download {
+    [download setDelegate:self];
+    [downloads addObject:[[BDSKWebDownload alloc] initWithDownload:download 
URL:[[download originalRequest] URL]]];
+}
+
+- (BDSKWebDownload *)webDownloadForDownload:(id)download {
+    for (BDSKWebDownload *webDownload in downloads) {
+        if ([webDownload download] == download)
             return download;
     }
     return nil;
@@ -89,9 +109,9 @@
 }
 
 - (BDSKWebDownload *)downloadWithUniqueID:(NSUInteger)uniqueID {
-    for (BDSKWebDownload *download in downloads) {
-        if ([download uniqueID] == uniqueID)
-            return download;
+    for (BDSKWebDownload *webDownload in downloads) {
+        if ([webDownload uniqueID] == uniqueID)
+            return webDownload;
     }
     return nil;
 }
@@ -105,13 +125,13 @@
 }
 
 - (void)cancel:(NSUInteger)uniqueID {
-    [[[self downloadWithUniqueID:uniqueID] URLDownload] cancel];
+    [[self downloadWithUniqueID:uniqueID] cancel];
 }
 
 - (void)remove:(NSUInteger)uniqueID {
-    BDSKWebDownload *download = [self downloadWithUniqueID:uniqueID];
-    if (download)
-        [downloads removeObject:download];
+    BDSKWebDownload *webDownload = [self downloadWithUniqueID:uniqueID];
+    if (webDownload)
+        [downloads removeObject:webDownload];
 }
 
 + (NSString *)webScriptNameForSelector:(SEL)aSelector {
@@ -140,24 +160,24 @@
 
 #pragma mark NSURLDownload delegate protocol
 
-- (void)downloadDidBegin:(NSURLDownload *)URLDownload {
-    [downloads addObject:[[BDSKWebDownload alloc] 
initWithURLDownload:URLDownload]];
+- (void)downloadDidBegin:(NSURLDownload *)download {
+    [downloads addObject:[[BDSKWebDownload alloc] initWithDownload:download 
URL:[[download request] URL]]];
 }
 
-- (void)downloadDidFinish:(NSURLDownload *)URLDownload {
-    BDSKWebDownload *download = [self downloadForURLDownload:URLDownload];
-    [download setStatus:BDSKDownloadStatusFinished];
+- (void)downloadDidFinish:(id)download {
+    BDSKWebDownload *webDownload = [self webDownloadForDownload:download];
+    [webDownload setStatus:BDSKDownloadStatusFinished];
     
-    if ([[NSUserDefaults standardUserDefaults] 
boolForKey:BDSKRemoveFinishedDownloadsKey] && download)
-        [downloads removeObject:download];
+    if ([[NSUserDefaults standardUserDefaults] 
boolForKey:BDSKRemoveFinishedDownloadsKey] && webDownload)
+        [downloads removeObject:webDownload];
 }
 
-- (void)download:(NSURLDownload *)URLDownload didFailWithError:(NSError 
*)error {
-    BDSKWebDownload *download = [self downloadForURLDownload:URLDownload];
-    [download setStatus:BDSKDownloadStatusFinished];
+- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error {
+    BDSKWebDownload *webDownload = [self webDownloadForDownload:download];
+    [webDownload setStatus:BDSKDownloadStatusFinished];
     
-    if ([[NSUserDefaults standardUserDefaults] 
boolForKey:BDSKRemoveFailedDownloadsKey] && download)
-        [downloads removeObject:download];
+    if ([[NSUserDefaults standardUserDefaults] 
boolForKey:BDSKRemoveFailedDownloadsKey] && webDownload)
+        [downloads removeObject:webDownload];
     
     NSString *errorDescription = [error localizedDescription] ?: 
NSLocalizedString(@"An error occured during download.", @"Informative text in 
alert dialog");
     NSAlert *alert = [[NSAlert alloc] init];
@@ -166,7 +186,7 @@
     [alert runModal];
 }
 
-- (void)download:(NSURLDownload *)URLDownload 
decideDestinationWithSuggestedFilename:(NSString *)filename {
+- (void)download:(NSURLDownload *)download 
decideDestinationWithSuggestedFilename:(NSString *)filename {
        NSString *extension = [filename pathExtension];
    
     NSString *downloadsDirectory = [[[NSUserDefaults standardUserDefaults] 
stringForKey:BDSKDownloadsDirectoryKey] stringByExpandingTildeInPath];
@@ -187,19 +207,69 @@
     // we need to do this modally, not using a sheet, as the download may 
otherwise finish on Leopard before the sheet is done
     NSInteger returnCode = [sPanel runModal];
     if (returnCode == NSModalResponseOK)
-        [URLDownload setDestination:[[sPanel URL] path] allowOverwrite:YES];
+        [download setDestination:[[sPanel URL] path] allowOverwrite:YES];
     else
-        [URLDownload cancel];
+        [download cancel];
 }
 
-- (void)download:(NSURLDownload *)URLDownload didCreateDestination:(NSString 
*)path {
-    [[self downloadForURLDownload:URLDownload] setFileURL:[NSURL 
fileURLWithPath:path isDirectory:NO]];
+- (void)download:(NSURLDownload *)download didCreateDestination:(NSString 
*)path {
+    [[self webDownloadForDownload:download] setFileURL:[NSURL 
fileURLWithPath:path isDirectory:NO]];
 }
 
-- (BOOL)download:(NSURLDownload *)URLDownload 
shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType {
+- (BOOL)download:(NSURLDownload *)download 
shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType {
     return YES;
 }
 
+#pragma mark WKDownload delegate protocol
+
+- (void)download:(WKDownload *)download didFailWithError:(NSError *)error 
resumeData:(NSData *)resumeData API_AVAILABLE(macos(11.3)) {
+    BDSKWebDownload *webDownload = [self webDownloadForDownload:download];
+    [webDownload setStatus:BDSKDownloadStatusFinished];
+    
+    if ([[NSUserDefaults standardUserDefaults] 
boolForKey:BDSKRemoveFailedDownloadsKey] && webDownload)
+        [downloads removeObject:webDownload];
+    
+    NSString *errorDescription = [error localizedDescription] ?: 
NSLocalizedString(@"An error occured during download.", @"Informative text in 
alert dialog");
+    NSAlert *alert = [[NSAlert alloc] init];
+    [alert setMessageText:NSLocalizedString(@"Download Failed", @"Message in 
alert dialog when download failed")];
+    [alert setInformativeText:errorDescription];
+    [alert runModal];
+}
+
+- (void)download:(WKDownload *)download 
decideDestinationUsingResponse:(NSURLResponse *)response 
suggestedFilename:(NSString *)filename completionHandler:(void (^)(NSURL * 
destination))completionHandler API_AVAILABLE(macos(11.3)) {
+    NSString *extension = [filename pathExtension];
+   
+    NSString *downloadsDirectory = [[[NSUserDefaults standardUserDefaults] 
stringForKey:BDSKDownloadsDirectoryKey] stringByExpandingTildeInPath];
+    NSURL *downloadsURL = nil;
+    if (downloadsDirectory)
+        downloadsURL = [NSURL fileURLWithPath:downloadsDirectory 
isDirectory:YES];
+    else
+        downloadsURL = [[NSFileManager defaultManager] downloadFolderURL];
+    
+    NSSavePanel *sPanel = [NSSavePanel savePanel];
+    if (NO == [extension isEqualToString:@""])
+        [sPanel setAllowedFileTypes:@[extension]];
+    [sPanel setAllowsOtherFileTypes:YES];
+    [sPanel setCanSelectHiddenExtension:YES];
+    [sPanel setNameFieldStringValue:filename];
+    [sPanel setDirectoryURL:downloadsURL];
+    
+    NSWindow *window = [[download webView] window];
+    void (^handler)(NSModalResponse) = ^(NSModalResponse result){
+        if (result == NSModalResponseOK) {
+            NSURL *fileURL = [[NSFileManager defaultManager] 
uniqueFileURL:[sPanel URL]];
+            completionHandler(fileURL);
+            [[self webDownloadForDownload:download] setFileURL:fileURL];
+        } else {
+            completionHandler(nil);
+        }
+    };
+    if (window)
+        [sPanel beginSheetModalForWindow:window completionHandler:handler];
+    else
+        [sPanel beginWithCompletionHandler:handler];
+}
+
 @end
 
 #pragma mark -
@@ -206,19 +276,19 @@
 
 @implementation BDSKWebDownload
 
-@synthesize URLDownload, uniqueID, URL, fileURL, status;
+@synthesize download, uniqueID, URL, fileURL, status;
 @dynamic fileName;
 
 static NSUInteger currentUniqueID = 0;
 
-- (instancetype)initWithURLDownload:(NSURLDownload *)aURLDownload {
+- (instancetype)initWithDownload:(id)aDownload URL:(NSURL *)aURL {
     self = [super init];
     if (self) {
         uniqueID = ++currentUniqueID;
-        URL = [[aURLDownload request] URL];
+        URL = aURL;
         fileURL = nil;
         status = BDSKDownloadStatusDownloading;
-        URLDownload = aURLDownload;
+        download = aDownload;
     }
     return self;
 }
@@ -241,10 +311,17 @@
     if (status != newStatus) {
         status = newStatus;
         if (status != BDSKDownloadStatusDownloading)
-            URLDownload = nil;
+            download = nil;
         if (status == BDSKDownloadStatusFailed)
             [self setFileURL:nil];
     }
 }
 
+- (void)cancel {
+    if ([download isKindOfClass:[NSURLDownload class]])
+        [download cancel];
+    else if (@available(macOS 11.3, *))
+        [(WKDownload *)download cancel:nil];
+}
+
 @end

Modified: trunk/bibdesk/BDSKTextImportController.h
===================================================================
--- trunk/bibdesk/BDSKTextImportController.h    2025-08-21 16:56:15 UTC (rev 
29441)
+++ trunk/bibdesk/BDSKTextImportController.h    2025-08-23 16:19:22 UTC (rev 
29442)
@@ -40,15 +40,14 @@
 #import "BDSKOwnerProtocol.h"
 #import "BDSKTextImportItemTableView.h"
 #import "BDSKCitationFormatter.h"
-#import "BDSKWebView.h"
 #import "BDSKDownloader.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
-@class BibDocument, BibItem, BDSKEdgeView, WebDownload;
+@class BibDocument, BibItem, BDSKEdgeView, BDSKWKWebView;
 @class BDSKCiteKeyFormatter, BDSKTextImportItemTableView, 
BDSKComplexStringFormatter;
 
-@interface BDSKTextImportController : NSWindowController <BDSKOwner, 
BDSKTextImportItemTableViewDelegate, NSTableViewDataSource, NSTextViewDelegate, 
NSSplitViewDelegate, BDSKCitationFormatterDelegate, BDSKWebViewDelegate,  
BDSKDownloadDelegate, NSTouchBarDelegate> {
+@interface BDSKTextImportController : NSWindowController <BDSKOwner, 
BDSKTextImportItemTableViewDelegate, NSTableViewDataSource, NSTextViewDelegate, 
NSSplitViewDelegate, BDSKCitationFormatterDelegate,  BDSKDownloadDelegate, 
NSTouchBarDelegate> {
     NSTextView *sourceTextView;
     BDSKTextImportItemTableView *itemTableView;
     NSTextField *citeKeyField;
@@ -87,7 +86,8 @@
        BOOL isLoading;
        BOOL isDownloading;
        
-    BDSKWebView *webView;
+    BDSKWKWebView *webView;
+    NSInteger customMenuAction;
     
     BDSKDownload *download;
        NSString *downloadFileName;
@@ -146,7 +146,6 @@
 
 - (void)copyLocationAsRemoteUrl:(nullable id)sender;
 - (void)copyLinkedLocationAsRemoteUrl:(nullable id)sender;
-- (void)saveFileAsLocalUrl:(nullable id)sender;
 - (void)downloadLinkedFileAsLocalUrl:(nullable id)sender;
 
 @end

Modified: trunk/bibdesk/BDSKTextImportController.m
===================================================================
--- trunk/bibdesk/BDSKTextImportController.m    2025-08-21 16:56:15 UTC (rev 
29441)
+++ trunk/bibdesk/BDSKTextImportController.m    2025-08-23 16:19:22 UTC (rev 
29442)
@@ -70,6 +70,8 @@
 #import "NSTableView_BDSKExtensions.h"
 #import "NSString_BDSKExtensions.h"
 #import "BDSKComplexString.h"
+#import "NSWorkspace_BDSKExtensions.h"
+#import "BDSKDownloadManager.h"
 
 #define BDSKTextImportControllerFrameAutosaveName @"BDSKTextImportController 
Frame Autosave Name"
 
@@ -81,11 +83,48 @@
 #define FIELDNAME_COLUMN @"FieldName"
 #define KEY_COLUMN @"Num"
 
-@interface BDSKTextImportController (Private)
+enum {
+    BDSKWebViewCustomMenuActionNone,
+    BDSKWebViewCustomMenuActionOpenLink,
+    BDSKWebViewCustomMenuActionBookmarkLink,
+    BDSKWebViewCustomMenuActionAddLink,
+    BDSKWebViewCustomMenuActionDownloadLink
+};
 
-- (void)handleWebViewDidChangeSelection:(NSNotification *)notification;
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 110300
+@class WKDownload;
+#define WKNavigationActionPolicyDownload 2
+#define WKNavigationResponsePolicyDownload 2
+#endif
+
+@protocol BDSKUIDelegate <WKUIDelegate>
+@optional
+- (void)webView:(WKWebView *)webView willPopUpMenu:(NSMenu *)menu;
+@end
+
+@interface BDSKWKWebView : WKWebView
+@property (nullable, nonatomic, weak) id<BDSKUIDelegate> UIDelegate;
+@end
+
+#pragma mark -
+
+@protocol BDSKScriptMessageHandlerDelegate <NSObject>
+- (void)scriptMessageHandlerWithName:(NSString *)name 
didReceiveMessage:(NSString *)body;
+@end
+
+@interface BDSKScriptMessageHandler : NSObject <WKScriptMessageHandler> {
+    __weak id<BDSKScriptMessageHandlerDelegate> delegate;
+}
+@property (nonatomic, nullable, weak) id<BDSKScriptMessageHandlerDelegate> 
delegate;
+@end
+
+#pragma mark -
+
+@interface BDSKTextImportController () <WKNavigationDelegate, BDSKUIDelegate, 
BDSKScriptMessageHandlerDelegate>
+
 - (void)handleFlagsChangedNotification:(NSNotification *)notification;
 - (void)handleBibItemChangedNotification:(NSNotification *)notification;
+- (void)handleTextSelectionChangedNotification:(NSNotification *)notification;
 
 - (void)finalizeChangesPreservingSelection:(BOOL)shouldPreserveSelection;
 
@@ -93,7 +132,8 @@
 - (void)showWebViewWithURL:(NSURL *)url;
 - (void)loadFromFileURL:(NSURL *)url;
 - (void)setShowingWebView:(BOOL)showWebView;
-- (void)setupTypeUI;
+- (void)setupWebView;
+- (void)clearWebView;
 - (void)updateTypeAndFields;
 - (void)updateColumnWidths;
 
@@ -106,7 +146,6 @@
 - (BOOL)addCurrentSelectionToFieldAtIndex:(NSUInteger)index;
 - (void)recordChangingField:(NSString *)fieldName toValue:(NSString *)value;
 
-- (void)autoDiscoverDataFromFrame:(WebFrame *)frame;
 - (void)autoDiscoverDataFromString:(NSString *)string;
 - (void)setCiteKeyDuplicateWarning:(BOOL)set;
 
@@ -126,8 +165,7 @@
         [item setOwner:self];
         [publications addObject:item];
         fields = [[NSMutableArray alloc] init];
-        webView = [[BDSKWebView alloc] init];
-        [webView setDelegate:self];
+        webView = nil;
         showingWebView = NO;
         itemsAdded = [[NSMutableArray alloc] init];
                webSelection = nil;
@@ -141,8 +179,8 @@
 
 - (void)dealloc{
     BDSKASSERT(download == nil);
-    // next line is a workaround for a nasty webview crasher; looks like it 
messages a garbage pointer to its undo manager
-    [webView setDelegate:nil];
+    [webView setNavigationDelegate:nil];
+    [webView setUIDelegate:nil];
     [itemTableView setDelegate:nil];
     [itemTableView setDataSource:nil];
     [splitView setDelegate:nil];
@@ -156,13 +194,10 @@
     
     [statusLine setStringValue:@""];
        
-    [webViewBox setEdges:BDSKEveryEdgeMask];
-    [webViewBox setBackgroundColors:nil];
-    [webViewBox setBackgroundView:nil];
-       [webViewBox setContentView:webView];
+    [itemTypeButton removeAllItems];
+    [itemTypeButton addItemsWithTitles:[[BDSKTypeManager sharedManager] 
types]];
+    [self updateTypeAndFields];
     
-    [self setupTypeUI];
-    
     [sourceTextView setTextColor:[NSColor textColor]];
     if (@available(macOS 10.14, *))
         [sourceTextView setDrawsBackground:NO];
@@ -185,9 +220,9 @@
                                                  
name:BDSKBibItemChangedNotification
                                                object:nil];
     [[NSNotificationCenter defaultCenter] addObserver:self
-                                             
selector:@selector(handleWebViewDidChangeSelection:)
-                                                 
name:WebViewDidChangeSelectionNotification
-                                               object:webView];
+                                             
selector:@selector(handleTextSelectionChangedNotification:)
+                                                 
name:NSTextViewDidChangeSelectionNotification
+                                               object:sourceTextView];
 }
 
 #pragma mark Accessors
@@ -201,14 +236,12 @@
 - (void)beginSheetForURL:(NSURL *)aURL modalForWindow:(NSWindow *)aWindow 
completionHandler:(void (^)(NSInteger result))handler {
     // make sure we loaded the nib
     [self window];
-    if (aURL == nil) {
+    if (aURL == nil)
         [self loadPasteboardData];
-       } else if ([aURL isFileURL]) {
+       else if ([aURL isFileURL])
                [self loadFromFileURL:aURL];
-       } else {
-               [self setShowingWebView:YES];
-        [webView setURL:aURL];
-    }
+       else
+               [self showWebViewWithURL:aURL];
     [super beginSheetModalForWindow:aWindow completionHandler:handler];
 }
 
@@ -248,7 +281,7 @@
     
     // cleanup
     [self cancelDownload];
-    [webView setDelegate:nil];
+    [self clearWebView];
     
     [itemTableView setTypeSelectHelper:nil];
     
@@ -321,7 +354,7 @@
                 [alert setInformativeText:NSLocalizedString(@"Mac OS X does 
not recognize this as a valid URL.  Please re-enter the address and try 
again.", @"Informative text in alert dialog")];
                 [alert beginSheetModalForWindow:[self window] 
completionHandler:NULL];
             } else {        
-                [webView setURL:url];
+                [webView loadRequest:[NSURLRequest requestWithURL:url]];
             }
         }        
     }];
@@ -341,8 +374,8 @@
 
 - (IBAction)openBookmark:(id)sender{
     NSURL *url = [sender representedObject];
-    [self setShowingWebView:YES];
-    [webView setURL:url];
+    if (url)
+        [self showWebViewWithURL:url];
 }
 
 - (IBAction)stopOrReloadAction:(id)sender{
@@ -432,8 +465,15 @@
 
 #pragma mark WebView contextual menu actions
 
+- (void)addBookmark:(id)sender {
+    NSURL *aURL = [webView URL];
+    NSString *name = [webView title] ?: [aURL lastPathComponent];
+    if (aURL)
+        [[BDSKBookmarkController sharedBookmarkController] 
addBookmarkWithURL:aURL proposedName:name modalForWindow:[self window]];
+}
+
 - (void)copyLocationAsRemoteUrl:(id)sender{
-       NSURL *aURL = [webView URL];
+    NSURL *aURL = [webView URL];
        
        if (aURL) {
         if ([[NSUserDefaults standardUserDefaults] 
boolForKey:BDSKUseLocalUrlAndUrlKey])
@@ -456,38 +496,6 @@
        }
 }
 
-- (void)saveFileAsLocalUrl:(id)sender{
-       WebDataSource *dataSource = [[webView mainFrame] dataSource];
-       if (!dataSource || [dataSource isLoading]) 
-               return;
-       
-       NSString *fileName = [[[[dataSource request] URL] relativePath] 
lastPathComponent];
-       NSString *extension = [fileName pathExtension];
-
-    NSSavePanel *sPanel = [NSSavePanel savePanel];
-    if (![extension isEqualToString:@""]) 
-               [sPanel setAllowedFileTypes:[NSArray 
arrayWithObjects:extension, nil]];
-    [sPanel setCanCreateDirectories:YES];
-    [sPanel setNameFieldStringValue:fileName];
-
-    [sPanel beginSheetModalForWindow:[self window] 
completionHandler:^(NSInteger result){
-        if (result == NSModalResponseOK) {
-            NSURL *fileURL = [sPanel URL];
-            if ([[[[webView mainFrame] dataSource] data] writeToURL:fileURL 
atomically:YES]) {
-                if ([[NSUserDefaults standardUserDefaults] 
boolForKey:BDSKUseLocalUrlAndUrlKey])
-                    [[self publication] setField:BDSKLocalUrlString 
toURLValue:fileURL];
-                else
-                    [[self publication] addFileForURL:fileURL autoFile:YES 
runScriptHook:NO];
-                [[self undoManager] setActionName:NSLocalizedString(@"Edit 
Publication", @"Undo action name")];
-            } else {
-                NSLog(@"Could not write downloaded file.");
-            }
-        }
-
-        [itemTableView reloadData];
-    }]; 
-}
-
 - (void)downloadLinkedFileAsLocalUrl:(id)sender{
        NSURL *linkURL = (NSURL *)[sender representedObject];
     if (isDownloading)
@@ -504,6 +512,27 @@
        }
 }
 
+- (void)performCustomMenuAction:(id)sender {
+    NSMenuItem *origItem = [sender representedObject];
+    
+    if ([origItem isKindOfClass:[NSMenuItem class]] == NO) {
+        customMenuAction = BDSKWebViewCustomMenuActionNone;
+        NSBeep();
+        return;
+    }
+    
+    customMenuAction = [sender tag];
+    
+    if (customMenuAction != BDSKWebViewCustomMenuActionNone) {
+        [NSApp sendAction:[origItem action] to:[origItem target] 
from:origItem];
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * 
NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+            customMenuAction = BDSKWebViewCustomMenuActionNone;
+        });
+    } else {
+        NSBeep();
+    }
+}
+
 #pragma mark UndoManager
 
 - (NSUndoManager *)undoManager {
@@ -547,14 +576,6 @@
 
 #pragma mark Private
 
-// workaround for webview bug, which looses its selection when the focus 
changes to another view
-- (void)handleWebViewDidChangeSelection:(NSNotification *)notification{
-       NSString *selString = [[[notification object] selectedDOMRange] 
toString];
-       if ([NSString isEmptyString:selString] || selString == webSelection)
-               return;
-       webSelection = [[selString 
stringByCollapsingAndTrimmingCharactersInSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet]] copy];
-}
-
 - (void)handleFlagsChangedNotification:(NSNotification *)notification{
     NSUInteger modifierFlags = [NSEvent standardModifierFlags];
     
@@ -583,11 +604,25 @@
         [itemTableView reloadData];
     } else if ([changeKey isEqualToString:BDSKPubTypeString]) {
         [self updateTypeAndFields];
-    } else {
+    } else if ([changeKey isEqualToString:BDSKRemoteURLString] == NO && 
[changeKey isEqualToString:BDSKLocalFileString] == NO) {
         [itemTableView reloadData];
     }
 }
 
+- (void)setTemporaryTypeSelectStatusMessage:(BOOL)shouldSet {
+    NSString *message = NSLocalizedString(@"Press \u2318= to select a field.", 
@"Status message");
+    if (shouldSet)
+        [statusLine setStringValue:message];
+    else if ([[statusLine stringValue] isEqualToString:message])
+        [statusLine setStringValue:@""];
+    
+}
+
+- (void)handleTextSelectionChangedNotification:(NSNotification *)notification{
+    if ([sourceTextView window])
+        [self setTemporaryTypeSelectStatusMessage:[sourceTextView 
selectedRange].length > 0];
+}
+
 - (void)finalizeChangesPreservingSelection:(BOOL)shouldPreserveSelection{
     NSResponder *firstResponder = [[self window] firstResponder];
     
@@ -611,6 +646,49 @@
 
 #pragma mark Setup
 
+- (void)setupWebView {
+    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
+    WKUserContentController *userController = [config userContentController];
+    BDSKScriptMessageHandler *messageHandler = [[BDSKScriptMessageHandler 
alloc] init];
+    [messageHandler setDelegate:self];
+    [userController addScriptMessageHandler:messageHandler 
name:@"changeSelection"];
+    [userController addScriptMessageHandler:messageHandler name:@"hoverLink"];
+    NSString *jsSource = @""
+        "function changeSelection(){ 
window.webkit.messageHandlers.changeSelection.postMessage(document.getSelection().toString());
 };\n"
+        "document.addEventListener('selectionchange', changeSelection);\n"
+        "function hover(){ 
window.webkit.messageHandlers.hoverLink.postMessage(this.href); }\n"
+        "function unhover(){ 
window.webkit.messageHandlers.hoverLink.postMessage(''); }\n"
+        "var links = document.links;\n"
+        "for(var i=0; i<links.length; i++){\n"
+        "  links[i].addEventListener('mouseover', hover);\n"
+        "  links[i].addEventListener('mouseout', unhover);\n"
+        "}";
+    WKUserScript *script = [[WKUserScript alloc] initWithSource:jsSource 
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
+    [userController addUserScript:script];
+    
+    webView = [[BDSKWKWebView alloc] initWithFrame:[webViewBox bounds] 
configuration:config];
+    [webView setNavigationDelegate:self];
+    [webView setUIDelegate:self];
+    
+    [webViewBox setEdges:BDSKEveryEdgeMask];
+    [webViewBox setBackgroundColors:nil];
+    [webViewBox setBackgroundView:nil];
+    [webViewBox setContentView:webView];
+    
+    [backButton setTarget:webView];
+    [backButton setAction:@selector(goBack:)];
+    [forwardButton setTarget:webView];
+    [forwardButton setAction:@selector(goForward:)];
+}
+
+- (void)clearWebView {
+    [webView setNavigationDelegate:nil];
+    [webView setUIDelegate:nil];
+    [[[webView configuration] userContentController] 
removeScriptMessageHandlerForName:@"hoverLink"];
+    [[[webView configuration] userContentController] 
removeScriptMessageHandlerForName:@"selectionChanged"];
+    [[[webView configuration] userContentController] removeAllUserScripts];
+}
+
 - (void)loadPasteboardData{
     NSPasteboard* pb = [NSPasteboard generalPasteboard];
 
@@ -621,12 +699,10 @@
     if([pbType isEqualToString:NSURLPboardType]){
         // setup webview and load page
         
-               [self setShowingWebView:YES];
-        
         NSArray *urls = (NSArray *)[pb propertyListForType:pbType];
-        NSURL *url = [NSURL URLWithString:[urls objectAtIndex:0]];
+        NSURL *url = [NSURL URLWithString:[urls firstObject]];
         
-        [webView setURL:url];
+        [self showWebViewWithURL:url];
         
     }else{
                
@@ -690,7 +766,7 @@
 
 - (void)showWebViewWithURL:(NSURL *)url{
     [self setShowingWebView:YES];
-    [webView setURL:url];
+    [webView loadRequest:[NSURLRequest requestWithURL:url]];
 }
 
 - (void)loadFromFileURL:(NSURL *)url {
@@ -716,23 +792,17 @@
        if (showWebView != showingWebView) {
                showingWebView = showWebView;
                if (showingWebView) {
+            if (webView == nil)
+                [self setupWebView];
                        [webViewView setFrame:[sourceView frame]];
                        [splitView replaceSubview:sourceView with:webViewView];
                } else {
                        [splitView replaceSubview:webViewView with:sourceView];
                }
+        [self setTemporaryTypeSelectStatusMessage:NO];
        }
 }
 
-- (void)setupTypeUI{
-
-    // setup the type popup:
-    [itemTypeButton removeAllItems];
-    [itemTypeButton addItemsWithTitles:[[BDSKTypeManager sharedManager] 
types]];
-    
-    [self updateTypeAndFields];
-}
-
 - (void)updateTypeAndFields {
     NSString *type = [[self publication] pubType];
     
@@ -874,9 +944,7 @@
 #pragma mark Menu validation
 
 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem{
-       if ([menuItem action] == @selector(saveFileAsLocalUrl:)) {
-               return NO == [webView isLoading];
-       } else if ([menuItem action] == @selector(importFromPasteboardAction:)) 
{
+       if ([menuItem action] == @selector(importFromPasteboardAction:)) {
                [menuItem setTitle:NSLocalizedString(@"Load Clipboard", @"Menu 
item title")];
                return YES;
        } else if ([menuItem action] == @selector(importFromFileAction:)) {
@@ -896,76 +964,205 @@
        return YES;
 }
 
-#pragma mark BDSKWebViewDelegate protocol
+#pragma mark WKNavigationDelegate protocol
 
-- (NSArray *)webView:(WebView *)sender 
contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray 
*)defaultMenuItems{
-       NSMutableArray *menuItems = [NSMutableArray 
arrayWithArray:defaultMenuItems];
-       NSMenuItem *menuItem;
-    
-    NSUInteger i = [[menuItems valueForKey:@"tag"] indexOfObject:[NSNumber 
numberWithInteger:WebMenuItemTagCopyLinkToClipboard]];
-       
-    if (i != NSNotFound) {
-        NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
-        
-        menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Copy 
Link To Url Field",@"Copy link to url field")
-                                          
action:@selector(copyLinkedLocationAsRemoteUrl:)
-                                   keyEquivalent:@""];
-        [menuItem setTarget:self];
-        [menuItem setRepresentedObject:linkURL];
-        [menuItems insertObject:menuItem atIndex:++i];
-        
-        menuItem = [[NSMenuItem alloc] initWithTitle:[NSLocalizedString(@"Save 
Link As Local File",@"Save link as local file") stringByAppendingEllipsis]
-                                          
action:@selector(downloadLinkedFileAsLocalUrl:)
-                                   keyEquivalent:@""];
-        [menuItem setTarget:self];
-        [menuItem setRepresentedObject:linkURL];
-        [menuItems insertObject:menuItem atIndex:++i];
-    }
-    
-    i = [[menuItems valueForKey:@"tag"] indexOfObject:[NSNumber 
numberWithInteger:BDSKWebMenuItemTagAddBookmark]];
-       
-    if (i == NSNotFound) {
-        [menuItems addObject:[NSMenuItem separatorItem]];
-        i = [menuItems count];
-       }
-    
-       menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Copy 
Page Location To Url Field", @"Menu item title")
-                                                                         
action:@selector(copyLocationAsRemoteUrl:)
-                                                          keyEquivalent:@""];
-       [menuItem setTarget:self];
-    [menuItems insertObject:menuItem atIndex:++i];
-       
-       menuItem = [[NSMenuItem alloc] initWithTitle:[NSLocalizedString(@"Save 
Page As Local File", @"Menu item title") stringByAppendingEllipsis]
-                                                                         
action:@selector(saveFileAsLocalUrl:)
-                                                          keyEquivalent:@""];
-       [menuItem setTarget:self];
-    [menuItems insertObject:menuItem atIndex:++i];
-       
-       return menuItems;
+- (void)webView:(WKWebView *)aWebView 
didStartProvisionalNavigation:(WKNavigation *)navigation {
+    [self setLoading:YES];
 }
 
-- (void)webView:(WebView *)sender setStatusText:(NSString *)text {
-    [statusLine setStringValue:text ?: @""];
+- (void)webView:(WKWebView *)aWebView didFinishNavigation:(WKNavigation 
*)navigation {
+    [self setLoading:[webView isLoading]];
+    [backButton setEnabled:[webView canGoBack]];
+    [forwardButton setEnabled:[webView canGoForward]];
 }
 
-- (void)webView:(WebView *)sender didStartLoadForFrame:(WebFrame *)frame {
-       [self setLoading:YES];
+- (void)webView:(WKWebView *)aWebView 
didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError 
*)error {
+    [self setLoading:[webView isLoading]];
+    [backButton setEnabled:[webView canGoBack]];
+    [forwardButton setEnabled:[webView canGoForward]];
 }
 
-- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
+- (void)webView:(WKWebView *)aWebView didFailNavigation:(WKNavigation 
*)navigation withError:(NSError *)error {
     [self setLoading:[webView isLoading]];
-       [backButton setEnabled:[webView canGoBack]];
-       [forwardButton setEnabled:[webView canGoForward]];
+    [backButton setEnabled:[webView canGoBack]];
+    [forwardButton setEnabled:[webView canGoForward]];
+}
 
-    [self autoDiscoverDataFromFrame:frame];
+- (void)webView:(WKWebView *)aWebView 
decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse 
decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
+    if ([navigationResponse canShowMIMEType])
+        decisionHandler(WKNavigationResponsePolicyAllow);
+    else if (@available(macOS 11.3, *))
+        decisionHandler(WKNavigationResponsePolicyDownload);
+    else
+        decisionHandler(WKNavigationResponsePolicyCancel);
 }
 
-- (void)webView:(WebView *)sender didFailLoadForFrame:(WebFrame *)frame {
-    [self setLoading:[webView isLoading]];
-       [backButton setEnabled:[webView canGoBack]];
-       [forwardButton setEnabled:[webView canGoForward]];
+- (void)webView:(WKWebView *)aWebView 
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction 
preferences:(WKWebpagePreferences *)preferences decisionHandler:(void 
(^)(WKNavigationActionPolicy, WKWebpagePreferences *))decisionHandler  
API_AVAILABLE(macos(10.15)) {
+    if (@available(macOS 11.3, *)) {
+        if ([navigationAction shouldPerformDownload])
+            decisionHandler(WKNavigationActionPolicyDownload, preferences);
+        else
+            decisionHandler(WKNavigationActionPolicyAllow, preferences);
+    } else {
+        decisionHandler(WKNavigationActionPolicyAllow, preferences);
+    }
 }
 
+- (void)webView:(WKWebView *)aWebView navigationAction:(WKNavigationAction 
*)navigationAction didBecomeDownload:(WKDownload *)aDownload 
API_AVAILABLE(macos(11.3)) {
+    [[BDSKDownloadManager sharedManager] addDownload:aDownload];
+}
+
+- (void)webView:(WKWebView *)aWebView navigationResponse:(WKNavigationResponse 
*)navigationResponse didBecomeDownload:(WKDownload *)aDownload 
API_AVAILABLE(macos(11.3)) {
+    [[BDSKDownloadManager sharedManager] addDownload:aDownload];
+}
+
+#pragma mark BDSKUIDelegate protocol
+
+- (NSString *)alertTitleForFrame:(WKFrameInfo *)frame {
+    NSURL *url = [[frame request] URL];
+    NSString *scheme = [url scheme];
+    NSString *host = [url host];
+    if (scheme != nil && host != nil)
+        return [NSString stringWithFormat:@"%@://%@", scheme, host];
+    return NSLocalizedString(@"JavaScript", @"Default JavaScript alert title");
+}
+
+- (void)webView:(WKWebView *)aWebView 
runJavaScriptAlertPanelWithMessage:(NSString *)message 
initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void 
(^)(void))completionHandler {
+    NSAlert *alert = [[NSAlert alloc] init];
+    [alert setMessageText:[self alertTitleForFrame:frame]];
+    [alert setInformativeText:message];
+    [alert beginSheetModalForWindow:[self window] 
completionHandler:^(NSModalResponse result){
+        completionHandler();
+    }];
+}
+
+- (void)webView:(WKWebView *)aWebView 
runJavaScriptConfirmPanelWithMessage:(NSString *)message 
initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL 
result))completionHandler {
+    NSAlert *alert = [[NSAlert alloc] init];
+    [alert setMessageText:[self alertTitleForFrame:frame]];
+    [alert setInformativeText:message];
+    [alert addButtonWithTitle:NSLocalizedString(@"OK", @"Button title")];
+    [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"Button title")];
+    [alert beginSheetModalForWindow:[self window] 
completionHandler:^(NSModalResponse result){
+        completionHandler(result == NSAlertFirstButtonReturn);
+    }];
+}
+
+- (WKWebView *)webView:(WKWebView *)aWebView 
createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration 
forNavigationAction:(WKNavigationAction *)navigationAction 
windowFeatures:(WKWindowFeatures *)windowFeatures {
+    NSURL *url = [[navigationAction request] URL];
+    
+    if (customMenuAction == BDSKWebViewCustomMenuActionOpenLink) {
+        [[NSWorkspace sharedWorkspace] openURLWithDefaultApp:url];
+    } else if (customMenuAction == BDSKWebViewCustomMenuActionBookmarkLink) {
+        [[BDSKBookmarkController sharedBookmarkController] 
addBookmarkWithURL:url proposedName:[url lastPathComponent] 
modalForWindow:[self window]];
+    } else if (customMenuAction == BDSKWebViewCustomMenuActionAddLink) {
+        if ([[NSUserDefaults standardUserDefaults] 
boolForKey:BDSKUseLocalUrlAndUrlKey])
+            [[self publication] setField:[url isFileURL] ? BDSKLocalUrlString 
: BDSKUrlString toURLValue:url];
+        else
+            [[self publication] addFileForURL:url autoFile:YES 
runScriptHook:NO];
+        [[self undoManager] setActionName:NSLocalizedString(@"Edit 
Publication", @"Undo action name")];
+    } else if (customMenuAction == BDSKWebViewCustomMenuActionDownloadLink) {
+        if (isDownloading)
+            return nil;
+        if (url) {
+            download = [[BDSKDownloader sharedDownloader] 
startFileDownloadWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
+            [self setDownloading:YES];
+        }
+        if (download == nil) {
+            NSAlert *alert = [[NSAlert alloc] init];
+            [alert setMessageText:NSLocalizedString(@"Invalid or Unsupported 
URL", @"Message in alert dialog when unable to download file for Local-Url")];
+            [alert setInformativeText:NSLocalizedString(@"The URL to download 
is either invalid or unsupported.", @"Informative text in alert dialog")];
+            [alert beginSheetModalForWindow:[self window] 
completionHandler:NULL];
+        }
+    } else {
+        [[NSWorkspace sharedWorkspace] openURLWithDefaultApp:url];
+    }
+    return nil;
+}
+
+- (void)webView:(WKWebView *)aWebView willPopUpMenu:(NSMenu *)menu {
+    NSMenuItem *item;
+    NSInteger i = [menu numberOfItems], j = -1;
+    while (i--  > 0) {
+        item = [menu itemAtIndex:i];
+        NSString *itemID = [item identifier];
+        if ([itemID 
isEqualToString:@"WKMenuItemIdentifierOpenLinkInNewWindow"]) {
+            NSMenuItem *openLinkItem = item;
+            [menu removeItemAtIndex:i];
+            
+            item = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Save 
Link As Local File", @"Menu item title") 
action:@selector(performCustomMenuAction:) keyEquivalent:@""];
+            [item setTarget:self];
+            [item setTag:BDSKWebViewCustomMenuActionDownloadLink];
+            [item setIdentifier:@"BDSKMenuItemIdentifierDownloadLink"];
+            [item setRepresentedObject:openLinkItem];
+            [menu insertItem:item atIndex:i];
+            
+            item = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Copy 
Link To Url Field", @"Menu item title") 
action:@selector(performCustomMenuAction:) keyEquivalent:@""];
+            [item setTarget:self];
+            [item setTag:BDSKWebViewCustomMenuActionAddLink];
+            [item setIdentifier:@"BDSKMenuItemIdentifierAddLink"];
+            [item setRepresentedObject:openLinkItem];
+            [menu insertItem:item atIndex:i];
+            
+            item = [[NSMenuItem alloc] 
initWithTitle:[NSLocalizedString(@"Bookmark Link", @"Menu item title") 
stringByAppendingEllipsis] action:@selector(performCustomMenuAction:) 
keyEquivalent:@""];
+            [item setTarget:self];
+            [item setTag:BDSKWebViewCustomMenuActionBookmarkLink];
+            [item setIdentifier:@"BDSKMenuItemIdentifierBookmarkLink"];
+            [item setRepresentedObject:openLinkItem];
+            [menu insertItem:item atIndex:i];
+            
+            item = [[NSMenuItem alloc] initWithTitle:[NSLocalizedString(@"Open 
Link in Browser", @"Menu item title") stringByAppendingEllipsis] 
action:@selector(performCustomMenuAction:) keyEquivalent:@""];
+            [item setTarget:self];
+            [item setTag:BDSKWebViewCustomMenuActionOpenLink];
+            [item setIdentifier:@"BDSKMenuItemIdentifierOpenLink"];
+            [item setRepresentedObject:openLinkItem];
+            [menu insertItem:item atIndex:i];
+            
+            if (j >= 0)
+                j += 3;
+        } else if ([itemID isEqualToString:@"WKMenuItemIdentifierCopy"] ||
+                   [itemID isEqualToString:@"WKMenuItemIdentifierCopyLink"]) {
+            if (j == -1)
+                j = i;
+        }
+    }
+    
+    [menu addItem:[NSMenuItem separatorItem]];
+    
+    if (j == -1)
+        j = [menu numberOfItems];
+    else
+        j++;
+    
+    if (j < [menu numberOfItems] && [[menu itemAtIndex:j] isSeparatorItem] == 
NO)
+        [menu insertItem:[NSMenuItem separatorItem] atIndex:j];
+    
+    item = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Copy Page 
Location To Url Field", @"Menu item title") 
action:@selector(copyLocationAsRemoteUrl:) keyEquivalent:@""];
+    [item setTarget:self];
+    [item setIdentifier:@"BDSKMenuItemIdentifierCopyLocationToUrl"];
+    [menu insertItem:item atIndex:j];
+    
+    item = [[NSMenuItem alloc] initWithTitle:[NSLocalizedString(@"Bookmark 
This Page", @"Menu item title") stringByAppendingEllipsis] 
action:@selector(addBookmark:) keyEquivalent:@""];
+    [item setTarget:self];
+    [item setIdentifier:@"BDSKMenuItemIdentifierBookmarkPage"];
+    [menu insertItem:item atIndex:j];
+    
+    if (j > 0 && [[menu itemAtIndex:j - 1] isSeparatorItem] == NO)
+        [menu insertItem:[NSMenuItem separatorItem] atIndex:j];
+}
+
+#pragma mark BDSKScriptMessageHandlerDelegate protocol
+
+- (void)scriptMessageHandlerWithName:(NSString *)name 
didReceiveMessage:(NSString *)body {
+    if ([name isEqualToString:@"hoverLink"]) {
+        [statusLine setStringValue:body ?: @""];
+    } else if ([name isEqualToString:@"changeSelection"]) {
+        if ([NSString isEmptyString:body] == NO)
+            webSelection = [body 
stringByCollapsingAndTrimmingCharactersInSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet]];
+        if ([webView window])
+            [self setTemporaryTypeSelectStatusMessage:[NSString 
isEmptyString:body] == NO];
+    }
+}
+
 #pragma mark  BDSKDownloadDelegate methods
 
 - (void)download:(BDSKDownload *)aDownload 
didReceiveExpectedContentLength:(int64_t)length {
@@ -1580,3 +1777,33 @@
 }
 
 @end
+
+#pragma mark -
+
+@implementation BDSKWKWebView
+
+@dynamic UIDelegate;
+
+- (void)willOpenMenu:(NSMenu *)menu withEvent:(NSEvent *)event {
+    [super willOpenMenu:menu withEvent:event];
+    
+    if ([[self UIDelegate] 
respondsToSelector:@selector(webView:willPopUpMenu:)])
+        [[self UIDelegate] webView:self willPopUpMenu:menu];
+}
+
+@end
+
+#pragma mark -
+
+@implementation BDSKScriptMessageHandler
+
+@synthesize delegate;
+
+- (void)userContentController:(WKUserContentController *)userContentController 
didReceiveScriptMessage:(WKScriptMessage *)message {
+    NSString *body = [message body];
+    if ([body isKindOfClass:[NSString class]] == NO)
+        body = nil;
+    [delegate scriptMessageHandlerWithName:[message name] 
didReceiveMessage:body];
+}
+
+@end

Modified: trunk/bibdesk/de.lproj/Localizable.strings
===================================================================
(Binary files differ)

Modified: trunk/bibdesk/en.lproj/Localizable.strings
===================================================================
(Binary files differ)

Modified: trunk/bibdesk/fr.lproj/Localizable.strings
===================================================================
(Binary files differ)

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
Bibdesk-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit

Reply via email to