3

The StandardAdditions.sdef indicates that particular data types can be retrieved from the clipboard using the key 'as'.

enter image description here

The clipboardInfo() function reveals what these keys are for Applescript, but is less eloquent in case of Yosemite JavaScript. (I haven't tried 10.11)

enter image description here

"text" and "string" seem to work, but none of the permutations which I have tried for public.html public.rtf «class HTML » «class RTF » rtf html etc. etc.

Has anyone found the keys that work here (assuming the presence of particular content types on the clipboard ?)

(In the meanwhile there are are, of course, some workable ObjC() alternatives for JXA:

ObjC.import('AppKit');

// Types: 'public.rtf', 'public.html' etc
function pboardUnpacked(strType) {
    return ObjC.unwrap(
        $.NSPasteboard.generalPasteboard.stringForType(
            strType
        )
    )
}

// Types: 'com.apple.webarchive' etc
function pboardPlist(strType) {
  return ObjC.deepUnwrap(
    $.NSPasteboard.generalPasteboard.propertyListForType(
      strType
    )
  )
}

but it would be good to have the briefer StandardAdditions idiom to hand as well ...

foo
  • 3,171
  • 17
  • 18
houthakker
  • 688
  • 5
  • 13
  • In terms of `data type` javascript (as well as html and xml) is just plain text. The AppleScript `class` specifier is not compatible with the UTI identifiers. `class` belongs to AppleScript’s object specifier classes. The JXA alternatives are probably the better choice. – vadian Aug 05 '15 at 13:27
  • 1
    Not quite sure that I follow your point about 'javascript' being plain text, but there is an additional level of complexity which perhaps I should have mentioned, which is that rtf and html are stored in the clipboard in hex-encoded formats, needing somthing like `perl -ne 'print chr foreach unpack(\"C*\", pack(\"H*\",substr($_,11,-3)))` to get at the text version. I would have expected the JXA names for these hex-packed contents to map simply on the «class HTML » «class RTF » «class weba» etc used by AS. – houthakker Aug 05 '15 at 17:16
  • 1
    JXA's AE support is crap; its inability to work with four-char codes is an example of that. Use the Cocoa APIs. If you're bothered by the length, JXA has crude library support, so put your `pboard...` functions into a separate `.scpt` file and save it in `~/Library/Script Libraries`. – foo Aug 05 '15 at 18:03
  • Thank you ! Your insights into AE are always helpful and constructive, which is certainly generous, considering how painful you have clearly found the failure to use all that excellent work which you put into Cocoa. I can't quite tell, though, if the aim of the four-letter words etc. is to discourage use of JXA, or to encourage its improvement ? Am I allowed to confess that I'm actually finding it very useful to be able to write in .js rather than AS ? Or that, to be honest, I haven't really encountered any significant obstacles to doing that ? Anyway, thanks again ! Rob. – houthakker Aug 05 '15 at 18:56
  • [Moved reply to answer as it was too long for comments] – foo Aug 06 '15 at 13:56
  • @houthakker: Your ObjC alternatives are great; wit the `pboardPlist()` function I've noticed that the return value is a nested JS object with a top-level `WebMainResource` property. However, the object that is its value has a `WebResourceData` property whose value is `{}`; i.e., the actual HTML source text seems to be missing; on a related note, I've been unable to do anything with the return value from `ObjC.deepUnwrap($.NSPasteboard.generalPasteboard.pasteboardItems)`; the `[object NSPasteboardItem]` instances returned seem to have no properties or methods. – mklement0 Oct 25 '15 at 05:43
  • Each browser varies in what it places in the clipboard - perhaps the nested object you describe is Safari webarchive ? I'm afraid that there is no shortcut, in reading properties from the NSPasteboardItem, to consulting the documentation of that object and using its particular ObjC methods, prefacing them with $. and adapting their names in the pattern described by the JXA release notes. – houthakker Nov 27 '15 at 16:11
  • @houthakker: Thanks; yes, I was referring to format `com.apple.webarchive`, Apple's webarchive format. After some more research I think the problem is that you should not blindly `.deepUnwrap()` such formats, because you won't be able to access (nested) properties whose values are opaque-to-JXA types such as `NSData` - once you've deep-unwrapped, access to these objects is lost. In the case at hand, you've lost access to `.WebMainResource.WebResourceData`, which contains the actual data (as opposed to the metadata in the other properties): in its _unwrapped_ form, it is unusable. – mklement0 Dec 03 '15 at 22:51
  • @houthakker I made the same blindly-deep-unwrap mistake when I tried `ObjC.deepUnwrap($.NSPasteboard.generalPasteboard.pasteboardItems)`, which yields an array of unwrapped-to-unusability `NSPasteboardItem` instances; instead, the `$.NSPasteboard.generalPasteboard.pasteboardItems` `NSArray` must be unwrapped to a _JS_ array first, yielding _unwrapped_ `NSPasteboardItem` instances, whose methods and properties you can access; e.g., to get the array of types supported by the first item, via `NSPasteboardItem`'s `types` property, use `$.NSPasteboard.generalPasteboard.pasteboardItems.js[0].types` – mklement0 Dec 03 '15 at 23:01
  • 1
    @mklement0 excellent work – I salute you. (I had quite given up on that :-) Many thanks. – houthakker Dec 03 '15 at 23:46

2 Answers2

4

Four-char codes (aka OSType, aka UInt32) were/are fundamental building blocks in Apple event and other classic Mac OS APIs, where extreme compactness and machine efficiency were far more important than developer convenience or readability. (Mind, System 7 had to run on 8MHz 68030 boxes with a couple MB RAM.) Most of those old APIs have long since been taken out and shot, or at least heavily abstracted over by more modern ones (e.g. the UTI APIs don't just provide native UTI string support but also encapsulate all the old MIME-type and 4CC crap as well).

The only time the old crap leaks out is when using equally ancient crusty APIs like clipboard info which is horribly painful and obsolete nowadays. The fact that some of the type names returned by it appear as raw 4CCs in AS's 'chevron' syntax («class weba», «class RTF », etc. vs string, Unicode text) merely reflects the absence of a corresponding keyword for that code in AppleScript's own built-in dictionary (which is limited to the keyword-code mappings manually defined by the AS developers). And even if you do retrieve textual clipboard data in one of those alternative formats, it's usually useless to you anyway since AS can't do anything with data of that type anyway, unless you can find another equally ancient API that can also understand it.

The UTI system is capable and mature, and has been widely supported since 10.6 or so, so there's no reason not to use it when available, and plenty reason to avoid the ancient, gnarly, crippled schemes they've long since superseded. Doing otherwise is just making a rod for your own back: that such APIs still exist in AS merely reflects the AS team's failure to deprecate/modernize/replace them in pace with the rest of Apple; it's not a recommendation to use them.

..

As to the problems with JXA and symbolic AE types in general...

That JXA is incapable of representing 4CCs at all is due to its authors being dilettantes with no real-world experience in application automation and who repeatedly fail to dogfood their own technologies (Scripting Bridge, JXA, etc) or take expert advice from those of us who do.

In fact, JXA can't represent type and enum names - Unicode text, document, yes/no/ask etc. (i.e. values of type type class and constant) - at all. since JS doesn't have a native Symbol type, its authors thought they'd be clever and just use String, and have the bridge decide whether to pack those strings as typeType/typeEnum instead of typeUnicodeText descriptors before sending them in an Apple event based on what type of values the command's dictionary definition says is required.

This works in trivial cases, e.g. close saving [yes|no|ask], where the dictionary definition contains all the information required to determine the actual type required, but unsurprisingly falls apart as soon as you start to deal with more complex use cases where the required type cannot be inferred from the dictionary, or where the dictionary is insufficiently complete or correct. Someone with a deep understanding of AE technology would already realize this: application dictionaries' AETE/SDEF formats were never intended to be complete, comprehensive, accurate Interface Description Languages; merely translation tables for mapping human-readable names (aka 'application keywords') to and/or from the corresponding low-level 4CCs, and everything else is just there as user documentation, with no guarantee of completeness or correctness; thus trying to use the latter to do anything else is about as reliable as you'd expect.

Funny enough, the 10.11 prelease notes for JXA indicate they've disabled this 'magical' conversion behavior by default (no doubt because it was biting users in lots of other exciting ways that its authors failed to anticipate). There's no indication in those notes that they've added a Symbol class to represent AE type and enum names correctly in JS, so it should be fun to see what else breaks next.

foo
  • 3,171
  • 17
  • 18
  • Kudos for an answer whose depth continues to reveal itself as I learn about the underlying technologies. If you're in the mood, perhaps you can shed a light on [this answer's](http://stackoverflow.com/a/34034704/45375) loose ends. – mklement0 Dec 04 '15 at 02:58
2

The correct answer, found by mklement0, (see comments at end of question) is that JXA uses Apple's Uniform Type Identifier strings to identify the types of text held in the clipboard.

For example:

(function() {

    ObjC.import('AppKit');

    return ObjC.deepUnwrap(
        $.NSPasteboard.generalPasteboard.pasteboardItems.js[0].types
    );

})(); 

// e.g. -->
    ["public.rtf", "public.utf8-plain-text", 
    "public.utf16-external-plain-text", "dyn.ah62d4rv4gk81n65yru",
    "com.apple.traditional-mac-plain-text", "dyn.ah62d4rv4gk81g7d3ru"]
houthakker
  • 688
  • 5
  • 13