Free Developer Christmas Gifts

Yes, the footer displaying the current mouse-over link in the beta is back.

Brent Simmons, a developer I have never met, has sent me a christmas gift. As those of you in the beta know, the web view that displays the details for an item is all brand new in the latest version and based on WKWebView. One of the features that got lost in the beta was the mouse-over link being shown in the footer bar.

The method for showing this information is there in WKWebView but is marked with the dreaded underscore prefix, which means it’s for Apple use only. I left it as a todo a few weeks back, I figured that with some JavaScript I could get a call back when mouse entered a link, but did not want to switch from programming in Objective-C to JavaScript at that exact moment.

Luckily for me Brent ran into the same issue and his project being open source and MIT license meant it saved me a lot time. I was able to piggy back off his code, without having to write any JavaScript, simply using his.

For those looking for an Objective-C version here is mine. I have templates being loaded from many places including user generated ones. So instead of embedding the JavaScript in the file, I inject it with the same WKWebView userContentController that handles the call back.

First the Javascript, pretty much the same as Brent’s.

/* From Brent Simmons https://github.com/brentsimmons/Evergreen/blob/master/Evergreen/MainWindow/Detail/ArticleRenderer.swift */

function startup() {
    var anchors = document.getElementsByTagName("a");
    for (var i = 0; i < anchors.length; i++) {
        anchors[i].addEventListener("mouseenter", function() { mouseDidEnterLink(this) });
        anchors[i].addEventListener("mouseleave", function() { mouseDidExitLink(this) });
    }
}
function mouseDidEnterLink(anchor) {
    window.webkit.messageHandlers.mouseDidEnter.postMessage(anchor.href);
}
function mouseDidExitLink(anchor) {
    window.webkit.messageHandlers.mouseDidExit.postMessage(anchor.href);
}

/* Gets loaded by the WKWebView addScript: */
startup();

Then the code to receive the call back in Objective-C when the mouse enters and exist any link.

#define MOUSE_DID_ENTER @"mouseDidEnter"
#define MOUSE_DID_EXIT @"mouseDidExit"

- (void)MyInit {
    [self.configuration.userContentController addScriptMessageHandler:self name:MOUSE_DID_ENTER];
    [self.configuration.userContentController addScriptMessageHandler:self name:MOUSE_DID_EXIT];

    NSString *webViewFiles = [[[NSBundle mainBundle] pathForResource:@"InfoTemplates" ofType:nil] retain];
    NSString *pathToJavaScript = [NSString stringWithFormat:@"%@/includes/bruji.js", webViewFiles];
    NSString *javaScript = [[NSString alloc] initWithContentsOfFile:pathToJavaScript encoding:NSUTF8StringEncoding error:NULL];
    WKUserScript *script = [[WKUserScript alloc] initWithSource:javaScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
    [self.configuration.userContentController addUserScript:script];
}

#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.name isEqualToString:MOUSE_DID_ENTER]) {
        NSString *link = message.body;
        if ([link isKindOfClass:[NSString class]]) {
            [self setFooterLink:link];
        }
    }
    else if ([message.name isEqualToString:MOUSE_DID_EXIT]) {
        [controller setNumberOfSelectedInFooter];
    }
}

Now included in the latest beta for those that mourned the lost functionality.

On a related note, I can’t wait for further improvements on Brent’s latest newsreader project: Evergreen. I’ve been using version 3.1 of NetNewsWire for ages now, as the new versions were never as great as the original. Sadly feeds are starting to go dead, I think due to some type of HTTPS compatibility.

With this christmas gift we are getting closer to that inevitable 6.0 release. But first it’s time to take a little break. Happy holidays everyone!