Copy link to clipboard
Copied
Hi there,
Does anyone know how to disable a panel conditionnaly thanks to scripts in window->extensions menu ?
My extension is made with 5 panels. With some conditions, I'd like users not to access to a panel.
I've got a menu inside my extensions and I can disabled panel access here ; but if users go to window->extensions, there are enabled.
Thanks
The following code I think is pretty clear.
...//////////////////////////////////////////////////////////////////
// MenuDemo.jsx By Trevor http://creative-scripts.com 12 Apr 18 //
// Demonstrates how to control menu items on InDesign //
//////////////////////////////////////////////////////////////////
#targetengine foo
// If using CSTK best to comment out the targetengine line
// Look at the bottom of the "Layout" menu
var installMenuItem;
/**
* [installMenuItem description] Helper
Copy link to clipboard
Copied
Remove the <Menu> Tag in the manifest.xml
Thomas
Copy link to clipboard
Copied
Thanks for your reply.
That's ok but I've to do that before constructing the zxp.
What I want is to do it programmatically and dynamically by javascript or other.
For example, if opened document contains a type of data then this extension panel is enabled.
If there isn't that data, the extension panel is disabled.
Copy link to clipboard
Copied
I don't think this is possible. The user will always get the notification "extension is not correctly signed ..." if you change the manifest file after signing. (Unless the user sets the debug flag)
Copy link to clipboard
Copied
I'm not sure it can be done "conditionally" (without restarting the host app), but rather permanently.
Copy link to clipboard
Copied
Manifest changes usually require Photoshop restart.
Copy link to clipboard
Copied
I would have thought that manifest changes always need? Do you know of any exceptions?
On InDesign I think it would be quite easy to do. For which app(s) is it?
Copy link to clipboard
Copied
It's for Indesign.
For example in panel menu I do this :
csInterface.updatePanelMenuItem(SUBSTITUTION_TEXT_LABEL, isEnabled, false);
Where "isEnabed" is a boolean calculated.
Copy link to clipboard
Copied
From jsx engine
app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Window').submenus.itemByName('$ID/Extensions'). menuItems.itemByName('My Super Duper Extension').remove()
So just do an evalScript
Copy link to clipboard
Copied
P.s.
localization of menu items is a real pain in the neck.
You might want to use
app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Window').submenus.itemByName('$ID/Exte&nsions');
The only safe way to deal with localization is to try out what ever you need on each one.
Fortunately there's only about 25
Copy link to clipboard
Copied
To disable the item (and not remove it) you need to target the target.
Very pseudo code.
menuAction = app.scriptMenuActions.add({ title: title, name: name });
var isLicenced = function(ev) {
ev.target.enabled = !trialExpired;
};
var isLicenced = function(ev) {
ev.target.enabled = !trialExpired;
};
menuAction.eventListeners.add('beforeDisplay', isLicenced);
Copy link to clipboard
Copied
Thanks Trevor for all your replies.
Could you explain me your last reply's code please ?
Copy link to clipboard
Copied
I'm sorry I can't spend too much time on in now but here's a 1 minute round up.
The InDesign jsx engine unlike Ai or Ps allows you to add / remove / change menu items.
See Indiscripts :: How to Create your Own InDesign Menus for some basics on this.
The indesign scripting forum has numerous examples.
A menu item comprises of 2 parts.
1) The bit you see.
2) The action it performs.
Mess around with the following code until you understand it.
The speech is quite useful for understanding it.
Keep on clicking the menu items until you understand why the menu items are doing what they do.
HTH
Trevor
#targetengine foo
// Look at the bottom of the Layout menu
var installMenuItem;
/**
* [installMenuItem description]
* @param {String} title The words you want displayed
* @param {DOM Menu / Sub-menu} parentMenu The menu / sub-menu on which the item should appear
* @param {Function} beforeDisplay like function(ev){ev.target.enabled = !!app.properties.activeDocument}
* @param {Function} onInvoke like
* function(ev){
* ev.target.title =
* (app.properties.activeDocument && app.properties.activeDocument.name) || 'Nope';
* }
* @param {DOM Constant} position LocationOptions.BEFORE, LocationOptions.AFTER, LocationOptions.AT_END,
* LocationOptions.AT_BEGINNING, or LocationOptions.UNKNOWN
* [Optional] default LocationOptions.AT_END
* @param {DOM Menu / Sub-menu / Menu Item} reference [description]
* [Optional] only needed if position is set to LocationOptions.BEFORE or LocationOptions.AFTER
* @return {DOM menuAction} The created or existing menu Item
*/
installMenuItem = function(title, parentMenu, beforeDisplay, onInvoke, name, position, reference) {
var menuAction;
if (typeof title === 'object') {
parentMenu = title.parentMenu;
beforeDisplay = title.beforeDisplay;
onInvoke = title.onInvoke;
position = title.position;
reference = title.reference;
name = title.name || title.title;
title = title.title || title.name;
}
position = position || LocationOptions.AT_END;
parentMenu = parentMenu || app.menus.item("$ID/Main");
menuAction = app.scriptMenuActions.add({ title: title, name: name });
if (beforeDisplay) {
menuAction.eventListeners.add('beforeDisplay', beforeDisplay);
}
if (onInvoke) {
menuAction.eventListeners.add('onInvoke', onInvoke);
}
return parentMenu.menuItems.add(menuAction, position, reference);
};
/*
____ __ _ _ ____ __ ____ _ _ ____ __ ___ ____
/ ___) / _\ ( \/ )( _ \( ) ( __) / )( \/ ___) / _\ / __)( __)
\___ \/ \/ \/ \ ) __// (_/\ ) _) ) \/ (\___ \/ \( (_ \ ) _)
(____/\_/\_/\_)(_/(__) \____/(____) \____/(____/\_/\_/ \___/(____)
*/
var foo;
foo = (function() {
var toggle1, toggle2, toggleEnabled, toggleText, pow, say;
toggle1 = toggle2 = false;
say = function(message) {
var isMac, script;
isMac = $.os[0] === 'M';
script = isMac ? 'Say "' + message + '"' : 'CreateObject("sapi.spvoice").Speak "' + message + '"';
app.doScript(script, ScriptLanguage[isMac ? 'APPLESCRIPT_LANGUAGE' : 'VISUAL_BASIC']);
};
pow = function(ev) {
say(ev.target.name);
};
toggleText = function(ev) {
say(ev.target.name);
ev.target.title = ev.target.name = toggle1 ? 'Do my script' : 'Don\'t do my script'; // ;-);
toggle1 = !toggle1;
};
toggleEnabled = function(ev) {
// ev.target.enabled = toggle1;
ev.target.title = ev.target.name = (toggle2 ? 'Yep' : 'Nope');
toggle2 = !toggle2;
say(ev.target.name);
};
var fooMenu = app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Layout').submenus.itemByName('FabScript');
if (fooMenu === null) {
fooMenu = app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Layout').submenus.add('FabScript', LocationOptions.AT_END);
}
if (fooMenu.menuItems.itemByName('Yep') === null) {
installMenuItem({
title: 'Yep',
name: 'Yep',
parentMenu: fooMenu,
onInvoke: pow,
beforeDisplay: toggleEnabled
});
}
if (fooMenu.menuItems.itemByName('Do my script') === null) {
installMenuItem({
title: 'Do my script',
name: 'Do my script',
parentMenu: fooMenu,
onInvoke: toggleText
});
}
return fooMenu;
})();
/*
To remove the menu
foo.remove();
*/
Copy link to clipboard
Copied
The following code I think is pretty clear.
//////////////////////////////////////////////////////////////////
// MenuDemo.jsx By Trevor http://creative-scripts.com 12 Apr 18 //
// Demonstrates how to control menu items on InDesign //
//////////////////////////////////////////////////////////////////
#targetengine foo
// If using CSTK best to comment out the targetengine line
// Look at the bottom of the "Layout" menu
var installMenuItem;
/**
* [installMenuItem description] Helper function for adding InDesign menu items by Trevor http://creative-scripts.com
* @param {String} title The words you want displayed
* @param {DOM Menu / Sub-menu} parentMenu The menu / sub-menu on which the item should appear
* @param {Function} beforeDisplay like function(ev){ev.target.enabled = !!app.properties.activeDocument}
* @param {Function} onInvoke like
* function(ev){
* ev.target.title =
* (app.properties.activeDocument && app.properties.activeDocument.name) || 'Nope';
* }
* @param {DOM Constant} position LocationOptions.BEFORE, LocationOptions.AFTER, LocationOptions.AT_END,
* LocationOptions.AT_BEGINNING, or LocationOptions.UNKNOWN
* [Optional] default LocationOptions.AT_END
* @param {DOM Menu / Sub-menu / Menu Item} reference [description]
* [Optional] only needed if position is set to LocationOptions.BEFORE or LocationOptions.AFTER
* @return {DOM menuAction} The created or existing menu Item
*/
installMenuItem = function(title, parentMenu, beforeDisplay, onInvoke, name, position, reference) {
var menuAction;
if (typeof title === 'object') {
parentMenu = title.parentMenu;
beforeDisplay = title.beforeDisplay;
onInvoke = title.onInvoke;
position = title.position;
reference = title.reference;
name = title.name || title.title;
title = title.title || title.name;
}
position = position || LocationOptions.AT_END;
parentMenu = parentMenu || app.menus.item("$ID/Main");
menuAction = app.scriptMenuActions.add({ title: title, name: name });
if (beforeDisplay) {
menuAction.eventListeners.add('beforeDisplay', beforeDisplay);
}
if (onInvoke) {
menuAction.eventListeners.add('onInvoke', onInvoke);
}
return parentMenu.menuItems.add(menuAction, position, reference);
};
/*
____ __ _ _ ____ __ ____ _ _ ____ __ ___ ____
/ ___) / _\ ( \/ )( _ \( ) ( __) / )( \/ ___) / _\ / __)( __)
\___ \/ \/ \/ \ ) __// (_/\ ) _) ) \/ (\___ \/ \( (_ \ ) _)
(____/\_/\_/\_)(_/(__) \____/(____) \____/(____/\_/\_/ \___/(____)
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This should add a "FabScript" submenu to the bottom of the "Layout" menu //
// It contains to menu items //
// Demonstrates how to change properties of the menu items like their text and enabled status //
// Keep playing with the menu until you understand how it's actions fit in with the code. //
// To remove the menu use either foo.remove() from the correct scriptEngine or use from any engine //
// app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Layout').submenus.itemByName('FabScript').remove(); //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var foo;
foo = (function() {
var toggleScriptEnable, toggleYepNopeTitle, yepNopeBeforeDisplay, enableMyScriptOnInvoke, yepNopeOnInvoke, wl, say, count;
count = 0;
toggleScriptEnable = toggleYepNopeTitle = false;
/*
_ _ _ ___ _ _
| || |___| |_ __ ___ _ _ | __| _ _ _ __| |_(_)___ _ _ ___
| __ / -_) | '_ \/ -_) '_| | _| || | ' \/ _| _| / _ \ ' \(_-<
|_||_\___|_| .__/\___|_| |_| \_,_|_||_\__|\__|_\___/_||_/__/
|_|
*/
/**
* [wl description] Shortcut to output to either ESTK or CSTK console, applying / filtering the css
* @param {String} message
* @param {String} css [Optional] css to be applied to the message if sent to the CSTK console
* @return {String} The message without the css
*/
wl = function(message, css) {
if ($.engineName === 'CSTK') {
$.writeln(message, css);
} else {
$.writeln(message);
}
return message;
};
/**
* [say description] Speaks the message out and passes the message out so it can be forwarded to a log etc.
* @param {String} message the message to say
* @return {String} The message
*/
say = function(message) {
const DONTSAY = false; // Change to true to shut the computers mouth
if (DONTSAY) { return message; }
var isMac, script;
isMac = $.os[0] === 'M';
script = (isMac ? 'Say "' : 'CreateObject("sapi.spvoice").Speak "') + message + '"';
app.doScript(script, ScriptLanguage[isMac ? 'APPLESCRIPT_LANGUAGE' : 'VISUAL_BASIC']);
return message;
};
/*
__ __ _ _ _ _
| \/ |___ _ _ _ _ _____ _____ _ _| |_| | (_)__| |_ ___ _ _ ___ _ _ ___
| |\/| / -_) ' \ || | / -_) V / -_) ' \ _| |__| (_-< _/ -_) ' \/ -_) '_(_-<
|_| |_\___|_||_\_,_| \___|\_/\___|_||_\__|____|_/__/\__\___|_||_\___|_| /__/
*/
enableMyScriptOnInvoke = function(ev) {
wl(say('On Invoke ' + ev.target.name), 'color: blue;background:yellow;');
ev.target.title = ev.target.name = toggleScriptEnable ? 'Enable my script' : 'Dis-enable my script'; // ;-);
toggleScriptEnable = !toggleScriptEnable;
};
yepNopeBeforeDisplay = function(ev) {
count++;
ev.target.enabled = toggleScriptEnable; // toggleScriptEnable
ev.target.name = count + // increments on beforeDisplay events
(toggleYepNopeTitle ? ' Yep script' : ' Nope script') + // toggles on beforeDisplay events
(toggleScriptEnable ? ' is enabled' : ' is not enabled'); // changes on the enableMyScriptOnInvoke event
////////////////////////////////////////////////////////////////////
// NOTE: The Yep and Nope are not connected to the enabled status //
// take note of when they swap and when the count changes //
////////////////////////////////////////////////////////////////////
toggleYepNopeTitle = !toggleYepNopeTitle;
wl(say('Before display ' + ev.target.name), 'color: orange');
// NOTE: The before display is triggered when the menu item is invoked and before the parent menu is displayed
// In this example the parent menu is the "Layout" menu
};
yepNopeOnInvoke = function(ev) {
wl(say('On Invoke ' + ev.target.name), 'color: red;background:yellow;');
///////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: before the onInvoke fires the beforeDisplay will fire //
// This is in addition to the beforeDisplay that fired on displaying the menu //
// In our case this will cause that it looks like the Yep Nope are not being toggled //
// To circumvent that one could place in the on Invoke `toggleYepNopeTitle = !toggleYepNopeTitle;` //
// Take note that the count changes with the onInvoke because of it's associated beforeDisplay event //
///////////////////////////////////////////////////////////////////////////////////////////////////////
};
/*
_ _ _ __ __
/_\ __| |__| | | \/ |___ _ _ _ _ ___
/ _ \/ _` / _` | | |\/| / -_) ' \ || (_-<
/_/ \_\__,_\__,_| |_| |_\___|_||_\_,_/__/
*/
var fooMenu = app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Layout').submenus.itemByName('FabScript');
// For convenience we shall remove the menu if it already exists.
if (fooMenu !== null) fooMenu.remove();
// Add the FabScript submenu
fooMenu = app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Layout').submenus.add('FabScript', LocationOptions.AT_END);
// Add the menu items with the event listeners
installMenuItem({
name: 'YepNope',
parentMenu: fooMenu,
onInvoke: yepNopeOnInvoke,
beforeDisplay: yepNopeBeforeDisplay
});
installMenuItem({
name: 'Enable my script',
parentMenu: fooMenu,
onInvoke: enableMyScriptOnInvoke
});
return fooMenu;
})();
/*
To remove the menu
foo.remove();
or
app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Layout').submenus.itemByName('FabScript').remove();
*/
Copy link to clipboard
Copied
Thanks Trevor, I will try it.
Copy link to clipboard
Copied
Can't make it work in my case because my menu items already exist and I cannot create them again.
I could remove all of them and run your script to add them again but I don't know if it's a good way to do that..
I also tried this to modified action associated with my existing menu item :
var mnu = app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Window').submenus.itemByName('Extensions').menuItems.itemByName('MyMenu');
var action = mnu.associatedMenuAction;
action.addEventListener(
/*event type*/ 'onInvoke',
/*event handler*/ function(){
alert('Hello World!');
}
);
I also tried to add eventListener
var t1 = app.scriptMenuActions;
for (var i = 0; i < t1.length; i++) {
var x = t1.item(i);
if (x.isValid && x.name == "MyMenu") {
var test = app.menus.itemByName('$ID/Main').submenus.itemByName('$ID/&Window').submenus.itemByName('Extensions').menuItems.itemByName('MyMenu');
x.eventListeners.add('beforeDisplay', function(ev) {
wl(say('beforeDisplay 2 ' + ev.target.name));
});
//test.add(x);
test.eventListeners.add('beforeDisplay', function(ev) {
wl(say('beforeDisplay 4' + ev.target.name));
});
}
But this seems to add a new submenuItem with "MyMenu" name and not updating existing menuItem.
My last code seems to work if my MenuItem does nothing at all. If it runs an extension, it does nothing like if no event is fired (or no event listener recorded)
I'm really lost in all of that !
Edit : My bad !!! It works ! "beforeDisplay" isn't available on my menuItem, but using beforeInvoke it's Ok.
I will post the final code soon.