Change as a Way of Life: CC Extensions and the Third-Party InDesign Developer

by Olav Martin Kvern


Software development is a crazy business. Every time you feel you’ve mastered a programming language or framework, it’s declared obsolete, and you’ve got to crawl your way back up a learning curve to master something new. These changes are never under your control—they are handed down from on high, from Apple, Microsoft, Google, Adobe, or whichever corporate tail it is that wags your particular dog. They make a change, and we scramble to adapt. You know, as if our livelihoods depended on it, or something.

I’m not exactly complaining, mind you, because there’s nothing I enjoy more than learning something new. But there are days when I wish I’d taken up, say, shoeing horses. There is no “Horseshoes 2.0” on the horizon.

If you’d like to follow along, you can find the project at:

http://siliconpublishing.com/resources/oleextensions/com.spi.basicCommunication.zip

For the Better…?

In the old days, before, say, 2009, a developer who wanted to develop a plug-in panel for InDesign would have to learn to set up their development environment to use the InDesign C++ SDK, then write and debug the code. This process could take weeks or months. Making the panel work in Illustrator would require the same process—install and study the SDK, write and debug the code, and install the plug-in. Want to add a panel for Photoshop? Repeat the process.

When I was working at Adobe, I helped (in a minor way) build the Creative Suite Extension Builder. CS Extension Builder gave developers a way to create add-ons for Creative Suite applications using Flex and Actionscript, rather than writing plug-ins in C++. Actionscript could connect to the scripting object model of the host application, with Flex providing the user interface controls. All of this was wrapped up in a neat package that you could install in FlashBuilder.

With the CS Extension Builder, you could build a working panel in about thirty seconds. In my opinion, it was one of the best third-party development tools ever created—and a testament to the skill and creativity of my hard-working teammates.

Imagine my surprise when, last September, Adobe announced that they would be discontinuing the CS Extension Builder and would replace it with a new development framework based on HTML and JavaScript. Instead of building your user interface in Flex, running inside a Flash window, you’ll use HTML and CSS, running in an embedded version of Google’s Chrome browser. This makes up part of Adobe’s Common Extensibility Platform—the other part is what we used to call “CSXS.” I’ll refer to this collection of technologies as “CEP” from here on out.

Imagine my further surprise when I found that the new system was not even close to replacing CS Extension Builder. Key capabilities were missing. The documentation was thin, and very few example projects were available.

Not only that—we don’t have a choice. SPI’s CS Extensions for InDesign are literally going to stop working in the near future. This includes the Template Editor, a key part of the Silicon Designer workflow, and a very large hunk of code. Some of our other extensions, such as Silicon Connector for Box, will need to be rewritten.

I think, at this point, that most Creative Suite third party developers went through the classic phases of grief and loss: denial, anger, bargaining, depression, and acceptance.

Coping with Change

I’ve only gotten to the “acceptance” stage very recently, myself—and that’s due to two factors: Not only have I had more time to work with HTML extensions, but the Adobe team has made great strides on the capabilities of the framework and have added more documentation and examples. The team has also started communicating more frequently—a critical, if often overlooked, part of any third-party developer infrastructure. Communication is actually more important than development when you’re in this role.

There was nothing to do, therefore, but to get started. What did we need to do in order to move our CS Extensions to the new world? In CS Extension Builder, we could use Actionscript to call into the scripting object model of the application, and respond to application events directly. In a CC extension, HTML and JavaScript run the user interface, while most of the work inside the application takes place in ExtendScript.

Given this, we needed to know how to:

By writing examples, and by studying what others had written, I convinced myself that the new system could handle the first three points when working with InDesign. The last point, however, was almost a show-stopper—if you want to create a user interface that responds to changes in the InDesign document, you’ve got to be able to monitor key application events, such as Application.AFTER_SELECTION_CHANGED.

The CC extension framework supports a small number of common Adobe application events: documentAfterActivate, documentAfterDeactivate, documentAfterSave, applicationBeforeQuit, and applicationActivate. As you can probably guess from the event names, they’re of limited use in finding out what’s going on inside an InDesign document.

Then, literally last week as I write this, Adobe released an external library that makes the remaining point possible in InDesign.

A Very Simple Example InDesign Extension

First, you’ll need to set up your extension’s folder structure. David Deraedt has created extensions for Brackets and Sublime Text that will do this for you (see “Resources,” later in this post), but I’m not going to do that—though I do use Brackets for my extension development. I have a template that I like to use for simple HTML extensions, and I just make a duplicate of it whenever I want to create a new one. I have a different, more complex template that I use when I create a template that uses the Angular.js framework, but that’s a topic for a future post.

You’ll notice two things about the template, right away:

Apart from the above, everything else should be straightforward—JavaScript files go in the “js” folder; ExtendScript files go into the “jsx” folder, css files are found in the “css” folder, and so on. For both JavaScript and ExtendScript, libraries we’ll be working with go in the “libraries” folders found inside those folders. Our main HTML file is, as you’d expect, “index.html.”

Expanded view of the BasicCommunication CC extension project.

Expanded view of the BasicCommunication CC extension project.

A couple of notes about the above file structure:

This extension does a number of things:

First, take a look at the “.debug” file for the project. Note that we’re not going to go through the steps of packaging this extension as a ZXP—we’re going to run it in debug mode. To get that set up, you’ll need the Google Chrome browser (if you don’t’ have it already) and you’ll need to work through the steps in the Adobe Application Extension SDK (aka CC14_Extension_SDK.pdf—see the “Resources” section later in this post). Once the extension folder is in the right place (again, refer to the PDF for the location on your specific platform), it’ll appear on the Window>Extensions menu as soon as you restart InDesign.

In the .debug file, note the name of the extension package (whatever you named the folder when you copied the template) and the extension ID you want to use for debugging. These are the two bits of text you’ll need to change when you get to the point of making your own extension from this template.

When and if you create a new extension based on this template, you’ll need to change the two highlighted attributes.

When and if you create a new extension based on this template, you’ll need to change the two highlighted attributes.

Next, take a look at the manifest.xml file inside the “CSXS” folder. This is the file that tells CEP what the extension is and where to find its various parts. If you’re using this template, there are five text changes (three of one sort; two of another). They’re highlighted in the markup below.

When and if you create a new extension based on this template, you’ll need to change the highlighted attributes and one element.

When and if you create a new extension based on this template, you’ll need to change the highlighted attributes and one element.

Note the <MainPath> and <ScriptPath> elements—these tell CEP where to find the main HTML and ExtendScript files for your extension. You’ll need to change this if you decide to change the name of either or both of the files in the template.

From CEP’s point of view, that’s all you need to create a new extension. It should be obvious that the index.html file needs to contain references to your JavaScript file (I strongly advocate using an external file, rather than writing your JavaScript inside the HTML) and any libraries you need to load.

I’m not going to walk through the JavaScript and ExtendScript code in this extension. I think it’s reasonably well-commented, and should be pretty easy to understand. Note that, in some cases, I have intentionally resisted the urge to refactor the code for efficiency—my idea is to make it easier to follow. A production version of this script would probably remove a lot of duplicated code (I’d probably use a single function for setting up event listeners, for example).

I do want to call attention to the tag-team between JavaScript and ExtendScript in getting the PlugPlugExternalObject library set up. On the JavaScript side, I use CEP to determine which version of the library should be loaded (Mac OS or Windows; 32-bit or 64-bit), then pass the library file location to ExtendScript. Loading this library is critical, because it gives us a way to respond to InDesign’s application-specific events. To do this, we rely on the getOSInformation() method of the CSInterface object.

This section of code gets the OS the extension is running in and directs the ExtendScript to the correct version of the PlugPlugExternalObject library. Note that there is no 32-bit version of InDesign on the Mac OS.

This section of code gets the OS the extension is running in and directs the ExtendScript to the correct version of the PlugPlugExternalObject library. Note that there is no 32-bit version of InDesign on the Mac OS.

Put the extension folder in the correct folder on your system (again, refer to the Adobe PDF for where that is), then:

  1. Restart InDesign.
  2. Choose Window>Extensions>BasicCommunication to display the extension panel.
Playing around with the extension.

Playing around with the extension.

  1. Start Chrome and point it at the port we assigned in the .debug file (8107, unless you’ve changed it). After the page loads, and before you do anything else, check the Console tab to verify that your extension loaded without an error (you’ll see an error message here, in red, if something happened as InDesign tried to load the extension).
Chrome developer tools. At this breakpoint, we’re looking at the values returned from ExtendScript.

Chrome developer tools. At this breakpoint, we’re looking at the values returned from ExtendScript.

  1. Click the Sources tab. If necessary, locate and select your JavaScript file. Once the file is open in the Sources tab, you can place breakpoints in the JavaScript source where you’d like to observe variables or step through lines of code.
When you see this, it’s time to switch to Chrome and see what’s going on in the debugger.

When you see this, it’s time to switch to Chrome and see what’s going on in the debugger.

  1. Return to InDesign and play with the extension. When you hit a breakpoint, “Stopped in Debugger” will appear in your panel.

You don’t have to quit and restart InDesign every time you make a change to the source code of the extension. All you need to do is close and re-open the extension (restarting your Chrome debugging session, if necessary). This is actually a better debugging workflow than we had in the CS Extension builder.

Tips and Tricks

A few, entirely personal, thoughts and observations on CEP extensions (your mileage may vary):

An HTML page with links to extensions for debugging.

An HTML page with links to extensions for debugging.

Trips and Tics

Some relatively standard HTML techniques/features don’t work in CEP. Here are a couple I’ve found:

There may be others. To test, try opening your index.html (or whatever you’ve named your base HTML file) in Google Chrome. If something works there, but doesn’t work in your extension, you’ve identified a limitation of CEP.

Resources

Download the sample project discussed in this post here:

http://siliconpublishing.com/resources/oleextensions/com.spi.basicCommunication.zip

You can find the Adobe CEP resources and documentation here (Adobe links tend to change frequently, but these should be good for a bit after this piece is posted):

http://adobe-cep.github.io/CEP-Resources/

Go to the section “For developing CEP5 HTML/JavaScript extensions for CC2014 host applications”—this will get you to the documentation and the samples.

The PlugPlugExternalObject library is here (it’s also included in the sample project):

https://github.com/Adobe-CEP/CEP-Resources/releases/tag/1

I use Brackets as my source editor for everything other than ExtendScript. You can find more about it here:

http://brackets.io/?lang=en

Sublime Text is another editor, and it looks pretty great. I haven’t tried it yet:

http://www.sublimetext.com/

David Deraedt has built extensions for Brackets and Sublime Text:

https://github.com/davidderaedt/CC-Extension-Builder-for-Brackets

https://github.com/davidderaedt/CC-Extension-Builder-for-Sublime-Text

Davide Barranca has created some excellent posts on CC extensibility (they’re for Photoshop, but most of the information also applies to InDesign):

http://www.davidebarranca.com/category/code/html-panels/

 


8 Responses
  • Dan Rodney

    The alt text attribute was never meant to be visually displayed as a tooltip, despite some browsers (mainly IE) displaying it. Modern browsers no longer display it, but they do display the title attribute which is designed for a tooltip. So try adding a title attribute and it may work for a tooltip. Hope that helps.

    On another subject, I wish Adobe let us use HTML, CSS, JS to write script interfaces (dialogs) instead of having to write ScriptUI. Extensions can be overkill (sometimes) when a simple script can work. I’m not saying extensions aren’t useful (they are), just that I’d love to see some of this tech also shared with ExtendScript scripts so I can use them when they are appropriate.

  • Olav Martin Kvern

    Hi Dan,

    re: “So try adding a title attribute and it may work for a tooltip.”

    I thought I said that I tried that? Neither @altText nor @title work in CEP.

    re: ScriptUI

    I agree. For InDesign, at least, I tend to use the Dialog object for simple user interfaces, rather than ScriptUI. Unlike ScriptUI-based dialog boxes, the fields in dialogs created using this InDesign-specific dialog act like fields in InDesign itself–you’ve got measurement unit overrides, the ability to do arithmetic, etc. But, obviously, it doesn’t work for more complex user interfaces. Peter Kahrel has done some beautiful things with ScriptUI.

    Thanks,

    Ole

  • Justin Putney

    Thanks for posting, Ole!

  • Peter Kahrel

    Thanks, Ole, that’s very informative. I’ll have to pull my socks up and explore the new CC Extensions framework, and your outline will definitely be helpful.

    As to ScriptUI (thanks for your kind words!), I favour that over the Dialog object because the latter doesn’t have non-modal windows. But I agree that the different types of input field in the Dialog object are much better than in ScriptUI.

    Peter

  • Ariel

    Fantastic article. I’ve played around with brackets, and really liked it, but haven’t yet tried putting it all together yet to create an extension, beyond that iFrame example…

    Still, HTML and CSS is a little clumsy for UIs, no? Also, everybody’s extensions will now look completely different. I’m not sure that’s an advantage.

    (These days I always use ScriptUI, even for the simplest dialogues. When I used InDesign’s Dialog object, it happened too often that I would need to add some feature to a script that couldn’t be done with the Dialog object, and have to rebuild the entire thing in ScriptUI just to add some small feature. It’s much easier to start with ScriptUI initially, with an eye to the future!)

    Ariel

  • Romano Studer

    For a few days I have googled around for information on how to write InDesign plugins, extensions or what the correct name now should become.
    I finally found some great posts by Hallgrimur Bjornsson and I finally got a Hello World working. I also managed to install a stack of sample code but nothing explained how to connect it to the core work inside InDesign. Today, I finally came across your posting.
    Thank you so much! I installed your sample and got it running. Tomorrow I will see if I get the debugging in the browser working.

    I have written a fare bit of scripts but so far had no intension to go for the pain of C++

    Now I am inspired to go ahead with some ideas for extensions.

    Again thank you very much for sharing your stuff!

    Romano

Leave a Reply