This cookbook is a guide to creating CEP 8.0 HTML/JavaScript Extensions for Creative Cloud applications. CSXS is the old name before CS6, and CEP (Common Extensibility Platform) is new name from CS6. When we talk about CEP or CSXS, they refer to the same project.
CEP Extensions
CEP (formerly CSXS) Extensions extend the functionality of the Adobe point products in which they run. Extensions are loaded into applications through the PlugPlug Library architecture. Starting from CEP 4.0, HTML/CSS and JavaScript (ECMAScript 5) can be used to develop extensions.
Extension Types
These extension types are supported by CEP. You need to specify an extension's type in its manifest.xml.
Panel
The Panel type behaves like any other application panel. It can be docked, participates in workspaces, has fly-out menus, and is re-opened at start-up if open at shutdown.
ModalDialog
A Modal Dialog type opens a new extension window and forces the user to interact only with the extenison window before returning control to the host application. User can interact with host application only after closing extension window.
Modeless
A Modeless Dialog type opens a new extension window but doesn't force the user to interact with the extension window.
Custom (Since CEP 5.0)
This type is for invisible extensions. An invisible extension remains hidden and never becomes visible during its whole life cycle. Read "Invisible HTML Extensions" for more details.
Applications Integrated with CEP
These applications support CEP HTML extensions.
Application
Host ID
CC Version
CC 2014 Version
CC 2015 Version
CC 2015 Dot Version
CC 2017 Version
CC 2018 Version
Photoshop
PHSP/PHXS
14 (CEP 4)
15 (CEP 5)
16 (CEP 6)
17.0.2 (CEP 7)
18 (CEP 7)
19 (CEP 8)
InDesign
IDSN
9 (CEP 4)
10 (CEP 5)
11 (CEP 6)
-
12 (CEP 7)
13 (CEP 8)
InCopy
AICY
9 (CEP 4)
10 (CEP 5)
11 (CEP 6)
-
12 (CEP 7)
13 (CEP 8)
Illustrator
ILST
17 (CEP 4)
18 (CEP 5)
19 (CEP 6)
20 (CEP 7)
21 (CEP 7)
22 (CEP 8)
Premiere Pro
PPRO
7 (CEP 4)
8
9
10.3 (CEP 6)
11 (CEP 6)
12 (CEP 8)
Prelude
PRLD
2 (CEP 4)
3
4
5.0.1 (CEP 6)
6 (CEP 7)
7 (CEP 8)
After Effects
AEFT
12
13
13.5
13.8.1 (CEP 6)
14 (CEP 6)
15 (CEP 8)
Animate (Flash Pro)
FLPR
13
14 (CEP 5)
15 (CEP 6)
15.2 (CEP 6.1)
16 (CEP 6.1)
18 (CEP 8)
Audition
AUDT
6
7
8
9.2.1 (CEP 6)
10 (CEP 6)
11
Dreamweaver
DRWV
13 (CEP 4)
15 (CEP 5)
16 (CEP 6)
-
17 (CEP 6.1)
18 (CEP 8)
Muse
MUSE
7.4
-
2015
-
2017
2018
Bridge
KBRG
6
-
6.3.1
-
-
8 (CEP 8)
Chromium Embedded Framework (CEF)
CEP HTML engine is based on Chromium Embedded Framework version 3 (CEF3). You can find more information about CEF here. Here are the versions used in CEP:
Each persistent cookie is a file. File name is HostID_HostVersion_ExtensionName, such as PHXS_15.0.0_com.adobe.extension1.
Development and Debugging
Guide for migrating from CEP 7 to CEP 8
Changes for Extensions Developers**
Please be aware that, we are moving to chromium version 57.0.2987.74 from 41.0.2272.104. Similarly for nodejs, we are moving to 7.7.4 from iojs 1.2.0. This migration guide is written based on CEP team's testing and if you find any new issues, please document or share with CEP team.
Chromium
Following Chromium APIs have been removed:
MediaStream.label, MediaStream.ended and MediaStream.stop()
Remove getUserMedia() from Insecure Contexts
SVG hasExtension() methods
SVGSVGElement.pixelUnitToMillimeterX and friends
Fetch API: Deprecate and remove Request.context
Document.charset setter
NPAPI plug-in support Range.compareNode() and Range.expand()
WebAudio: Disallow setting AudioBufferSourceNode.buffer more than once
Deprecate and remove SVGViewElement.viewTarget attribute
Deprecate SVGSVGElement.viewport attribute
Remove FileError interface
Deprecate and remove: WebKit legacy window.postMessage() overload
Deprecate and remove: 'results' attribute for
NodeJS
Below listed changes are applicable when --enable-nodejs is passed as CEFCommandline parameter.
New Symbols in the global context
CEP 8 introduces additional symbol: cep_node in the global context when nodejs is enabled. cep_node will hold following node specific symbols:
cep_node members Buffer, global, process and require
Accessing nodejs APIs in iframe
nodejs symbols will not be available in iframe's global context, only way you can access nodejs APIs within iframe's context is through cep_node. When --mixed-context is enabled, global node symbols and cep_node is available within iframe's global context as browser and node gets executed at the same context. It is also important to note that, if you have existing code to check or use nodejs symbols in iframe's global context, it used to work till last release and in the current release, it breaks in separate context mode.
JS Lib Break due to node symbols (possible for many other libraries)
Newly integrated nodejs adds "module" and "exports" symbols to the global context. Many libraries such as JQuery relies on its booting based on the availability of "module" symbol in the global scope. For ex, JQuery has following code while booting:
JQuery startup code
if(typeofmodule==="object"&&typeofmodule.exports==="object"){// set jQuery in `module`}else{// set jQuery in `window`}
When this code is executed in CEP's browser with nodejs enabled, it will make JQuery to load in module context instead of Browser context. This would cause issues to extension's startup. Please use below code to handle such scenarios:
global symbols handling
<!-- Insert this line above script imports --><script>if(typeofmodule==='object'){window.module=module;module=undefined;}</script><script>if(typeofexports==='object'){window.exports=exports;exports=undefined;}</script><!-- extension's imports --><scriptsrc="scripts/jquery.min.js"></script><scriptsrc="scripts/csinterface.js"></script><!-- Insert this line after script imports --><script>if(window.module)module=window.module;</script><script>if(window.exports)exports=window.exports;</script>
If you are not using "module" and "exports" in the extension, you could skip last 2 lines of above code. This logic is similar to how users handled nodejs's require while importing. If you are handling require already, you should continue to handle same way.
require path is absolute instead of relative
Nodejs 7.7.4 requires path to be included as absolute path. So, if you have nodejs require for the js file,replace the path to absolute instead of relative. For eg. replace:
CEP will have multiple contexts defined at the start. Following are the default contexts:
Browser Context
This is the default JS context associated with CEP's browser engine. Apart from Browser objects, CEP's file system APIs are accessed in this context.
Native Context
This is extended context through "cep" object to provide file system access via CSInterface.js.
Node Context (When nodejs is enabled through --enable-nodejs command line switch)
1. Separate Context
2. Mixed Context
Host app context
This is the context which would be accessed through evalscript API.
Separate Context Mode
This context will be created with following command line switch: --enable-nodejs (and --mixed-context is not passed). When CEP is starting with this context, it would have following symbols:
cep_node: This is treated as global symbol available across frames and helps to access node symbols. Any modification to this symbol will be reflected at all the frame context. This symbols is introduced from CEP 8.
node globals: https://nodejs.org/api/globals.html could be accessed only in main frame (which is current document). If there is a new frame created in the current document, these symbols will not be available in frame's context. Please note that, this behavior is different CEP 7 for frames. In CEP 7, node globals are available for access in all frames.
Following representation provides visual context:
Separate Context
<html><head><!-- cep_node and node globals are available in this context --></head><body><!-- cep_node and node globals are available in this context --><iframename="iframe_1"><!-- only cep_node is available and node globals are not available within this iframe --></iframe><iframename="iframe_2"><!-- only cep_node is available and node globals are not available within this iframe --><!-- In the following line cep_node is modified and this change will be available for any frame's which is loading later than iframe_2 -->
cep_node.process.myVar = "Hello";
</iframe><iframename="iframe_3"><!-- cep_node is available with change: cep_node.process.myVar(iframe's loading order is important as change should be accessed after the modifications) and node globals are not available --></iframe></body></html>
Mixed Context Mode
This context will be created with following command line switch: --enable-nodejs and --mixed-context. When CEP is starting with this context, it would have following symbols:
cep_node: This is treated as local symbol available within each frames and helps to access node symbols. Any modification to this symbol will not be reflected to other frames. This symbols is introduced from CEP 8.
<html><head><!-- cep_node and node globals are available in this context --></head><body><!-- cep_node and node globals are available in this context --><iframename="iframe_1"><!-- only cep_node is available and node globals are available within this iframe --></iframe><iframename="iframe_2"><!-- only cep_node is available and node globals are available within this iframe --><!-- In the following line cep_node is modified and this change will not be available for any other frames -->
cep_node.process.myVar = "Hello";
</iframe><iframename="iframe_3"><!-- cep_node is available which is unique to this context and it's built from start up time. So, it will not have the changes from previous iframe. node globals are available --></iframe></body></html>
Development Machine Setup
CEP HTML Extensions can be developed on both Windows and Mac platforms. The development machine needs to have the following applications in order to successfully develop CSXS extensions:
Adobe Creative Cloud applications supporting CEP HTML extensions.
HTML Extension Builder (Nice to have, but not mandatory).
Adobe ExtendScript Tool Kit (This is available as an optional install).
Chrome browser for debug workflow.
HTML Extension Builder
HTML Extension Builder is a tool set built on top of Eclipse and can be used for developing and debugging HTML extensions. Please download the Extension Builder 3 from here.
Signing extensions
Before you sign the extensions, you need to get or create the certificate file. Configurator and Adobe Exchange Packer can create certificates. Developers can get all information here after logging in.
CC Extensions Signing Toolkit (also on above labs web site)
Example of using CC Extension signing toolkit: ccextensionswin64.exe -sign "d:\Adobe Layer Namer\Adobe Layer Namer"(input extension path) d:\AdobeLayerNamer.zxp (output zxp path) d:\sign.p12 (certificate path) 1 (certificate password) Adobe Exchange Packer (please sign in so that you can see it.)
If you are in the midst of development and are not using HTML Extension Builder for debug workflows and want to bypass the need to sign your extensions, you can bypass the check for extension signatures by editing the CSXS preference properties file, located at:
Win: regedit > HKEY_CURRENT_USER/Software/Adobe/CSXS.8, then add a new entry PlayerDebugMode of type "string" with the value of "1".
Mac: In the terminal, type: defaults write com.adobe.CSXS.8 PlayerDebugMode 1 (The plist is also located at /Users/<username>/Library/Preferences/com.adobe.CSXS.8.plist)
These entries will enable debug extensions to be displayed in the host applications. Please note that, CSXS.8 is given with the assumption that, you are developing the extension for CEP 8. If you are developing extension for previous version of CEP, replace 8 with corresponding version number.
Special notes for Mac 10.9 and higher
Staring with Mac 10.9, Apple introduced a caching mechanism for plist files. Your modifications to plist files does not take effect until the cache gets updated (on a periodic basis, you cannot know exactly when the update will happen). To make sure your modifications take effect, there are two methods.
Kill cfprefsd process. It will restart automatically. Then the update takes effect.
Restart your Mac, or log out the current user and re-log in.
CEP supports remote debugging for HTML extensions from 5.0.
Create a “.debug” file to the extension root directory such as Test_Extension\.debug. The .debug file contains remote debug ports. Developers must create this file and use valid debug ports because both remote debugging and dev tools are based on it.
".debug" file name is special for both Windows and Mac platforms, it has to be created via command line.
On Windows, use "copy con .debug" and "Ctrl+Z" to create an empty file.
On Mac, use "touch .debug" to create an empty file.
The value of Port should be between 1024 and 65535 (not include 65535), otherwise remote debugging and dev tools will not work.
One extension bundle may have multiple extensions. The .debug file can specify debug ports for each extension. Here is an example file:
If you load an extension whose debug port is 8088, you can load the debugger through http://localhost:8088/ on Chrome.
Where are the Log Files
PlugPlug Logs
Log files with useful debugging information are created for each of the applications supporting CEP extensions. The platform-specific locations for the log files are as follows:
Win: C:\Users\<USERNAME>\AppData\Local\Temp
Mac: /Users/<USERNAME>/Library/Logs/CSXS
These files are generated with the following naming conventions:
CEP 4.0 - 6.0 releases: csxs<versionNumber>-<HostID>.log. For example, PlugPlug in Illustrator generates log file csxs8-ILST.log.
CEP 6.1 and later releases: CEP<versionNumber>-<HostID>.log. For example, PlugPlug in Illustrator generates log file CEP8-ILST.log.
Logging levels can be modified as per the following levels:
0 - Off (No logs are generated)
1 - Error (the default logging value)
2 - Warn
3 - Info
4 - Debug
5 - Trace
6 - All
The LogLevel key can be updated at the following location (The application should be restarted for the log level changes to take effect):
In CEP 6.1 and later releases, CEPHtmlEngine generates logs. Each CEPHtmlEngine instance usually generate two log files, one for browser process, the other for renderer process. These files are generated with the following naming conventions:
In CEP 6.1 and later releases, this log is merged into CEPHtmlEngine log.
Extension Folders
CEP supports 3 types of extension folders.
Product extension folder. Here is a suggestion, but each point product can decide where this folder should be. Third party extension can't be installed at this location.
${PP}/CEP/extensions (PPs may use different folder.)
The manifest.xml file is required for every extension and provides the necessary information to configure a CEP extension. ExtensionManifest is the root element of the manifest.xml file. Extensions, ExtensionList, and DispatchList are the three child elements of the ExtensionManifest root element.
This will support Photoshop version 15.0 up to, and including, 15.9. If you use the following syntax then you are supporting releases up to 15.9 but not including 15.9
CEP 7.0 manifest files now support the use of a HostList specific to an extension in the bundle. For example, the following qualifies as the "default" HostList:
HostLists specified under extension tags will override the default HostList specified under the execution environment tag. It is important to note that adding HostList nodes with no child nodes is akin to turning that particular extension off for all host applications; this behavior is intentional. Please refrain from specifying both HostList tags and Host attributes in DispatchInfo tags for each extension; choose one or the other. Specifying both will more than likely result in unexpected behavior. The Host attribute is only maintained for backward compatibility. New extensions should use HostList tags, not the Host attribute.
Extension Size
You can specify extension size, max size and min size in extension manifest. Size is mandatory; max size and min size are optional.
A modal or modeless dialog is resizable if there are different max and min size, otherwise it is un-resizable. When you move mouse pointer over dialog border, CEP shows different cursor for resizable and un-resizable dialogs.
You can customize the extension menu by editing <menu/> item in manifest. Here is an example. In this example, the Adobe Add-ons extension is displayed under Windows main menu, rather than extensions menu under Windows. You can customize the location of extension to somewhere else by changing the value of attribute Placement in <menu/> item.
CEP 5.2 supports shortcut keys for HTML extensions. When focus is on HTML extensions, these shortcut keys are handled by extension.
Windows Keys
Mac Keys
Function
Ctrl + A
Command + A
Select All
Ctrl + C
Command + C
Copy
Ctrl + V
Command + V
Paste
Ctrl + X
Command + X
Cut
Other shortcut keys are handled by point products, such as pressing Ctrl + N to create a new document.
CEP JavaScript Programming
CEP JavaScript Libraries
CEP JavaScript Libraries are counterparts of the Flex CSXS Library and the CEP IMS Library. They provide JavaScript APIs to access application and CEP information.
To use them, please include these JavaScript files in your HTML extension.
API version
The CEP JavaScript APIs keep changing in each new CEP release. The changes are guaranteed to be backward compatible. For newly added APIs, a version tag like "Since x.x.x" is added to its API comments indicating since which CEP version the APIs is available.
You will need to check the version tag against the version of CEP integrated by the Adobe Product you are using to make sure the API you want to use is available. To do so, use CSInterface.getCurrentApiVersion() to retrieve the version of CEP integrated by the Adobe Product. Please note this API itself is available only since 4.2.0. If you get an error saying getCurrentApiVersion is undefined, then you are running in CEP 4.0 or 4.1. Otherwise, the value returned will tell you the version of CEP integrated by the Adobe product.
CEP Events
CEP supports sending and receiving events within an extension, among extensions in an application, and among extensions in different applications. Since all extensions are based on the common communication layer with the same event data format, they can communicate with each other through CEP events, and even they can communicate with native side as long as point products invoke PlugPlugAddEventListener/PlugPlugDispatchEvent accordingly.
There are dispatchEvent/addEventListener/removeEventListener APIs available in JavaScript to dispatch and listen for events. Let's go through CEP event data format/structure, APIs to dispatch and listen event, and sample code snippet accordingly in JavaScript.
CSEvent
In terms of CSEvent, it just means CEP Event here. The data structure of CSEvent (CEP Event) is as below.
/** * Class CSEvent. * You can use it to dispatch a standard CEP event. * * @param type Event type. * @param scope The scope of event, can be "GLOBAL" or "APPLICATION". * @param appId The unique identifier of the application that generated the event. Optional. * @param extensionId The unique identifier of the extension that generated the event. Optional. * * @return CSEvent object */functionCSEvent(type,scope,appId,extensionId){this.type=type;this.scope=scope;this.appId=appId;this.extensionId=extensionId;};
You could create a CSEvent object and dispatch it by using CSInterface.dispatchEvent. Also you could access its property in your callback of CSInterface.addEventListener. Refer to the section addEventListener/dispatchEvent below for more details.
Listen for and Dispatch CSEvent
dispatchEvent/addEventListener/removeEventListener APIs are available in JavaScript world to dispatch and listen for CSEvent.
addEventListener
Here is the definition for addEventListener. Refer to CSInterface.js for more information:
/** * Registers an interest in a CEP event of a particular type, and * assigns an event handler. * The event infrastructure notifies your extension when events of this type occur, * passing the event object to the registered handler function. * * @param type The name of the event type of interest. * @param listener The JavaScript handler function or method. * @param obj Optional, the object containing the handler method, if any. * Default is null. */CSInterface.prototype.addEventListener=function(type,listener,obj)
One thing needs to be mentioned here is both named and anonymous callback functions are supported in CSInterface.addEventListener.
An example of how to use named callback function in CSInterface.addEventListener.
varcsInterface=newCSInterface(); csInterface.addEventListener(“com.adobe.cep.test”,callback);//invoke the function
An example of how to use anonymous callback function in CSInterface.addEventListener.
varcsInterface=newCSInterface();csInterface.addEventListener(“com.adobe.cep.test”,function(event){console.log(“type=”+event.type+“,data=”+event.data);});// Anonymous function is the second parameter
The event.data can be an object (i.e. you could use an object as event.data).
Before CEP 6.1, we regarded every attribute in event.data object as a regular string, but from CEP 6.1, we revised the behavior that keep the type of each attribute in event.data as it was. If the value is a valid JSON string, CEP will parse it natively and convert it to an object. Here is an example on how to use it.
varcsInterface=newCSInterface();csInterface.addEventListener(“com.adobe.cep.test”,function(event){varobj=event.data;console.log(“type=”+event.type+“,data.property1=”+obj.property1+“,data.property2=”+obj.property2);});// Anonymous function is the second parameter
dispatchEvent
Here is the definition for CSInterface.dispatchEvent. Refer to CSInterface.js for more details.
/** * Triggers a CEP event programmatically. Yoy can use it to dispatch * an event of a predefined type, or of a type you have defined. * * @param event A \c CSEvent object. */CSInterface.prototype.dispatchEvent=function(event)
Here are three samples to demonstrate how to dispatch an event in JavaScript.
An example of how to dispatch event in JavaScript.
varcsInterface=newCSInterface();varevent=newCSEvent("com.adobe.cep.test","APPLICATION");event.data="This is a test!";cSInterface.dispatchEvent(event);
Another example of creating event object and setting property, then dispatch it.
varcsInterface=newCSInterface();varevent=newCSEvent();event.type="com.adobe.cep.test";event.scope="APPLICATION";event.data="This is a test!";cSInterface.dispatchEvent(event);
An example of dispatching an event whose data is an object.
Communication between Native Point Product and CEP extensions
CEP event based communication between native point product and CEP extensions is simple. You can use PlugPlugAddEventListener/PlugPlugDispatchEvent to communicate with CEP extensions.
Please refer the following steps:
First, define a callback function in CEP extension:
functioncallback(event){// do something here}
Then call CSInterface.addEventListener with event type you want to listen and the callback function:
Following table lists the standard events supported by point products.
Event Type
Event Scope
Description
Event Parameter
PS
ID
AI
AN
PR
PL
AU
documentAfterActivate
APPLICATION
Event fired when a document has been activated(after new/open document; after document has retrieved focus).
URL to the active document. If the doc was not save, the NAME will be set instead of the URL.
documentAfterDeactivate
APPLICATION
Event fired when the active document has been de-activated.(after document loses focus)
URL to the active document. If the doc was not save, the name will be set instead of the URL.
applicationBeforeQuit
APPLICATION
Event fired when the application got the signal to start to terminate.
none
applicationActivate
APPLICATION
Event fired when the Application got an "activation" event from the OS.
none
on Mac; on Windows
on Mac; on Windows
documentAfterSave
APPLICATION
Event fired after the document has been saved
URL to the saved document.
( = supported, = not supported)
Note: CEP is unloaded from the point products ID and AI right after the event applicationBeforeQuit is emitted from the point products, therefore CEP may have no chance to get this event handled in HTML extensions.
Specific Events in Products
Photoshop
In Photoshop, the following specific events are defined:
com.adobe.PhotoshopPersistent
com.adobe.PhotoshopUnPersistent
com.adobe.PhotoshopWorkspaceSet
com.adobe.PhotoshopWorkspaceGet
com.adobe.PhotoshopWorkspaceAware
com.adobe.PhotoshopWorkspaceData
com.adobe.PhotoshopWorkspaceRequest
com.adobe.PhotoshopRegisterEvent
com.adobe.PhotoshopUnRegisterEvent
com.adobe.PhotoshopLoseFocus
com.adobe.PhotoshopQueryDockingState
For example, a CEP extension yields the mouse focus back to Photoshop by sending the com.adobe.PhotoshopLoseFocus event:
com.adobe.PhotoshopCallback will be removed in Photoshop 17.0 as adding a listener results in all CS Extensions receiving the event. As of Photoshop CC 2015 June release, developers can now use this alternative, which fixes the broadcast issue:
Please be aware that the script in evalScript and the jsx file which is configured in <ScriptPath> in the extension's manifest are executed in host application's ExtendScript engine, which runs in host application's main thread. On the other hand, CEP event is also dispatched from host application's main thread. If the interaction between the script and CEP event is needed, please split the script into small parts and call them separately so that CEP event has a chance to be scheduled.
Vulcan messages
Starting with CEP 5.0, global CEP Events whose scope attribute is set to "GLOBAL" are no longer supported. Please use the APIs in Vulcan.js instead.
Vulcan message
The data structure of Vulcan message in JavaScript is as below.
/** * @class VulcanMessage * Message type for sending messages between host applications. * A message of this type can be sent to the designated destination * when appId and appVersion are provided and valid. Otherwise, * the message is broadcast to all running Vulcan-enabled applications. * * To send a message between extensions running within one * application, use the <code>CSEvent</code> type in CSInterface.js. * * @param type The message type. * @param appId The peer appId. * @param appVersion The peer appVersion. * */functionVulcanMessage(type,appId,appVersion){this.type=type;this.scope=VulcanMessage.SCOPE_SUITE;this.appId=requiredParamsValid(appId) ? appId : VulcanMessage.DEFAULT_APP_ID;this.appVersion=requiredParamsValid(appVersion) ? appVersion : VulcanMessage.DEFAULT_APP_VERSION;this.data=VulcanMessage.DEFAULT_DATA;}
addMessageListener, removeMessageListener, dispatchMessage and getPayload APIs are available to dispatch and listen for Vulcan messages. The API definitions are as below. Refer to Vulcan.js for more information.
/** * Registers a message listener callback function for a Vulcan message. * * @param type The message type. * @param callback The callback function that handles the message. * Takes one argument, the message object. * @param obj Optional, the object containing the callback method, if any. * Default is null. */Vulcan.prototype.addMessageListener=function(type,callback,obj)
/** * Removes a registered message listener callback function for a Vulcan message. * * @param type The message type. * @param callback The callback function that was registered. * Takes one argument, the message object. * @param obj Optional, the object containing the callback method, if any. * Default is null. */ Vulcan.prototype.removeMessageListener=function(type,callback,obj)
/** * Dispatches a Vulcan message. * * @param vulcanMessage The message object. */ Vulcan.prototype.dispatchMessage=function(vulcanMessage)
/** * Retrieves the message payload of a Vulcan message for the registered message listener callback function. * * @param vulcanMessage The message object. * @return A string containing the message payload. */ Vulcan.prototype.getPayload=function(vulcanMessage)
Here is the example to demonstrate how to use the APIs in JavaScript.
vartestVulcanMessage=newVulcanMessage(VulcanMessage.TYPE_PREFIX+"test");testVulcanMessage.setPayload("To be or not to be that is a question!");
getEndPoints and getSelfEndPoint APIs are available to support point-to-point Vulcan message. The API definitions are as below. Refer to Vulcan.js for more information.
/** * Gets all available endpoints of the running Vulcan-enabled applications. * * Since 7.0.0 * * @return The array of all available endpoints. * An example endpoint string: * <endPoint> * <appId>PHXS</appId> * <appVersion>16.1.0</appVersion> * </endPoint> */Vulcan.prototype.getEndPoints=function()
/** * Gets the endpoint for itself. * * Since 7.0.0 * * @return The endpoint string for itself. */ Vulcan.prototype.getSelfEndPoint=function()
The steps to send point-to-point Vulcan message are as follows:
Get all available endpoints.
Select the destination endpoint and get appId and appVersion from it.
Create Vulcan message with the destination appId and appVersion.
JavaScript engine of host application - Application DOM/Extend script DOM
JavaScript engine of CEP HTML runtime - HTML DOM
Application DOM is not available in CEP extension's engine and CEP DOM is not available in host application's engine.
To access Application DOM from CEP extensions, CEP JavaScript library provides an API, CSInterface.evalScript, to execute extend script to access the host application's DOM. Here is a brief diagram to indicate how to access Application DOM through this API.
Here is the sample JavaScript code snippet in HTML extension.
There is no way to access HTML extension's JavaScript DOM directly from Application's ExtendScript. If you need to access it, CEP event based communication can be used as a substitution.
CEP creates a library which uses External Object mechanism of ExtendScript to send CSXS events. The external object provides an ExtendScript class CSXSEvent for creating and dispatching application-level CSXS events. On HTML extension side, event listeners can be registered via the addEventListener API in CSInterface.js to listen to the events.
Some CC applications (Photoshop, Illustrator, Premiere Pro) integrated PlugPlugExternalObject library and started to support this functionality in CC 2014 release. Audition supports this functionality since CC 2015.1 release.
Sample Code
ExtendScript developers need to create external object instance first.
If user wants to be notified when clicking a menu item, user needs to register com.adobe.csxs.events.flyoutMenuClicked event by calling AddEventListener. When a menu item is clicked, the event callback function will be called. The data attribute of event is an object which contains menuId and menuName attributes.
To get notified when fly-out menu is opened and closed, register event listener for below event types respectively:
The "menu" parameter for "setContextMenu" is a XML string.
Id - Menu item ID. It should be plain text.
Icon - Menu item icon path. It is a path relative to the extension root path. For optimal display results please supply a 16 x 16px PNG icon as larger dimensions will increase the size of the menu item.
Label - Menu item label. It supports localized languages.
Enabled - Whether the item is enabled or disabled. Default value is true.
Checkable - Whether the item can be checked/unchecked. Default value is false.
Checked - Whether the item is checked or unchecked. Default value is false.
The items with icons and checkable items cannot coexist on the same menu level. The former take precedences over the latter.
The "callback" parameter is the callback function which is called when user clicks a menu item. The only parameter is the ID of clicked menu item.
If you prefer to using a JSON string to set context menu, you can achieve it by calling setContextMenuByJSON.
The "menu" parameter for setContextMenuByJSON is a JSON string.
id - Menu item ID. It should be plain text.
icon - Menu item icon path. It is a path relative to the extension root path. For optimal display results please supply a 16 x 16px PNG icon as larger dimensions will increase the size of the menu item.
label - Menu item label. It supports localized languages.
enabled - Whether the item is enabled or disabled. Default value is true.
checkable - Whether the item can be checked/unchecked. Default value is false.
checked - Whether the item is checked or unchecked. Default value is false.
The items with icons and checkable items cannot coexist on the same menu level. The former take precedences over the latter.
If developers do not set context menu, CEP shows default items (Back, Forward, View Source, etc.). This is compatible with previous releases. If developers set context menu which has no any default id, CEP removes all default items and show customized items only. If one of the following default ids is set, the default menu item against that id will be shown.
id
"print"
"back"
"view source"
"forward"
Notes:
They are case-insensitive.
The quotation marks is not a part of an id.
The default callback associated to each id will be used and cannot be customised.
Disable Context Menu
To disable the context menu, you can call setContextMenu by null.
Another way is to add oncontextmenu="return false;" to the HTML tag. For example,
Observe com.adobe.csxs.events.panelWindowStatusChanged CSXS event, this is for PANEL extensions only. If user hides the panel window by clicking "X" or collapsing window, this event is going to be sent to observer with the "true" or "false" string in data attribute, while the event is not going to be sent if the extension is closed. That is to say, currently, only panel extensions which are running on Ai and persistent can receive this event, when the extension is hiding, event with "false" data is sent while the extension is shown, event with "true" is sent.
Call isWindowVisible API
Call isWindowVisible JS interface. Both dialog and panel extension enable to access this API, but it always returns true for modal and modeless dialog extensions while it always returns false for invisible extensions.
Getting and Changing Extension Content Size
Getting Extension Content Size
Getting extension content size can be done using window.innerWidth and window.innerHeight. However, if you are accessing these properties from inside an IFrame, you are actually accessing the properties of the IFrame's window object, not the ones for the HTML document. To access the top-most one, you will need to do parent.window.innerWidth and parent.window.innerWidth.
Changing Extension Content Size
Changing modal and modeless extension content size is supported in all Adobe applications that supports CEP. However, changing panel HTML extension size is not supported in Premiere Pro, Prelude, After Effects and Audition.
The width and height parameters are expected to be unsigned integers. The function does nothing when parameters of other types are passed.
Please note that extension min/max size constraints as specified in the manifest file apply and take precedence. If the specified size is out of the min/max size range, the min or max bounds will be used. When a panel is docked with other panels, there are chances that it won't resize as expected even when the specified size satisfies the min and max constraints. The restriction is imposed by host applications, not by CEP.
Register invalid certificate error callback
(Since 6.1) Register the invalid certificate error callback for an extension. This callback will be triggered when the extension try to access the web site that contains the invalid certificate on main frame. But if the extension does not call this function and try to access the web site containing the invalid certificate, a default error page will be shown:
This function works with modeless extensions and panel extensions. Generally all the key events will be sent to the host application for these two extensions if the current focused element is not text input or dropdown.
If you want to intercept some key events and you want them to be handled in the extension, please call this function in advance to prevent them being sent to the host application.
keyEventsInterest: A JSON string describing those key events you are interested in. A null object or an empty string will lead to removing the interest
This JSON string should be an array, each object has following keys:
keyCode: [Required] represents an OS system dependent virtual key code identifying the unmodified value of the pressed key.
ctrlKey: [optional] a Boolean that indicates if the control key was pressed (true) or not (false) when the event occurred.
altKey: [optional] a Boolean that indicates if the alt key was pressed (true) or not (false) when the event occurred.
shiftKey: [optional] a Boolean that indicates if the shift key was pressed (true) or not (false) when the event occurred.
metaKey: [optional] (Mac Only) a Boolean that indicates if the Meta key was pressed (true) or not (false) when the event occurred. On Macintosh keyboards, this is the command key. To detect Windows key on Windows, please use keyCode instead.
(Since 6.1) CEP 6.1 introduces two APIs to set and get the title of extension windows. Those functions work with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Animate (Flash Pro) and Audition:
CEP JavaScript library provides APIs for detecting the availability of HI-DPI display on the Mac platform.
CSInterface.getScaleFactor() Use this function to retrieve the scale factor of the display on which the calling extension window is located.
var scaleFactor = CSLibrary.getScaleFactor();
CSInterface.setScaleFactorChangedHandler() Use this function to add a event handler that will be called when calling extension window is moved between HI-DPI and non-HI-DPI displays.
The JavaScript engine in CEP HTML engine had been extended to provide some APIs, including:
local file access
native process
others
These APIs are in JavaScript DOM and can be used as other built-in JavaScript APIs. You do NOT need to include any JavaScript files.
API reference is as below.
CEPEngine_extensions.js is actually a CEF extension that is built in CEPHtmlEngine to expand the DOM of CEPHtmlEngine, like create/delete folder, read/write file, create/quit process, and so on. You can invoke these built-in APIs directly in your HTML extension without any JavaScript file reference.
vardata="This is a test.";varpath="/tmp/test";varresult=window.cep.fs.writeFile(path,data);if(0==result.err){
...// success}else{
...// fail}
Write file with base64 encoding mode. To use this mode, you need to convert the input string to a base64-encoded string before calling writeFile(). The following is an example.
vardata="This is a test.";varpath="/tmp/test";data=cep.encoding.convertion.utf8_to_b64(data);
varpath="/tmp/test";varresult=window.cep.fs.readFile(path);if(result.err===0){//successalert(result.data);//result.data is file content}else{
...// fail}
Read file with base64 encoding mode in which the read data after readFile called is converted to a base-encoded string. You need to decode this string to any format you want. The following is an example
In order to support localization, both the extension and the host application must provide locale information. There are two distinct types of locale information.
The License Locale (returned as the applicationLocale by the AMT library)
The Effective/Language/UI Locale (which is controlled by the user in the OS settings).
The extension must provide the list of supported locales for both the License Locale and the Language Locale via the HostEnvironment. This is particularly important in cases where the extension has features for a specific locale. PlugPlug library expects the host application to provide the locale information as part of the environmental data.
JavaScript API HostEnvironment has the appLocale property in place.
License Locale and locales supported by extension
CEP checks the License Locale of host application against supported locales declared in extensions locale list to determine if the extension is loadable for the host application.
Locale folder structure
Each property file should be placed in its corresponding locale folder. For example, the en_US property file should be <YourExtension>/locale/en_US/messages.properties. Users can define a default property file (<YourExtension>/locale/messages.properties), which will be used when the corresponding locale file is not defined.
YourExtension/
|-csxs/
|-locale/ <-- Directory for localized resources
|-- messages.properties <-- The one to fallback to if no localized resources is provided for a locale
|-- en_US/
| |- messages.properties
|-- zh_CN/
|- messages.properties
A locale file contains multiple lines of <key>=<value>. There should be a new line below the last property key/value.
CEP provides a JS interface named initResourceBundle to initialize the locale resources. This should be called during the loading of the extension. CEP initializes the resource bundle for the extension with property values for the current application and UI locale. Then users can access the resource bundle (object) to get the localized strings.
Sharing localization resources across multiple locales
CEP 6.0 provided a mechanism to allow multiple locales to share the same localization resources (messages.properties).
For example, you want es_MX to use the messages.properties for es_ES. To do so, supply a file named fallback.properties in the es_MX folder as illustrated below.
In the fallback.properties file, you specify which locale's localized resources you want es_MX to use, in below format
fallback=es_ES
Side Notes:
The fallback.properties file takes precedence when both messages.properties and fallback.properties exist at the same time.
If fallback.properties is malformed, or it specifies a non-existent fallback locale, the messages.properties file in the same directory will be used.
Localized menu
In manifest, it supports to use locale string as menu. For example, in ShareOnBehance's manifest, it is using %UI_share_on_Behance. UI_share_on_Behance is defined as UI_share_on_Behance=xxx in messages.properties.
varcs=newCSInterface();// Get properties according to current locale of host application.varresourceBundle=cs.initResourceBundle();// Use the localized strings.<scripttype="text/javascript">document.write(resourceBundle.key1);</script>
Example 2
data-locale is the custom HTML element attribute and you can add to each HTML element that you want to localize.
In this example, there is key3.value=value3 in the property file. In the HTML file, the input widget has attribute data-locale with key3, then its value is set to value3.
In this example, there is key4.innerHTML=value4 in the property file. In the HTML file, the text area widget has attribute data-locale with key4, then its innerHTML is set to value4.
MENA stands for "Middle East and North Africa". Support needs to be provided for Arabic, Hebrew, and NA French languages.
Language
ISO Code
Arabic (Middle East Enabled English Arabic)
en_AE
Hebrew (Middle East Enabled English Hebrew)
en_IL
NA French
fr_MA
If an extension needs to be loaded in host applications in MENA locales, MENA locales must be added to the supported locale list of the extension manifest file. For example:
Extension/
|-csxs/
|-locale/ <-- Directory for localized resources
|-- messages.properties <-- The one to fallback to if no localized resources is provided for a locale
|-- fr_FR/
| |- messages.properties
|-- en_GB/
|- messages.properties
When CSInterface.initResourceBundle() is called, CEP uses the app UI locale (not app locale) reported by PP to load localized resources. If there is no localized resources for an app UI locale, for example fr_MA, then CEP will fall back to use messages.properties located under the locale folder.
With MENA feature, point products map en_AE/en_IL to en_US and fr_MA to fr_FR for app UI locale. In this case, for en_AE and en_IL build of point product, en_US resources will be used if provided and for fr_MA build of point product, fr_FR resources will be used if provided. What extension team needs to do in this case is to provide en_US version of resources for en_AE/en_IL and fr_FR version of resources for fr_MA.
Video/Audio Playback
CEP 5.0 supports playing video and audio encoded in below formats.
Format
MIME-Type
Misc.
MP4
video/mp4
MPEG 4 files with H.264 video codec and AAC audio codec
Ogg
video/ogg
Ogg files with Theora video codec and Vorbis audio codec
mp3
audio/mpeg
Here is an example of playing video in your extension:
One thing to note is that because HTML extensions are hosted in integrating application's windows, video cannot be played in full-screen mode.
WebRTC
WebRTC is targeting to serve stream audio, video capture, like online video conference. WebRTC is not enabled by default. To enable it, the schema below need to be added in manifest file. For details, refer to Customize CEF command parameters.
For WebRTC related development, CEP runtime just keeps the same experiences as the usage in Chrome. Please refer to samples for the implementation.
Scroll bar tips
On Mac, scroll bars of panel are hidden by OS (since Lion by design). It can be always shown by settings as below.
Click the Apple menu at the top-left of the screen, then select System Preferences.
Next, select the General preferences pane; it’s the very first one, up at the top.
Under the “Show scroll bars” heading, you’ll find three options: “Automatically based on input device,” “When scrolling,” and “Always.” Chose "Always."
Invisible HTML Extensions
An HTML extension can be invisible during its whole life cycle. This means
It always runs in the background
It is never visible
To make an HTML extension invisible
Set extension manifest version to "5.0" or higher.
Specify its window type as 'Custom' in the manifest file.
Set <AutoVisible> to false in the manifest file.
If you do not want the extension to appear in the Window->Extensions menu, do not add the <Menu> tag.
If you want the extension to start on specific types of events, specify those events using <StartOn> tag.
Here is an example:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ExtensionManifestxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"ExtensionBundleId="IamInvisible"ExtensionBundleVersion="1.0"Version="5.0">
<ExtensionList>
<ExtensionId="IamInvisible"Version="1.0"/>
</ExtensionList>
<ExecutionEnvironment>
<HostList>
<HostName="PHXS"Version="13.0"/>
</HostList>
<LocaleList>
<LocaleCode="All"/>
</LocaleList>
<RequiredRuntimeList>
<RequiredRuntimeName="CSXS"Version="5.0"/>
</RequiredRuntimeList>
</ExecutionEnvironment>
<DispatchInfoList>
<ExtensionId="IamInvisible">
<DispatchInfo>
<Resources>
<MainPath>./html/index.html</MainPath>
</Resources>
<Lifecycle>
<AutoVisible>false</AutoVisible>
<StartOn>
<!-- Photoshop dispatches this event on startup -->
<Event>applicationActivate</Event>
<!-- Premiere Pro dispatches this event on startup -->
<Event>com.adobe.csxs.events.ApplicationActivate</Event>
<!-- You can add more events -->
<Event>another_event</Event>
</StartOn>
</Lifecycle>
<UI>
<Type>Custom</Type>
<Geometry>
<Size>
<Height>1</Height>
<Width>1</Width>
</Size>
</Geometry>
</UI>
</DispatchInfo>
</Extension>
</DispatchInfoList>
</ExtensionManifest>
One important thing to note is that not all host applications support Invisible HTML Extension. See table below for more information:
Point Product
Supports Invisible Extension
Misc.
Photoshop
Yes
Premiere Pro
Yes
Prelude
Yes
Animate (Flash Pro)
Yes
Audition
Yes
InDesign
No
Doesn't work at all because InDesign doesn't support 'Custom' window type.
InCopy
No
Doesn't work at all because InCopy doesn't support 'Custom' window type.