Is it possible to execute JSX scripts from outside ExtendScript? - javascript

Typically when you're writing a .jsx script to automate an Adobe product (like InDesign, Illustrator or Photoshop), you write, debug and execute the script from the ExtendScript IDE. Is it possible to bypass ExtendScript and run the script from a third program?
I think Adobe products have a built-in JavaScript interpreter which ExtendScript can connect to to access the Adobe object models and automate their software. I'd like to be able to connect directly to that interpreter and run jsx files just as I would in ExtendScript.

Are you on a Mac? If so, you can use AppleScript with the osascript tool to execute your JavaScript. Here are some examples:
Running JSX and Returning a Value
Save this as ~/temp/foo.scpt:
tell application "Adobe Illustrator"
-- 'do javascript' runs any arbitrary JS.
-- We're using the #include feature to run another
-- file. (That's an Adobe extension to JS.)
--
-- You have to pass a full, absolute path to #include.
--
-- The documentation alleges that 'do javascript'
-- can be passed an AppleScript file object, but
-- I wasn't able to get that to work.
do javascript "#include ~/temp/foo.jsx"
end tell
And save this as ~/temp/foo.jsx:
var doc = app.activeDocument;
var numLayers = doc.layers.length;
// The last value in the JSX file will be printed out by
// osascript.
numLayers;
Now, from the command line run osascript ~/temp/foo.scpt It will print the number of layers in the active Illustrator document.
Getting data out of the JavaScript is limiting. You can't print to stdout from within the JavaScript. Instead, place the value you want to return as the last statement of the JSX file; it will be printed by osascript. (Here's why: The last value in the JSX file is the return value of the do javascript AppleScript statement. That is also the last value in the AppleScript file, and osascript prints the final value.)
The value you return from JavaScript can be a number, a string, an array, or anything else that retains its value when converted to a string. If you want to return a complex object, you'll need to #include a JSON library and call .toJSONString() on the object.
Passing Arguments to JSX
To pass arguments to the JSX code, follow this example:
File ~/temp/args.scpt:
on run argv
tell application "Adobe Illustrator"
set js to "#include '~/temp/args.jsx';" & return
set js to js & "main(arguments);" & return
do javascript js with arguments argv
end tell
end run
File ~/temp/args.jsx
function main(argv) {
var layer = app.activeDocument.activeLayer;
app.defaultStroked = true;
app.defaultFilled = true;
// Top, left, width, height (in points).
// Note that parameters start at argv[0].
layer.pathItems.rectangle(argv[0], argv[1], argv[2], argv[3]);
}
And then run osascript args.scpt 50 30 10 80
Debugging
The do javascript command also has options for launching the ExtendScript debugger. For details, open the Illustrator dictionary in AppleScript Editor.

For Windows users, you can use a vbs script. Pass arguments to the .jsx script by providing arguments to the cscript command like so: cscript test.vbs "hello". test.vbs could look like so:
Dim appRef
Dim javaScriptFile
Dim argsArr()
Dim fsObj : Set fsObj = CreateObject("Scripting.FileSystemObject")
Dim jsxFile : Set jsxFile = fsObj.OpenTextFile("C:\Users\path\test.jsx", 1, False)
Dim fileContents : fileContents = jsxFile.ReadAll
jsxFile.Close
Set jsxFile = Nothing
Set fsObj = Nothing
javascriptFile = fileContents & "main(arguments);"
Set appRef = CreateObject("Illustrator.Application")
ReDim argsArr(Wscript.Arguments.length-1)
For i = 0 To Wscript.Arguments.length-1
argsArr(i) = Wscript.Arguments(i)
Next
Wscript.Echo appRef.DoJavaScript(javascriptFile, argsArr, 1)
The Wscript.Echo will return the last line returned by the .jsx file. A .jsx file example could be:
function main(argv) {
alert(argv[0]);
return "test";
}
When ran, you should seee Illustrator (or whatever adobe program) alert "hello" and then "test" will be returned to stdout (you should see it in the command prompt window).

This works in windows:
"C:\Program Files (x86)\Adobe\Adobe Photoshop CS5\Photoshop.exe" C:\completepathto\my.jsx
Pay attention to the path to Photoshop. It must be quoted since it contains spaces.
There are plenty of tricks for figuring out where Photoshop is loaded. Here is one that finds every location where Photoshop has been loaded and places those in x.lst
#REM The Presets\Scripts doesn't really restrict where the loop is looking,
#REM thus the "IF EXIST" is needed. The FIND makes sure that the
#for /R "%ProgramFiles(x86)%\Adobe" %%f in (Presets\Scripts)
DO #IF EXIST %%f
(echo %%f | FIND /I "Adobe Photoshop C" >> x.lst )
You can then process each line in x.lst. NOTE: The entire "#for" should be on ONE line, I split it to multiple lines for readability.
If you believe there will be only one Photoshop (and not Elements) then you could change
"echo %%f"
to
"%%f\..\..\Photoshop.exe" C:\completepathto\my.jsx

The straight answer is YES. Illustrator, InDesign and Photoshop can all be scripted through COM. Any program that you make that can access COM (such as a .net language, C++, BCX, Autohotkey or Powerpro) can tell Illustrator, InDesign or Photoshop to do things.
Here is an example for Powerpro(you will need powerpro's com plugin), and this works in CS4 and CS5:
Function ComLoad() ;;MAKE SURE TO CALL .#ComUnload WHEN EXITING FUNCTION CALLS!
static objname="Illustrator.Application"
static com_status, com_type
static appRef=com.create_object(objname)
endfunction
Function ComUnload();;this is end the com calls and unload com
com.unload
endfunction
After you use the ComLoad() function, you then run any kind of method or function offered by the COM library. Here is how to use Powerpro to tell Illustrator to run your jsx or js file:
;Run a script from anywhere
Function RunOtherScript(whatscript)
If (file.Validpath(whatscript) == 0)do
messagebox("ok","Whoops! That script doesn't exist!","ILL Runscript")
quit
endif
.#ComLoad()
appRef.DoJavaScriptFile(whatscript)
.#ComUnload()
quit
Here is an image of a floating toolbar that I made using Powerpro. The buttons are all attached to com functions. Most of the time I use the com functions to run external jsx scripts.
[edit]
There is another way! You can use the Adobe Configurator to create new panels which are capable of launching scripts. You can design the panel in any way you like, and the results are quite similar in effect to the powerpro toolbar I've described above. In fact, I moved from the powerpro toolbar to an Adobe Configurator Panel.

If you place the .jsx files in the right location
Photoshop
folder location:
/Applications/Adobe\ Photoshop\ CS5/Presets/Scripts
menu location:
File > Scripts
Illustrator
folder location:
/Applications/Adobe\ Illustrator\ CS5/Presets.localized/en_GB/Scripts
menu location:
File > Scripts
InDesign
folder location:
/Users/{user}/Library/Preferences/Adobe\ InDesign/Version\ 7.0/en_GB/Scripts/Scripts\ Panel
menu location:
Window > Utilities > Scripts
These are the paths on OSX, it should be easy to find the equivalent on Windows for Photoshop and Illustrator, but for InDesign it might be easier to open the Scripts Panel and open the scripts folder using the Panel's context menu.
I know that you can run .jsfl scripts from the command line by opening Flash and passing the path to the .jsfl script as an argument, but that doesn't seem to work for .jsx files with InDesign.
HTH

This question is quite old. I am going to answer this on the assumption that:
You're running JSX scripts for after effects.
You're using Windows.
I'm not sure whether you want to pass arguments to a script (in which case my simple solution won't work, or might need nasty workarounds).
Fortunately there is an easy way to do this with after effects. You can launch cmd and type the following command:
afterfx -r C:/Users/me/myscript.jsx
If afterfx isn't recognized, you'll need to add the after effects installation path to Path in your System Variables. I'm not aware of the availability of this feature in other Adobe programs.
For more information about running your after effects scripts from the command line, you can consult: https://helpx.adobe.com/after-effects/using/scripts.html

You can use extend script to run it .
there is a free extension on creative cloud will help you to run scripts fast in illustrator , aftereffects, photoshop and premiere pro
you can find it on adobe exchange ( liveview )

Related

How to generate JavaScript from a template with terminal similar to Laravel's Artisan?

I have been recently been working with Laravel, and Artisan has several useful make commands that generates php from template stubs on the fly based off a class name, as well as allowing for custom make commands to speed things up.
Short of copy-pasting, there an easy tool that lets me generate plain JS in a similar way based on a templates that allows me to specify some variables to be replaced, then generated in my project?
The ultimate goal of mine for this project is to run a single terminal command with some arguments that generate all the files I need (at least 8-10 PHP files, as well as around 4 JS files), all put into the right directories that lets me do minimal "plugging in" so I can start using them right away. I can chain custom artisan commands, but the next step is getting some kind of terminal JS generator. The nature of the project is that there is approx. 12-14 files that need to be generated and generically filled in before being able to interface with a database table and the front end, so you can understand why I want to do this.
You can do it with bash like this
#!/bin/bash
file_location=path/to/dir/$1.js
if [ -e $1 ]; then
echo "File $1.js already exists!"
else
cat > $file_location <<EOF
let hi = '$2'
console.log(hi)
EOF
fi
$1 is the filename and $2 is another parameter you can pass to the script to be written in the js file.
I would look at hygen. I don't know what your output files are supposed to look like, but hygen allows you to create your own templates and generators. This has a relevant code snippet that displays some JS code. I can't give any advice beyond that as I've not used it thus far.
If this is looking like a bit too much, you can always use VS Code's templates to build up a base, but you won't have any params. A VS Code extension could overcome that I'd guess, but then you're not within a cli.

Debug dynamically loaded JavaScript code with IntelliJ and the Nashorn engine

I am dynamically loading and running JavaScript code that is stored on disk in a YAML file. I would like to know if it is possible (using intelliJ) to debug the JS code even though I am not loading it from a standalone JS file. To simplify the problem description, consider the following Java code:
NashornScriptEngineFactory nashornFactory = new NashornScriptEngineFactory();
ScriptEngine engine = nashornFactory.getScriptEngine();
engine.eval("var a = 1 + 1;\nprint(a);");
How do I set a breakpoint on line two (the "print" function call) and how do I examine the value of variable "a"? If this is not possible, what would be the best workaround?
Based on this blog post https://blogs.oracle.com/sundararajan/remote-debugging-of-nashorn-scripts-with-netbeans-ide-using-debugger-statements, you can just attach a remote java debugger to process.
You can do this in IntelliJ IDEA by creating a new remote run configuration.
After attaching, use the JavaScript command:
debugger;
This will force the debugger to break if it is attached. You can then inspect the values of variables within the variable window.
If you can't manage to attach IntelliJ, open the browsers inspector/debugger and this same line of javascript will cause the browser's debugger to break on that line.

Calling an executable with parameters in ExtendScript

My Illustrator ExtendScript produces some XML files and I need to call an executable file WITH these files as parameters at the end of Main(). The solutions I've found have been disappointing at best.
Currently my solution without parameters is just
if (confirm("Would you like to open the NineGridViewer utility?", false)) {
// Temporary: prompt user to manually find path to executable
File.openDialog( 'Select path for NineGridViewer utility executable file.', '*.exe' ).execute();
}
I understand that I could produce a file which contains the .\executable [params] that I want and call that file as an executable. But I'd really like a nicer solution if possible.
Edit: This post and page 180 of this documentation reference a system class with convenient methods that do exactly what I need. But the interpreter seems to have no clue what I'm talking about when I use that. What am I misunderstanding here?

tracking a javascript found in pagesource

ive tried everything i cud to figure this out, but i cannot track a piece of javascript in a webpage
so, just to give you some context even though my problem is not related to just this scenario. it depends on a much bigger spectrum.
Anyway, im developing on sugarCRM and im trying to edit the default onclick behavior of a slot in calendar module (you dont need to understand this to help me, so please keep reading). when i click on a slot, a modal dialog window opens that lets me log a meeting or a call.
So i tracked down the javascript behind this. ive used firebug and chrome, and they both give a list of all the JS files that are being used on a given webpage
for example i search for "SUGAR.collection" and firebug tells me its located in a file named "sugar_field_grp.js?v=FVh1Z-v5nA6bYov7-aFFqQ" i can see this piece of code resides in sugar_field_grp.js,
but the code im trying to change resides in "index.php?module=Calendar&action=index&parentTab=Activities", firebug actually tells me this is the file that has the javascript i want to change.
I can also right click view page source and i can see that piece of code inside the script tag. so considering this piece of code doesnt reside in a JS file, i cannot change it, its generated at runtime (i think) but there must be some source, there must be a file thats telling sugarCRM to generate this code
tl;dr how to track down a piece of javascript code that resides on pagesource and theres no JS file specified by firebug or chrome save for index.php (this file doesnt have that javascript either)
i know its been a long post
thanks for reading
Learn how to search for strings in files on disk on your machine.
On Linux, MacOS and most unixen the go-to tool for this is grep. This applies to any programming language you work with. For your case simply cd into the directory of your source code and do:
grep -r SUGAR.collection .
If you're using git as your source control tool then git grep is much faster.
On Windows there are various GUI tools you can use to search for text in files. Just google: grep for windows.
If you're using an IDE then just your IDE's find-in-files functionality.
To track down specific code using Chrome / Webkit go through the following two steps:
Client:
1. Search all static text sources
Open the Dev Panel using CTRL + SHIFT + I
Hit CTRL + SHIFT + F for a global search dialog to pop up
Right next to it you can set pretty printing of the JS code to on: button { }
Enter your search term or terms using regular expressions
Optional: Decide if you need a case insensitive search which has a greater searchspace and takes longer
Example:
2. Search the dynamic user-DOM contents
Go to the Tab 'Elements' hit CTRL + F.
Enter your search term (This will also search iframes, svg's etc... within the parent DOM)
3. Recommended:
Cross-reference the results of step 1. and step 2.
If a given string is present in both the DOM and the static sources, then you can assume that the content is not programmatically created on the client-side.
Server:
Many projects perform a media bundling step prior to content-delivery. They pack web-resources into the main file (e.g. index.php) to save HTTP roundtrips.
Use sourcemaps / and or search the entire codebase for a salient static string or a salient keyword near the static string to locate the original source files.
Searching files:
Locally, I generally use the rapid index, and heuristic search of JetBrain's IDE's (IDEA, PHPStorm,...) and Sublime. The grep-command tool can definitely not compete here in terms of performance. On Windows I additionally use Totalcommander and its archive/regex finding abilities.
When quickly looking up code on the server you may use something like:
grep -r -C10 --color=always 'keyword1|keyword2' htdocs/ | less -R
which will also provide you with line-context. two caveats: you may want to filter out binaries first and symlinks outside the scope will be ignored.

What is #targetengine?

My only prior experience with #targetengine is when I've used #targetengine "session"; to turn a dialog into a palette when scripting in InDesign. But as I'm trying to figure out how to script a menu, I'm starting to see it pop up being used in other ways and using a term (target?) other than session.
Adobe likes to assume that everyone who wants to script is an experienced programmer sometimes, so I haven't found a clear explanation as to what this is.
So, when I use #targetengine, what am I doing? Can I use any term other than "session"? Some searches suggested this feature has to do with global variables; is that the case? If so, how can I clear them out without restarting InDesign? Is this a JavaScript thing or an ExtendScript/InDesign feature?
#targetengine is specific to the Adobe scripting in InDesign, PhotoShop, Illustrator etc. - it is not a general Javascript feature.
It specifies how to handle all the global 'stuff' - not only variables but also function declarations and any other change to the global status.
If you use the default 'main' engine all the globals disappear as soon as the script completes. If you use the 'session' engine all the globals are preserved as long as the host application keeps running. This means that if you run the script:
#targetengine "session"
var test = "test";
and later run the script:
#targetengine "session"
alert(test);
you get a message box showing test instead than giving an error
Besides the two standard 'main' and 'session' engines you can create your own ones, with arbitrary names - so if you run the script
#targetengine "mine"
var test = "another test";
and then run
#targetengine "mine"
alert(test);
you get a message box showing another test, but if you run again
#targetengine "session"
alert(test);
you still get test: there are two different 'test' global variables, one in the 'session' engine and one in the (newly created) 'mine' one.
This discussion was brought up in a Slack channel I monitor. One long-time developer said the following (cleaned up a bit for clarity):
As far as I know //#targetengine only works on InDesign (probably
including InCopy) and Illustrator.
On InDesign it works properly and on Illustrator it does not. Nevertheless other apps as far as I know all have the ability to use targetengines with C++ and that’s what CEP does with each CEP [extension?] having its own isolated engine.
There are at least 3 types of engine.
main engines, in InDesign it’s a temp engine that forgets everything after completing a scripts execution.
Public Private engines like session that remember and are active after script execution and good for event listeners. These and main can be identified using $.engineName and found on ESTK / vsCode
Private Private $.engineName will show "" can only be created with C++ that what most of the apps use and CEP uses except for InDesign where CEP uses Public Private engines which can be chosen.
He thinks there's also a 4th type he's forgetten.

Categories

Resources