Skip to content

Commit

Permalink
Merge pull request #50 from johnste/finicky-2
Browse files Browse the repository at this point in the history
Finicky 2
  • Loading branch information
johnste committed May 19, 2019
2 parents ceb32e4 + 81cb5b1 commit 7aa3f81
Show file tree
Hide file tree
Showing 16 changed files with 476 additions and 289 deletions.
4 changes: 4 additions & 0 deletions Finicky/Finicky.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
543EC33F21DE54EA004789DF /* validateConfig.js in Resources */ = {isa = PBXBuildFile; fileRef = 543EC33E21DE54E9004789DF /* validateConfig.js */; };
544B57891B28B87900812908 /* statusitem.png in Resources */ = {isa = PBXBuildFile; fileRef = 544B57871B28B87900812908 /* statusitem.png */; };
544B578A1B28B87900812908 /* statusitem@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 544B57881B28B87900812908 /* statusitem@2x.png */; };
546F1678228B487F006C5375 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 546F1677228B487F006C5375 /* Utilities.swift */; };
5479FDD421655A3400D15A3C /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5479FDD321655A3400D15A3C /* Notifications.swift */; };
548479A22278ADB40003D51C /* validate.js in Resources */ = {isa = PBXBuildFile; fileRef = 548479A12278ADB40003D51C /* validate.js */; };
54899CD61B20D5BC00647101 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54899CD51B20D5BC00647101 /* AppDelegate.swift */; };
Expand Down Expand Up @@ -45,6 +46,7 @@
543EC33E21DE54E9004789DF /* validateConfig.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = validateConfig.js; sourceTree = "<group>"; };
544B57871B28B87900812908 /* statusitem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = statusitem.png; sourceTree = "<group>"; };
544B57881B28B87900812908 /* statusitem@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "statusitem@2x.png"; sourceTree = "<group>"; };
546F1677228B487F006C5375 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
5479FDD321655A3400D15A3C /* Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
548479A12278ADB40003D51C /* validate.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = validate.js; sourceTree = "<group>"; };
54899CD01B20D5BC00647101 /* Finicky.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Finicky.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -121,6 +123,7 @@
54B0E7021B4678CE003F8AEE /* ShortUrlResolver.swift */,
5479FDD321655A3400D15A3C /* Notifications.swift */,
54B5771522860D0B0016BF77 /* Credits.rtf */,
546F1677228B487F006C5375 /* Utilities.swift */,
);
path = Finicky;
sourceTree = "<group>";
Expand Down Expand Up @@ -278,6 +281,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
546F1678228B487F006C5375 /* Utilities.swift in Sources */,
5479FDD421655A3400D15A3C /* Notifications.swift in Sources */,
54E33FD71B24E27000998E13 /* Config.swift in Sources */,
54899CD61B20D5BC00647101 /* AppDelegate.swift in Sources */,
Expand Down
28 changes: 6 additions & 22 deletions Finicky/Finicky/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import JavaScriptCore
@objc protocol FinickyAPIExports : JSExport {
static func log(_ message: String?) -> Void
static func notify(_ title: JSValue, _ subtitle: JSValue) -> Void
static func matchDomains(_ domains: [String]) -> ((_ url: String) -> JSValue)
static func getUrlParts(_ url: String) -> Dictionary<String, Any>
}

Expand Down Expand Up @@ -38,33 +37,19 @@ import JavaScriptCore
self.logToConsole = logToConsole
}

@objc class func matchDomains(_ domains: [String]) -> ((_ url: String) -> JSValue) {
func matchDomain(url: String) -> JSValue {
for domain in domains {
let urlParts = getUrlParts(url);
if( urlParts["host"] as! String == domain) {
return JSValue(bool: true, in: context)
}
}
return JSValue(bool: false, in: context)
}

return matchDomain;
}

@objc public class func getUrlParts(_ urlString: String) -> Dictionary<String, Any> {
let url: URL! = URL.init(string: urlString)

guard url != nil else { return [:] }

let _protocol = url.scheme ?? nil
let username = url.user ?? nil
let password = url.password ?? nil
let host = url.host ?? nil
let _protocol = url.scheme ?? ""
let username = url.user ?? ""
let password = url.password ?? ""
let host = url.host ?? ""
let port = url.port ?? nil
let pathname = url.path
let search = url.query ?? nil
let hash = url.fragment ?? nil
let search = url.query ?? ""
let hash = url.fragment ?? ""

let urlDict = [
"hash": hash as Any,
Expand All @@ -79,5 +64,4 @@ import JavaScriptCore

return urlDict
}

}
76 changes: 34 additions & 42 deletions Finicky/Finicky/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
statusItem.menu = statusItemMenu
statusItem.highlightMode = true
statusItem.image = img
_ = toggleDockIcon(showIcon: false)
toggleDockIcon(showIcon: false)

func toggleIconCallback(show: Bool) {
guard statusItem != nil else { return }
Expand All @@ -45,7 +45,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele

configLoader = FinickyConfig(toggleIconCallback: toggleIconCallback, logToConsoleCallback: logToConsole, setShortUrlProviders: setShortUrlProviders)
configLoader.reload(showSuccess: false)

}

@IBAction func reloadConfig(_ sender: NSMenuItem) {
Expand Down Expand Up @@ -79,23 +78,30 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
return
}
if let url = URL.init(string: value) {
if let appDescriptor = configLoader.determineOpeningApp(url: url, sourceBundleIdentifier: "net.kassett.finicky") {
var description = ""

if let openInBackground = appDescriptor.openInBackground {
description = """
Would open \(AppDescriptorType.bundleId == appDescriptor.appType ? "bundleId" : "") "\(appDescriptor.name)" \(openInBackground ? "application in the background" : "") URL: "\(appDescriptor.url)"
"""
} else {
description = """
Would open \(AppDescriptorType.bundleId == appDescriptor.appType ? "bundleId" : "") "\(appDescriptor.name)" URL: "\(appDescriptor.url)"
"""
}
logToConsole(description)
shortUrlResolver.resolveUrl(url, callback: {(URL) -> Void in
self.performTest(url: URL)
})
}
}

func performTest(url: URL) {
if let appDescriptor = configLoader.determineOpeningApp(url: url, sourceBundleIdentifier: "net.kassett.finicky") {
var description = ""

if let openInBackground = appDescriptor.openInBackground {
description = """
Would open \(AppDescriptorType.bundleId == appDescriptor.appType ? "bundleId" : "")\(appDescriptor.name) \(openInBackground ? "application in the background" : "") URL: \(appDescriptor.url)
"""
} else {
description = """
Would open \(AppDescriptorType.bundleId == appDescriptor.appType ? "bundleId" : "")\(appDescriptor.name) URL: \(appDescriptor.url)
"""
}
logToConsole(description)
}
}

@discardableResult
@objc func toggleDockIcon(showIcon state: Bool) -> Bool {
var result: Bool
if state {
Expand All @@ -112,13 +118,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
let pid = event!.attributeDescriptor(forKeyword: AEKeyword(keySenderPIDAttr))!.int32Value
let sourceBundleIdentifier = NSRunningApplication(processIdentifier: pid)?.bundleIdentifier

if shortUrlResolver.isShortUrl(url) {
shortUrlResolver.resolveUrl(url, callback: {(URL) -> Void in
self.callUrlHandlers(sourceBundleIdentifier, url: url)
})
} else {
self.callUrlHandlers(sourceBundleIdentifier, url: url)
}
shortUrlResolver.resolveUrl(url, callback: {(URL) -> Void in
self.callUrlHandlers(sourceBundleIdentifier, url: URL)
})
}

@objc func callUrlHandlers(_ sourceBundleIdentifier: String?, url: URL) {
Expand All @@ -138,7 +140,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
if bundleId != nil {
openUrlWithBrowser(appDescriptor.url, bundleIdentifier:bundleId!, openInBackground: appDescriptor.openInBackground )
} else {
print ("Finicky was unable to find the application \"" + appDescriptor.name + "\"")
let description = "Finicky was unable to find the application \"" + appDescriptor.name + "\"";
print(description)
logToConsole(description)
showNotification(title: "Unable to find application", informativeText: "Finicky was unable to find the application \"" + appDescriptor.name + "\"", error: true)
}
}
Expand All @@ -154,27 +158,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele


func openUrlWithBrowser(_ url: URL, bundleIdentifier: String, openInBackground: Bool?) {
let urls = [url]

// Launch in background by default if finicky isn't active to avoid something..
// Launch in background by default if finicky isn't active to avoid something that causes some bug to happen...
// Too long ago to remember what actually happened
let openInBackground = openInBackground ?? !isActive

if !openInBackground {
NSWorkspace.shared.launchApplication(
withBundleIdentifier: bundleIdentifier,
options: NSWorkspace.LaunchOptions.default,
additionalEventParamDescriptor: nil,
launchIdentifier: nil
)
print("opening " + url.absoluteString)
if (openInBackground) {
shell("open", url.absoluteString , "-b", bundleIdentifier, "-g")
} else {
shell("open",url.absoluteString , "-b", bundleIdentifier)
}

NSWorkspace.shared.open(
urls,
withAppBundleIdentifier: bundleIdentifier,
options: openInBackground ? NSWorkspace.LaunchOptions.withoutActivation : NSWorkspace.LaunchOptions.default,
additionalEventParamDescriptor: nil,
launchIdentifiers: nil
)
}

func application(_ sender: NSApplication, openFiles filenames: [String]) {
Expand All @@ -183,7 +176,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
}
}


func applicationWillFinishLaunching(_ aNotification: Notification) {
let appleEventManager:NSAppleEventManager = NSAppleEventManager.shared()
appleEventManager.setEventHandler(self, andSelector: #selector(AppDelegate.handleGetURLEvent(_:withReplyEvent:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))
Expand Down
59 changes: 52 additions & 7 deletions Finicky/Finicky/Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,17 @@ open class FinickyConfig {
dispatchSource?.resume()
}

@discardableResult
open func createContext() -> JSContext {
ctx = JSContext()

ctx.exceptionHandler = {
context, exception in
(context: JSContext!, exception: JSValue!) in
self.hasError = true;
//let stacktrace = exception.objectForKeyedSubscript("stack").toString()
//let lineNumber = exception.objectForKeyedSubscript("line").toString()
//let columnNumber = exception.objectForKeyedSubscript("column").toString()
//let message = "Error parsing config: \"\(String(describing: exception!))\" \nStack: \(stacktrace!):\(lineNumber!):\(columnNumber!)";
let message = "Error parsing config: \"\(String(describing: exception!))\"";
print(message)
showNotification(title: "Error parsing config", informativeText: String(describing: exception!), error: true)
Expand All @@ -131,6 +136,7 @@ open class FinickyConfig {
return ctx
}

@discardableResult
open func parseConfig(_ config: String) -> Bool {
ctx.evaluateScript(config)

Expand Down Expand Up @@ -173,18 +179,19 @@ open class FinickyConfig {

if config == nil {
let message = "Config file could not be read or found"
showNotification(title: message, subtitle: "Click here to show example config file", error: true)
showNotification(title: message, subtitle: "Click here for assistance", error: true)
print(message)
if (self.logToConsole != nil) {
self.logToConsole!(message + "\n\n" + """
// --------------------------------------------------------------
// Example config, save as ~/.finicky.js
// For more examples, see the Finicky github page https://github.com/johnste/finicky
module.exports = {
defaultBrowser: "Safari",
handlers: [
{
match: /^https?:\\/\\/(youtube|facebook|twitter|linkedin|keep\\.google)\\.com/,
app: "Google Chrome"
match: finicky.matchDomains(["youtube.com", "facebook.com", "twitter.com", "linkedin.com"]),
browser: "Google Chrome"
}
]
};
Expand Down Expand Up @@ -230,12 +237,16 @@ open class FinickyConfig {

open func getShortUrlProviders() -> [String]? {
let urlShorteners = ctx.evaluateScript("module.exports.options && module.exports.options.urlShorteners || []")?.toArray()
return urlShorteners as! [String]?;
let list = urlShorteners as! [String]?;
if (list?.count == 0) {
return nil;
}
return list;
}

open func determineOpeningApp(url: URL, sourceBundleIdentifier: String? = nil) -> AppDescriptor? {
let appValue = getConfiguredAppValue(url: url, sourceBundleIdentifier: sourceBundleIdentifier)

if ((appValue?.isObject)!) {
let dict = appValue?.toDictionary()
let appType = AppDescriptorType(rawValue: dict!["appType"] as! String)
Expand Down Expand Up @@ -268,8 +279,10 @@ open class FinickyConfig {
func getConfiguredAppValue(url: URL, sourceBundleIdentifier: String?) -> JSValue? {
let optionsDict = [
"sourceBundleIdentifier": sourceBundleIdentifier as Any,
"urlString": url.absoluteString,
"url": FinickyAPI.getUrlParts(url.absoluteString),
] as [AnyHashable : Any]
let result = ctx.evaluateScript(processUrlJS!)?.call(withArguments: [url.absoluteString, optionsDict])
let result = ctx.evaluateScript(processUrlJS!)?.call(withArguments: [optionsDict])
return result
}

Expand All @@ -279,5 +292,37 @@ open class FinickyConfig {
}
FinickyAPI.setContext(ctx)
ctx.setObject(FinickyAPI.self, forKeyedSubscript: "finicky" as NSCopying & NSObjectProtocol)

ctx.evaluateScript("""
finicky.matchDomains = function(matchers) {
if (!Array.isArray(matchers)) {
matchers = [matchers];
}
return function({ url }) {
const domain = url.host;
return matchers.some(matcher => {
if (matcher instanceof RegExp) {
return matcher.test(domain);
} else if (typeof matcher === "string") {
return matcher === domain;
}
return false;
});
}
}
// Warn when using deprecated API methods
finicky.onUrl = function() {
finicky.log("finicky.onUrl is no longer supported in this version of Finicky, please go to https://github.com/johnste/finicky for updated documentation");
finicky.notify("finicky.onUrl is no longer supported", "Check the Finicky website for updated documentation");
}
finicky.setDefaultBrowser = function() {
finicky.log("finicky.setDefaultBrowser is no longer supported in this version of Finicky, please go to https://github.com/johnste/finicky for updated documentation");
finicky.notify("finicky.setDefaultBrowser is no longer supported", "Check the Finicky website for updated documentation");
}
""")
}
}
2 changes: 1 addition & 1 deletion Finicky/Finicky/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.0-alpha</string>
<string>2.0-beta</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand Down

0 comments on commit 7aa3f81

Please sign in to comment.