JSX.js is a simple API to significantly speedup and simplify your extensions development.
The manifest.xml is the file that instructs the CEP engine about the setup of the extension, in which host applications should it be run, what should be the dimensions of the UI if any, etc. etc. and the location of the "index.html" and "host.jsx", well thus goes the manual. The problem with the manual's approach is that every time you make a change in the host.jsx you have to restart the application to see the change. Wouldn't it be nice if you could just at a click of a button and in an instance restart the extension so that all the changes in all the files including the jsx files are reflected? Well it's dead simple, at least when someone's done the tough stuff for you. Also wouldn't it be nice if executing jsx scripts from the js engine was made really simple without the need of "quoting" + every + "other" + word? Wouldn't it be nice if when we run our jsx scripts they can know there own path? If the answer to those question is yes then continue reading otherwise adios amigos
On some of the versions of some of the applications on Windows changes are reflected after closing and reopening the extension. Changes made in the manifest are not reflected, you need to restart the app for that one.
The error messages are more useful now, both the jsx.evalScript and jsx.evalFile methods provide detailed error messages.
I need to update this post but in the meantime look at the scripts annotations to see changes in the defaults :-|
Compare the following 2 manifest snippets.
If you use the "Typical" method then 1) in order to have the extension reflect the changes you make you'll need to restart the host app and 2) you'll never really know what gets loaded first the js or the jsx (well maybe smarty pants out there does know). If you use the "Trevor" method then 1) you'll see the jsx changes reflected with a single click and 2) you'll know the order the 2 engines or run. The "Trevor" method misses out the line <ScriptPath>./jsx/myFab.jsx</ScriptPath>
so what do we do instead? JSX.js in particular the jsx.evalFile() method.
JSX.js has 2 methods jsx.evalFile(file);
for executing jsx snippets and jsx.evalScript(script);
for executing jsx
files.
PARAMETERS:
The 4 parameters
One can also use the lowercase jsx.evalfile()
or shorthand jsx.file()
instead of the camelCase jsx.evalFile()
Description: The path of the jsx file to be executed. Can be an absolute path or path relative to the
extensions folder or a file in the extensions jsx folder.
Description: The callback function that receives the result from the jsx script.
The result will always be a string so you might need to eval
it in the callback function.
See the not by the
Description: The replacements that you might want made. In the jsx file surround words you want
replaced with __
like __this__
and __that__
and then you make your replacement object where the keys are the
strings you want replace and the values are their replacements.
Description: This wraps the script in an eval
What for? The callback as mentioned above can only accept a String
. All the apps pass the result of the script as a String
except for InDesign unless the script explicitly returns a string. Let's compare the following 2 scripts. Script 1
(length 1 byte) 1
, Script 2
(length 3 bytes) '1'
Script 1
will in all the apps except for InDesign pass the 1
to the callback, in InDesign the callback will be triggered but the 1
will not be received In Script 2
even InDesign will will pass the 1 to the callback because it was explicitly passed as a string. 2 methods of non-explicitly forcing the result to be a string are 1) to run the script using $.evalFile()
and 2) to wrap the script in an eval
. By default the jsx.evalFile()
method will execute the jsx script using $.evalFile()
and therefore even InDesign will return the result as a String
however when replacements are made then $.evalFile()
is not used and therefore unless the result was explicitly set as a String
InDesign will not receive the result. Setting the String
Summary: Don't set true
unless you are 1) Using InDesign and 2) Using replacements and 3) Not explicitly passing the result as a string and 4) You need the result.
NOTE: When you execute the jsx script using the "Typical" manifest.xml
method the
$.fileName
will not return the file's path. When using jsx.evalFile()
the correct Path will be returned unless replacements have passed. To return the correct path in all cases you can use $.__fileName('baseName')
where baseName
is the files baseName without the path. In most cases $.__fileName()
without the baseName will also work, see below for the exceptions. If on a Mac you have a root folder and a volume of the same name, for example you have the root folder /myScripts
and you have a volume /Volumes/myScripts
and your script has the path /Volumes/myScripts/myScript.jsx
then $.fileName
will give the wrong path /myScripts/myScript.jsx
. The correct path will be returned if you use $.__fileName('myScript.jsx')
. If you just use $.__fileName()
without the baseName then the same wrong path will be given as by the $.fileName
property. In InDesign $.__fileName()
without the baseName will only return the correct path if no other script has be executed using the jsx.evalFile()
method after the current script has be executed. The other apps don't have this issue and all the apps including InDesign $.__fileName('myScript.jsx')
will return the correct path. The only case where it won't is if you executed multiple jsx files using the jsx.evalFile()
on files with different paths and the same baseName. So either avoid doing that or use $.__fileName()
without the basename subject to it's limitations. $.__fileName('baseName')
will only work for scripts executed using the jsx.evalFile()
method. A new property $.__dirname
will be available to all jsx scripts run in the extension's target engine as long as JSX.js loaded first.
RETURNS: Boolean
Description: Will return true if the js
engine could process the jsx.evalFile()
command and false
if it couldn't (like the file didn't exist). True will be returned even if the jsx
engine cannot execute the script
(like if (5 = 3){2}
).
PARAMETERS:
The 4 parameters
readability purposes use a single object, in which each parameter has multiple keys that can be used for them that can
be either lowercase or camelCase.
One can also use the lowercase jsx.evalscript()
or the shorthand jsx.eval()
or jsx.script()
instead of the
camelCase jsx.evalScript()
Description: The jsx script to be executed.
Like csInterface.evalScript()
you need to escape \
Description: The callback function that receives the result from the jsx script.
The result will always be a string so you might need to eval
it in the callback function.
InDesign does not by default pass the result as a string so you need to either pass the result
explicitly as a string or set the true
if you need the result from InDesign, see more details
of this by the
Description: The replacements that you might want made. Surround words you want replaced with __
like
__this__
and __that__
and then you make your replacement object where the keys are the strings you want replace and
the values are their replacements.
With ES6 Template literals, which should be available in CEP8, replacements should become much more simple even
using the csInterface.evalScript method, so the only advantage of using jsx.evalScript would be for the forceEval
argument when using with InDesign.
Description: This wraps the script in an eval
What for? The callback as mentioned above can only accept a String
. All the apps pass the result of the script as a String
except for InDesign unless the script explicitly returns a string. Let's compare the following 2 scripts. Script 1
(length 1 byte) 1
, Script 2
(length 3 bytes) '1'
Script 1
will in all the apps except for InDesign pass the 1
to the callback, in InDesign the callback will be triggered but the 1
will not be received In Script 2
even InDesign will will pass the 1 to the callback because it was explicitly passed as a string. Setting the String
Summary: Don't set true
unless you are
1) Using InDesign and
2) You need the result.
How does one set up the extension so that one can restart the extension at a click of a button and all the changes in
both the js and jsx files will be reflected?
Include in the index.html
file the following line (or something similarish) to add the button. When the scripts
development is done you can remove the line.
Include the following files. If you prefer you can use plain js instead of jQuery. ../js/buttons.js
is the name I give
the js script for controlling th HTML UI, substitute with the name you use.
In your main.js
file you execute your host.jsx
file
In your buttons.js
(or whatever you call your file that deals with your UI functions) file include something like
this.
Then when you click on your button the extension will restart including all the jsx files, slashing development time
See the annotation at the beginning of the script for cost and terms of use.
I want to make it clear the the jsx.evalFile is a very useful function which save restarting the app on many occurrences BUT you should be aware that there will be times when you will need to restart the app. One important consideration is to put the window.location.href = "../html/index.html";
early in the code.
11 Comments on “JSX.js A Game Changer in Adobe HTML Extensions Development?”
This script is a blessing, it really ease my pain during this nightmare that is writing CEP extensions.
Thank you so much Trevor. I would hug you for a whole minute if I could.
Hi, I'm trying to test your example with parameters passing to jsx script, but no results.
I'm getting "Test" alert, but nothing more. Any ideas what could happened? Btw, great plugin and thanks for creating it.
The snippet I placed was not good it should end
('__name__', age);
I've updated the snippet, nice to see someone tried it out!
When a script doesn't act as it should you can debug it using a callback.
You can use
$.writeln
or whatever you want instead.Hi Trevor, thanks for developing JSX.js. I've started using to handle communication in my CEP extension. However, I'm seeing that the console is no longer available in the
evalFile
'd JSX. For instance, if I haveand calling thins in my index.html
I'm seeing the alert say "undefined".
Is the console available elsewhere (like
$.__console
) or is it unaccessible due to the file being run from another thread by JSX.js?Thanks for any help.
Make sure to include
<script src="../js/JSX.js"></script>
in the header or at least before you reference it in theonclick
.If you are then try removing line 62
var jsx
Report back if the above helps.
I think I misunderstood you and that you want the CEPS js engines
console
to be available in the Extend Scripts jsx engine. That is not going to happen! It would be very easy to access the console by adding an event listener in the JS script "com.shawn.console" that forwards data from and event dispatched in the jsx script.Look at the source code of https://github.com/Trevor-/console
In particular https://github.com/Trevor-/console/blob/master/com.creative-scripts.console/jsx/__log.jsx#L33-L59 and
https://github.com/Trevor-/console/blob/master/com.creative-scripts.console/js/console.js#L125-L150
Hi Trevor
Thanks for your quick response. I am using CEP 6 with illustrator CC 2015, ver 19.0.0.
Do you have any workable example host.jsx, please provide me. Any examples host.jsx much appreciated.
Well your real basic host.jsx would be
alert("hello world")
Hi Trevor,
Its really wonderful and useful article, only thing the host.jsx is not working in this, can you post some example.
Hi VV
The post includes quite a lot of examples already, I think you need to read the section "Setting up the extension with JSX.js" carefully. Basically you need to in the manifest.xml file not include
You also have to include the line
see the start of the post as to where in the manifest file to include these. In index.html include the line
given that you have placed the JSX.js file in the js folder. Place your host.jsx file in the jsx folder and then in your main.js call the host.jsx file using
jsx.file('host.jsx', myCallBack);
where myCallBack is a function that does something with the result. It could bemyCallBack = function (result){ alert(result); };
or perhaps something more useful.HTH, Trevor
Thank You Trevor,
I can't wait to test it out. Specially for the replacements method.
This all sounds very nice.
Ben
Hi Ben,
Thanks for your comment. I've added a note by the replacement parameter of the jsx.evalScript method about replacements in CEP8 using template literals. You should see there.