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

Line breaks not working on secondary script running from UI

Participant ,
Apr 15, 2021 Apr 15, 2021

Copy link to clipboard

Copied

I have an issue I have encoutered a couple of times recently whereby a '\n' line break works fine in a script if it is run directly from the script menu, but if run from a palette UI I have created it returns as literal text i.e. 'Line \nBreak' rather than 'Line

Break' (see screenshots and simple code example of the script being run from the UI palette):

alert("Line \nBreak");

Does anyone know the reason for this and how I would overcome the issue?

Run_From_UI.png

Run_Direct.png

  

TOPICS
Scripting

Views

1.7K

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 2 Correct answers

Valorous Hero , Apr 26, 2021 Apr 26, 2021

As promised, check this out:

 

#target illustrator
#targetengine main // <--- IMPORTANT: turns out, BridgeTalk.onResult is USELESS without the #targetengine

function test () {

	function bridgeTalkEncode (txt) {
		txt = encodeURIComponent (txt);
		txt = txt.replace( /\r/, "%0d" );
		txt = txt.replace( /\n/, "%0a" );
		txt = txt.replace( /\\/, "%5c" );
		txt = txt.replace(/'/g, "%27");
		return txt.replace(/"/g, "%22"); 
	};

	function sendBasicBT (targetApp, scriptCode, resultFunc) {
		var bt =
...

Votes

Translate

Translate
Community Expert , May 28, 2021 May 28, 2021

Hi glibshaft,

try this:

var alertMessage = 
'''
Line
Break
''';

alert( alertMessage );

 

From my German Windows 10 machine with AI 25.2.3:

AlertWithTrippleFencingString.PNG

 

Regards,
Uwe Laubender

( ACP )

Votes

Translate

Translate
Adobe
Community Expert ,
Apr 15, 2021 Apr 15, 2021

Copy link to clipboard

Copied

I don't have a complete answer for you, but i can say that when you run code from a UI Panel, things get wonky. I think you need to pass the information through BridgeTalk in order to get the expected output. I've never sat down and tried to figure out bridgetalk, so i don't have any specific advice. But hopefully that'll at least give you a good jumping off point for finding the answer you need. 

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
Valorous Hero ,
Apr 15, 2021 Apr 15, 2021

Copy link to clipboard

Copied

For doing more powerful Palette functions (or as you may think of it, doing them as a normal person would expect- you pass the script in and it should just work as usual, no added funny-business, right?) - you have to go ahead and hide the string's stuff that BridgeTalk messes with or doesn't work well with, by encoding them.
Thanks to Bob Stucky.

  function bridgeTalkEncode(txt) {

    /* thanks to Bob Stucky */

    txt = encodeURIComponent(txt);

    txt = txt.replace(/\r/, "%0d");

    txt = txt.replace(/\n/, "%0a");

    txt = txt.replace(/\\/, "%5c");

    txt = txt.replace(/'/g, "%27");

    return txt.replace(/"/g, "%22");

  };

 

 

  function bridgeTalkDecode(txt) {

    return txt.replace(/%0d/g, "\r").replace(/%0a/g, "\n").replace(/%5c/g, "\\").replace(/%27/g, "'").replace(/%22/g, '"');

  };

 

 

https://community.adobe.com/t5/illustrator/how-can-i-read-the-color-of-a-given-pixel-in-an-image/m-p/9353278

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
Participant ,
Apr 15, 2021 Apr 15, 2021

Copy link to clipboard

Copied

Thanks for this, I will take a look.

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
Valorous Hero ,
Apr 15, 2021 Apr 15, 2021

Copy link to clipboard

Copied

I have spent countless hours effing around with why my BridgeTalk was doing these types of things in 2014, so once I found an old post featuring this code from Bob Stucky, I remain forever grateful to the great Bob Stucky.
Other people may have found this sooner and it would have been no-big-deal. But me, I pulled my hair out and was close to barking at people - so regarding this issue you'll always find me heaping praises on none other than.. Bob Stucky!

 

I tried the link but it's not working even though it works: https://community.adobe.com/t5/illustrator/how-can-i-read-the-color-of-a-given-pixel-in-an-image/m-p...

Maybe I need to edit the post if my paste did that.
But here's the code which uses the function, notice for some reason I never used the decode function except the simple decodeURI.

    meat = bridgeTalkEncode(meat);

    btMsg = "var scp ='" + meat + "'";

    btMsg += ";\nvar scpDecoded = decodeURI( scp );\n";

    if (typeof resultFunc == "function") {

      btMsg += "btResult = eval( scpDecoded );";

    } else {

      btMsg += "eval( scpDecoded );";

    }

    bt.body = btMsg;

    if (typeof resultFunc == "function") {

      bt.onResult = function(info) {

        info = JSON.parse(info.body);

        resultFunc(info);

      };

    }

    bt.onError = function(res) {

      alert(res.body);

    };

    bt.send();

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
Participant ,
Apr 15, 2021 Apr 15, 2021

Copy link to clipboard

Copied

So, excuse my ignorance, but how would I go about applying this to the onclick function in my UI and my secondary script? (see below for my current onclick function):

  var scriptLoc = File($.fileName).path;
var scriptToLoad = new File (scriptLoc + "/Sub_Code/Create_Line_Break_Text.jsx/")

    scriptToLoad.open ("r");
    var message = scriptToLoad.read();
    scriptToLoad.close()

var scriptPath = File($.fileName).path;
var bt = new BridgeTalk();
bt.target = "Illustrator";
bt.body = message;
bt.send();

And my current secondary script to run from the UI:

alert("Line \nBreak");

 

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
Valorous Hero ,
Apr 15, 2021 Apr 15, 2021

Copy link to clipboard

Copied

I say, use it by wrapping your scriptToLoad.read() call in it.

 

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
Participant ,
Apr 16, 2021 Apr 16, 2021

Copy link to clipboard

Copied

Thanks for the suggestion, to be honest, I got a little lost with how to do this and have tried all sorts to get it to work but can't seem to get it to work as I need.

 

I did however add an interim script that then launches the line break script from the UI that seems to works (the only down side is that as I am using the 'execute()' command I have had to set my final script to open into Illustrator by default). See codes below:

 

UI onClick function:

var scriptLoc = File($.fileName).path;
var scriptToLoad = new File (scriptLoc + "/Sub_Code/LaunchLineBreak.jsx/")


    scriptToLoad.open ("r");
    var message = scriptToLoad.read();
    scriptToLoad.close()

var scriptPath = File($.fileName).path;
var bt = new BridgeTalk();
bt.target = "Illustrator";
bt.body = "var SCRIPT_LOCATION = \"" + scriptPath + "\"" + message;
bt.send();

 

Interim script:

var fileLocation = (typeof(SCRIPT_LOCATION) == "string")? SCRIPT_LOCATION : $.fileName;
var f = fileLocation + "/Sub_Code/CreateLineBreakText.jsx";
var file1 = File(f);
file1.execute();

 

Final script:

alert("Line \nBreak");

I am still interested as to how I would actually wrap my scriptToLoad.read() call in my onClick function to eliminate the interim script. Sorry to be a pain but could you elaborate on how I would go about that?

Many thanks in advance for your hugely helpful advise.

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
Valorous Hero ,
Apr 21, 2021 Apr 21, 2021

Copy link to clipboard

Copied

Yea, I'll try to make a snippet soon.

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
Valorous Hero ,
Apr 26, 2021 Apr 26, 2021

Copy link to clipboard

Copied

As promised, check this out:

 

#target illustrator
#targetengine main // <--- IMPORTANT: turns out, BridgeTalk.onResult is USELESS without the #targetengine

function test () {

	function bridgeTalkEncode (txt) {
		txt = encodeURIComponent (txt);
		txt = txt.replace( /\r/, "%0d" );
		txt = txt.replace( /\n/, "%0a" );
		txt = txt.replace( /\\/, "%5c" );
		txt = txt.replace(/'/g, "%27");
		return txt.replace(/"/g, "%22"); 
	};

	function sendBasicBT (targetApp, scriptCode, resultFunc) {
		var bt = new BridgeTalk();
		bt.target = targetApp;

		var btMsg = "var scp ='" + bridgeTalkEncode( scriptCode ) + "';\n";
		btMsg += "var scpDecoded = decodeURI( scp );\n"; 
		btMsg += "res = eval( scpDecoded );";
	
		bt.body = btMsg;
		bt.onError = function (e) {
			alert("BT Error:\n" + e.body);
			if (typeof resultFunc != "undefined") {
				resultFunc(e.body);
			}
		}
		if (typeof resultFunc != "undefined") {
			bt.onResult = function (msg) {
				alert(msg.body);
				var myResult = msg.body;
				resultFunc(myResult);
			}
		}
// alert(btMsg);
		bt.send();
	};

	// NORMAL STRING: note the double-escape backslashes.
	// var myStringScript = "alert('Line \\n break'); 'ABCDEF!';";

	var myScriptCode = function btTest () { alert('Line \n break'); return 'ABCDEF!'; };
	var myScriptToSend = myScriptCode.toString() + "\nbtTest()"; // <--- create the result return variable here.

	var doc = app.activeDocument;

	var completionFunc = function (btResult) {
		alert("Hello back in Illustrator, the result was:\n" + btResult);
		postCompletionFunc();
	}

	function postCompletionFunc () {
		alert("But the fun doesn't stop here, we go on and on doing stuff back in Illustrator");
	}

	// When sending a simple string.
	// sendBasicBT("photoshop", myStringScript, completionFunc);

	// When sending a function:
	sendBasicBT("photoshop", myScriptToSend, completionFunc);

};
test();

 

 

Turns out, BT is a gift that just keeps on giving. For instance, I discovered that I nearly accidentally (may have forgotten) had it working the whole time. But when I tried to make this, it wasn't working until I inserted the #targetengine directive.

 

So, in the snippet here we have two ways of sending the message and it takes special consideration for how you treat those nextlines. For a simple script string you must double-escape all the stuff you don't want to have the "\" show up. You may be able to maybe do new String() to auto-do this I am not sure.
But for things which are a function in your code-file, you can forego this (use .toString() which automatically does string-escaping) and simply make sure you add the function's call at the end of the message.
For items ran from a separate file which can be activated as a stand-alone piece of code even when not used via BT, I think just reading the entire text and using the encoding/decoding URI methods will work just like the function-call message, but you won't have to add the function call at the bottom as it is likely to already be there.

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
Participant ,
May 17, 2021 May 17, 2021

Copy link to clipboard

Copied

Hi, me again. I have been playing around with this sode you sent but I fear I may have not been clear in what I was asking.

I was using the alert function as an example of the line break. In reality, I actually need the final script to create me a text frame with prepopulated text (rather than just an alert).

 

The following is actually what I need, the first script is the onclick function of my UI (just launches a script to create the text frame wich is shown in the second snippet). How would I go about sending the 'bridgeTalkEncode' function to the second script that creates the text frame (and how would I go about having the second script understand to decode the hard return? 

UI onclick:

var scriptLoc = File($.fileName).path;
var scriptToLoad = new File (scriptLoc + "/Sub_Code/Test.jsx/")


    scriptToLoad.open ("r");
    var message = scriptToLoad.read();
    scriptToLoad.close()

var scriptPath = File($.fileName).path;
var bt = new BridgeTalk();
bt.target = "Illustrator";
bt.body = "var SCRIPT_LOCATION = \"" + scriptPath + "\"" + message;
bt.send();

 

2nd script to create text frame:

 

      var doc = app.activeDocument;
      var object1 = doc.textFrames.add();
      object1.contents = 'Line \n break';


I appreciate I have asked a lot of questions on this but just can't seem to get my head around it. Many 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
Valorous Hero ,
May 17, 2021 May 17, 2021

Copy link to clipboard

Copied

Do this:

		var btMsg = "var scp ='" + bridgeTalkEncode( message ) + "';\n";
		btMsg += "var scpDecoded = decodeURI( scp );\n"; 
		btMsg += "res = eval( scpDecoded );";
		bt.body = btMsg;
		

The "message" is going to be the script content you obtained with a File.read().

Alternatively you can engineer the strings to contain the string "eval('#include path/to/script.jsx')" and then you won't have to do a file-read, probably avoiding all encoding issues of the code content.
The utility of the bridgeTalkEncode function is using encodeURIComponent/encodeURI which converts the nextlines among other things to masked character groups which represent a nextline. Thus the string is being sent as plaintext to places where a multi-line text would not work, and then the decodeURI() function in the string sent via above snippet re-births the string content from URI-encoded entities to their regular representation.
Another really important note is that while my snippet in the thread above says:

	function postCompletionFunc () {
		alert("But the fun doesn't stop here, we go on and on doing stuff back in Illustrator");
	}

This function produces an alert in Illustrator, but it actually has no access to the Illustrator DOM. This means that any code that runs inside here can't do anything to an open document without having an error, but it can be used to interact with your palette and change text in it for such purposes and showing a log of what just happened.
If for some reason you also wanted to run another Illustrator script after such a message script is ran, you have to put another BridgeTalk call, this time to Illustrator itself (as in my example I was using Photoshop), essentially repeating the same technique as your first call. So basically the onResult functions which can be called from a message call you sent from a palette can only work for that palette or other ScriptUI palettes which may be placed by other scripts.. 
 

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
Participant ,
May 26, 2021 May 26, 2021

Copy link to clipboard

Copied

Hi, sorry, I got no notification of your message and have only just checked back now. I will take a look tomorrow. Thanks for all your help on this so far. I will post back to let you know how I get on. Thanks.

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
Participant ,
May 27, 2021 May 27, 2021

Copy link to clipboard

Copied

Got it to work, brilliant, thank you so much, but I have one further question.

 

How would I add in the BT message to look for a file loction that you helped me out with in this thread 'https://community.adobe.com/t5/illustrator/script-losing-path-when-run-from-another-script/m-p/11852... ("var SCRIPT_LOCATION = \"" + scriptPath + "\"" + message)?

In short, I need the BT message to incorporate both the file path and the line breaks together. I have tried the following (and many other variants) but with no luck;

 

UI script:

CreateLineBreakText.onClick = function(){
aiscriptE2 ();
}

function aiscriptE2() {
function bridgeTalkEncode (txt) {
  txt = encodeURIComponent (txt);
  txt = txt.replace( /\r/, "%0d" );
  txt = txt.replace( /\n/, "%0a" );
  txt = txt.replace( /\\/, "%5c" );
  txt = txt.replace(/'/g, "%27");
  return txt.replace(/"/g, "%22");
};

var scriptLoc = File($.fileName).path;
var scriptToLoad = new File (scriptLoc + "/Sub_Code/Test.jsx/")


    scriptToLoad.open ("r");
    var message = scriptToLoad.read();
    scriptToLoad.close()

var scriptPath = File($.fileName).path;
var bt = new BridgeTalk();
bt.target = "Illustrator";
var btMsg = "var scp ='" + bridgeTalkEncode( message ) + "';\n";
btMsg += "var scpDecoded = decodeURI( scp );\n";
btMsg += "res = eval( scpDecoded );\n";
btMsg += "var SCRIPT_LOCATION = \"" + scriptPath + "\"";// + message;
bt.body = btMsg;
bt.send();
//alert(btMsg)
}

 

second script:

function1A()

function function1A() {
var fileLocation = (typeof(SCRIPT_LOCATION) == "string")? SCRIPT_LOCATION : $.fileName;
var address1 = fileLocation + "/Sub_Code/Lockup_Elements/Portrait_Lockup.ai";
var file1 = File(address1);
file1 = open(file1);
}

      var doc = app.activeDocument;
      var object1 = doc.textFrames.add();
      object1.contents = 'Line\nbreak';

 

 

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
Valorous Hero ,
May 27, 2021 May 27, 2021

Copy link to clipboard

Copied

You can add it as a parameter to the 'message' if your BT message is a function-declaration only or if it comes with a function call at the end: use string replacing to add in the text-form of the function call with a baked-in parameter.

There's an issue with backslashes in the BT message string concerning the parsing of JSON for which you will need to replace all \\ with \\\\ so that windows file paths do not cause JSON parsing issues. It may work OK as is if you're not using JSON at this time though or aren't using backslashes in the file paths (using the file.toString() vs file.fsName on Windows).

Suppose you have this as your stand-alone script:

 

/*
function MyScript (parentScriptFilePath) {
  ...
  IF parentScriptFilePath is good THEN
  Do the action that is controlled by the parent calling script, featuring this file path.
  ELSE...
  Do the stand-alone action,
  ...
}
MyScript();
*/

 

Then in your function that creates the BT message, you replace the last line using string replacing:

  1. txt = txt.replace("MyScript();", "");
  2. txt = txt + "\nMyScript('" + File($.fileName).path + "')";

 

And if your child script is simply a function declaration, 
Do almost the same thing, you just don't have to do the replacing.

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 28, 2021 May 28, 2021

Copy link to clipboard

Copied

Hi glibshaft,

try this:

var alertMessage = 
'''
Line
Break
''';

alert( alertMessage );

 

From my German Windows 10 machine with AI 25.2.3:

AlertWithTrippleFencingString.PNG

 

Regards,
Uwe Laubender

( ACP )

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
Participant ,
Jun 01, 2021 Jun 01, 2021

Copy link to clipboard

Copied

Hi, this solution seems to work for me. I still want to investigate Silly-V's way of doing it, but for now this is a perfectly workable solution for my issue.

Thanks to eveyone for there help 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
Participant ,
Jun 01, 2021 Jun 01, 2021

Copy link to clipboard

Copied

*their

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
Participant ,
Aug 24, 2021 Aug 24, 2021

Copy link to clipboard

Copied

Bit of an update on this. After many attempts to get this to work how I wanted, I think I have finally cracked it. I was trying to make it run a 2nd script and pass the BT message, but realised I can now put complex scripts into my palette UI using this method without the need to call the external complex scripts, just run from my UI script.

 

Silly-V, thanks so much for all your help on this, it took me a while but think I am there with it now. Thank you so much for your help and wealth of knowledge 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
Valorous Hero ,
Aug 24, 2021 Aug 24, 2021

Copy link to clipboard

Copied

Great!! Way to go, I knew you would get it - those who frequently require BT eventually get on this train and now maybe you can actually explain it to someone new way better than I can.
And there used to be this sort of a misconception that long scripts take a long time to run; that's some carryover from the web world when people used to be worried especially in early years about the size of javascripts passed through the internet - it would slow the web page down a little. But in our land, I pass in a good 7000 liner every single time to run any one little thing and it works just great. Of course most of those lines are filler code like prototypes and utility functions, but since it doesn't really matter regarding speed we can be pretty liberal and arbitrary about the complexity of scripts being passed.

I'm happy to hear that you have cracked the code!

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
Valorous Hero ,
Aug 24, 2021 Aug 24, 2021

Copy link to clipboard

Copied

LATEST

By the way, it's way easier to work with files individually, but it works best with BT when it's in one file.
You can use the eval("#include 'scripts folder/some folder/thescript.jsx'") in your one file to bring in other files that you are working on as stand-alones.
A benefit is that you can be developing stand-alone functions and test them against the document with no BT headaches, and even debug them using the ESTK or VSCode's sometimes-working ESTK extension.
Then when you are happy with the results, try the same from your UI palette by running the index script which should bring in your stand-alone functions through the eval statements, but it doesn't actually contain actual #include directives so there's not a BT problem where some things may go wrong. <-- Actually I am not sure if there's a problem - I just know on Windows for running a BT script that has #include, it wants the absolute path and I don't want absolute paths because I go from my PC to my Mac to test it on Mac OS which has my same code via google drive or a repository, and the system paths are different.

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