CEP Panels and JSON Objects
Update 4/10/2018: Our CEP Getting Started resources are now on GitHub! See the repo for the latest info.
This article is part two of Scripting CC Apps Using CEP Panels, by guest developer Davide Barranca, a Photoshop retoucher based in Italy.
This series of posts is aimed at beginning developers who have built a panel, or are just starting to build a panel, and would like to understand how CEP communicates with CC host applications like Photoshop, InDesign, and so forth. (If you’ve never built a panel, check out our first post: “How to create your first Adobe panel in 6 easy steps”)
— Erin Finnegan, Community Engineer, Adobe
In this post we will learn how to pass JSON string objects to the host application from our panel. Let’s assume your web sharpening routine from part one of our series has been updated and uses several parameters: the panel has grown, and features a multitude of sliders, checkboxes and buttons. It would be awkward to list them all, like:
https://gist.github.com/undavide/505fa755d2b40b75743466c914cb73f2
It’s string interpolation madness. It’s much better to provide an object parameter: in order to let the JSX engine to properly digest your code, remember to transform it into a JSON string first!
https://gist.github.com/undavide/2e4f66eae6e85596479207d49ef541bc
Without a doubt, this is nicer. Please note that even if the parameter is passed from the JS as a JSON string, the JSX side receives it as an actual object.
Communicating from the host application to the panel
The Communication flow is bidirectional, so the Adobe application can tell things to the panel too. In order for the panel to listen to what e.g. Photoshop has to say, you need to include a callback in the csInterface.evalScript() function:
https://gist.github.com/undavide/829737b204900e44958e4e2e6b85a1d8
In the snippets above, the callback function we’ve added will receive "true" back from Photoshop (mind you, "true" as a string, not an actual true boolean). Why might we want this? Well, it could be that the panel needs to know whether the addSharpeningForWeb() function has been doing its job successfully or not. In case of errors thrown on the JSX side, the returned value is always the "EvalScript error." string.
If you’re familiar with Promises, instead of callbacks, please refer to Steve’s post about ES6 promises.
In more sophisticated panels (this is just an example), the aspect of the panel itself may be dependent on the document currently open in Photoshop. Say, for instance, that the panel needs to somehow display layer names, and current foreground/background colors in the panel GUI. You may need to extract structured data from the host application. You know how to do this via scripting, but how can you pass this data, e.g. as an object from Photoshop to the panel?
The trick is to convert the object to a JSON string first (in the JSX), and then JSON.parse() it back (in the panel's JS).
https://gist.github.com/undavide/258a87a0359a3f9c9eb00f265a2df5e5
Pay attention, though, because the ExtendScript engine has no way to know about JSON: it's not natively featured in the language specifications from 2009, so you have to include extra code to implement JSON.stringify() and JSON.parse() otherwise an error will be thrown when you use them in the JSX.
Usually, developers borrow code from Douglas Crockford’s json2.js, directly injecting it in their JSX; for better compatibility with the ExtendScript language itself, you can also use the code in json.jsx, written by the InDesign developer Marc Autret instead. Please note that instead of stringify() and parse() he's implemented functions named eval() and lave().
Wrap up
In this post you’ve seen how two different and fundamental parts of CEP panels (the panel’s JS engine, and the host application’s JSXengine) can communicate. On one side, the panel's JS can send ExtendScript strings to the host application by means of the evalScript() function. On the other side, the host application can send strings back to the panel that the evalScript() second parameter callback is able to receive.
If you need to pass complex parameters such as objects from your panel’s JS to the host app's JSX, JSON.stringify() them first (no need to JSON.parse() them in the JSX – they arrive as objects). If you need to pass an object the other way around (from the host application JSX to the panel JS), you need to JSON.stringify() it in the JSX first, and JSON.parse() it in the JS. There's no native support of JSON in ExtendScript, so you need either json2.js or json.jsx.
What’s next?
Another form of communication between CEP Panels and host applications is based on events, but before tackling such topic you should feel comfortable with JSON objects. Try implementing this technique on a simple panel, head over my HTML Panels Tips, and follow the Adobe I/O blog for more insights!
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Davide Barranca is the author of several books about Photoshop development. He blogs about panels and script development on his homepage, davidebarranca.com.
For more stories like this, subscribe to our Creative Cloud Developer Newsletter.