Copy link to clipboard
Copied
I was referred to @Peter Kahrel excellent tutorial on ScriptUI located here https://creativepro.com/files/kahrel/indesign/scriptui.html, but I am having a few issues with my scripts:
w.input = w.group.add ('edittext {characters: 10, active: true, justify: "right"}');
I don't see where "characters: 10" is explained. I thought it would limit the input to 10 characters, but it does not seem to, either in his example or in my testing. Is there a way to do this? One of my input fields needs to be 7 characters and one of them needs to be 8 character date in format YYYYMMDD.
win.Panel2.txt2.onChanging = function () {
var valid = /^[\d]+$/.test (win.Panel2.txt2.text);
this.graphics.backgroundColor = this.graphics.newBrush (this.graphics.BrushType.
SOLID_COLOR, valid ? [1, 1, 1, 1] : [1, 0.5, 0.5, 1]);
win.Panel2.ApplyBtn.enabled = valid && win.Panel2.txt2.text.length=7;
}
win.Panel2.txt3.onChanging = function () {
var valid = /^[\d]+$/.test (win.Panel2.txt3.text);
this.graphics.backgroundColor = this.graphics.newBrush (this.graphics.BrushType.
SOLID_COLOR, valid ? [1, 1, 1, 1] : [1, 0.5, 0.5, 1]);
var valid2 = Date.parse(win.Panel2.txt3.text);
win.Panel2.ApplyBtn.enabled = !valid2==NaN;
}
I'll probably have more questions as I get further into my script, and I'll add them to this thread, if that is okay.
(The forum gave me an error about invalid HTML that it removed, but I'm not seeing what it changed).
Thanks in advance!
= is used to assign a value to a variable.
== and === test equality. === is used for strict equality, which means that the two items you compare must be the same type. == is for looser comparisons. == is slower because it tries to coerce the two items into type-equality.
Example:
var a = 5;
var b = '5';
a == b; // => true
a === b // => false
a is a number, b is a string. Strict comparison returns false because the variables are not the same type. Loose comparison returns true, it successfu
...Playing with text then textselection, in that order, may solve the cursor issue in EditText widgets. That's a bit of black magic so I do not guarantee the universality of the following code:
// . . .
// Your UI components (w, w.input, etc)
// . . .
// Predeclare brushes
var gx = w.input.graphics;
var BH =
[
gx.newBrush(gx.BrushType.SOLID_COLOR, [1.0, 0.5, 0.5, 1]), // KO
gx.newBrush(gx.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0, 1]) // OK
];
// Text changing handle
...
@Marc Autret (or others)
Funny how things work - or maybe not if you are religious!!! Anyway, I was getting really frustrated and typed up a long post. I hit preview and walked away from my computer and never posted it. I couldn't see the forest for the trees, but I solved the problem!!!
This will be a long post, but it should help some people.
The main problem I was having had to do with "partially valid" regex. I have enough trouble coming up with "fully valid" regex - although I think I have t
...
Sorry I don't understand your code 😕 I'm afraid I've already detailed everything I can say about my own approach, so the code below basically just repeats the same logic.
Some advice to prevent infinite loops and other errors: Keep your objects encapsulated, only play with text/textselection once (and only if needed!), do not take the risk of reintroducing a changing event while you modify the text, do not resolve again the EditText instance (it is and remains this within t
...Copy link to clipboard
Copied
@Marc Autret (or others)
Funny how things work - or maybe not if you are religious!!! Anyway, I was getting really frustrated and typed up a long post. I hit preview and walked away from my computer and never posted it. I couldn't see the forest for the trees, but I solved the problem!!!
This will be a long post, but it should help some people.
The main problem I was having had to do with "partially valid" regex. I have enough trouble coming up with "fully valid" regex - although I think I have that down. Short question - let's say my proprietary regex is K-50dd (K-5011, K-5024, etc.). It isn't really, but ... My fully qualified regex would be /^K-50\d\d$\. What would I use for the partially valid regex for "contains anything other than K, dash, or a number?" I tried if(/[^K-]\D/.test(t)) - never replaced anything and if(!/[^K-]\D/.test(t)) - stack overrun. If I can figure that out, I think I can adapt it to what I really need.
Answer was right in front of me. If you can figure out your replacement regex (i.e. anything other than this gets replace by ""), you can use that for your partially valid test regex.
Anyway, here is Mark's original script.
var w = new Window ('palette');
// Marc's Original - works.
w.group = w.add ('group');
w.group.add ('statictext {text: "Enter a valid 7-Digit number Anything other than a numeral will be ignored:"}');
w.input = w.group.add ('edittext {characters: 10, active: true, justify: "right"}');
w.clear = w.group.add ('button {text: "Clear"}');
w.buttons = w.add ('group {alignment: "right"}');
w.ok = w.buttons.add ('button {text: "OK", enabled: false}');
w.buttons.add ('button {text: "Cancel"}');
// Predeclare brushes
var gx = w.input.graphics;
var BH =
[
gx.newBrush(gx.BrushType.SOLID_COLOR, [1.0, 0.5, 0.5, 1]), // KO
gx.newBrush(gx.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0, 1]) // OK
];
// Text changing handler
w.input.onChanging = function( t)
{
t = this.text;
if( !/^\d{0,7}$/.test(t) )
{
t = t.replace(/\D+/g,'').slice(0,7);
this.text = '';
this.textselection = t;
}
t = 7===t.length;
w.ok.enabled = t;
this.graphics.backgroundColor = BH[+t];
}
w.show();
And here is a modification, which made it easier for me to see what was really happening. (This also works):
var w = new Window ('palette');
// Marc's Modified - works.
w.group = w.add ('group');
w.group.add ('statictext {text: "Enter a valid 7-Digit number Anything other than a numeral will be ignored:"}');
w.input = w.group.add ('edittext {characters: 10, active: true, justify: "right"}');
w.clear = w.group.add ('button {text: "Clear"}');
w.buttons = w.add ('group {alignment: "right"}');
w.ok = w.buttons.add ('button {text: "OK", enabled: false}');
w.buttons.add ('button {text: "Cancel"}');
// Predeclare brushes
var gx = w.input.graphics;
var BH =
[
gx.newBrush(gx.BrushType.SOLID_COLOR, [1.0, 0.5, 0.5, 1]), // KO
gx.newBrush(gx.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0, 1]) // OK
];
// Text changing handler
w.input.onChanging = function( t)
{
t = this.text;
if( !/^\d{0,7}$/.test(t))
{
t = t.replace(/\D+/g,'').slice(0,7);
this.text = '';
this.textselection = t;
}
if(/\d{7}$/.test(t)){
w.ok.enabled=true;
this.graphics.backgroundColor = BH[1];
}
else{
w.ok.enabled=false;
this.graphics.backgroundColor = BH[0];
}
}
w.show();
Initially, I tried to use the same lower valid fully qualifed regex in both if statements, and got the stack overrun error. That somewhat makes sense in hindsight, b/c basically I am saying "If this … If not this, else - which is the same as the first statement.
Finally, here is the working K-50xx solution. I still don't FULLY understand it, but I can make it work for what I need it to do - hopefully others can as well:
var w = new Window ('palette');
// Marc's Modified - proprietary - Works!!!
w.group = w.add ('group');
w.group.add ('statictext {text: "Enter a valid code as K-50dd. Anything other than K, dash, or a numeral will be ignored:"}');
w.input = w.group.add ('edittext {characters: 10, active: true, justify: "right"}');
w.clear = w.group.add ('button {text: "Clear"}');
w.buttons = w.add ('group {alignment: "right"}');
w.ok = w.buttons.add ('button {text: "OK", enabled: false}');
w.buttons.add ('button {text: "Cancel"}');
// Predeclare brushes
var gx = w.input.graphics;
var BH =
[
gx.newBrush(gx.BrushType.SOLID_COLOR, [1.0, 0.5, 0.5, 1]), // KO
gx.newBrush(gx.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0, 1]) // OK
];
// Text changing handler
w.input.onChanging = function( t)
{
t = this.text;
if(/[^-0-9K]+/.test(t))
{
t = t.replace(/[^-0-9K]+/g, '');
this.text = '';
this.textselection = t;
}
if(/^K-50\d\d$/.test(t)){
w.ok.enabled=true;
this.graphics.backgroundColor = BH[1];
}
else{
w.ok.enabled=false;
this.graphics.backgroundColor = BH[0];
}
}
w.show();
Thanks for all assistance!!!
Copy link to clipboard
Copied
@Marc Autret (or others), sorry to keep bothering you, but I have one field in which the Stack Overrun problem is re-occurring and I can't figure out how to work around it.
For this field, there will likely be dashes and numbers, and all letters should be uppercase, except the letter "v" which should always be lowercase. And I want to remove the letter X as it is initially in the field, but is not used. It should never be more than 30 characters, but it could be less.
I'm using this code without the textselection and it works, except it wraps back to the beginning of the field:
win.Panel2.txt1.onChanging = function(t){
win.Panel2.ApplyBtn.enabled = false;
win.Panel2.CancelBtn.enabled = true;
t = this.text;
t=t.toUpperCase();
t=t.replace(/V/g, "v");
t=t.replace(/X/g, "");
win.Panel2.txt1.text = t
t = this.text;
if(t.length>30){
t=t.slice(0,30);
this.text = '';
this.textselection =t;
}
win.Panel2.ApplyBtn.enabled = true;
}
This gives me the stack overrun error (I tried a lot of variants with no success, but this is one of them that fails):
win.Panel2.txt1.onChanging = function(t){
win.Panel2.ApplyBtn.enabled = false;
win.Panel2.CancelBtn.enabled = true;
t = this.text;
if(/\w+/.test(t)){
t=t.toUpperCase();
t = t.replace(/V/g, "v");
t=t.replace(/X/g, "");
this.text = '';
this.textselection = t;
}
t = this.text;
if(t.length>30){
t=t.slice(0,30);
this.text = '';
this.textselection =t;
}
var valid1 = /[^-0-9]+/.test (win.Panel2.txt1.text);
this.graphics.backgroundColor = this.graphics.newBrush (this.graphics.BrushType.
SOLID_COLOR, valid1 ? [1, 1, 1, 1] : [1, 0.5, 0.5, 1]);
win.Panel2.ApplyBtn.enabled = valid1;
}
Assistance will be greatly appreciated!!!
Copy link to clipboard
Copied
Sorry I don't understand your code 😕 I'm afraid I've already detailed everything I can say about my own approach, so the code below basically just repeats the same logic.
Some advice to prevent infinite loops and other errors: Keep your objects encapsulated, only play with text/textselection once (and only if needed!), do not take the risk of reintroducing a changing event while you modify the text, do not resolve again the EditText instance (it is and remains this within the event handler, that's all you need), avoid external object references as much as possible, work with local strings until you have to finally update—once!—the text of the control.
Steps: 1. normalize the input (remove junk characters, adjust letter case, size, etc); 2. if the normalized string is not the input string, update this.text through the textselection trick; 3. then, check whether the string is strictly valid and update the button state accordingly.
<yourEditText>.onChanging = function(t,s)
{
t = this.text;
// Normalize.
s = t && t.slice(0,30).toUpperCase()
.replace(/[^-0-9A-WY-Z]+/gi,'')
.replace(/V/gi,'v');
// Need filtering?
if( s !== t )
{
this.text = '';
this.textselection = s;
}
// Valid?
t = 30===s.length;
<yourOkButton>.enabled = t;
this.graphics.backgroundColor = BH[+t]; // Using the [OK,KO] brush array.
};
There are certainly other ways to approach the question. If my scheme doesn't work for you, I'm sure my colleagues on this forum will provide you with better options.
Best,
Marc
Copy link to clipboard
Copied
AMAZING!!!
It works perfectly. For anyone following along, I made some minor changes, basically I left off this part of it:
// Valid?
t = 30===s.length;
<yourOkButton>.enabled = t;
this.graphics.backgroundColor = BH[+t]; // Using the [OK,KO] brush array.
};
And the OK button.enabled is always true for this function.
As I understand it (scary to say that), your code would only allow the OK button when the code reached 30 characters and I need it to be UP TO 30 characters, which the code already does.
And for this section, there really was no such thing as invalid input - or there is, but there is no way to predict it or limit it with filtering.
Again - much thanks and I would never have figured this out on my own!!!!
Copy link to clipboard
Copied
> Can I call a universal function - i.e.
> w.input.onChanging = DoSomething();
> function DoSomething(){
> }
Yes.
> does ScriptUI (or more likely ESTK) support optional variables for functions
Yes. How it works exactly you can look up or determione by experiments.
Copy link to clipboard
Copied
Thanks! Does anyone know how to put the ScriptUI pop-up window on the second monitor if FM is on the second monitor?
Copy link to clipboard
Copied
The trouble is that (as far as I know) you won't be able to figure out whether FM is on the second monitor. Once you figured that out, then yes, you can place a window on any screen.
Copy link to clipboard
Copied
Does what I posted in the other thread help? I can tell the resolution of the monitor that FM is on or that the document is on. If monitor 2 was a different resolution than monitor 1, I could test for that.
But for me, both monitors are the same resolution and if I am writing for other users, I have no way to know what resolution they are using ...
(But I could guess ... i.e. is screen0.bottom == App.ScreenHeight, display on screen 0, else if screen1.bottom == App.ScreenHeight, display on screen1.)
But again, fails if screen0 and screen1 have the same resolution.
Copy link to clipboard
Copied
> if I am writing for other users, I have no way to know what resolution they are using
Well, there's your answer. You can't tell which screen FM is on, so you can't decide where to place the script window.
Copy link to clipboard
Copied
I'm afraid you are correct.
It seems pretty basic to want to be able to display a window on the same screen as the application is running on.
I found three things, not sure any of them are useful:
Copy link to clipboard
Copied
Is there no way to maybe use the windows API's to figure out what monitor FM is running on?
Something similar to Approach 3 on this page, but that is VBA for Microsoft Office: https://bettersolutions.com/vba/userforms/positioning.htm ?
Copy link to clipboard
Copied
What I would do is this:
- Assume that a user will have the application (FM) always on the same screen.
- The script looks for a config file. When it first runs the config file isn't there, so it places its window at the centre of the first screen (wherever, really, doesn't matter).
- The user drags the script window to some other place.
- When the use clicks OK, before executing whatever needs to be done, the script writes a text file that contains the location of the window. And you can add all the user selections.
- Next time the script runs it reads the config file and places the script window where the user last put it. And adds all the selections the user made earlier.
Copy link to clipboard
Copied
@Peter Kahrel - That is clever. That is very, very clever. Unfotunately, I see quite a few problems with it:
As much as I hate to admit it, I think my best option is to display the window on Screen0 and if someone uses a second display and uses FM on it, they'll have to adjust to the window being on the wrong screen - which is what happens when I have the window auto-center without specifying parameters.
I appreciate the thoughts and feedback, though!!!
Copy link to clipboard
Copied
Ran into another snag. I'll try to be brief.
I have a pop-up palette window with radio buttons on the left and input boxes and an apply button on the right. You click a radio button and the script reads values into the input boxes and you click Apply and it writes the input box values to variables. That works fine.
I wanted to add a "MouseOver" function so that if the apply button was enable, but was not clicked, you would get a confirmation dialog to drop the changes BEFORE the button click was applied.
The "click" code looks like this:
win.radioPanel.rad01.onClick = win.radioPanel.rad02.onClick = win.radioPanel.rad03.onClick = function () {
if(win.radioPanel.rad01.value) {
// Do stuff;
}
}
I tried to add something similar for the first button:
win.radioPanel.rad01.onMouseover = function(){
if (win.radioPanel.rad01.value){
alert("mousedover!");
}
}
But it doesn't seem to be doing anything - I never get the alert - unless I made a typo.
I tried onmouseover and onMouseOver and without the if statement and no luck - but no real error messages either.
Copy link to clipboard
Copied
onMouseover is not a radiobutton event. . .
Copy link to clipboard
Copied
That would explain it!!!
I can do it from the click event.
Complicated question:
User clicks Button 1 and makes changes. Apply button is enabled. User does not click Apply. User Clicks Button 2.
else if(win.radioPanel.rad02.value) {
if (win.Panel2.ApplyBtn.enabled){
if (confirm("Do you want apply the changes?") ===false) {
win.Panel2.ApplyBtn.enabled = false;
}
else{
return;
}
}
I want to replace the return statement with the same steps as the reply button.
If I can't, it works, but it shows Button 2 selected with the Button 1 info in the input boxes. If there anything simple like Return that would change it back to Button 1 (or the previously selected button?)
Copy link to clipboard
Copied
@Peter Kahrel - I ran into a new issue, and I hope I'm missing something obvious, but I'm somewhat afraid I'm not.
Now that the code is pretty much working, I decided I might try making the window borderless.
I looked at Pages 8 and 9 of the guide.
I can make the window borderless, but I agree, it looks plain with no border on it.
I tried:
w = new Window ("dialog", undefined, undefined, {borderless: true});
w.margins = [0,0,0,0];
myPanel = w.add ("panel");
myPanel.add ("statictext", undefined, "borderless: not quite true");
w.show ();
And it looks like Peter's example. There is a THIN gray border around the window, but not really noticeable compared to no border at all. (It also locks up FrameMaker and when I click the blue square, it says FM did not respond and I have to close and re-open it manually).
I tried:
w = new Window ("dialog", undefined, undefined, {borderless: true});
w.margins = [0,0,0,0];
myPanel = w.add ("panel", undefined,"",{borderStyle:'black'});
myPanel.add ("statictext", undefined, "borderless: not quite true");
w.show ();
And that gives me more what I am looking for (and also locks up FM).
However, I have a bounded window since I wanted my panels side-by-side, so my window looks like this:
var win = new Window("palette", "Update Document Variables:", [$.screens[0].right/2 - 255,$.screens[0].bottom/2 - 143, $.screens[0].right/2 + 255, $.screens[0].bottom/2 + 143],{borderless:true}); // bounds = [left, top, right, bottom] Width - 505 Height 285
win.margins = [0,0,0,0];
// myPanel = win.add ("panel", undefined,"",{borderStyle:'black'});
myPanel = win.add ("panel",[0,0,200,200],"",{borderStyle:'black'});
win.radioPanel = win.add("panel", [5, 5, 230, 250], "");
win.Panel2 = win.add("panel", [235, 5, 505, 250], "");
win.okBtn = win.add("button", [187,255,277,280], "OK"); //Centered on divider
win.okBtn.Active="True"
win.defaultElement=win.okBtn;
win.okBtn.onClick = function() {
win.close();
}
win.show();
The commented line didn't seem to do anything. The new bounded panel looks like what I want, but it is covering over my other panels and controls.
Is there a way to make the new panel transparent?
If not, I think I can get the effect I want by:
Is there an easier solution?
Copy link to clipboard
Copied
Disregard, I figured it out - I had to make the panels (and maybe the window buttons) part of the new panel, but not the controls - i.e.
win.P3 = win.add ("panel",[0,0,510,285],"",{borderStyle:'black'});
win.Panel2 = win.P3.add("panel", [235, 5, 505, 250], "");
win.Panel2.txt1 = win.Panel2.add('edittext', [5,25,190,45], '');
Blue text didn't need to change, only 3 lines needed to change.