36 Replies Latest reply on Mar 28, 2018 1:33 AM by Sudha K

    Menus Enable/Disable (Built-in Menus)

    Sudha K Level 1

      Hi,

       

           We can invoke the menus using MenuActions.  How can i disable/enable InDesign's built-in menus using indesign javascript?

        • 1. Re: Menus Enable/Disable (Built-in Menus)
          Laubender Adobe Community Professional & MVP

          Hi Sudha,

          just ask yourself how you would accomplish that with a user interface action?

           

          That's under Edit/Menus… where you can restrict the view on a menu.

          Never tried to access this by scripting.

           

          Another way is to add an event listener to the menu that listens at the beforeDisplay event and do something—maybe invoking something else?—to prevent that menu from executing. Just a vague idea…

           

          Regards,
          Uwe

          • 2. Re: Menus Enable/Disable (Built-in Menus)
            Colin Flashman Adobe Community Professional

            I'd use Laubender's suggestion with the event listener. I have a startup script that prevents a user from being able to print or export a PDF unless the preflight panel uses a specific preflight profile and has zero issues. The script listens for an Export or Print request and then calls the checkJob function to perform the rest of the script:

             

            var  beforeExport = app.menuActions.itemByName ( "$ID/Export..." ).addEventListener ( "beforeInvoke", checkJob );  
            var  beforePrint = app.menuActions.itemByName ( "$ID/Print..." ).addEventListener ( "beforeInvoke", checkJob );             
            
            

             

            The checkJob function runs just like any other function, but note the "preventDefault()" and "stopPropagation" portions:

            function checkJob(myEvent){    
            //other stuff goes here to make the script do what I want
            myEvent.preventDefault();  
            myEvent.stopPropagation();  
            exit(0);}
            
            
            1 person found this helpful
            • 3. Re: Menus Enable/Disable (Built-in Menus)
              Laubender Adobe Community Professional & MVP

              Hi Colin,

              yes. And there is another thing what can be done with menus. One could use merhod remove() on them.
              But then the problem is to add them to the application again without doing a new install of InDesign.
              I would never try that on purpose… Just wanted to add this option to the repertoire of harsh actions ;-)

               

              Regards,
              Uwe

              • 4. Re: Menus Enable/Disable (Built-in Menus)
                Colin Flashman Adobe Community Professional

                G'day Uwe

                 

                I agree, I would not use the remove() method either... that's a rabbit-hole that is NOT worth exploring! I like the event listener option because it's easy to remove a startup script if it's causing too much grief, whereas restoring removed menu items (as I understand it) would be done through either a reinstall or trashing preferences, two things I dislike doing.

                • 5. Re: Menus Enable/Disable (Built-in Menus)
                  Sudha K Level 1

                  Hi,

                   

                       Thank you for your replies...

                   

                       I want to do disable Export Menu. Using event listener we can do some process. but how to disable that menu like Export and print?

                   

                       Can u pls suggest any links or documents to learn startup scripts..

                  • 6. Re: Menus Enable/Disable (Built-in Menus)
                    Colin Flashman Adobe Community Professional

                    Sudha K

                    Perhaps have a look at my video that features the startup script in question: Episode 19: Preflight overview and "enforcer" scripts - YouTube

                    If you want the startup script, please contact me via my website that is linked in the Youtube video. The script is free but I'm trying to gauge interest in the script at this stage.

                    • 7. Re: Menus Enable/Disable (Built-in Menus)
                      Sudha K Level 1

                      Hi,

                       

                           Ok... I could not able to look that video due to connectivity.

                       

                           Can u pls suggest any links or discussion...

                       

                           I can get the code for invoke and do further coding but don't know how to disable specific menus..

                      • 8. Re: Menus Enable/Disable (Built-in Menus)
                        Sudha K Level 1

                        Hi,

                         

                             I am trying the startup script using the below code.  But its throwing the attached warning.

                         

                        error.png

                         

                        #target indesign

                         

                        #targetengine 'onOpen'

                         

                        (function() {

                         

                          app.eventListeners.add("afterOpen", afterOpen);

                         

                          function afterOpen(myEvent) {   

                                var doc = app.activeDocument;

                                app.menuActions.itemByName ( "$ID/Export..." ).enabled = false;

                                alert(doc.name);       

                           }

                         

                        }())

                         

                             Is it possible to disable indesign's menu item "Export" and "Print"?

                        • 9. Re: Menus Enable/Disable (Built-in Menus)
                          Laubender Adobe Community Professional & MVP

                          Hi Sudha,

                          you forgot one function: If you want to disable "Export" you have also to disable the Packaging feature where an export to IDML and PDF is possible.

                           

                          A solution:

                          You can add an event listener to the beforeExport and beforePrint events.

                          Search the forum, there are some examples waiting for you.

                           

                          Regarding packaging see into this threads here:

                          Get Packaged Folder Path [JS]

                          Stop Packaging based on file path [JS]

                           

                          Regards,
                          Uwe

                          • 10. Re: Menus Enable/Disable (Built-in Menus)
                            Sudha K Level 1

                            Hi,

                             

                                 Thank you so much....

                             

                                 I have used the below code... Place the script into startup script folder. If i click the menu Export and Package, nothing is happen. So i think its working. My doubt is..

                             

                            1. The below code is stop the process of "Export" functionality. Its not showing the menu as like disabled. How to show the menu as disabled.

                             

                            2.  When we need to disable the menu "Export", why should we disable the menu "Package".

                             

                                  Can you pls clarify...

                             

                             

                            #target indesign

                             

                            app.menuActions.itemByID (39938).addEventListener ("beforeInvoke", disableProcess);      // Package Menu

                            app.menuActions.itemByID (113411).addEventListener ("beforeInvoke", disableProcess);     // Export Menu

                             

                            function disableProcess(evt)

                            {

                                evt.stopPropagation();

                                evt.preventDefault();

                                return;

                            }

                            • 11. Re: Menus Enable/Disable (Built-in Menus)
                              Colin Flashman Adobe Community Professional

                              Hello there again.

                               

                              in relation to your questions in your last post (in order):

                              1: Have a look at the conversation that Uwe and I were having earlier in this post and you can see that we agree that adding "destructive" elements to the startup script (such as remove() are not a good idea and that neither of us would implement them). It's not impossible to do, but it's information that we think is not a good idea to have in the public domain for other readers to misinterpret or misuse.

                              2: Uwe has highlighted a workaround that someone could use if they realise they can't export a PDF using either the file menu, keyboard shortcut or quick apply menu. If using the package feature, a PDF can successfully be made, despite the event listener looking for the "export" function. Similarly, if someone makes the ID file a data merge file and then chooses to export to PDF through the Data Merge palette, this is another workaround that won't trigger the event listener.

                               

                              While testing my preflight enforcer scripts to confirm the last two paragraphs, I've indeed discovered faults with them that I will put down to the latest version of ID (I haven't tested the scripts in a while, there's been no demand for it).

                              • 12. Re: Menus Enable/Disable (Built-in Menus)
                                Laubender Adobe Community Professional & MVP

                                https://forums.adobe.com/people/Colin+Flashman  wrote

                                … 1: Have a look at the conversation that Uwe and I were having earlier in this post and you can see that we agree that adding "destructive" elements to the startup script (such as remove() are not a good idea and that neither of us would implement them). It's not impossible to do, but it's information that we think is not a good idea to have in the public domain for other readers to misinterpret or misuse.

                                Hi Colin,

                                using remove() on a menu would not show it at all.
                                It would not show it disabled ( grayed out ).

                                 

                                I don't think one could show menus like Export… and Package… as disabled.

                                At least not the original InDesign ones.

                                 

                                One way could be to remove them at all and add new menus with the same name and show them as disabled perhaps.

                                But then you have the problem to add the original menus again if you want to. That would require a reinstall of InDesign and trashing preferences and/or cleaning the cache. Perhaps only cleaning the cache ( never tried that ).

                                 

                                Regards,
                                Uwe

                                1 person found this helpful
                                • 13. Re: Menus Enable/Disable (Built-in Menus)
                                  Sudha K Level 1

                                  Hi,

                                   

                                       I don't want to remove and all... Its enough to stop the process alone.

                                   

                                       Thank you for ur patient reply... Thank you..

                                   

                                       Any error in my code.. Its not working now...  I dont know the reason...

                                  • 14. Re: Menus Enable/Disable (Built-in Menus)
                                    Sudha K Level 1

                                    Hi,

                                     

                                         I have commented below  line. so its not working...

                                     

                                         #targetengine 'onOpen'

                                     

                                         What is the uses of "target" and "targetengine" and when and how to use it??

                                     

                                         I am new to startup script... is there is any basic tutorial or documents to learn startup script?

                                    • 15. Re: Menus Enable/Disable (Built-in Menus)
                                      Colin Flashman Adobe Community Professional

                                      Here is another resource you may find interesting: Prevent executing menu items | IndiSnip [InDesign® Snippets]

                                      So far as tutorials, if you download the Javascript SDK InDesign SDKs and tools | Adobe Developer Connection  there are some eventlistener tutorials that may assist you.

                                      • 16. Re: Menus Enable/Disable (Built-in Menus)
                                        Sudha K Level 1

                                        Thank you...

                                         

                                         

                                        I will check the given links...

                                        • 17. Re: Menus Enable/Disable (Built-in Menus)
                                          Laubender Adobe Community Professional & MVP

                                          Hi,

                                          you could test your script without being a start-up script first.

                                           

                                          Best would be to include a "toggle" functionality:

                                          Start the script: The event listeners will be added.

                                          Start the script a second time: The event listeners will be removed.

                                           

                                          Include alert messages.

                                           

                                          How would that work? Identify your event listeners by name. For example:

                                           

                                          ( function()
                                          {
                                          #targetengine "bestChooseUniqueNameHere"
                                          var myEventListenerName = "givenName";
                                          var myEventListener = app.menuActions.itemByID(39938).eventListeners.itemByName( myEventListenerName );
                                          if( myEventListener.isValid ){ myEventListener.remove(); alert("Listener removed."); return } // End script here!
                                          
                                          myEventListener = app.menuActions.itemByID(39938).addEventListener("beforeInvoke", disableProcess);
                                          myEventListener.name = myEventListenerName ;
                                          alert("Listener added!");
                                          // …
                                          }() )
                                          

                                           

                                          So you see, you can give event listeners names.

                                          Look into this: Adobe InDesign CS6 (8.0) Object Model JS: EventListener

                                           

                                          Otherwise you always have to restart InDesign if something goes wrong.
                                          Or you need a second script to remove it…

                                           

                                          app.menuActions.itemByID(39938).eventListeners.everyItem().remove();
                                          

                                           

                                          Regards,
                                          Uwe

                                          • 18. Re: Menus Enable/Disable (Built-in Menus)
                                            Sudha K Level 1

                                            HI,

                                             

                                                 I run the code given above.  It gives the alert for "Listener added" but did not give any alert for "Listener removed". I quit the application and run the script.

                                             

                                                 My doubt is, startup script start to work when indesign is on.  When application is quit, event listener wont get removed??

                                             

                                            Screen Shot 2018-03-13 at 7.21.53 AM.png

                                             

                                                 Scripts all will load when app is on.. Then how to call it as second script?

                                             

                                                 Can I use like this...

                                             

                                             

                                            #target indesign

                                             

                                            #targetengine 'onOpen'

                                             

                                            var elPackageName = "PackageEventListner";

                                            var elPackage = app.menuActions.itemByID(39938).eventListeners.itemByName( elPackageName );

                                             

                                            if(elPackage.isValid)

                                            {

                                                elPackage.remove();

                                            }

                                             

                                            var elExportName = "ExportEventListner";

                                            var elExport = app.menuActions.itemByID(39938).eventListeners.itemByName( elExportName );

                                             

                                            if(elExport.isValid)

                                            {

                                                elExport.remove();

                                            }

                                             

                                            var elExportToPDFName = "PackageEventListner";

                                            var elExportToPDF = app.menuActions.itemByID(39938).eventListeners.itemByName( elExportToPDFName );

                                             

                                            if(elExportToPDF.isValid)

                                            {

                                                elExportToPDF.remove();

                                            }

                                             

                                            var elPackage = app.menuActions.itemByID (39938).addEventListener ("beforeInvoke", disableProcess);      // Package

                                             

                                            var elExport =  app.menuActions.itemByID (113411).addEventListener ("beforeInvoke", disableProcess);     // Export...

                                             

                                            var elExportToPDF =  app.menuActions.itemByID (108046).addEventListener ("beforeInvoke", disableProcess);     // Export To PDF

                                             

                                             

                                             

                                            function disableProcess(evt)

                                                evt.stopPropagation();

                                                evt.preventDefault();

                                                return;

                                            }

                                            • 19. Re: Menus Enable/Disable (Built-in Menus)
                                              Laubender Adobe Community Professional & MVP

                                              https://forums.adobe.com/people/Sudha+K  wrote

                                               

                                              HI,

                                               

                                                   I run the code given above.  It gives the alert for "Listener added" but did not give any alert for "Listener removed". I quit the application and run the script. …

                                               

                                              Hi,

                                              if you run my script snippet above ( you have to add the handler function disableProcess ) from the ESTK or with a double-click from InDesign's Scripts Panel the listener will be added. An alert is showing this. Now to remove the listener you have to run it a second time. That's the thought behind the "toggle" functionality of the snippet. I tested this and it should work as I described it.

                                               

                                              To answer your second question: Yes, the event listener is removed if you quit InDesign.
                                              Therefore: For a permanent solution you have to run the script as startup-script.

                                               

                                              I think it's tedious if one is in a testing/debugging phase to permanently quit and restart InDesign to get a clean environment if one want to change code and try things out. So I suggested the toggle functionality…

                                               

                                              That's all to it.

                                               

                                              Regards,
                                              Uwe

                                              • 20. Re: Menus Enable/Disable (Built-in Menus)
                                                Marc Autret Level 5

                                                Hi Sudha,

                                                 

                                                 

                                                [It seems to me that most of the points discussed above have already been touched by my fellows in sparse existing threads. Anyway the subject remains specially difficult to beginners and it's probably worthwhile to summarize the picture, so let's try!]

                                                 

                                                 

                                                The general issue in dealing with menu items (including associated actions, event listeners, etc.) is to get a clear understanding of object lifecycles in InDesign scripting model. Most of us have gradually grasped these subtleties, although there are still many secrets to discover.

                                                 

                                                In short, what you MUST know before going any further is:

                                                 

                                                0. Menus and Submenus own MenuItems which are connected to InDesign processes through MenuActions (and ScriptMenuActions, but I'll leave that aside.) On the other hand, Events may be connected to custom callback functions through EventListeners. Most—if not all—InDesign entities can be the target of some event, and this includes Menus (cf beforeDisplay) and MenuActions (cf beforeInvoke), but also PageItems or even the app itself. In your example, though, MenuActions are the actual center of interest.

                                                 

                                                Lifecycles:

                                                 

                                                1. As objects, native InDesign MenuActions are permanent. That is, you can't remove or change them, ever.

                                                 

                                                2. As objects, Menus, Submenus and MenuItems are application-persistent. That is, if you remove or change something in that space, these changes will persist beyond the ID session. That's a crucial and not very intuitive fact.

                                                 

                                                3. As objects, EventListeners (and ScriptMenuActions, but ok, let's really forget them) are always session-persistent. That is, changes in that space are intended to persist throughout the whole ID session, until you quit the app.

                                                 

                                                4. Finally, your event handlers—that is, the callback functions contained in your JSX code and attached to particular events via EventListeners—are at best engine-persistent (if a #targetengine directive is active) or simply “script-persistent”, in other words purely volatile, if you run in the default main engine.

                                                 

                                                Note: There are in fact more persistent event handlers, those which are attached as JSX File objects.

                                                See also: Indiscripts :: How to Create your Own InDesign Menus

                                                 

                                                Now you can clearly see that attaching an event handler to a MenuAction (invoked from a MenuItem) via a freshly created EventListener, may cause some issues if not carefully designed. For example, you may have an EventListener still alive—in the session—whose callback function is yet dead. In other threads we also discussed the problem of having a custom Menu and its MenuItem children (all application-persistent) waiting for an appropriate EventListener to wake up—which can be achieved with startup scripts only.

                                                 

                                                So, the very first step is to clearly have in mind how these respective lifecycles have to be dealt with and connected in any project that interacts with such objects. The gold rule is, you need at least two distinct stages:

                                                 

                                                (A) The Install Stage. This is the part of your code that initializes the persistent objects to be connected and used throughout the scope (usually, the engine) so that things are guaranteed to exist when you'll need them. That's typically the place to declare event handlers (but not to call them!), and to manage EventListeners to be either created or destroyed, not to mention menu structure, etc. In most projects the Install Stage is intended to run once per session, but since it could be manually executed again and again by an inquiring user, we must prevent troubles with object duplication.

                                                 

                                                (B) The Script-In-Action Stage. Ideally, This Should Be an Empty Zone! Indeed, when installing event handlers, what you want is just to process outside events (that may or will happen later), hence the script itself should have nothing more to do than installing (once.) I think it important to stress this point because some scripters have trouble capturing it well: the script "in action" does basically nothing once installed. The real process is delayed to event handlers that wait patiently to take action.

                                                 

                                                However, there are cases where (B) can have a job, namely, the job of reversing (A). This is what seems to emerge from reading the previous posts. The script, apart from the fact that it sets up listeners and event handlers, may be thought as a switch that toggles the whole event processing. So we create, within the Install area, a slightly enhanced function—say toggleListeners—designed to address this special feature.

                                                 

                                                Now, better is to provide a (generously commented) code to illustrate the approach I recommend:

                                                 

                                                //==========================================================================
                                                // We definitely need a session-persistent engine to keep our event
                                                // handler(s) alive, so we use the #targetengine directive.
                                                //==========================================================================
                                                
                                                #targetengine 'ExportAndPackageSpy'
                                                
                                                
                                                //==========================================================================
                                                // Since we have a session-persistent engine, executing the
                                                // present script shouldn't cause re-declaration of existing
                                                // data. The following conditional block takes this into
                                                // account and provides the 'installation' brick.
                                                //==========================================================================
                                                
                                                if( !$.global.hasOwnProperty('DATA') )
                                                {
                                                    // Builds a set of native MenuActions of interest.
                                                    //----------------------------------
                                                    $.global.DATA = (function(  o,r)
                                                        {
                                                            // Register package&export action specifiers, and other hosts if needed.
                                                            // ---
                                                            o = app.menuActions;
                                                            r = {
                                                                Package:   { host:o.itemByName("$ID/Package...").toSpecifier(),    etp:'beforeInvoke' },
                                                                Export:    { host:o.itemByName("$ID/Export...").toSpecifier(),     etp:'beforeInvoke' },
                                                                PdfExport: { host:o.itemByName("$ID/Export To PDF").toSpecifier(), etp:'beforeInvoke' },
                                                                };
                                                
                                                            // In addition you'd like to catch PDF 'sub-actions' which 'Export To
                                                            // PDF' does not cover: [High Quality Print]..., [PDF/X-1a:2001]...,
                                                            // etc. Unfortunately, the listeners of those menu actions do not work!
                                                            // As a fallback mechanism you can globally spy the beforeExport event.
                                                            // It occurs *after* menu actions but can still be used to prevent
                                                            // the user from exporting the document by unexpected means.
                                                            // ---
                                                            r['AnyExport'] = { host:app.toSpecifier(), etp:'beforeExport' };
                                                
                                                            // Debug.
                                                            // alert( r.toSource() );
                                                
                                                            return r;
                                                        })();
                                                
                                                
                                                    // Defines the *actual function to be executed* by the
                                                    // present script. In this particular case a 'toggle' feature
                                                    // is wanted in order to turn listening ON/OFF. This process
                                                    // is slighlty different from a pure menu installer but most
                                                    // implementations use very similar tricks.
                                                    //----------------------------------
                                                    $.global.toggleListeners = function(/*fct*/callback,  loading,k,o,a,t)
                                                    {
                                                        // Even if a default callback is provided below, making it
                                                        // visible as an input argument improves the modularity of
                                                        // the code. (Technically, we could attach other event
                                                        // handlers as well.)
                                                        // ---
                                                        'function' == typeof callback || (callback=$.global.disableProcess);
                                                        
                                                        // Paranoid checkpoint.
                                                        // ---
                                                        if( 'function' != typeof callback) throw "No function callback supplied!"
                                                
                                                        // Here we use the function itself (callee) as a 'flag keeper,'
                                                        // taking advantage of its persistence. If loading is 1,
                                                        // listeners are to be added.
                                                        // ---
                                                        loading = 1 - (callee.LOADED||0);
                                                
                                                        // Loop in the DATA.
                                                        // ---
                                                        for( k in DATA )
                                                        {
                                                            if( !DATA.hasOwnProperty(k) ) continue;
                                                
                                                            // Collection of event listeners registered for this
                                                            // menu action.
                                                            // ---
                                                            o = resolve(DATA[k].host).eventListeners;
                                                
                                                            // *In any case*, remove any existing listener that matches
                                                            // callback. This prevents debug or non-well-formed code from
                                                            // duplicating listeners throughout the current session
                                                            // (should #targetengine be missing or other bug occur...)
                                                            // ---
                                                            a = o.length ? o.everyItem().getElements() : [];
                                                            while( t=a.pop() ) t.handler===callback && t.remove();
                                                
                                                            if( !loading ) continue;
                                                
                                                            // If loading is required, add the listener.
                                                            // ---
                                                            o.add(DATA[k].etp, callback);
                                                        }
                                                
                                                        // Upate the internal flag.
                                                        // ---
                                                        callee.LOADED = loading;
                                                
                                                        // Debug.
                                                        alert( loading ? "Listeners LOADED." : "Listeners UNLOADED.");
                                                    };
                                                
                                                
                                                    // Now comes the particular callback being invoked when any of the
                                                    // spied events occurs. A critical property of this function is to
                                                    // remain in memory as long as the event listeners may exist. Since
                                                    // they are by nature session-persistent, we need a session-persistent
                                                    // function as well (or a File, in other implementations.)
                                                    // ---
                                                    // This part of the code entirely depends on your specific goal. In
                                                    // your example the actions have to be inhibited (likely under some
                                                    // additional conditions?) Here we simply cancel the event, using
                                                    // the fact that both BEFORE_INVOKE & BEFORE_EXPORT are cancelable.
                                                    //----------------------------------
                                                    $.global.disableProcess = function(/*Event*/ev)
                                                    {
                                                        // Make sure no other hypothetical target
                                                        // would catch that event (from now.)
                                                        // ---
                                                        ev.stopPropagation();
                                                
                                                        // Cancels the event. (In some versions, InDesign may prompt
                                                        // a message telling the user that a native action has been
                                                        // cancelled.)
                                                        ev.preventDefault();
                                                
                                                        // Debug.
                                                        alert( "Cancelled event:\r\r" + {}.toSource.call(ev.properties) );
                                                    };
                                                }
                                                
                                                
                                                //==========================================================================
                                                // From this point the installation process is ready (data and functions
                                                // are known to the engine), but no event listener has been either added
                                                // or removed. The below instructions represent the actual finality of
                                                // executing the present script, that is, toggling event listeners. This
                                                // could be performed from a *startup script*, with the effect of turning
                                                // listeners ON (since no flag is attached to the function yet.)
                                                //==========================================================================
                                                
                                                toggleListeners();
                                                
                                                

                                                 

                                                Hope that helps.

                                                Marc

                                                2 people found this helpful
                                                • 21. Re: Menus Enable/Disable (Built-in Menus)
                                                  Laubender Adobe Community Professional & MVP

                                                  https://forums.adobe.com/people/Marc+Autret  wrote

                                                   

                                                   

                                                  Lifecycles:

                                                   

                                                  1. As objects, native InDesign MenuActions are permanent. That is, you can't remove or change them, ever.

                                                  Hi Marc,

                                                  thank you very much for that summary!

                                                   

                                                  We briefly discussed the case that native menus could be removed, but shouldn't. It happened to me once accidently and I had really trouble to get the removed native menu back. In such a case I suppose—I will not test that !—that the menuActions coming along with that native menu are gone as well.

                                                   

                                                  You did mention:

                                                  B) The Script-In-Action Stage. Ideally, This Should Be an Empty Zone! Indeed, when installing event handlers, what you want is just to process outside events (that may or will happen later), hence the script itself should have nothing more to do than installing (once.) I think it important to stress this point because some scripters have trouble capturing it well: the script "in action" does basically nothing once installed. The real process is delayed to event handlers that wait patiently to take action.

                                                   

                                                  I think, we should never expect that an event handler is there. From the perspective of any #targetengine running at the same time—various startup scripts are running concurrently plus some scripts the user starts from the Scripts Panel—attached listeners are available to all scripts indepenently of the #targetengine they were added from. A script from a different developer could remove them by a careless menu.eventListeners.everyItem().remove() . So the snippet I gave in answer #17 is really bad practice. I only added it as a potential tool in the debugging and development phase of a script.

                                                   

                                                  What can we do about that potential threat?

                                                  Running an eventListener on an idleTask that is checking if all is ok?

                                                   

                                                  That all asked in the light of:

                                                  … the script "in action" does basically nothing once installed. The real process is delayed to event handlers that wait patiently to take action. …

                                                   

                                                  Thanks again,
                                                  Uwe

                                                  • 22. Re: Menus Enable/Disable (Built-in Menus)
                                                    Marc Autret Level 5

                                                    Hi Uwe,

                                                     

                                                    We briefly discussed the case that native menus could be removed, but shouldn't. It happened to me once accidently and I had really trouble to get the removed native menu back. In such a case I suppose—I will not test that !—that the menuActions coming along with that native menu are gone as well.

                                                    (…)

                                                     

                                                    I don't think so, but better would be to ask Adobe team to have a 100% certainty. To my knowledge, you can remove a MenuItem but you cannot remove a native MenuAction, even if it becomes invisible in GUI terms. For example, suppose you remove the File > Open… item [please, readers, don't do that!], my guess is that the underlying menu action still permanently exists.

                                                     

                                                    . . .

                                                     

                                                    OK, let's play guinea pigs! In my CS4 installation (French-localized), I have a menu item named "Programme d'amélioration des produits Adobe..." in the Help (=Aide) submenu. It will never have any function again, since CS4 support is abandoned. So this is a good candidate for the experiment:

                                                     

                                                    var mi = app.menus.itemByName('$ID/Main')
                                                               .submenus.itemByName('$ID/&Help')
                                                               .menuItems.itemByName("Programme d'amélioration des produits Adobe...");
                                                    
                                                    function showActionId(/*MenuItem*/mi)
                                                    //----------------------------------
                                                    // => `0x164ED`
                                                    {
                                                        alert( '0x'+mi.associatedMenuAction.id.toString(16).toUpperCase() )
                                                    }
                                                    
                                                    if( mi.isValid )
                                                    {
                                                        showActionId(mi); // Save it in a const!!!
                                                        mi.remove();      // the menu is gone
                                                    }
                                                    

                                                     

                                                    From now the menu item is gone:

                                                     

                                                    RemovingMenuItem.png

                                                     

                                                    But you know what? I can still invoke the associated menu action:

                                                     

                                                    const AID = 0x164ED;
                                                    
                                                    var ma = app.menuActions.itemByID(AID);
                                                    ma.isValid && ma.invoke();
                                                    

                                                     

                                                    Result:

                                                     

                                                    ImproveScreen.png

                                                     

                                                    @+

                                                    Marc

                                                     

                                                     

                                                    1 person found this helpful
                                                    • 23. Re: Menus Enable/Disable (Built-in Menus)
                                                      Laubender Adobe Community Professional & MVP

                                                      Ah! Thank you for testing that, Marc!

                                                       

                                                      Regards,
                                                      Uwe

                                                      • 24. Re: Menus Enable/Disable (Built-in Menus)
                                                        Marc Autret Level 5

                                                        Laubender  wrote

                                                         

                                                        I think, we should never expect that an event handler is there. From the perspective of any #targetengine running at the same time—various startup scripts are running concurrently plus some scripts the user starts from the Scripts Panel—attached listeners are available to all scripts independently of the #targetengine they were added from. A script from a different developer could remove them by a careless menu.eventListeners.everyItem().remove() . (…)

                                                         

                                                        What can we do about that potential threat?

                                                        Running an eventListener on an idleTask that is checking if all is ok?

                                                         

                                                        You're absolutely right about the potential threat. I seem to remember we touched that topic before.

                                                        A script should NEVER use instructions of the form …eventListeners.everyItem().remove()—unless you are in the process of fixing a critical bug that totally breaks ID!

                                                         

                                                        The reason is, as I wrote above, EventListeners are session-persistent, their lifespan exceeds that of your particular script (which runs in its own engine.) In other words, your script is not the omniscient owner of every event listener currently running. Indeed, parallel scripts (in particular, startup scripts) may have their own stuff installed, based on dedicated listeners. Scripters should keep in mind, in addition, that the same event can be addressed by multiple listeners!

                                                         

                                                        “Running an eventListener on an idleTask that is checking if all is ok?”

                                                         

                                                        That's an option, assuming your enemies won't kill idle tasks as well!

                                                         

                                                        To me the best solution is, scripting ethics & good practices.

                                                         

                                                        @+

                                                        Marc

                                                        • 25. Re: Menus Enable/Disable (Built-in Menus)
                                                          Marc Autret Level 5

                                                          Uwe,

                                                           

                                                          One more word.

                                                           

                                                          In the cleanup part of the code provided at #20, you may notice the condition under which I actually remove a listener:

                                                           

                                                          <listener>.handler===callback && <listener>.remove()

                                                           

                                                          Other implementations may rely on id or name property (name is not CS4-compliant, btw). The advantage of using a strict === check on the handler itself, IMO, it that you are absolutely sure that the handler belongs to your own script—since you delared it in your own engine. We could paraphrase the test as follows: “If I AM THE ONE that is called by an event listener, then I can remove that event listener."

                                                           

                                                          @+

                                                          Marc

                                                          1 person found this helpful
                                                          • 26. Re: Menus Enable/Disable (Built-in Menus)
                                                            Sudha K Level 1

                                                            Hi,

                                                             

                                                                 Thanks for your help...

                                                             

                                                                 I need one more clarification, we can disable the menus functionality using event listener.  Can we disable (stop) the process of only export PDF from Export menu?

                                                             

                                                                 Export menu have multiple options (html, idml, pdf etc..). Can we stop the process of specific file format of export??

                                                            • 27. Re: Menus Enable/Disable (Built-in Menus)
                                                              Marc Autret Level 5

                                                              (…) Can we disable (stop) the process of only export PDF from Export menu?

                                                               

                                                              I think so. The ImportExportEvent object has a format property that should be useful to filter file format.

                                                              In the callback function (disableProcess), you could add a condition of the form:

                                                               

                                                              if( ev.properties.format == … ) etc

                                                               

                                                              @+

                                                              Marc

                                                              • 28. Re: Menus Enable/Disable (Built-in Menus)
                                                                Laubender Adobe Community Professional & MVP

                                                                Hi Sudha,

                                                                see into the properties of the event that goes into your handler function.

                                                                There is property event.fullName with the value of the file that will export.
                                                                You could check the suffix from that and react accordingly.

                                                                 

                                                                Regards;
                                                                Uwe

                                                                • 29. Re: Menus Enable/Disable (Built-in Menus)
                                                                  Laubender Adobe Community Professional & MVP

                                                                  See also DOM documentation for the importExport event. From Jongware:

                                                                  Adobe InDesign CS6 (8.0) Object Model JS: ImportExportEvent

                                                                   

                                                                  Regards,
                                                                  Uwe

                                                                  • 30. Re: Menus Enable/Disable (Built-in Menus)
                                                                    Dirk Becker Level 4

                                                                    You're absolutely right about the potential threat. I seem to remember we touched that topic before.

                                                                    A script should NEVER use instructions of the form …eventListeners.everyItem().remove()—unless you are in the process of fixing a critical bug that totally breaks ID!

                                                                     

                                                                    I plead guilty for removing event listeners in that way as part of testing my code without restarts, but I think it is a bug that the event listeners are shared. Target engines are supposed to be isolated, at the C++ side there is plenty code dedicated to engine awareness. EngineContext or RequestContext pointers passed all over the place. On the other hand, this opens interesting ways of inter-engine communication.

                                                                     

                                                                    #targetengine Foo
                                                                    app.eventListeners.add(Application.AFTER_ACTIVATE,dummy);
                                                                    function dummy(){"Foo!"}
                                                                    dummy.secret = "oops!";
                                                                    $.writeln($.engineName);
                                                                    $.writeln(app.eventListeners.length);
                                                                    

                                                                     

                                                                    #targetengine main
                                                                    var el = app.eventListeners.lastItem();
                                                                    $.writeln($.engineName);
                                                                    $.writeln(el.handler.toSource());
                                                                    $.writeln(el.handler.secret);
                                                                    
                                                                    2 people found this helpful
                                                                    • 31. Re: Menus Enable/Disable (Built-in Menus)
                                                                      Sudha K Level 1

                                                                      Hi,

                                                                       

                                                                           thank you for the reply...

                                                                          

                                                                           I will check and get back...

                                                                      • 32. Re: Menus Enable/Disable (Built-in Menus)
                                                                        Sudha K Level 1

                                                                        HI,

                                                                         

                                                                            The below code stop the process of export pdf using event format beforeExport. But when i click the export menu (Adobe PDF Print) the below dialog appeared and then only process gets stop.  Can I skip this dialog??

                                                                         

                                                                              Similary for Adode PDF (Interactive).

                                                                         

                                                                             Can i use jsxbin file instead of jsx in startup script folder?? it will work without any issue??

                                                                         

                                                                         

                                                                        Screen Shot 2018-03-27 at 9.47.01 AM.png

                                                                         

                                                                        Code:

                                                                         

                                                                        #targetengine "exportPDF"

                                                                         

                                                                        main();

                                                                         

                                                                        function main() {

                                                                            //var myApplicationEventListener = app.eventListeners.add("afterExport", disableExportOption, false);

                                                                            var myApplicationEventListener = app.eventListeners.add("beforeExport", disableExportOption, false);

                                                                        }

                                                                         

                                                                        function disableExportOption(evt) {

                                                                            if(evt.format == "Adobe PDF (Interactive)" || evt.format == "Adobe PDF (Print)")

                                                                            {

                                                                                alert("Don't Export PDF as Manual. Use Script to Export PDF!!");

                                                                                evt.stopPropagation();

                                                                                evt.preventDefault();

                                                                                return;

                                                                            }

                                                                        }

                                                                        • 33. Re: Menus Enable/Disable (Built-in Menus)
                                                                          Marc Autret Level 5

                                                                          Hi Sudha K,

                                                                           

                                                                          As commented in the code at #20, the best solution would have been to listen to the submenu actions [High Quality Print], [PDF/X-1a:2001] and so on, using the beforeInvoke event. I tried this approach first, but it didn't work for me. So we seem to have no choice but to detect the beforeExport event, downstream. Alas, it only occurs once the user has validated the Export Adobe PDF dialog.

                                                                           

                                                                          Maybe there is a way to hook that dialog, I don't know.

                                                                           

                                                                          > Can i use jsxbin file instead of jsx in startup script folder?? it will work without any issue??

                                                                           

                                                                          1. Compile the script without its #targetengine directive.

                                                                          2. Open the jsxbin in an editor, remove line breaks and copy the entire string.

                                                                          3. Create a jsx with:

                                                                           

                                                                          #targetengine "<yourEngine>"

                                                                          eval("<yourJsxBinString>");

                                                                           

                                                                          @+

                                                                          Marc

                                                                          1 person found this helpful
                                                                          • 34. Re: Menus Enable/Disable (Built-in Menus)
                                                                            Marc Autret Level 5

                                                                            Hi Dirk,

                                                                             

                                                                            I plead guilty for removing event listeners in that way as part of testing my code without restarts, but I think it is a bug that the event listeners are shared. Target engines are supposed to be isolated, at the C++ side there is plenty code dedicated to engine awareness. EngineContext or RequestContext pointers passed all over the place. On the other hand, this opens interesting ways of inter-engine communication.

                                                                             

                                                                            #targetengine Foo app.eventListeners.add(Application.AFTER_ACTIVATE,dummy); function dummy(){"Foo!"} dummy.secret = "oops!"; $.writeln($.engineName); $.writeln(app.eventListeners.length);

                                                                             

                                                                            #targetengine main var el = app.eventListeners.lastItem(); $.writeln($.engineName); $.writeln(el.handler.toSource()); $.writeln(el.handler.secret);

                                                                             

                                                                            Nice trick. You need to access the right eventListener though—and lastItem() is usually not a safe specifier ;-)

                                                                            Also, itemByName(myUniqueIdentifier) is not supported in CS4 (for eventListeners.)

                                                                            So in absolute terms we either need a unique DOM id (which is not necessarily known from the co-script at hard-coding time), or some lookup mechanism throughout existing listeners and their associated handlers.

                                                                             

                                                                            Question: What's your opinion about using $.setenv() and $.getenv() to share data across the session? I use that approach in IdExtenso, in particular in the Settings module. To your knowledge, is there any drawback with it?

                                                                             

                                                                            Best,

                                                                            Marc

                                                                            • 35. Re: Menus Enable/Disable (Built-in Menus)
                                                                              Dirk Becker Level 4

                                                                              Marc, of course you could add the event listener to some obscure object where nobody looks. Anyway it is a hack and I would not be surprised if the next garbage collection blows up straight into your face, or similar side effects.

                                                                               

                                                                              Regarding $.getenv, that is for processes sharing string values with child processes. So if you launch InDesign from a shell script and want to pass a file name, that could be an option. Pick up the Unix user name. Also the opposite way, when you fork sub-processes from InDesign. I recently learned that Photoshop has app.system, maybe even File.execute would pass the environment. Better don't use it to store gigabytes, and the environment is shorter lived than app.insertLabel and friends. Also avoid variables that have special meanings, e.g. DYLD_LIBRARY_PATH.

                                                                              • 36. Re: Menus Enable/Disable (Built-in Menus)
                                                                                Sudha K Level 1

                                                                                Hi,

                                                                                 

                                                                                     Thank you.... Its working...