• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
1

Validating Data in ScriptUI

Community Beginner ,
May 25, 2023 May 25, 2023

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:

  • On page 93, he has an example with this code:

 

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.

 

  • For the field that needs to be 7 characters, I use an Apply instead of an Okay button and I used his red-background code (and modified it to NOT allow commas or decimals). But I don't want the apply button enabled unless the field has seven characters - not 8 or 6. I tried this and it doesn't work:

 

            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;              
                }​

 

  • Similarly for the date field, I found this: https://www.scaler.com/topics/date-validation-in-javascript/ and I verified Date.parse() generates NaN for an invalid date in the format above and a number for a valid date. I want the apply button to be enabled only if I have a valid date in the field, and I want the red text if the field contains anything besides numbers. I tried this and it doesn't work - the Apply button is never enabled:

 

            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!

TOPICS
Scripting

Views

338

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , May 26, 2023 May 26, 2023

= 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

...

Votes

Translate

Translate
Community Beginner ,
May 25, 2023 May 25, 2023

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 25, 2023 May 25, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 25, 2023 May 25, 2023

Copy link to clipboard

Copied

I figured out the date validation code and posted it in the other thread related to this:

https://community.adobe.com/t5/framemaker-discussions/extendscript-and-date-formats/td-p/13798426/pa...

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 25, 2023 May 25, 2023

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!

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 25, 2023 May 25, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 25, 2023 May 25, 2023

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?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 26, 2023 May 26, 2023

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 ==

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 30, 2023 May 30, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 30, 2023 May 30, 2023

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!!!

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 30, 2023 May 30, 2023

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?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 30, 2023 May 30, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 30, 2023 May 30, 2023

Copy link to clipboard

Copied

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 31, 2023 May 31, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 31, 2023 May 31, 2023

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 type 1234A567, I should get 1234567, but I get 5671234.
  • If I type 123456789, I should get 1234567, but I get 9123456.

If I could simulate sending the end key or moving the cursor to the end of the field, it should work.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 31, 2023 May 31, 2023

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:

https://www.geeksforgeeks.org/how-to-place-cursor-position-at-end-of-text-in-text-input-field-using-...

 

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.

 

ID-Tasker - most powerful tool ever created for InDesign

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 31, 2023 May 31, 2023

Copy link to clipboard

Copied

Thanks, Robert, but those properties aren't available in ScriptUI.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 31, 2023 May 31, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Jun 03, 2023 Jun 03, 2023

Copy link to clipboard

Copied

LATEST

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()
   // . . .

 

@Marshall_Brooks 

 

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines