implement 'current article' property of the application

Also, fix the unique-id based accessors (the four byte code  for id was
wrong in the sdef)
Add valueIn<Key>WithUniqueID accessors
Add a few protocols and protocol implementations for the AppDelegate
and MainWindowControllor so as to expose needed functionality for
scriptability
This commit is contained in:
Olof Hellman
2018-02-08 00:11:52 -08:00
parent 2e4217236b
commit 395af1420e
9 changed files with 192 additions and 10 deletions

View File

@@ -54,12 +54,29 @@ class ScriptableAccount: NSObject, UniqueIdScriptingObject, ScriptingObjectConta
return feeds.map { ScriptableFeed($0, container:self) } as NSArray
}
@objc(valueInFeedsWithUniqueID:)
func valueInFeeds(withUniqueID id:String) -> ScriptableFeed? {
let feeds = account.children.compactMap { $0 as? Feed }
guard let feed = feeds.first(where:{$0.feedID == id}) else { return nil }
return ScriptableFeed(feed, container:self)
}
@objc(folders)
var folders:NSArray {
let folders = account.children.compactMap { $0 as? Folder }
return folders.map { ScriptableFolder($0, container:self) } as NSArray
}
@objc(valueInFoldersWithUniqueID:)
func valueInFolders(withUniqueID id:NSNumber) -> ScriptableFolder? {
let folderId = id.intValue
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 ---
@objc(contents)

View File

@@ -0,0 +1,28 @@
//
// AppDelegate+Scriptability.swift
// Evergreen
//
// Created by Olof Hellman on 2/7/18.
// Copyright © 2018 Ranchero Software. All rights reserved.
//
/*
Note: strictly, the AppDelegate doesn't appear as part of the scripting model,
so this file is rather unlike the other Object+Scriptability.swift files.
However, the AppDelegate object is the de facto scripting accessor for some
application elements and properties. For, example, the main window is accessed
via the AppDelegate's MainWindowController, and the main window itself has
selected feeds, selected articles and a current article. This file supplies the glue to access
these scriptable objects, while being completely separate from the core AppDelegate code,
*/
import Foundation
import Data
protocol ScriptingAppDelegate {
var scriptingCurrentArticle: Article? {get}
var scriptingSelectedArticles: [Article] {get}
var scriptingMainWindowController:ScriptingMainWindowController? {get}
}

View File

@@ -85,11 +85,19 @@ class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContaine
return self.feed.OPMLString(indentLevel:0)
}
// MARK: --- scriptable elements ---
@objc(authors)
var authors:NSArray {
let feedAuthors = feed.authors ?? []
return feedAuthors.map { ScriptableAuthor($0, container:self) } as NSArray
}
@objc(valueInAuthorsWithUniqueID:)
func valueInAuthors(withUniqueID id:String) -> ScriptableAuthor? {
guard let author = feed.authors?.first(where:{$0.authorID == id}) else { return nil }
return ScriptableAuthor(author, container:self)
}
@objc(articles)
var articles:NSArray {
@@ -100,5 +108,12 @@ class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContaine
})
return sortedArticles.map { ScriptableArticle($0, container:self) } as NSArray
}
@objc(valueInArticlesWithUniqueID:)
func valueInArticles(withUniqueID id:String) -> ScriptableArticle? {
let articles = feed.fetchArticles()
guard let article = articles.first(where:{$0.uniqueID == id}) else { return nil }
return ScriptableArticle(article, container:self)
}
}

View File

@@ -0,0 +1,16 @@
//
// MainWindowController+Scriptability.swift
// Evergreen
//
// Created by Olof Hellman on 2/7/18.
// Copyright © 2018 Ranchero Software. All rights reserved.
//
import Foundation
import Data
protocol ScriptingMainWindowController {
var scriptingCurrentArticle: Article? { get }
var scriptingSelectedArticles: [Article] { get }
}

View File

@@ -20,27 +20,74 @@ extension NSApplication : ScriptingObjectContainer {
return "application"
}
@objc(currentArticle)
func currentArticle() -> ScriptableArticle? {
var scriptableArticle: ScriptableArticle?
if let currentArticle = appDelegate.scriptingCurrentArticle {
if let feed = currentArticle.feed {
let scriptableFeed = ScriptableFeed(feed, container:self)
scriptableArticle = ScriptableArticle(currentArticle, container:scriptableFeed)
}
}
return scriptableArticle
}
@objc(selectedArticles)
func selectedArticles() -> NSArray {
let articles = appDelegate.scriptingSelectedArticles
let scriptableArticles:[ScriptableArticle] = articles.compactMap { article in
if let feed = article.feed {
let scriptableFeed = ScriptableFeed(feed, container:self)
return ScriptableArticle(article, container:scriptableFeed)
} else {
return nil
}
}
return scriptableArticles as NSArray
}
// MARK: --- scriptable elements ---
@objc(accounts)
func accounts() -> NSArray {
let accounts = AccountManager.shared.accounts
return accounts.map { ScriptableAccount($0) } as NSArray
}
@objc(valueInAccountsWithUniqueID:)
func valueInAccounts(withUniqueID id:String) -> ScriptableAccount? {
let accounts = AccountManager.shared.accounts
guard let account = accounts.first(where:{$0.accountID == id}) else { return nil }
return ScriptableAccount(account)
}
/*
accessing feeds from the application object skips the 'account' containment hierarchy
this allows a script like 'articles of feed "The Shape of Everything"' as a shorthand
for 'articles of feed "The Shape of Everything" of account "On My Mac"'
*/
@objc(feeds)
func feeds() -> NSArray {
*/
func allFeeds() -> [Feed] {
let accounts = AccountManager.shared.accounts
let emptyFeeds:[Feed] = []
let feeds = accounts.reduce(emptyFeeds) { (result, nthAccount) -> [Feed] in
return accounts.reduce(emptyFeeds) { (result, nthAccount) -> [Feed] in
let accountFeeds = nthAccount.children.compactMap { $0 as? Feed }
return result + accountFeeds
}
}
@objc(feeds)
func feeds() -> NSArray {
let feeds = self.allFeeds()
return feeds.map { ScriptableFeed($0, container:self) } as NSArray
}
@objc(valueInFeedsWithUniqueID:)
func valueInFeeds(withUniqueID id:String) -> ScriptableFeed? {
let feeds = self.allFeeds()
guard let feed = feeds.first(where:{$0.feedID == id}) else { return nil }
return ScriptableFeed(feed, container:self)
}
}