Closed RobTrew closed 4 years ago
For the record, this kind of thing may be easier:
ObjC.import('AppKit');
// Types: 'public.rtf', 'public.html' etc
function pboardUnpacked(strType) {
return ObjC.unwrap(
$.NSPasteboard.generalPasteboard.stringForType(
strType
)
)
}
pboardUnpacked('public.rtf');
And for plist formats like the Safari clipboard web content:
ObjC.import('AppKit');
// Types: 'com.apple.webarchive' etc
function pboardPlist(strType) {
return ObjC.deepUnwrap(
$.NSPasteboard.generalPasteboard.propertyListForType(
strType
)
)
}
pboardPlist('com.apple.webarchive');
( .clipbboardInfo() returns an array of byte sizes for various types of clipboard data, but offers only undefined where one might expect to see the type class names.
On top of that, it takes 3 statements in JXA for 1 statement in AppleScript
Output from AppleScript
set lstCBInfo to clipboard info
(*
{{«class HTML», 1961}, {«class weba», 51332}, {«class rtfd», 1418},
{«class RTF », 1327}, {«class ut16», 304}, {uniform styles, 1080},
{string, 151}, {scrap styles, 182}, {«class utf8», 150},
{Unicode text, 302}, {uniform styles, 1080}, {scrap styles, 182}}
*)
Output from JXA:
var app = Application.currentApplication()
app.includeStandardAdditions = true
app.clipboardInfo()
/*
[[undefined, 1961], [undefined, 51332], [undefined, 1418],
[undefined, 1327], [undefined, 304], [undefined, 1080],
["string", 151], [undefined, 182], [undefined, 150],
[undefined, 302], [undefined, 1080], [undefined, 182]]
*/
Maybe it will get improved in the future. It is hard to say how that from AppleScript was supposed to be converted to JS other than string types. I prefer using the Objective-C bridge regardless most of the time. This is where JXA trumps AppleScript.
To see this at work, for example:
ObjC.import('AppKit');
// Types: 'public.rtf', 'public.html' etc
function pboardUnpacked(strType) {
return ObjC.unwrap(
$.NSPasteboard.generalPasteboard.stringForType(
strType
)
)
}
pboardUnpacked('public.rtf');
Copy some RTF, perhaps from an app like TextEdit, and then run the script in Script Editor:
The return value will be an upacked RTF string like:
"{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf130\n{\\fonttbl\\f0\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\pard\\tx566\\tx1133\\tx1700\\tx2267\\tx2834\\tx3401\\tx3968\\tx4535\\tx5102\\tx5669\\tx6236\\tx6803\\pardirnatural\\partightenfactor0\n\n\\f0\\fs24 \\cf0 It takes some courage to \n\\b shout\n\\b0 in the dark :-)}"
Not sure if the dramatic headline formatting was intentional :-) but all tools have their particular profiles, applicabilities, learning curves and levels of documentation.
JXA may be the tool you need at the moment, or may not be. It doesn't particularly strike me as 'dropping the ball' anywhere, and I find it very useful. JS certainly has a more flexible data model than Applescript, richer libraries, and a wider field of application, too.
@RobTrew, I was responding to your statement that the clipboard info returned by JXA is nearly useless, as compared with the full info provided by AppleScript:
.clipbboardInfo() returns an array of byte sizes for various types of clipboard data, but offers only undefined where one might expect to see the type class names.
So the bottom line is that with JXA we must resort to using ObjC to unpack the clipboard. Is there a reference that provides the clipboard class types like "public.rtf" that is needed for ObjC? I searched and couldn't find one.
I think Apple calls those "Uniform Type Identifiers"
Great. So how do we get a list of the class types available on the current clipboard?
IOW, since the JXA app.clipboardInfo()
doesn't work, what do we use instead? Is there on ObjC equivalent that works?
I'm afraid you'll just have to jump in and find your away around:
The JXA release notes are worth rereading on how you translate an NS object name to the format expected by the JavaScript bridge.
More simply, of course, you could loop/map through the UTI identifiers that interest you, testing whether pboardUnpacked() (above) yields any content for each of them.
you could loop/map through the UTI identifiers that interest you
The problem, of course, is learning the actual name of the UTI identifiers. You can't search for something you don't know the name of. :wink: Even though there is a big list in the UTI document, as you have posted elsewhere, all apps don't use them the same.
Surely there is a way to loop through each class type on the clipboard using ObjC, listing the class name and size (what the app.clipboardinfo()
was supposed to do. Any clues on how to do this?
A solution – thanks to mklement0
(function() {
ObjC.import('AppKit');
return ObjC.deepUnwrap(
$.NSPasteboard.generalPasteboard.pasteboardItems.js[0].types
);
})();
--> (for example)
["public.rtf", "public.utf8-plain-text", "public.utf16-external-plain-text",
"dyn.ah62d4rv4gk81n65yru", "com.apple.traditional-mac-plain-text",
"dyn.ah62d4rv4gk81g7d3ru"]
My thanks to Rob for following through on this quest, and providing us with the basic code to get the clipboard/pasteboard types in JavaScript.
I took Rob's code and dressed it up a bit, and put into a function you can put into your script library.
I've also included a log()
function that I find helpful in easily generating output to the console.
getClipboardTypes()
// --- Example Usage of getClipboardTypes() Function ---
var arrCBTypes = getClipboardTypes()
log("arrCBTypes")
//–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
function getClipboardTypes() { // Get array of Pasteboard Types for JS
//–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
/*
PURPOSE:
• Return an array of Clipboard (AKA Pasteboard) types
available on current Clipboard
Based directly on code from Rob Trew (@ComplexPoint)
JXA-Cookbook: https://github.com/dtinth/JXA-Cookbook/issues/12#issuecomment-162172909
FOR MORE DISCUSSION, SEE:
• [Stackoverflow: What clipboard type class strings does OS X JavaScript for Applications recognise?]
(http://stackoverflow.com/questions/31833291/what-clipboard-type-class-strings-does-os-x-javascript-for-applications-recognis)
• [JXA-Cookbook: Clipboard typeClasses]
(https://github.com/dtinth/JXA-Cookbook/issues/12)
*/
'use strict';
ObjC.import('AppKit');
return ObjC.deepUnwrap($.NSPasteboard.generalPasteboard.pasteboardItems.js[0].types);
} // ===================== END function getClipboardTypes() =====================
//–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
function log(psVarName) { // Log variable info & contents to Console for debug
//–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
/* Parameters:
• psVarName string Name of the Variable to log
Purpose:
• Provide one function to make it easy to log all types of variables, name and
value, to the Console in a readable format.
• Array elements are logged in a list
Ver: 2.0 Fri, Dec 4, 2015
Author:
• JMichaelTX (in GitHub, and MacScripters and Keyboard Maestro forums)
• PM me in either if you find issues or have suggestions for improvement
Programmer's Note:
• Normally I avoid using the eval() function
• But this is a simple exception, where there is no other way to
call the function with one parameter, and log both the name and
the value of the variable.
• IMO, the risk of using eval() in this case is very low.
--------------------------------------------------------------------------------
*/
// --- GET THE VARIABLE TYPE ---
var strType = eval("typeof(" + psVarName + ")")
// --- CHECK FOR UNDEFINED VARIABLE ---
if (strType === "undefined") {
console.log("*** ERROR *** Variable is UNDEFINED: " + psVarName)
//-------------
return "ERROR"
//-------------
} // *** END if undefined ***
if (strType === "object") {
if ( eval("Array.isArray(" + psVarName + ")") ) {
strType = "array"
} else {
strType = "other"
}
}
strType = strType.toUpperCase()
// --- SET OUPUT BASED ON VARIABLE TYPE ---
switch (strType) {
case "ARRAY":
var strLog = "console.log('ARRAY: " + psVarName + " Len: ' + " + psVarName + ".length)"
break;
case "STRING":
var strLog = "console.log('" + strType + ": " + psVarName + " Len: ' + " + psVarName + ".length + ' Value: \"' + " + psVarName + " + '\"')"
break;
default: // All other types, including "number"
var strLog = "console.log('" + strType + ": " + psVarName + " Value: ' + " + psVarName + ")"
break;
} // *** END switch (strType) ***
//--- OUTPUT TO CONSOLE ---
eval(strLog)
// --- IF ARRAY, OUTPUT ARRAY ELEMENTS ---
if (strType === "ARRAY") {
var lenArr = eval(psVarName + ".length")
for (i=0; i<lenArr; i++) {
strLog = "console.log('[' + i + ']: ' + " + psVarName + "[i])"
eval(strLog)
}
} // *** END if ARRAY ***
return "DONE"
} // ========================== END function log() ==============================
/* ARRAY: arrCBTypes Len: 7 */
/* [0]: public.rtf */
/* [1]: public.utf8-plain-text */
/* [2]: public.utf16-external-plain-text */
/* [3]: dyn.ah62d4rv4gk81n65yru */
/* [4]: com.apple.traditional-mac-plain-text */
/* [5]: dyn.ah62d4rv4gk81g7d3ru */
/* [6]: org.nspasteboard.TransientType */
Closing due to age.
In Applescript we can evaluate
and get an object with keys to any RTF, HTML utf8 etc data
The Javascript view of the StandardAdditions.sdef documentation suggests something similar, but doesn't (I think) define the set of accepted
type class
arguments.It might be good, if anyone can unlock JXA access to HTML and RTF clipboard contents, to have a clipboard section of this Wiki …
(
.clipbboardInfo()
returns an array of byte sizes for various types of clipboard data, but offers onlyundefined
where one might expect to see the type class names. Perhaps ObjC access to NSPasteBoard is the route to take … )