6 Replies Latest reply on Apr 12, 2009 1:42 PM by Steven..

    [JS][CS3] Validating edittexts in ScriptUI

    moniuch
      Hi,

      I have to attach validation methods to a bunch of edit fields' onChange. Some fields would have to contain floats (toFixed(2)), some - integers, some - capitalized strings after the field has lost focus. I'm ready with 3 functions to be attached to controls, but I would like to hear the most robust solution to this problem. Would you use ctrl.onChange = fn, or rather ctrl.addEventListener()...?

      Any comments welcome.
      M.
        • 1. Re: [JS][CS3] Validating edittexts in ScriptUI
          Level 1
          In CS3, you don't get any real benefit from using the event listener. Just use the onChange and onChanging callbacks.

          In CS4, you get a key press event, and that changes everything.

          Harbs - you're desire to make ScriptUI edit boxes act like the InDesign equivalent is now relatively easy to do, including the nudges.

          Bob
          • 2. Re: [JS][CS3] Validating edittexts in ScriptUI
            Level 1
            Wait a second... Something I hadn't considered before.

            The problem of relying on the onChange event of a single field is that a click in an OK button will still close the window.

            But, if you set an event listener to the OK button's click event, you can validate all fields and then cancel the event.

            Here's an example that does work in ESTK2 (CS3) (I think this code will paste and show correctly, if it doesn't, sorry)

            // Basic ScriptUI validation

            /* This script shows the basics of validation using ScriptUI events

            By using the "change" event, a script can be notified that a value has changed. The problem with this approach is that it
            requires a field to lose focus for the event to fire. For example, a user can type an invalid number in a field, then, without leaving
            the field, click the OK button (which is still enabled because validation has not happened on the invalid field yet). In this case, clicking
            the OK button causes the field to lose focus, the validation occurs, but the OK button has already been pressed, and the dialog will
            close with an invalid entry.

            We could use the "changing" event that fires for every character typed; but, that approach brings its own set of complications. For example, the
            user is typing "12 inches" in the field. If the validation routine accepts units and abbreviations, as the user types we get the following states:
            "1" - valid
            "2" - valid
            " " - valid
            "i" - INVALID
            "n" - valid
            "c" - INVALID
            "h" - valid
            "e" - INVALID
            "s" - valid

            That doesn't work.

            If we intercept the OK button's mouseDown event, we can validate all fields, and either allow the OK button click event or cancel it.
            If cancelled, the OK button can disabled, and a visual cue could be provided as to the offending field(s).
            With this approach, the valdiation routines need to have a reference to the OK button, and all registered validations
            must happen each time a field is edited to set the state of the OK button.

            */

            // setControlState sets the background color of a control to "good" or "bad". The white for good, red for bad
            setControlState= function( myControl ) {
            if ( myControl.isValid ) { // we're good, make it white
            myControl.graphics.backgroundColor = myControl.graphics.newBrush( myControl.graphics.BrushType.SOLID_COLOR, [1,1,1,1] );
            } else { // we're bad, make the field background red (straight red, [ 1, 0, 0, 1] is a bit harsh, so we're using a red-ish color
            var myRedColorArray = [ 210/255, 12/255, 82/255, 1];
            myControl.graphics.backgroundColor = myControl.graphics.newBrush( myControl.graphics.BrushType.SOLID_COLOR, myRedColorArray );
            }
            }
            // validateInteger will ensure that a field contains a valid integer
            validateInteger = function( myEvent ) {
            /*
            myEvent is passed to the handler when the event fires, myEvent.target is the target control of the event.
            We're adding a property "isValid" to the control so we can quickly check the state of any control
            Note that parseInt parses "12x" as 12, so you can't just check for isNaN on a parseInt...
            */
            // make this a required field by checking to see if there's anything there
            if ( myEvent.target.text.length == 0 ) {
            myEvent.target.isValid = false;
            } else if ( isNaN( Number( myEvent.target.text ) ) ) { // if it can't be cast to a number, it's obviously bad
            myEvent.target.isValid = false;
            } else {
            // if we can parseIn the content of the field, change it back to a string, and get the original value, the original value must have been a string
            myEvent.target.isValid = ( parseInt( myEvent.target.text ).toString() == myEvent.target.text );
            }
            // set the control's background to red if it's invalid
            setControlState( myEvent.target );
            // check all the fields, and set the OK button state
            validateAll( myEvent.target.window.okButton );
            }
            // validateReal will ensure a field has a valid Real number
            validateReal = function( myEvent ) {
            // make this a required field by checking to see if there's anything there
            if ( myEvent.target.text.length == 0 ) {
            myEvent.target.isValid = false;
            } else if ( isNaN( Number( myEvent.target.text ) ) ) { // if casting to a number is NaN, it's bad...
            myEvent.target.isValid = false;
            } else {
            // if user enters ".2", parseFloat turns it into "0.2" so the same parseFloat().toString() won't work like it does for integers
            // using a regex instead
            var regex = /\d*\.{0,1}\d*/g; // zero or more digits, possibly a decimal point, followed by zero or more digits
            // if the first element of the array returned from String.match equals the original, we're good
            try {
            myEvent.target.isValid = ( myEvent.target.text == myEvent.target.text.match( regex )[ 0 ] );
            } catch( e ) {
            myEvent.targetisValid = false;
            }
            }
            //set the control's background to red if it's invalid
            setControlState( myEvent.target );
            // now check all the fields
            validateAll( myEvent.target.window.okButton );
            }
            // uses the UnitValue object to ensure whatever is typed in will be a valid measurement unit
            // for this handler, we wil set a "fieldUnit" property on the edit box, all units will be converted to those units
            // we're supporting all units that UnitValue supports except pixels and percents as they are based on a base unit and traditional points/picas as no one will likely enter "tpc" or "tpt" vs "pt" or "pc"
            validateUnits = function( myEvent ) {
            // no empty fields
            if ( myEvent.target.text.length == 0 ) {
            myEvent.target.isValid = false;
            } else {
            // this regex will validate the basic form of a unit value - a real number followed by zero or more spaces and possibly a valid unit string
            var regex = /\d*\.{0,1}\d* *(?:in|inch|inches|ft|foot|feet|yd|yard|yards|mi|mile|miles|mm|millimeter|millimeters|cm| centimeter|centimeters|m|meter|meters|km|kilometer|kilometers|pt|point|points|pc|pica|pica s|ci|cicero|ciceros)?/gi;
            var myMatch = myEvent.target.text.match( regex );
            try {
            myEvent.target.isValid = ( myEvent.target.text == myEvent.target.text.match( regex )[ 0 ] );
            } catch( e ) {
            myEvent.target.isValid = false;
            }

            if ( myEvent.target.isValid ) {
            // create a new UnitValue from the target text
            // it's posible that the units were left off, in which case the fieldUnits are assumed.
            // so use the regex from validateReal to see if there's a unit attached to the value
            var regex = /\d*\.{0,1}\d*/g; // zero or more digits, possibly a decimal point, followed by zero or more digits
            // if the first element of the array returned from String.match equals the original, there's no units
            try {
            var hasUnits = ( myEvent.target.text != myEvent.target.text.match( regex )[ 0 ] );
            } catch( e ) { // if this errors, something is very, very wrong...
            myEvent.target.isValid = false;
            setControlState( myEvent.target );
            validateAll( myEvent.target.window.okButton );
            return;
            }
            if ( !hasUnits ) {
            var myUnitValue = new UnitValue( myEvent.target.text + " " + myEvent.target.fieldUnit );
            } else {
            var myUnitValue = new UnitValue( myEvent.target.text );
            }
            if ( isNaN( myUnitValue ) ) {
            myUnitValue = new UnitValue( "0 " + myEvent.target.fieldUnit );
            }
            try {
            // attempt to convert it to the fieldUnit - if it can't be done, this will error
            myUnitValue.convert( myEvent.target.fieldUnit );
            // the reason for the convert is that the UnitValue.toString() will inclue the abbreviated units for us, using UnitValue.as() will not
            myEvent.target.text = myUnitValue.toString();
            } catch ( e ) {
            // if we errored, it wasn't a valid measurement
            myEvent.target.isValid = false;
            }
            }
            }
            setControlState( myEvent.target );
            validateAll( myEvent.target.window.okButton );
            }

            // validateAll - this function is hard wired to check the isValid state (set in the validation routines) of the edit boxes used in the test example
            validateAll = function
            • 3. Re: [JS][CS3] Validating edittexts in ScriptUI
              Level 1
              Damn, too big.

              If you would like the script, please send me an email:

              rstucky@starband.net

              I also have a version for CS4. I also have a script for CS4 that shows how to "nudge" a field's value up or down using the arrow keys.

              Regards

              Bob
              • 4. Re: [JS][CS3] Validating edittexts in ScriptUI
                pjaromin Level 1

                Bob-

                 

                I found your post after writing something similar for my app...but I get an error when attempting to set the backgroundColor on the edit text element.

                 

                My code:

                FieldValidator.setState = function(control) {
                    $.writeln('Control is: ' + control.constructor.name);
                    try {
                        var g = control.graphics;
                        var color = FieldValidator.COLOR_VALID;
                        if (!control.isValid) {
                            color = FieldValidator.COLOR_INVALID;
                        }
                        g.backgroundColor = g.newBrush(g.BrushType.SOLID_COLOR, color);
                    } catch (error) {
                        $.writeln(error);
                    }
                    if (!control.isValid) { $.writeln("Field invalid."); }
                }

                 

                The output:

                Control is: EditText
                Error: Cannot set backgroundColor property for this element type
                Field invalid.

                 

                 

                What am I missing? This is CS3 on Windows Vista...perhaps it only works on OSX?

                • 5. Re: [JS][CS3] Validating edittexts in ScriptUI
                  Olav Martin Kvern Level 3

                  Hi Bob,

                   

                  Oh, hey, that's right, that's the stuff I asked you to write that I've never gotten around to writing up as a tutorial. Jeez.

                   

                  Still, there seems to be this other stack of work that's deemed to be higher priority....:-)

                   

                  Thanks,

                   

                  Ole

                  • 6. Re: [JS][CS3] Validating edittexts in ScriptUI
                    Steven.. Level 3

                    If I remember correctly either backcolor or forecolor for ScriptUI EditText is new to CS4, even though the property existed an crashed beforehand.

                    Steven F.

                    http://www.scriptui.com