我希望JXA等同于这个AppleScript片段:
tell application "Finder"
# Get path
set currentTarget to target of window 1
set posixPath to (POSIX path of (currentTarget as alias))
# Show dialog
display dialog posixPath buttons {"OK"}
end tell
我最接近的是使用url
属性初始化Foundation NSURL对象并访问其fileSystemRepresentation属性,如下所示:
// Get path
var finder = Application('Finder')
var currentTarget = finder.finderWindows[0].target()
var fileURLString = currentTarget.url()
// I'd like to get rid of this step
var fileURL = $.NSURL.alloc.initWithString(fileURLString)
var posixPath = fileURL.fileSystemRepresentation
// Show dialog
finder.includeStandardAdditions = true
finder.displayAlert('', {buttons: ['Ok'], message: posixPath})
但这似乎不必要地复杂。是否有更好的方式到达POSIX路径而不使用Foundation API 或手动字符串争论?
如果我天真地尝试这个:
finder.finderWindows[0].target().posixPath()
我收到此错误:
app.startupDisk.folders.byName("Users").folders.byName("kymer").folders.byName("Desktop").posixPath()
--> Error -1728: Can't get object.
此SO answer似乎相关,但我似乎无法根据自己的需要对其进行调整:
App = Application.currentApplication()
App.includeStandardAdditions = true
SystemEvents = Application('System Events')
var pathToMe = App.pathTo(this)
var containerPOSIXPath = SystemEvents.files[pathToMe.toString()].container().posixPath()
非常感谢任何帮助!
答案 0 :(得分:1)
理论上你会写一些类似的东西:
finder.finderWindows[0].target({as:"alias"})
但这不起作用,文档中没有任何内容表明它受支持。但这就是JXA的SOP,就像Apple早期的Scripting Bridge一样,它遭受了许多设计缺陷和遗漏,而这些设计缺陷和遗漏从未(也可能永远不会)修复。[1]
FWIW,以下是使用NodeAutomation在Node.js中执行此操作的方法:
$ node
> Object.assign(this,require('nodeautomation'));undefined
> const fn = app('Finder')
> var file = fn.FinderWindows[0].target({asType:k.alias}) // returns File object
> file.toString() // converts File object to POSIX path string
'/Users/jsmith/dev/nodeautomation'
(请注意,NodeAutomation对我来说是一个非常低优先级的项目,因为Mac自动化看起来几乎是苹果公司的最后一步.Caveat emptor等。对于非平凡的脚本,我强烈建议坚持使用AppleScript因为它是唯一正式支持的解决方案,实际上正常工作。)
[1]例如,另一个JXA限制是大多数应用程序的move
和duplicate
命令严重受损,因为JXA作者忘记实施insertion reference forms。 (顺便说一下,我在JXA发布之前报告了所有这些问题,而且appscript已经在十年前解决了所有这些问题,所以他们也没有理由不能把它弄好。)
答案 1 :(得分:1)
这样一个简单的AppleScript代码片段没有直接的JXA翻译这一事实证明了基于OSA脚本编写的JXA和macOS自动化的遗憾状态:
foo's excellent answer包含有用的背景信息。
另一个指针是the last time release notes were published was for OS X 10.11 (El Capitan)(在撰写本文时,我们处于macOS 10的边缘。 13 (High Sierra' s)发布)。
This third-party July 2017 blog post更广泛宣布"这个问题最终在上个月的WWDC上得到了解答: Apple放弃了自动化技术,让它们枯萎死亡。 "
正如您自己的示例所示,在两种垂死的自动化脚本语言 AppleScript中 - 尽管存在各种瑕疵 - 是更成熟,更可靠的选择。
要解决您在JXA中遇到的问题,您自己可能会想出最好的方法。 让我把它打包成一个帮助函数,或许可以轻松地解决这个问题 - 要明确:这样的辅助函数不应该是必需的:
// Helper function: Given a Finder window, returns its folder's POSIX path.
// Note: No need for an ObjC.import() statement, because NSURL is
// a Foundation class, and all Foundation classes are implicitly
// available.
function posixPath(finderWin) {
return $.NSURL.alloc.initWithString(finderWin.target.url()).fileSystemRepresentation
}
// Get POSIX path of Finder's frontmost window:
posixPath(Application('Finder').finderWindows[0])
答案 2 :(得分:0)
@Kymer,你说:
但这似乎不必要地复杂。有没有更好的方式去 没有使用Cocoa API或手动字符串争论的POSIX路径?
你走在正确的轨道上。这是我所知道的最好的方法。如果有更好的,我也想了解它们。但是,这似乎运行得很快,适用于文件和文件夹。
var finderApp = Application("Finder");
var itemList = finderApp.selection();
var oItem = itemList[0];
var oItemPaths = getPathInfo(oItem);
/* --- oItemPaths Object Keys ---
oItemPaths.itemClass
oItemPaths.fullPath
oItemPaths.parentPath
oItemPaths.itemName
*/
console.log(JSON.stringify(oItemPaths, undefined, 4))
function getPathInfo(pFinderItem) {
var itemClass = pFinderItem.class(); // returns "folder" if item is a folder.
var itemURL = pFinderItem.url();
var fullPath = decodeURI(itemURL).slice(7);
//--- Remove Trailing "/", if any, to handle folder item ---
var pathElem = fullPath.replace(/\/$/,"").split('/')
var itemName = pathElem.pop();
var parentPath = pathElem.join('/');
return {
itemClass: itemClass,
fullPath: fullPath,
parentPath: parentPath,
itemName: itemName
};
}
答案 3 :(得分:0)
这是一个相当简单的示例函数,它只抓取窗口target
,然后从file://
中删除前导url
。
/*
pathToFrontWindow()
returns path to front Finder window
*/
function pathToFrontWindow() {
if ( finder.windows.length ) {
return decodeURI( finder.windows[0].target().url().slice(7) )
} else {
return ""
}
}
答案 4 :(得分:0)
(() => {
// getFinderDirectory :: () -> String
const getFinderDirectory = () =>
Application('Finder')
.insertionLocation()
.url()
.slice(7);
return getFinderDirectory();
})();