Adding a Prompt to a Variable

Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

I am a beginner in scripting, self taught – finding it easier to learn from examples when I stumble over one that interests me.

 

I found the following script:

 

// https://graphicdesign.stackexchange.com/questions/58812/specific-resize-layer-action

#target photoshop

(function (){

    var startRulerUnits = app.preferences.rulerUnits; 

    app.preferences.rulerUnits = Units.PIXELS; 

    var bounds = activeDocument.activeLayer.bounds; 

    var width = bounds[2].value - bounds[0].value;

    var newSize = (100 / width) * 300;  // 300px

    activeDocument.activeLayer.resize(newSize, newSize, AnchorPosition.MIDDLECENTER);

    app.preferences.rulerUnits = startRulerUnits; 

})();

 

 

To which I added a prompt (line 08) to enter a user defined variable rather than a hard coded value.

 

// https://graphicdesign.stackexchange.com/questions/58812/specific-resize-layer-action

#target photoshop

(function (){

    var startRulerUnits = app.preferences.rulerUnits; 

    app.preferences.rulerUnits = Units.PIXELS; 

    var bounds = activeDocument.activeLayer.bounds; 

    var width = bounds[2].value - bounds[0].value;

    var newWidth = prompt("Enter a new width in pixels.", 300);

    var newSize = (100 / width) * newWidth;

    activeDocument.activeLayer.resize(newSize, newSize, AnchorPosition.MIDDLECENTER);

    app.preferences.rulerUnits = startRulerUnits; 

})();

 

 

All is good if one hits OK, but if one presses Cancel – the actual active layer that should be resized has all content deleted. My guess is that cancel returns a value of null and that null is not a number so therefore the layer content is scaled to nothing.

 

So I tried adding the following line of code suggested in an Illustrator scripting discussion, however it does not stop the layer content being removed:

 

// User pressed the Cancel button: 

if( newWidth == null ){ break };

 

 

I read up on prompts, however I didn’t find anything that helped:

 

user-notification-dialogs

 

Hoping somebody can help set me straight, thanks!

TOPICS
Actions and scripting

Views

1.0K

Likes

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

Adobe Community Professional , Apr 24, 2019 Apr 24, 2019
This is your code that I'm using OK with PhotoShop CS6:(function (){     var startRulerUnits = app.preferences.rulerUnits;       app.preferences.rulerUnits = Units.PIXELS;       var bounds = activeDocument.activeLayer.bounds;       var width = bounds[2].value - bounds[0].value;        var newWidth = prompt("Enter a new width in pixels.", 300);    if( newWidth == null ){ return }; // Test if CANCEL returns null, then do nothing.    if( newWidth == "" ){ return }; // Test if an empty string is ret...

Likes

Translate

Translate
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

Hi Stephen,

instead of break use return

Also make sure that the return value of the prompt is converted to a number if it is not null.

And if that cannot be done that the function will do nothing. Do that with an error alert and then do return.

Also test the returned value with isNaN( returnValueFromPrompt )

isNaN means is not a number.

But do that test after you tested the return value with null.

Note: isNaN( null ) returns falls !

if( isNaN( newWidth ) ){ return };

FWIW: If I run your code with the added line using break the ESTK will throw an error.

I cannot see that the contents of the active layer is scaled to nothing.

Regards,
Uwe

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

See for isNaN( null ) here:

javascript - Why is isNaN(null) == false in JS? - Stack Overflow

Some food for thought:

isNaN( parseInt(null) ); // returns true

isNaN( Number(null) ); // returns false

isNaN( NaN ); // true

NaN == NaN ; // false

Regards,
Uwe

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

Thank you for the reply Uwe!

So I changed break into return. Same result: the history panel shows that there was a Free Transform step and the transparent layer that had pixel content is now blank.

I am trying to digest the rest of your code, however it is currently beyond me… I may have to do some more searches for other uses of the prompt command to see where the differences are. I’m sure that this is very simple, yet currently elusive.

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

Hi Stephen,

post all your code with the added line to test for null.

If I do that code without testing for null I indeed see the issue that the layer content is not there anymore.

null is coerced to +0 and the result therefore is 0 for the new size.

Regards,
Uwe

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

This is where I am at with no success:

 

// https://graphicdesign.stackexchange.com/questions/58812/specific-resize-layer-action

#target photoshop

(function (){

    var startRulerUnits = app.preferences.rulerUnits;

    app.preferences.rulerUnits = Units.PIXELS;

    var bounds = activeDocument.activeLayer.bounds;

    var width = bounds[2].value - bounds[0].value;

// User Interface:

    var newWidth = prompt("Enter a new width in pixels:", 300);

    var newSize = (100 / width) * newWidth;

    activeDocument.activeLayer.resize(newSize, newSize, AnchorPosition.MIDDLECENTER);

// User pressed the Cancel button:

if (newWidth === null) {

        return;

}

    app.preferences.rulerUnits = startRulerUnits;

})();

 

This is apparently common and expected, however I can’t seem to find any examples of how to overcome the issue, converting null to returning no input back to the variable. If zero was returned, then the resize would be 0px which is not good either, so it probably should return the width variable so that there is no change from the input.

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

You have to test before you use the value!

Regards,
Uwe

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

One could do the following tests and drop my other two:

 

if( Number( newWidth ) == 0 ){ return };

if( isNaN( newWidth ) ){ return };

 

But you also have to be careful when using method Number() .

 

Read e.g. here:

Converting strings to numbers with vanilla JavaScript

 

Regards,

Uwe

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

You could also refine the returned string with a RegExp and test the result for NaN.

if( isNaN( parseFloat( newWidth.replace(/^\D+/,"") )) ){ return };

So f a user enters " garbage896.78garbage" parseFloat() could extract the 896.78 .

Using this approach a bit differently so that a new value could be fed into a new prompt:

var newWidth = " garbage656.78garbage ";

var mightBeANumber = parseFloat( newWidth.replace(/^\D+/,"") );

if( !isNaN( mightBeANumber ) ){ $.writeln( mightBeANumber ) }

else{ $.writeln( "Input is not a number." ) };

Regards,

Uwe

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

I would prefer to write the function slightly differently but that should not be the problem.

#target photoshop 

function scale (){ 

    var startRulerUnits = app.preferences.rulerUnits;   

    app.preferences.rulerUnits = Units.PIXELS;   

    var bounds = activeDocument.activeLayer.bounds;   

    var width = bounds[2].value - bounds[0].value; 

    var newWidth = prompt("Enter a new width in pixels.", 300);

  if (newWidth == null) {return};

    var newSize = (100 / width) * newWidth; 

    activeDocument.activeLayer.resize(newSize, newSize, AnchorPosition.MIDDLECENTER); 

    app.preferences.rulerUnits = startRulerUnits;   

};

scale ();

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

This is your code that I'm using OK with PhotoShop CS6:

(function (){

    var startRulerUnits = app.preferences.rulerUnits;  

    app.preferences.rulerUnits = Units.PIXELS;  

    var bounds = activeDocument.activeLayer.bounds;  

    var width = bounds[2].value - bounds[0].value;

  

    var newWidth = prompt("Enter a new width in pixels.", 300);

    if( newWidth == null ){ return }; // Test if CANCEL returns null, then do nothing.

    if( newWidth == "" ){ return }; // Test if an empty string is returned, then do nothing.

    // Now hope for the best that prompt returns something that can be easily coerced to a reasonable number

    var newSize = (100 / width) * newWidth;

    activeDocument.activeLayer.resize(newSize, newSize, AnchorPosition.MIDDLECENTER);

    app.preferences.rulerUnits = startRulerUnits;  

})();

My concern is that someone, me?, is typing something to the prompt that cannot be coerced to a number.

Prompt always returns strings when the OK button is used. The default of the prompt is highlighted. If I use backspace and Return an empty string will be returned that also is coerced to 0 and the result is the same: An empty layer. So I included yet another line to test for this.

Regards,
Uwe

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

Thank you Uwe, that is working!

So, if one is using numerical entry, it is probably best to not use prompt as a quick and dirty UI object?

Would it then be a case of using scriptUI and more complex code instead?

Likes

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
Adobe Community Professional ,
Apr 24, 2019 Apr 24, 2019

Copy link to clipboard

Copied

Stephen_A_Marsh  wrote

Thank you Uwe, that is working!

So, if one is using numerical entry, it is probably best to not use prompt as a quick and dirty UI object?

Would it then be a case of using scriptUI and more complex code instead?

Prompt is much less complex then a Script UI dialog.  You just need to validate that the user entered a valid data for your use. If they enter something other than you what you want you can alert them to that while re-prompting.    Put the prompt in a loop till a valid replay is entered or the user cancels..

You may have a range in mind  like 72 to 600 you can test that the reply is a number in the range. If they cancel return it not in the range re-prompt.

JJMack

Likes

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
Explorer ,
Nov 25, 2021 Nov 25, 2021

Copy link to clipboard

Copied

How would I script a prompt for the units of measurement?

I want to prompt if the Units should be in INCHES or MM

and then would use the response here: 

app.preferences.rulerUnits = Units.INCHES OR Units.MM

And I would also use the response in the filename, along with the doc width & height (filename would include the widthXheight + "inches", else filename would include the widthXheight + "mm")

 

 

Likes

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
Explorer ,
Nov 25, 2021 Nov 25, 2021

Copy link to clipboard

Copied

Or could I get the units from the document size already open? ie. what appears in Image > Image Size > where the width & height have "Inches" beside them?

Likes

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
Adobe Community Professional ,
Nov 26, 2021 Nov 26, 2021

Copy link to clipboard

Copied

quote

How would I script a prompt for the units of measurement?

By @CatoPbx

 

Prompt, confirm  and  alert  are easy UI choices, however, they may require some extra code to make them more usable. This is essentially the same answer to the one that I made in your other question in a different topic thread. 

 

A prompt is a poor UI element choice for this task as one has to take into account users entering incorrect information into the prompt. Ideally you would use scriptUI to create a custom user interface with dropdown menu items, radio-buttons etc. This requires more code and scripting knowledge.

 

So yes, it is possible to use a prompt for this task, however, to do it well one would need to do better than this:

 

var userUnits = prompt('Enter the ruler unit of measure as either MM or INCHES in UPPERCASE text only!', 'INCHES');
eval("app.preferences.rulerUnits = Units." + userUnits);

 

Note: It is simple enough to directly pass a number from a variable to a statement (numbers are numbers)... However it is not as simple to pass text (string) from a variable to a statement, as the statement is broken by the string. This is where eval(); comes into play, the entire statement is constructed as a string and is then parsed and run as a standard statement.

Likes

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
Adobe Community Professional ,
Nov 27, 2021 Nov 27, 2021

Copy link to clipboard

Copied

LATEST

The following code may not be foolproof, however, I'm happy enough with it for now:

 

rulerUnitPrompt();

function rulerUnitPrompt() {

    // Prompt user for input
    var userInput = prompt('Enter the unit of measure as either MM or INCHES in UPPERCASE text only!', 'INCHES');

    // Test if cancel returns null
    if (userInput === null) {
        //alert('Script cancelled!');
        return;
    }

    // Test if an empty string is returned and loop the prompt
    while (userInput.length === 0) {
        userInput = prompt('Blank value not accepted! Enter the unit of measure as either MM or INCHES in UPPERCASE text only!', 'INCHES');
    }

    /*
    // Test if an empty string is returned 
    if (userInput === "") {
        alert('A value was not entered, script cancelled!');
        return;
    }
    */

    // Force uppercase
    var inputToUpper = userInput.toUpperCase();

    // Regex gyrations to coerce inappropriate input to something useable
    var finalInput = inputToUpper.replace(/[^MINCHES]/g, '').replace(/(.*)(IN)(.*)/g, '$2CHES').replace(/(.*)(MM)(.*)/g, '$2');

    // Conditional check for INCHES or MM
    if (/INCHES|MM/.test(finalInput) === false) {
        alert('A valid value was not entered, script cancelled!');
        return;
    }

    // Final (redundant?) fallback test if an empty string is returned 
    if (finalInput === "") {
        alert('A value was not entered, script cancelled!');
        return;
    }

    // Set the ruler units to the prompt value
    eval("app.preferences.rulerUnits = Units." + finalInput);

    //alert("app.preferences.rulerUnits = " + app.preferences.rulerUnits);

}

 

P.S. When working with ruler units, one may wish to capture and restore the original units:

 

https://gist.github.com/MarshySwamp/898ae3237305787d0683125166aeb480

 

Likes

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