Skip navigation
Replies 1 2 Previous Next
  • Currently Being Moderated
    Dec 18, 2011 6:10 AM   in reply to Dan Rodney

    Great.

     

    I infer that my code did not work for you (although I don't know why).

     

    OK, considering the final "Correct Answer," I just would like to point out that your event handlers (menuItem1Handler, menuItem2Handler...) are all unnecessary. You can directly supply a script File as second argument in the eventListeners.add() method. In addition, your code does not check whether the corresponding files actually exist, so it does not accordingly update the menu items if some feature is missing.

     

    @+
    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 6:35 AM   in reply to Marc Autret

    Hi Marc,

     

    I wouldn't infer any such thing. Looking at your code, it probably works fine.

     

    Chances are, my code was probably easier to read...

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 7:13 AM   in reply to Harbs.

    Harbs. wrote:

     

    Chances are, my code was probably easier to read...

     

    Well, in this area, I think "all is relative" but I'm not going to argue this specific point.

     

    Now, let's suppose that someone wants to use your menu loader in another project having a different number of menu items and submenus. Say he wants to obtain the following hierarchy:

     

    MyMenu

       MyFeature1
       MyFeature2

       MySubmenuA

          MyFeatureA1

          MyFeatureA2

          MyFeatureA3

       MySubmenuB

          MyFeatureB1

          MyFeatureB2

    etc.

     

    Do you see how many changes he needs to do in your code?

     

    In the solution I suggest, he only has  to update the FEATURES array this way:

     

    FEATURES = [
       { caption: "MyFeature1", fileName: "File-One.jsx", subName: "" },
       { caption: "MyFeature2", fileName: "File-Two.jsx", subName: "" },

     

       { caption: "MyFeatureA1", fileName: "File-A-One.jsx", subName: "MySubmenuA" },
       { caption: "MyFeatureA2", fileName: "File-A-Two.jsx", subName: "MySubmenuA" },
       { caption: "MyFeatureA3", fileName: "File-A-Three.jsx", subName: "MySubmenuA" },

     

       { caption: "MyFeatureB1", fileName: "File-B-One.jsx", subName: "MySubmenuB" },
       { caption: "MyFeatureB2", fileName: "File-B-Two.jsx", subName: "MySubmenuB" }

       ]

     

    Is this less readable?

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 7:37 AM   in reply to Marc Autret

    Like you said, it's relative. I personally find your code a pleasure to read, but my natural style is a bit different.

     

    It really depends on your background.

     

    If you have a strong OOP background, your code is pure poetry!

     

    If you don't have an OOP background, it takes a lot of mental overhead to follow how the code is supposed to work.

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 7:41 AM   in reply to Marc Autret

    When I answer questions, I try to stick as closely to the coding style of the OP as I can, to help answer the question at hand. (It helps clarify the answer in few words -- and I don't enjoy excessive writing...)

     

    Chances are I'm not going to change anyone's coding style in a single forum post...

     
    |
    Mark as:
  • John Hawkinson
    5,512 posts
    Jun 25, 2009
    Currently Being Moderated
    Dec 18, 2011 7:41 AM   in reply to Marc Autret

    Hey, Marc: I'm going to be sort of blunt. Your code is hard for most people to read because it uses Javascript idioms they are entirely unfamiliar with, which don't make a lot of sense to people not really familiar with the language. And that's what most people here are. Let's take a walk through it:


    (function(/*obj|undefined*/HOST)

     

    The comment itself is confusing. Actually, it's even confusing to me.

     

     

        HOST || (HOST=$.global);

     

     

    Tbe || idiom is confusing. Most people don't know what it means offhand.

     

        // ---
        // Prevent the current (startup) script from being uselessly rerun
        // ---
        if( HOST[$.engineName] )
            {
            alert( "This script is automatically executed at startup. You shouldn't run it manually." );

    Well, this isn't confusing, but I think it's bad. One of the important things to do is to test what happens when the menus already exist, and that's easiest to do by rerunning the script.

     

     

        var MENU_NAME = "My Test Menu",

     

     

    All caps for a function-local variable? Even using all caps for a globally scoped variable (Crockford) is confusing, but for a function-scope variable? That confuses me!

     

     

            FEATURES = [
                { caption: "My Menu Item 1", fileName: 'File-One.jsx', subName: "" },

     

     

    Use of Objects is justified here, but they are probably confusing.

     

     

            FEATURE_LOCATION_PATH = (function()

     

     

    Anonymous functions...definitely confusing! I'm also not sure what the point of this function heere is. Why not execute the code directly

    on the next line?

     

                try{ f=app.activeScript; }
                catch(_){ f=File(_.fileName); }

     

    Variables named "_"? Confusing!

     

                })();

     

    And this is why anonymous functions are confusing! Not much to be done about it, but why use one where you don't need to. It's not like we're polluting the global namespace here.

     

     

        while( i-- )

     

     

    Use of a while loop is a totally legitimate style choice, but I think it's typically less readable than a for loop. YMMV, of course!

     

            t = FEATURES[i];

     

    I'm horribly guilty of this, but single-letter variable names are not the most readable.

     

                (t.action = app.scriptMenuActions.add( t.caption )).
                    addEventListener('onInvoke', f);

     

    More parentheses imply more mental gymnastics to understand. Breaking this into two lines,

    with t.action=addEventListener... would help readability.

     

      var s,
            n = FEATURES.length,
            subs = {},
            sub = null;

     

    Wait, a mid-function var block? Gasp! What's up with that? Crockford's right on this. One var statement and all at the top.

    I am not sure why we're initializing sub to null -- what's wrong with the good old undefined? This probably doesn't qualify as confusing.

     

        for( i=0 ; i < n ; ++i )

     

    Caching FEATURES.length in n is good for performance, but it probably doesn't matter here, and makes it more confusing to read. Not by much, but let's say half a confusion point. I would also say that "++i" is harder to read than "i++", maybe to the tune of 0.1 confusion-points, but maybe that's just me. YMMV Extremely.

            sub = (s=t.subName) ?
                ( subs[s] || (subs[s]=mnu.submenus.add( s, LO_END )) ) :
                mnu;

    The ternary conditional operator, ?:, is pretty much always hard to read. And it's worse with short-circuit or-ing, ||, or three close-parens in rapid succession. Of course ?: tends to promote extra () as it almost always becomes ()?(): so...

     


            }
    })();

     

    And then it's worth re-emphasizing, basically nobody understands the anonymous function paradigm .

     

    So there we have it, that's why I think your code is confusing to most readers.

    (On the other hand Dan's final code ignores my recommendation and still has those abysmal ==null tests in there. What's up with that? )

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 7:50 AM   in reply to Dan Rodney

    That's odd. John's post seems to exist, but doesn't show up...

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 7:51 AM   in reply to Harbs.

    That seemed to do it... Weird...

     
    |
    Mark as:
  • John Hawkinson
    5,512 posts
    Jun 25, 2009
    Currently Being Moderated
    Dec 18, 2011 8:11 AM   in reply to Harbs.

    That's odd. John's post seems to exist, but doesn't show up...

     

    It's worse than that. Cache corruption.

    Viewing from adobe-vm-wa06.sgvm2hosted.jiveland.com

    I see my post but not your replies. Dumping cookies and reloading

    fixes it, because I get another server.

    I'll start a thread in Forum Comments.

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 8:17 AM   in reply to John Hawkinson

    OK guys. Once again I admit my coding style has many faults and I really do not claim it is better than any other. It's just my way. I use it because I understand it better, I make it more easily evolve and I identify more easily the internal logic. But it's only because I used to do like that, and what is right for someone may definitely be wrong for someone else.

     

    Anyway, my point is not about style. I'm just talking about factorization and reusability. Let down my code in itself, just consider the approach I suggest. What I mean is that the response considered correct has some issues and can be improved clearing useless event handlers, adding file checking, removing global vars and, why not, supporting reusability.

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 8:58 AM   in reply to Dan Rodney

    Dan Rodney wrote:

     

    Marc. Is it possible to insert menu dividers in your example? And if so, how?

     

    You mean menuSeparators, right?

     

    I slightly expanded the code to support the following syntax:

     

     

    FEATURES = [
       { caption: "My Menu Item 1", fileName: 'File-One.jsx', subName: "" },
       { separator: true, subName: "" },
       { caption: "My Menu Item 2", fileName: 'File-Two.jsx', subName: "My Sub Menu" },
       { separator: true, subName: "My Sub Menu" },
       { caption: "My Menu Item 3", fileName: 'File-Three.jsx', subName: "My Sub Menu" }
    ]
    

     

    Also, I removed the #targetengine stuf and the HOST argument. As John said, this is uselessly complicated for such a project. Note that this startup script does not need to run in a persistent engine.

    Here is a possible implementation:

     

    // MenuLoader
    // (#targetengine is not required)
     
    (function()
    // -------------------------------------
    // Install and/or update the menu/submenu and connect
    // the corresponding menu actions if script files are available
    {
        // Settings and constants
        // ---
        var MENU_NAME = "My Test Menu",
            FEATURES = [
                { caption: "My Menu Item 1", fileName: "File-One.jsx", subName: "" },
                { separator: true, subName: "" },
                { caption: "My Menu Item 2", fileName: "File-Two.jsx", subName: "My Sub Menu" },
                { separator: true, subName: "My Sub Menu" },
                { caption: "My Menu Item 3", fileName: "File-Three.jsx", subName: "My Sub Menu" }
                ],
            LO_END = LocationOptions.atEnd,
            INDESIGN_ROOT_MENU = app.menus.item( '$ID/Main' ),
            FEATURE_LOCATION_PATH = (function()
                {
                var f;
                try{ f=app.activeScript; }
                catch(_){ f=File(_.fileName); }
                return f.parent.parent + '/';
                })();
     
        // (Re)set the actions
        // Note: checks also whether script files are available
        // ---
        var    t, f,
            i = FEATURES.length;
        while( i-- )
            {
            t = FEATURES[i];
            if( t.separator ) continue;
     
            if( (f=File(FEATURE_LOCATION_PATH + t.fileName)).exists )
                {
                // The script file exists => create the corresponding action
                // and directly attach the event listener to the file
                // (no need to use app.doScript(...) here)
                // ---
                (t.action = app.scriptMenuActions.add( t.caption )).
                    addEventListener('onInvoke', f);
                }
            else
                {
                // The script file does not exist => remove that feature
                // ---
                FEATURES.splice(i,1);
                }
            }
     
        // ---
        // Create/reset the custom menu container *if necessary*
        // Note:  menus/submenus are application-persistent
        // ---
        var    mnu = INDESIGN_ROOT_MENU.submenus.itemByName( MENU_NAME );
        if( !mnu.isValid )
            {
            // Our custom menu hasn't been created yet
            // ---
            if( !FEATURES.length ) return;
            mnu = INDESIGN_ROOT_MENU.submenus.add(
                MENU_NAME,
                LocationOptions.after,
                INDESIGN_ROOT_MENU.submenus.item( '$ID/&Window' )
                );
            }
        else
            {
            // Our custom menu already exists, but we must clear
            // any sub element in order to rebuild a fresh structure
            // ---
            mnu.menuElements.everyItem().remove();
     
            // If FEATURES is empty, remove the menu itself
            // ---
            if( !FEATURES.length ){ mnu.remove(); return; }
            }
     
        // ---
        // Now, let's fill mnu with respect to FEATURES' order
        // (Possible submenus are specified in .subName and created on the fly)
        // ---
        var s,
            n = FEATURES.length,
            subs = {},
            sub = null;
        for( i=0 ; i < n ; ++i )
            {
            t = FEATURES[i];
     
            // Target the desired submenu
            // ---
            sub = (s=t.subName) ?
                ( subs[s] || (subs[s]=mnu.submenus.add( s, LO_END )) ) :
                mnu;
     
            // Connect the related action OR create a separator
            // ---
            if( t.separator )
                sub.menuSeparators.add( LO_END);
            else
                sub.menuItems.add( t.action, LO_END );
            }
    })();
    

     

    menuLoader.png

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 10:50 AM   in reply to Dan Rodney

    About isValid missing in CS3, you could try sth like this:

     

    // Declare isValid() at the beginning of the current scope/script
    // ---
    var isValid = ( parseFloat(app.version) >= 6 ) ?
        function(o)
        {
            return o.isValid;
        } :
        function(o)
        {
            var r = false;
            try    {
                ('id' in o && o.id) ||
                ('index' in o && o.index);
                r = true;
                }
            catch(_){}
            return r;
        };
    

     

    Then replace myObj.isValid by isValid(myObj) in the entire code.

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 11:13 AM   in reply to Marc Autret

    null works perfectly well for menu actions. I'm not sure why we're making a deal of this...

     

    FWIW, here's the IsValid function that I use:

     

    IsValid = function (obj){
        try{
            if(!obj){return false}
            if(kAppVersion>=6){
                return obj.isValid;
            }
            var test = obj.parent;
            return true;
        }
        catch(err){return false;}
    }
    

     

    kAppVersion is a constant I have defined like so:

     

    kAppVersion = parseFloat(app.version);
    

     

    (Every valid object in InDesign has a parent.)

     

    Harbs


    ( P.S. The test variable name is extraneous, but it makes it obvious what it's doing...)

     
    |
    Mark as:
  • John Hawkinson
    5,512 posts
    Jun 25, 2009
    Currently Being Moderated
    Dec 18, 2011 11:20 AM   in reply to Dan Rodney

    John, as for the ==null tests, they work in CS3 and later. If I switch to isValid that only works in CS5 (from what I understand). What cross-version compatible code do you think is better?

    Oh, I wasn't referring to .isValid! I didn't mean that at all. I meant what I said in post #1, after I mentioned it. Replace if (var==null) with if (!var). === is almost always better than ==, because truthiness of == causes confusion and problems. But in ifs, you might as well use the implicit truthiness and not test explicitly, and write for clarity. (Someone is going to say this argument is defective ).

     

    By the way, there's some sample Adobe script that creates menus. Maybe it's hidden in the Bridge SDK or something. I can't remember, something to do with some font. I haven't looked at the code though, so who knows. I suspect it is rather different than any of the examples so far...

     

    Marc's absolutely right, your code should not be using global variables! What a nightmare those are. Remember anything in a function without an explicit 'var' on it somewhere is global. "Oops." That's what happens when you design a language in 10 days (Javascript).

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 11:38 AM   in reply to John Hawkinson

    John Hawkinson wrote:

     

    By the way, there's some sample Adobe script that creates menus.

    Is this what you're talking about? It's distributed in the InDesign SDK...

     

    XHTMLExportMenuItem.install = function()
    {    
        if(app.name == "Adobe InDesign") {
            // set up our script preferences
            var currDOMVersion = app.scriptPreferences.version;
            if (currDOMVersion != XHTMLExportMenuItem.requiredDOMVersion)
                app.scriptPreferences.version = XHTMLExportMenuItem.requiredDOMVersion;
     
            // determine and store the path from were we load our scripts from
            XHTMLExportMenuItem.storeScriptsFolderPath();
            // load XHTMLExporter for the strings
            var xhtmlExporterScript = XHTMLExportMenuItem.loadScript('XHTMLExport.jsxbin');
            if ( !xhtmlExporterScript.exists )
            {
                xhtmlExporterScript = XHTMLExportMenuItem.loadScript('XHTMLExport.jsx');
            }
            assert( xhtmlExporterScript.exists, "XHTMLExport.jsx* missing; load failed" ) ;
            if ( xhtmlExporterScript.exists )
            {
                var cacheCurrent = Folder.current ;
                try
                {
                    Folder.current = XHTMLExportMenuItem.scriptsFolder ;
                    app.doScript( xhtmlExporterScript ) ;
                }
                finally
                {
                    Folder.current = cacheCurrent ;
                }
                if ($.locale != 'en_US')
                {
                    // try to load localized strings
                    var localizationScript = XHTMLExportMenuItem.loadScript('Resources/XHTMLStrings-' + $.locale + '.jsxbin');
                    if ( !localizationScript.exists )
                    {
                        localizationScript = XHTMLExportMenuItem.loadScript('Resources/XHTMLStrings-' + $.locale + '.jsx');
                    }
                    assert( localizationScript.exists, 'Resources/XHTMLStrings-' + $.locale + '.jsx* missing; load failed' ) ;
                    if ( localizationScript.exists )
                    {
                        var cacheCurrent = Folder.current ;
                        try
                        {
                            Folder.current = Folder( XHTMLExportMenuItem.scriptsFolder + '/Resources' ) ;
                            app.doScript( localizationScript ) ;
                        }
                        finally
                        {
                            Folder.current = cacheCurrent ;
                        }
                    }
                }
                // menu action for the File:Export for menu
                var actionname = localize(xhtmlExportStrings.FORDREAMWEAVERACTIONNAME);
                var action = app.scriptMenuActions.item(actionname);
                if(action == null) {
                    // first launch:
                    // we need to create the menu action
                    var action = app.scriptMenuActions.add(actionname);
                    action.area = app.translateKeyString('$ID/KBSCE File menu: ExportForSubMenu');
                    action.checked = false;
                    action.enabled = true;
                }
     
                // install event listeners for our action
                action.addEventListener("onInvoke", XHTMLExportMenuItem.exportSelectedItems);    
                action.addEventListener("beforeDisplay", XHTMLExportMenuItem.enableDisable);
                action.addEventListener("afterInvoke", XHTMLExportMenuItem.cleanup);
     
                // install the menu item
                var exportForMenu = app.menus.item(app.translateKeyString('$ID/Main')).submenus.item(app.translateKeyString('$ID/&File')).submenus.item(app.translateKeyString('$ID/ExportForSubMenu')) ;
                exportForMenu.menuItems.add(action);
     
                // store the action in a class variable
                XHTMLExportMenuItem.action = action;
            }
            if(currDOMVersion != XHTMLExportMenuItem.requiredDOMVersion)
                app.scriptPreferences.version = currDOMVersion;
        }
    }
    

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 11:45 AM   in reply to Harbs.

    Harbs. wrote:

     

    null works perfectly well for menu actions. I'm not sure why we're making a deal of this...

     

     

    Because—I totally agree with John— using ==null is both a bad practice and semantically irrelevant.

     

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 11:48 AM   in reply to John Hawkinson

    John Hawkinson wrote:

     

    Replace if (var==null) with if (!var). === is almost always better than ==, because truthiness of == causes confusion and problems. But in ifs, you might as well use the implicit truthiness and not test explicitly, and write for clarity. (Someone is going to say this argument is defective ).

     

    In my opinion, discussions about == vs. === vs implicit resolutions is kind of silly. I have no issue using ==. Just make sure you understand what it means.

     

    Personally, I only use === when I really need it. That way it's clear what I'm testing for... When I'm testing for bull or boolean values, I usually skip the "==" altogether.

     

    I don't take everything Crawford says as if it's the bible. They're only his opinions after all...

     

    Harbs

     
    |
    Mark as:
  • John Hawkinson
    5,512 posts
    Jun 25, 2009
    Currently Being Moderated
    Dec 18, 2011 11:49 AM   in reply to Harbs.

    Is this what you're talking about? It's distributed in the InDesign SDK...

    *cry*

     

    No. Normally I'd say you should include the filename when you make such references, but in this case... please don't.


    There's some script that adds a toplevel menu for a Font. I guess I am just not excited enough (afraid?) to go looking for it. Especially after that snippet you posted.

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 11:50 AM   in reply to Marc Autret

    Marc Autret wrote:

     

     

    Because—I totally agree with John— using ==null is both a bad practice and semantically irrelevant.

     

     

    Tell that to Jonathan Brown who designed it in the first place!

     

    (See the code I pasted above.)

     
    |
    Mark as:
  • John Hawkinson
    5,512 posts
    Jun 25, 2009
    Currently Being Moderated
    Dec 18, 2011 11:52 AM   in reply to Harbs.

    In my opinion, discussions about == vs. === vs implicit resolutions is kind of silly. I have no issue using ==. Just make sure you understand what it means.

     

    Personally, I only use === when I really need it. That way it's clear what I'm testing for... When I'm testing for bull or boolean values, I usually skip the "==" altogether.

    The problem is that it is often fairly subtle "when you really need it," and you don't notice until you've been bitten by it.

    Everyone is pretty much always better off with ===.

     

    I don't take everything Crawford says as if it's the bible. They're only his opinions after all...

    Crockford.

     

    And yes, his opinions are actually increasingly problematic. I can't even use JSLint anymore, he's added so many inappropriate checks that really boil down to style. The jslint_com yahoo group is kind of unpleasant. Oh well.

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 11:53 AM   in reply to John Hawkinson

    (I love making grown men cry...)

     

    The snippet I posted above was written by Jonathan Brown. It's pretty obvious where it came from (HTML export).

     

    The font snippet is in the InDesign Scripting Guide pdf.

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 12:07 PM   in reply to John Hawkinson

    John Hawkinson wrote:

    The problem is that it is often fairly subtle "when you really need it," and you don't notice until you've been bitten by it.

    Everyone is pretty much always better off with ===.

     

    I actually came across a situation where === was problematic, but I don't remember the details. There's no replacement for properly learning a language you use. (Whether it's a spoken language or computer one...)

     

     

    John Hawkinson wrote:

     

    Crockford.

     

    Oops. Never nice to bollix up someone's name...

     
    |
    Mark as:
  • John Hawkinson
    5,512 posts
    Jun 25, 2009
    Currently Being Moderated
    Dec 18, 2011 3:00 PM   in reply to Harbs.

    I actually came across a situation where === was problematic, but I don't remember the details.

    I think a common case is confusion between null and undefined. For instance:

     

    var v;

    ...

    if (v==0) { v="now initialized!"; }

     

    will "work" and initialize v, because v is undefined, and "undefined==0" returns true. So if you just changed it to

     

    var v;

    ...

    if (v===0) { v="now initialized"; }

     

    then v would never get initialized. Of course, this is bad code because you should have initialized v in the var line anyhow, or you should have tested it against "undefined" and not "0" or "null," or halfadozen other reasons.

     

    Anyhow, I feel like your exception proves the rule. Use '===' always, unless you learn the language well enough to require truthiness promotion, because if you don't, you are likely to make an assumption about whether something is false versus null versus undefined, and that assumption will come back and hurt you later.

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 10:12 PM   in reply to John Hawkinson

    No. That wasn't what I was talking about. I think it had something to do with String objects and String literals. But, I don't remember...

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 18, 2011 10:38 PM   in reply to John Hawkinson

    John Hawkinson wrote:

     

    Anyhow, I feel like your exception proves the rule. Use '===' always, unless you learn the language well enough to require truthiness promotion, because if you don't, you are likely to make an assumption about whether something is false versus null versus undefined, and that assumption will come back and hurt you later.

    This is a bit like philosophy. You can argue both sides until you're blue in the face. Just about anyone coming from a C background would probably disagree. There's quite a lot of people who look at 0 and false as synonymous...

     

    Whatever; I have bigger fish to fry...

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 23, 2011 12:33 PM   in reply to Marc Autret

    Hi Marc,

     

    i tried your MenuLoader and it works like a charm.

    One question is still open: Is there a chance to create KeyboardShortcuts for a custom menu that will work even after a ShutDown & Restart of InDesign?

     

    Cheers

    Juergen

     
    |
    Mark as:
  • John Hawkinson
    5,512 posts
    Jun 25, 2009
    Currently Being Moderated
    Dec 23, 2011 12:38 PM   in reply to JuMayr

    Juergen:

    One question is still open: Is there a chance to create KeyboardShortcuts for a custom menu that will work even after a ShutDown & Restart of InDesign?

    They should just work. Did you try them?

     

    Please note that you cannot create KBSCs in the scripting interface, you must do so by hand in the UI. (well, I suppose you could edit InDesign's xml file that stores this information, but that wouldn't be very...clean.)

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 23, 2011 12:40 PM   in reply to John Hawkinson

    Hi John,

     

    i created the KBSCs via the Indesign UI.

    They are shown in the menu and work.

    But when i restart Indesign they are gone.

     

    Cheers

    Juergen

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 23, 2011 4:09 PM   in reply to JuMayr

    JuMayr wrote:

     

    Hi Marc,

     

    i tried your MenuLoader and it works like a charm.

    One question is still open: Is there a chance to create KeyboardShortcuts for a custom menu that will work even after a ShutDown & Restart of InDesign?

     

    Cheers

    Juergen

     

    Hi Juergen,

     

    Thanks for your feedback. I haven't seriously studied keyboard shortcuts issues but I know this is a very complicated topic to scripters. What we can guess is that temporarily removing/refreshing menu actions—as my script does—does not preserve the existing KB shortcuts, because InDesign dynamically clears them as soon as the 'link' is broken between a shortcut and a custom action—I suppose. So we need to restore removed shortcuts, but AFAIK the scripting DOM does not provide any interface do do that. I don't even know if rewriting on the fly the 'indk' file could actually work. Maybe other people here have already investigated this point.

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 24, 2011 11:27 AM   in reply to Marc Autret

    Yes. Menu Actions are saved cross-session. They are cleared out on shutdown only if there's no associated menu item.

     

    If you remove it and create a new one, keyboard shortcuts are lost.

     

    I'm pretty sure you should be able to add and remove menu items without issues. The keyboard shortcuts are associated with the actions.

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Dec 19, 2012 3:02 AM   in reply to Harbs.

    Hi,

     

       Why the customized menuItems cannot displaying in "Edit->Menus...->category - > application menu"???

         But it displaying customized submenu...

     

    Thanks.

     
    |
    Mark as:
1 2 Previous Next

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points