Merge pull request #385 from danielpunkass/safari-extension

Safari extension fixes
This commit is contained in:
Brent Simmons 2018-08-19 15:22:27 -07:00 committed by GitHub
commit c60da0fefc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 135 additions and 129 deletions

View File

@ -18,7 +18,7 @@ class SafariExtensionHandler: SFSafariExtensionHandler {
// to verify whether our code is installed.
// I tried to use a NSMapTable from String to the closure directly, but Swift
// complains that the object as to be a class type.
// complains that the object has to be a class type.
typealias ValidationHandler = (Bool, String) -> Void
class ValidationWrapper {
let validationHandler: ValidationHandler
@ -30,6 +30,7 @@ class SafariExtensionHandler: SFSafariExtensionHandler {
// Maps from UUID to a validation wrapper
static var gPingPongMap = Dictionary<String, ValidationWrapper>()
static var validationQueue = DispatchQueue(label: "Toolbar Validation")
// Bottleneck for calling through to a validation handler we have saved, and removing it from the list.
static func callValidationHandler(forHandlerID handlerID: String, withShouldValidate shouldValidate: Bool) {
@ -39,8 +40,6 @@ class SafariExtensionHandler: SFSafariExtensionHandler {
}
}
var validationQueue = DispatchQueue(label: "Toolbar Validation")
override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : Any]?) {
if (messageName == "subscribeToFeed") {
if let feedURLString = userInfo?["url"] as? String {
@ -73,12 +72,25 @@ class SafariExtensionHandler: SFSafariExtensionHandler {
let uniqueValidationID = NSUUID().uuidString
SafariExtensionHandler.validationQueue.sync {
// Save it right away to eliminate any doubt of whether the handler gets deallocated while
// we are waiting for a callback from the getActiveTab or getActivatePage methods below.
let validationWrapper = ValidationWrapper(validationHandler: validationHandler)
SafariExtensionHandler.gPingPongMap[uniqueValidationID] = validationWrapper
validationQueue.sync {
// To avoid problems with validation handlers dispatched after we've, for example,
// switched to a new tab, we aggressively clear out the map of any pending validations,
// and focus only on the newest validation request we've been asked for.
for thisValidationID in SafariExtensionHandler.gPingPongMap.keys {
if thisValidationID != uniqueValidationID {
// Default to valid ... we'll know soon enough whether the latest state
// is actually still valid or not...
SafariExtensionHandler.callValidationHandler(forHandlerID: thisValidationID, withShouldValidate: true);
}
}
// See comments above where gPingPongMap is declared. Upon being asked to validate the
// toolbar icon for a specific page, we save the validationHandler and postpone calling
// it until we have either received a response from our installed JavaScript, or until
@ -101,7 +113,7 @@ class SafariExtensionHandler: SFSafariExtensionHandler {
// Capture the uniqueValidationID to ensure it doesn't change out from under us on a future call
activePage.dispatchMessageToScript(withName: "ping", userInfo: ["validationID": uniqueValidationID])
let pongTimeoutInNanoseconds = Int(NSEC_PER_SEC / UInt64(1))
let pongTimeoutInNanoseconds = Int(Double(NSEC_PER_SEC) * 0.5)
let timeoutDeadline = DispatchTime.now() + DispatchTimeInterval.nanoseconds(pongTimeoutInNanoseconds)
DispatchQueue.main.asyncAfter(deadline: timeoutDeadline, execute: { [timedOutValidationID = uniqueValidationID] in
SafariExtensionHandler.callValidationHandler(forHandlerID: timedOutValidationID, withShouldValidate:false)

View File

@ -1,13 +1,7 @@
// Prevent injecting the JavaScript in IFRAMES, and from acting before Safari is ready...
if ((window.top === window) && (typeof safari != 'undefined') && (document.location != null)) {
document.addEventListener("DOMContentLoaded", function(event) {
if (window.top === window)
{
var thisPageLinkObjects = null;
var thisPageLinkObjects = null;
// I convert the native "link" node into an object that I can pass out to the global page
function objectFromLink(theLink)
{
// I convert the native "link" node into an object that I can pass out to the global page
function objectFromLink(theLink) {
var linkObject = new Object();
linkObject.href = theLink.href;
@ -15,13 +9,12 @@ if ((window.top === window) && (typeof safari != 'undefined') && (document.loca
linkObject.title = theLink.title;
return linkObject;
}
}
// Some sites will list feeds with inappropriate or at least less-than-ideal information
// in the MIME type attribute. We cover some edge cases here that allow to be passed through,
// where they will successfully open as "feed://" URLs in the browser.
function isValidFeedLink(theLink)
{
// Some sites will list feeds with inappropriate or at least less-than-ideal information
// in the MIME type attribute. We cover some edge cases here that allow to be passed through,
// where they will successfully open as "feed://" URLs in the browser.
function isValidFeedLink(theLink) {
var isValid = false;
switch (theLink.type)
@ -42,10 +35,9 @@ if ((window.top === window) && (typeof safari != 'undefined') && (document.loca
}
return isValid;
}
}
function scanForSyndicationFeeds()
{
function scanForSyndicationFeeds() {
// In case we don't find any, we establish that we have at least tried by setting the
// variables to empty instead of null.
thisPageLinkObjects = []
@ -64,10 +56,9 @@ if ((window.top === window) && (typeof safari != 'undefined') && (document.loca
}
}
}
}
}
function subscribeToFeed(theFeed)
{
function subscribeToFeed(theFeed) {
// Convert the URL to a feed:// scheme because Safari
// will refuse to load e.g. a feed that is listed merely
// as "text/xml". We do some preflighting of the link rel
@ -84,10 +75,9 @@ if ((window.top === window) && (typeof safari != 'undefined') && (document.loca
}
safari.extension.dispatchMessage("subscribeToFeed", { "url": feedURL });
}
}
safari.self.addEventListener("message", function(event)
{
function messageHandler(event) {
if (event.name === "toolbarButtonClicked")
{
// Workaround Radar #31182842, in which residual copies of our
@ -116,9 +106,13 @@ if ((window.top === window) && (typeof safari != 'undefined') && (document.loca
// Pass back the same validationID we were handed so they can look up the correlated validationHandler
safari.extension.dispatchMessage("pong", { "validationID": event.message.validationID, "shouldValidate": shouldValidate });
}
}, false);
}
document.addEventListener("DOMContentLoaded", function(event) {
// Prevent injecting the JavaScript in IFRAMES, and from acting before Safari is ready...
if ((window.top === window) && (typeof safari != 'undefined') && (document.location != null))
{
safari.self.addEventListener("message", messageHandler, false)
scanForSyndicationFeeds();
}
});
}
});