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
...Copy link to clipboard
Copied
Figured out the first issue:
win.Panel2.ApplyBtn.enabled = valid && win.Panel2.txt2.text.length=7;
needs to be:
win.Panel2.ApplyBtn.enabled = valid && win.Panel2.txt2.text.length==7;
Double == before the 7
Copy link to clipboard
Copied
Ran into a hiccup with the date. Date.parse() will not work for me. 20230523 is valid and what I want, but 05232023 is also valid, but NOT compatible for my purposes. There is code further up the page that should work, but it doesn't seem to work with ScriptUI/ESTK.
Copy link to clipboard
Copied
I figured out the date validation code and posted it in the other thread related to this:
Copy link to clipboard
Copied
> I don't see where "characters: 10" is explained.
Well, the PDF has an index, which has an entry for 'characters' and guides you to p. 11, where it says:
> The characters property is used to set the control’s width
The control's width is not the same as the number of characters that you can enter in the control, but I'll agree with you that there's room for confusion here.
You can monitor what's entered into a control ('field'), there are some examples of that in the PDF.
> But I don't want the apply button enabled unless the field has seven characters
Take a look at this script: https://creativepro.com/files/kahrel/indesign/grep_query_manager.html
There's an option to save a configuration as a preset. The interface has two buttons: Save and Cancel. While you're typing a preset name, if what you type matches an existing preset, the Save button's text changes to Replace. It's in the function getValidName
> 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.
Absolutely!
Copy link to clipboard
Copied
Here's a sample of how to enable a button only when a text field's content has a certain length:
w = new Window ('dialog');
w.field = w.add ('edittext {characters: 10, active: true}');
w.button = w.add ('button {text: "Apply"}');
w.field.onChanging = function () {
w.button.enabled = w.field.text.length === 7;
}
w.show();
You'd probably need to set the burron's state when the script is started, but I didn't add that here because the field might be populated from a history file.
(But I now see that you already fixed it. Mustard after the meal. Sorry.)
P.
Copy link to clipboard
Copied
Actually, stupid question time ...
I've done much more in Visual Basic, thus =7 seemed logical to me. I changed it to ==7 and that worked. You said ===7.
What are the differences and when would I use either one?
Copy link to clipboard
Copied
= 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 successfully coerces the variables into the same type (string or number, I don't know which).
Because strict comparison evaluates considerably quicker you should use it where you can. Especially in InDesign's DOM, when you test some enumeration repeatedly. For example
if (myPage.side === PageSideOptions.LEFT_HAND) {
is considerably quicker than
if (myPage.side == PageSideOptions.LEFT_HAND) {
If you don't know whether the two items to be compared are type-compatible, use ==
Copy link to clipboard
Copied
Excellent explanation - like I said, my main background is Visual Basic, which is only one "=" sign and the equivalent of "==" would be a type mismatch error.
Copy link to clipboard
Copied
Okay - this is what I have so far:
var w = new Window ('dialog');
// First attempt - allows more than 7 Characters.
w.group = w.add ('group');
w.group.add ('statictext {text: "Enter a 7-Digit number:"}');
w.input = w.group.add ('edittext {characters: 10, active: true, justify: "right"}');
w.buttons = w.add ('group {alignment: "right"}');
w.ok = w.buttons.add ('button {text: "OK", enabled: false}');
w.buttons.add ('button {text: "Cancel"}');
w.input.onChanging = function () {
var valid = /^[\d]+$/.test (w.input.text);
this.graphics.backgroundColor = this.graphics.newBrush (this.graphics.BrushType.
SOLID_COLOR, valid ? [1, 1, 1, 1] : [1, 0.5, 0.5, 1]);
w.ok.enabled = valid && w.input===7;
}
w.show();
It works fairly well - if you put anything other than a digit, it turns red, if you have more or less than 7 characters, OK is not enabled.
What I ideally want:
Field starts with "XXXXXXX". I will add a clear button that empties the field. I want cut and paste to work, but I only want to allow digits in the field (and probably delete or backspace). If the user types "A", I don't want an "A" and red background, I just want the input ignored, and I don't want more than 7 characters, if the field text is already 7 characters, I want the input ignored.
There were some helpful answers here, but https://stackoverflow.com/questions/2808184/restricting-input-to-textbox-allowing-only-numbers-and-d... but the most elegant seemed to be:
var validNumber = new RegExp(/^\d*\.?\d*$/);
var lastValid = document.getElementById("test1").value;
function validateNumber(elem) {
if (validNumber.test(elem.value)) {
lastValid = elem.value;
} else {
elem.value = lastValid;
}
}
But I wasn't sure how to implement it - or if I had to be using the keyboard input value or the onchanging value.
Thanks in advance!!!
Copy link to clipboard
Copied
Something I thought would be easy...
I started with a previous script that I had written which had panel 1 above panel 2. For this script, I would like to have panel1 on the left side of the window and Panel 2 next to it on the right. I would prefer the window to auto-size.
I thought this would work:
var win = new Window("palette", "My Window:"); // bounds = [left, top, right, bottom]
win.radioPanel = win.add("panel", [5, 10, 230, 90], "Panel 1");
win.Panel2 = win.add("panel", [235, 10, 505, 230], "Panel 2");
win.show();
But it still shows Panel 1 above Panel 2.
This works:
var win = new Window("palette",'MyWindow:', [15, 45, 525, 300]); // bounds = [left, top, right, bottom]
win.radioPanel = win.add("panel", [5, 10, 230, 90], "Panel 1");
win.Panel2 = win.add("panel", [235, 10, 505, 230], "Panel 2");
win.show();
But if I use this, I think ideally, I need to figure out which screen is running FM, what the resolution of that screen is, set left to 1/2 screen width - 1/2 window width, set top to 1/2 screen heigth - 1/2 window height, etc.
Is there a simpler way?
Copy link to clipboard
Copied
Somewhat clunky, but:
//var win = new Window("palette",'MyWindow:', [15, 45, 525, 300]); // bounds = [left, top, right, bottom]
var win = new Window("palette",'MyWindow:', [$.screens[0].right/2 - 253,$.screens[0].bottom/2 - 127, $.screens[0].right/2 + 253, $.screens[0].bottom/2 + 127]); // bounds = [left, top, right, bottom]
//var win = new Window("palette", "My Window:"); // bounds = [left, top, right, bottom]
win.radioPanel = win.add("panel", [5, 10, 230, 90], "Panel 1");
win.Panel2 = win.add("panel", [235, 10, 505, 230], "Panel 2");
win.show();
Works for single-screen or dual-monitor if FrameMaker is on screen 1. (Otherwise, it will show the dialog on Screen 1.) If I could figure out how to tell which screen has the active document, I could use that in the code and it would work.
Copy link to clipboard
Copied
See https://community.adobe.com/t5/framemaker-discussions/determine-screen-number-of-active-document/m-p... - for the sizing - at least the clunky method ...
Copy link to clipboard
Copied
I tried to implement the StackOverflow solution. Logically, it makes sense to me. If you type a valid character, it stores the field text in the lastValid variable. If you add a valid character, it increases that variable. If you type an invalid character, it replaces the field with the last valid content - basically it deletes the character you just input.
The issue I am having is lastValid becomes undefined, and I'm not sure why. Here is what I have so far:
// Attempt to limit input.
w.group = w.add ('group');
w.group.add ('statictext {text: "Enter a 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"}');
w.input.text="XXXXXXX"
var lastValid = w.input.text;
alert(lastValid); // returns XXXXXX
w.input.onChanging = function (lastValid) {
alert(lastValid); // returns undefined
w.ok.enabled = false;
var valid = /^[\d]+$/.test (w.input.text)&& w.input.text.length===7;
this.graphics.backgroundColor = this.graphics.newBrush (this.graphics.BrushType.
SOLID_COLOR, valid ? [1, 1, 1, 1] : [1, 0.5, 0.5, 1]);
w.ok.enabled = valid;
alert(lastValid); // returns undefined
var valid2 = /^[\d]+$/.test (w.input.text)&& w.input.text.length<7;
if (valid2){
alert("valid2");
lastValid = w.input.text;
alert(lastValid); // Returns field contents
}
else{
alert("Not valid2");
w.input.text = lastValid; // changes field contents to undefined
}
}
w.clear.onClick = function(){
var valid = /^[\d]+$/.test (w.input.text) && w.input.text.length===7;
if (valid){
if (confirm("Do you want clear the input field") ===false) {
return;
}
}
w.input.text = "";
}
w.show();
Initially, I have lastValid defined in the onChanging event function, but then it was updating whether the input was valid or not, so it didn't work.
Hopefully, someone sees a typo above, but otherwise, I'm going to look into keypress events, and then give up on this.
Copy link to clipboard
Copied
Took a brute force approach. Again, what I am looking for is anything other than a number is ignored, and once 7 characters are reached, any input is ignored.
New Code:
var w = new Window ('palette');
// Secong Attempt to limit input.
w.group = w.add ('group');
w.group.add ('statictext {text: "Enter a 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"}');
w.input.onChanging = function (lastValid) {
w.ok.enabled = false;
var valid = /^[\d]+$/.test (w.input.text)&& w.input.text.length===7;
this.graphics.backgroundColor = this.graphics.newBrush (this.graphics.BrushType.
SOLID_COLOR, valid ? [1, 1, 1, 1] : [1, 0.5, 0.5, 1]);
w.ok.enabled = valid;
var valid2 = /^[\d]+$/.test (w.input.text)
if (!valid2){
// https://stackoverflow.com/questions/27772805/need-a-regex-to-remove-everything-except-numbers
w.input.text = w.input.text.replace(/\D+/g, "");
// https://stackoverflow.com/questions/596481/is-it-possible-to-simulate-key-press-events-programmatically
w.input.dispatchEvent(new KeyboardEvent('keydown', {'key': 'End'})); // Keyboard Event does not have a constructor.
}
var valid3 = w.input.text.length<7;
if (!valid3){
w.input.text =w.input.text.substring(0,7);
}
}
w.clear.onClick = function(){
var valid = /^[\d]+$/.test (w.input.text) && w.input.text.length===7;
if (valid){
if (confirm("Do you want clear the input field") ===false) {
return;
}
}
w.input.text = "";
}
w.show();
What this does:
If you type anything other than a number, the code deletes the non-numeric items. If you add numbers after the length is 7, the code returns the first 7 characters. If I could simulate pressing the "End" key, it would work fine.
Unfortunately, it moves the cursor back to the beginning after it does the replacement - for example:
If I could simulate sending the end key or moving the cursor to the end of the field, it should work.
Copy link to clipboard
Copied
I'm not JS expert and definitely not on InDesign's ScriptUI implementation - prefer VB6 - but from quick googling - javascript textfield cursor position - there is a selectionStart and selectionEnd for text fields in JS:
http://help.dottoro.com/ljtfkhio.php
Supported by objects:
HTML elements:
input:password, input:search, input:text, isindex, textarea
Or even more:
TextRange.moveEnd(): It helps to move the end of the range by a specified number of units.
TextRange.moveStart(): It moves the start of the range by a specified number of units.
Copy link to clipboard
Copied
Thanks, Robert, but those properties aren't available in ScriptUI.
Copy link to clipboard
Copied
> Unfortunately, it moves the cursor back to the beginning after it does the replacement
Yes, that's annoying. Not much you can do about it I don't think. Unless @Marc Autret has an idea.
Copy link to clipboard
Copied
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 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];
}
// . . .
// Other stuff, w.show()
// . . .
Note 1. — Dispatching new KeyboardEvent instances does not work in ScriptUI in the way you expect it. We tried this strategy for a very long time to work around some bugs, but it only produces logical events without any impact in the UI. Put more briefly, we have never succeeded in emulating keystrokes in a SUI control (although we can positively receive and analyze KB user events through a "keydown" listener).
Note 2. — To my knowledge, the property EditText.graphics.backgroundColor is no longer effective in CC (?) but it may depend on the OS (?) [Still works in CS3-CS6 though.]
Hope that helps.
Best,
Marc