UndoModes in InDesign (CS4 and later) allow for multiple steps in a script to be saved as a single step in the undo stack. Using this capability in a CS SDK extension is not very straight-forward because you can't pass in ActionScript code to a doScript. doScript() accepts one of the three scripting languages which ActionScript is not one.
Use one of the native scripting languages as the argument of the doScript(). There are many ways of approaching this as described below.
1) Execute native scripting code
2) Execute ActionScript code using an ExtendScript function
The doScript() method can actually accept a few different types of parameters:
1) It can accept a File object
2) It can accept a string (of code to execute)
3) It can accept a reference to a function
All three of these parameter types can be used from ActionScript, but there are points to keep in mind:
If method #1 is used, you can save a script file to a specific location and execute the file. However, you must pass in an ExtendScript File object which is very different than an ActionScript one. This is complicated by the fact that ActionScript does not recognize ExtendScript File objects. One way to work around this problem would have been to use eval() to construct a File object inside the doScript() call, but you can't do that from ActionScript directly. Instead, you would need to execute the doScript in ExtendScript:
var fileString:String = "File(\"" + filePath + "\")";
var evalFileString:String = "eval('" + fileString + "')";
CSXSInterface.getInstance().evalScript("app.doScript",evalFileString,"","[]",String(UndoModes.ENTIRE_SCRIPT.value),scriptName);
A much simpler way to handle this would be to pass in the string rather than trying to construct an ExtnedScript File object. Assuming the ExtendScript string is coming from a file you could do that like this:
var script:String = "";
var scriptFile:File = new File();
scriptFile.url = url;// this is the file path
if (scriptFile.exists) {
var stream:FileStream = new FileStream();
stream.open(scriptFile, FileMode.READ);
script = new String(stream.readUTFBytes(stream.bytesAvailable));
stream.close();
}
if(script != ""){
app.doScript(script,ScriptLanguage.JAVASCRIPT,[],UndoModes.ENTIRE_SCRIPT,scriptName);
}
Generally when using doScript in ExtendScript, I pass in a variable which references an ExtendScript function object. Something like this:
function foo(){
alert("Foo!");
}
app.doScript(foo);
The problem is that from ActionScript it's not quite so straight-forward. Using this method is not very difficult, but it requires a different approach than the first two. For simplicity sake, I'm assuming that the ExtendScript code exists at the time of compiling the extension:
1) First use the method
described here to create a "jsxInterface" object which references your saved ExtendScript file.
2) In you ExtendScript file create your function. We'll call it "doSomethingComplicated()".
3) From ActionScript simply call your ExtendScript function like so:
app.doScript(jsxInterface.doSomethingComplicated,ScriptLanguage.JAVASCRIPT,[],UndoModes.ENTIRE_SCRIPT,scriptName);
Until now I am assuming that you are executing native script code (in my examples I used ExtendScript). You might want to write your code in ExtendScript and execute that . How would we go about doing that since doScript will not accept ActionScript as an argument?
My solution is to have ActionScript call ExtendScript which in turn calls ActionScript. How do you do that you might ask? Thank Bob Stucky for coming up with the following method:
// Create a global nameSpace object to hold all our globals
gUniqueNS = {};
// asWrapper is set via initWrapper. It is an object reference to the AS Side of our extension
gUniqueNS.asWrapper = {};
gUniqueNS.initWrapper = function( wrapper ) {
gUniqueNS.asWrapper = wrapper;
}
[ Embed (source= "myScript.jsx" , mimeType= "application/octet-stream" )] private static var myScriptClass:Class; var jsxInterface:HostObject = HostObject.getRoot(HostObject.extensions[0]); jsxInterface.eval( new myScriptClass().toString());
jsxInterface.gUniqueNS.initWrapper(this);
public function doSomethingComplex(){
//Our really cool code
}
gUniqueNS.executeActionScript = function(){ gUniqueNS.asWrapper.doSomthingComplex(); }
app.doScript(jsxInterface.gUniqueNS.executeActionScript,ScriptLanguage.JAVASCRIPT,[],UndoModes.ENTIRE_SCRIPT,scriptName);
+