6 Replies Latest reply on Nov 18, 2014 3:06 AM by mlavie

    How to call an ActionScript method from the ExtendScript/JavaScript function defined in a .jsx file.

    m_mfsi Level 1

      I've an InDesign ExtensionBuilder2.1 project for InDesignCS5-CS6.

      I needed to add event listeners on some MenuAction like 'Add Page'. so I added the line similar as below in one of my ActionScript method,

       

      myActionScript.as

      public class MyController

      {

      public function attachAddPageWatcher():void{

      try{

      //......................................

      var addPageMenuAction:* = InDesign.app.menuActions.itemByName("$ID/Add Page");

      addPageMenuAction.addEventListener('afterInvoke', addPageMenuActionHandler);

      //.....................................

      }catch(e:Error){

      trace(e);

      }

      }

       

      public static function addPageMenuActionHandler(evt:*){

      Alert.show("A new page added !!!");

      }

      }

       

      But at runtime I get an error saying that 'handler' argument of addEventListener method requires either a File or JavaScript Function.

       

      So I moved the above code to register event listener and its handler funtion inside a myScript.jsx file and changed the above code as below,

       

      myActionScript.as

      public class MyController

      {

      public static var  jsxInterface:HostObject = HostObject.getRoot(HostObject.extensions[0]);

       

      public function attachAddPageWatcher():void{

      try{

      //......................................

      jsxInterface.attachAddPageWatcher(); // call the method in .jsx file.

      //.....................................

      }catch(e:Error){

      trace(e);

      }

      }

      }

       

      myScript.jsx

      function attachAddPageWatcher(){

      try{

      app.menuActions.itemByName("$ID/Add Page").addEventListener("afterInvoke", addPageMenuActionHandler);

       

      }catch(e){

      alert("Error in attachAddPageWatcher() - myScript.jsx " + e);

      }

      }

       

      function addPageMenuActionHandler(evt){

      alert("A new page added - myScript.jsx !!!");


      // Now I need to send some data from here to my extension or need to call a method defined in my ActionScript class

      // or some how notify my extension to do some task after adding a new page.

      }

       

      Now I'm getting alert saying "A new page added - myScript.jsx !!!" each time Add Page menu item is clicked but I need to notify my extension to do some task after clicking Add Page menu item.


      I tried but didn't find any way to do so or like any dispatchEvent() kind of method to notify my extension from this ExtendScript/JavaScript method.

       

      Any suggestion to do so or to achive similar task is highly appreciated.

       

      - Thanks.

        • 2. Re: How to call an ActionScript method from the ExtendScript/JavaScript function defined in a .jsx file.
          m_mfsi Level 1

          It looks that I'm unfortunate enough that experinced users/moderators or folks who know something about this haven't seen this post.


          ....well still waiting for some help on whether its possible or not.

          • 3. Re: How to call an ActionScript method from the ExtendScript/JavaScript function defined in a .jsx file.
            Dominik Guzei Level 1

            From what I know calling the ActionScript code from JSX is not possible at the moment.

             

            The only thing you can do is invoke a function defined in JSX from ActionScript and work with the return values in AS.

             

            A good guide for me was this blog post:
            http://thirdroute.com/blog/2013/7/6/jsx-scripting-with-creative-suite-extensions-in-practi ce

             

            But be aware, the communication between AS and JSX is really fragile, as the article explains you have to take several measures (hex encoding / JSON.stringify) to make it work. I have it working for my application Prisma and will probably release this part of it as open source soon on my github account: Code Adventure Github Account

             

            I will probably also write a post on my blog about that topic, since it is really important for most extensions and there are no definitive guides on how to do it correctly yet ;-)

            • 4. Re: How to call an ActionScript method from the ExtendScript/JavaScript function defined in a .jsx file.
              mlavie Level 1

              m_mfsi,

               

              Have you solved this yet? If not, I'd be willing to take the time to explain how.

               

              mlavie

              • 5. Re: How to call an ActionScript method from the ExtendScript/JavaScript function defined in a .jsx file.
                m_mfsi Level 1

                @malive No not yet. I'd left that case. Please tell what you have.

                • 6. Re: Re: How to call an ActionScript method from the ExtendScript/JavaScript function defined in a .jsx file.
                  mlavie Level 1

                  The solution follows. I will be showing the HostObject.eval technique, instead of the CSXSInterface.instance.evalScript technique, as it is much easier for passing and returning complex parameters such as class objects.

                  This example assumes that the JS is in a file called InDesign,jsx in the source folder:

                   

                  Salient points:

                  1. Never pass InDesign objects from AS to JS, instead, pass hostObjectDelgates ((e.g., myPage.hostObjectDelegate), as in my example. If even one JS function gets passed an InDesign object, then bad things happen all over. Very bad things...
                  2. Even when in JS you return (or rather, appear to be returning) an InDesign object to AS, you are in fact returning a "Specifier" (conceptually, a sort of logical pointer). Therefore, in AS you must instantiate a new object of the desired return type, and then set its hostObjectDelegate property to the value returned by the JS function. See my example, below.
                  3. If you need to pass an InDesign enum from AS to JS, you must pass its value, and not the enum itself. E.g.,
                    _inDesignJsxInterface.closeDocument(document.hostObjectDelegate, SaveOptions.NO.value);
                  4. JS cannot return an Array to AS which AS sees as a native AS Array object. The JS Array will be converted to a HostObject with indexed values (myObj[0], myObj[1], etc.). The debugger does not show a "length" property, but it is indeed there and can be referenced in the AS code.

                   

                  My response may be overkill for you, but I thought it might be nice for someone to post a complete example of all (?) aspects of calling between AS and JS. I must state here that 90% of what I have written is based on posts by Harbs and Davide Barraca. Most were cookbooks which have since been taken down by Adobe...

                   

                  In AS:

                   

                  import com.adobe.csawlib.indesign.InDesign;

                  import com.adobe.indesign.*;

                  import flash.external.HostObject;

                  import mx.controls.Alert;

                   

                  public class AS2JSInDesign
                  {
                       [Embed(source="InDesign.jsx", mimeType= "application/octet-stream" )]
                       private static var _inDesignJsxProxyClass:Class; 
                       private static var _inDesignJsxInterface:HostObject;
                       _inDesignJsxInterface = HostObject.getRoot(HostObject.extensions[0]);
                       _inDesignJsxInterface.eval(new _inDesignJsxProxyClass().toString());
                       _inDesignJsxInterface.init(this);

                   

                       public function callJSFromAS():void

                       {

                          // This demonstrates how to pass InDesign objects to JS and how to receive them as return values

                          // NEVER pass an actual InDesign object between AS and JS.

                          // Instead, use the HostObjectDelegate, which is sort of like a logical pointer

                   

                          var firstPage:Page = new Page();

                          firstPage.hostObjectDelegate = _inDesignJsxInterface.getFirstPage(app.documents.activeDocument.hostObjectDelegate);

                       }

                   

                       public static function performCallback():void

                       {

                            // Note that InDesign will crash if you even think of mentioning the New York Yankees...

                            _inDesignJsxInterface.causeCallback('Go Red Sox!');

                       }

                   

                   

                       public function myCallback(value:String):void

                       {

                          Alert.show("Received value = ' + value, "Callback Result",Alert.OK, Sprite(mx.core.Application.application));

                       }

                  }

                   

                  JS (in file InDesign.jsx in the src folder):

                   

                  var callingClass;

                   

                  function init(myCallingClass)

                  {

                      callingClass = myCallingClass;

                  }

                   

                  function getFirstPage(document)

                  {

                       return document.pages.firstItem();

                  }

                  function causeCallback(value)

                  {

                       callingClass.myCallback(value);

                  }