diff --git a/Evergreen/Resources/Evergreen.sdef b/Evergreen/Resources/Evergreen.sdef
index 2cedc5478..56ab039db 100644
--- a/Evergreen/Resources/Evergreen.sdef
+++ b/Evergreen/Resources/Evergreen.sdef
@@ -13,6 +13,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Evergreen/Scriptability/Account+Scriptability.swift b/Evergreen/Scriptability/Account+Scriptability.swift
index 4530dfea8..5f5d2822c 100644
--- a/Evergreen/Scriptability/Account+Scriptability.swift
+++ b/Evergreen/Scriptability/Account+Scriptability.swift
@@ -45,6 +45,11 @@ class ScriptableAccount: NSObject, UniqueIdScriptingObject, ScriptingObjectConta
var scriptingClassDescription: NSScriptClassDescription {
return self.classDescription as! NSScriptClassDescription
}
+
+ @objc(isLocationRequiredToCreateForKey:)
+ func isLocationRequiredToCreate(forKey key:String) -> Bool {
+ return false;
+ }
// MARK: --- Scriptable elements ---
@@ -61,7 +66,6 @@ class ScriptableAccount: NSObject, UniqueIdScriptingObject, ScriptingObjectConta
return ScriptableFeed(feed, container:self)
}
-
@objc(folders)
var folders:NSArray {
let folders = account.children.compactMap { $0 as? Folder }
@@ -74,8 +78,7 @@ class ScriptableAccount: NSObject, UniqueIdScriptingObject, ScriptingObjectConta
let folders = account.children.compactMap { $0 as? Folder }
guard let folder = folders.first(where:{$0.folderID == folderId}) else { return nil }
return ScriptableFolder(folder, container:self)
- }
-
+ }
// MARK: --- Scriptable properties ---
diff --git a/Evergreen/Scriptability/AppDelegate+Scriptability.swift b/Evergreen/Scriptability/AppDelegate+Scriptability.swift
index 47e3bf5e1..512f0801e 100644
--- a/Evergreen/Scriptability/AppDelegate+Scriptability.swift
+++ b/Evergreen/Scriptability/AppDelegate+Scriptability.swift
@@ -56,8 +56,18 @@ extension AppDelegate : AppDelegateAppleEvents {
}
}
+class EvergreenCreateElementCommand : NSCreateCommand {
+ override func performDefaultImplementation() -> Any? {
+ let classDescription = self.createClassDescription
+ if (classDescription.className == "feed") {
+ return ScriptableFeed.handleCreateElement(command:self)
+ }
+ return nil
+ }
+}
+
class EvergreenExistsCommand : NSExistsCommand {
-
+
// cocoa default behavior doesn't work here, because of cases where we define an object's property
// to be another object type. e.g., 'permalink of the current article' parses as
// of of
diff --git a/Evergreen/Scriptability/Feed+Scriptability.swift b/Evergreen/Scriptability/Feed+Scriptability.swift
index 8a5ddad8b..24d89970a 100644
--- a/Evergreen/Scriptability/Feed+Scriptability.swift
+++ b/Evergreen/Scriptability/Feed+Scriptability.swift
@@ -7,6 +7,7 @@
//
import Foundation
+import RSParser
import Account
import Data
@@ -27,6 +28,11 @@ class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContaine
return (scriptObjectSpecifier)
}
+ @objc(scriptingSpecifierDescriptor)
+ func scriptingSpecifierDescriptor() -> NSScriptObjectSpecifier {
+ return (self.objectSpecifier ?? NSScriptObjectSpecifier() )
+ }
+
// MARK: --- ScriptingObject protocol ---
var scriptingKey: String {
@@ -47,6 +53,141 @@ class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContaine
var scriptingClassDescription: NSScriptClassDescription {
return self.classDescription as! NSScriptClassDescription
}
+
+
+ // MARK: --- Create Element Handlers ---
+
+ class func parsedFeedForURL(_ urlString:String, _ completionHandler: @escaping (_ parsedFeed: ParsedFeed?) -> Void) {
+ guard let url = URL(string: urlString) else {
+ completionHandler(nil)
+ return
+ }
+ InitialFeedDownloader.download(url) { (parsedFeed) in
+ completionHandler(parsedFeed)
+ }
+ }
+
+ class func urlForNewFeed(arguments:[String:Any]) -> String? {
+ var url:String?
+ if let withDataParam = arguments["ObjectData"] {
+ if let objectDataDescriptor = withDataParam as? NSAppleEventDescriptor {
+ url = objectDataDescriptor.stringValue
+ }
+ } else if let withPropsParam = arguments["ObjectProperties"] as? [String:Any] {
+ url = withPropsParam["url"] as? String
+ }
+ return url
+ }
+
+ class func accountAndFolderForNewFeed(appleEvent:NSAppleEventDescriptor?) -> (Account, Folder?) {
+ var account = AccountManager.shared.localAccount
+ var folder:Folder? = nil
+ if let appleEvent = appleEvent {
+ var descriptorToConsider:NSAppleEventDescriptor?
+ if let insertionLocationDescriptor = appleEvent.paramDescriptor(forKeyword:keyAEInsertHere) {
+ print("insertionLocation : \(insertionLocationDescriptor)")
+ // insertion location can be a typeObjectSpecifier, e.g. 'in account "Acct"'
+ // or a typeInsertionLocation, e.g. 'at end of folder "
+ if (insertionLocationDescriptor.descriptorType == "insl".FourCharCode()) {
+ descriptorToConsider = insertionLocationDescriptor.forKeyword("kobj".FourCharCode())
+ } else if ( insertionLocationDescriptor.descriptorType == "obj ".FourCharCode()) {
+ descriptorToConsider = insertionLocationDescriptor
+ }
+ } else if let subjectDescriptor = appleEvent.attributeDescriptor(forKeyword:"subj".FourCharCode()) {
+ descriptorToConsider = subjectDescriptor
+ }
+
+ if let descriptorToConsider = descriptorToConsider {
+ guard let newContainerSpecifier = NSScriptObjectSpecifier(descriptor:descriptorToConsider) else {return (account, folder)}
+ let newContainer = newContainerSpecifier.objectsByEvaluatingSpecifier
+ if let scriptableAccount = newContainer as? ScriptableAccount {
+ account = scriptableAccount.account
+ } else if let scriptableFolder = newContainer as? ScriptableFolder {
+ if let folderAccount = scriptableFolder.folder.account {
+ folder = scriptableFolder.folder
+ account = folderAccount
+ }
+ }
+ }
+ print("found account : \(account)")
+ print("found folder : \(folder)")
+ }
+ return (account, folder)
+ }
+
+ class func handleCreateElement(command:NSCreateCommand) -> Any? {
+ let appleEventManager = NSAppleEventManager.shared()
+ if let receivers = command.receiversSpecifier {
+ print("receivers : \(receivers)")
+ }
+ if let evaluatedReceivers = command.evaluatedReceivers {
+ print("evaluatedReceivers : \(evaluatedReceivers)")
+ }
+ if let evaluatedArguments = command.evaluatedArguments {
+ print("evaluatedArguments : \(evaluatedArguments)")
+ }
+ if let directObject = command.directParameter {
+ print("directObject : \(directObject)")
+ }
+ if let appleEvent = command.appleEvent { // keyDirectObject
+ print("appleEvent : \(appleEvent)")
+ if let subjectDescriptor = appleEvent.attributeDescriptor(forKeyword:"subj".FourCharCode()) {
+ print("subjectDescriptor : \(subjectDescriptor)")
+ let subjectObjectSpecifier = NSScriptObjectSpecifier(descriptor:subjectDescriptor)
+ let subjects = subjectObjectSpecifier?.objectsByEvaluatingSpecifier
+ print("resolvedSubjects : \(subjects)")
+ }
+ }
+ let commandDescription = command.commandDescription
+ print("commandDescription : \(commandDescription)")
+
+ let (account, folder) = self.accountAndFolderForNewFeed(appleEvent:command.appleEvent)
+ let scriptableAccount = ScriptableAccount(account)
+ guard let arguments = command.arguments else {return nil}
+ guard let newObjectClass = arguments["ObjectClass"] as? Int else {return nil}
+ guard (newObjectClass.FourCharCode() == "Feed".FourCharCode()) else {return nil}
+ guard let url = self.urlForNewFeed(arguments:arguments) else {return nil}
+
+ if let existingFeed = account.existingFeed(withURL:url) {
+ return ScriptableFeed(existingFeed, container:scriptableAccount)
+ }
+
+ // at this point, we have to download the feed and parse it.
+ // RS Parser does the callback for the download on the main thread
+ // because we can't wait here (on the main thread, maybe) for the callback, we have to return from this function
+ // generally, the means handling the appleEvent is over, but to prevent the apple event from returning
+ // we call suspendExecution here. When we get the callback, we can resume execution
+ command.suspendExecution()
+
+ self.parsedFeedForURL(url, { (parsedFeedOptional) in
+ if let parsedFeed = parsedFeedOptional {
+ let titleFromFeed = parsedFeed.title
+ let titleFromArgs = arguments["name"] as? String
+
+ guard let feed = account.createFeed(with: titleFromFeed, editedName: titleFromArgs, url: url) else {
+ command.resumeExecution(withResult:nil)
+ return
+ }
+ account.update(feed, with:parsedFeed, {})
+
+ // add the feed, puttin git in a folder if needed
+ if account.addFeed(feed, to: folder) {
+ NotificationCenter.default.post(name: .UserDidAddFeed, object: self, userInfo: [UserInfoKey.feed: feed])
+ }
+
+ let resolvedKeyDictionary = command.resolvedKeyDictionary
+ print("resolvedKeyDictionary : \(resolvedKeyDictionary)")
+ let scriptableFeed = ScriptableFeed(feed, container:ScriptableAccount(account))
+ command.resumeExecution(withResult:scriptableFeed.objectSpecifier)
+ } else {
+ command.resumeExecution(withResult:nil)
+ }
+ })
+ return nil
+ }
+
+
+
// MARK: --- Scriptable properties ---
diff --git a/Frameworks/Account/Account.swift b/Frameworks/Account/Account.swift
index 76d32af9b..e37f5242a 100644
--- a/Frameworks/Account/Account.swift
+++ b/Frameworks/Account/Account.swift
@@ -257,6 +257,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
let feed = Feed(accountID: accountID, url: url, feedID: url)
feed.name = name
feed.editedName = editedName
+
return feed
}