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

Passing information from jsx to js.

New Here ,
Jan 25, 2018 Jan 25, 2018

Copy link to clipboard

Copied

Hello Community,

I have a problem with passing information from jsx to js file.

my jsx file:

$.extendScript = {

  test : function() {

    return "string";

  },

}

my js file.

(function () {

    var cs = new CSInterface();

    var variable = "";

    cs.evalScript('$.extendScript.test()', function(result) {

       variable = result;

       alert("variable in evalScript =" + variable);

    });

    alert("variable in outside = " + variable);   

}());

In evalScript function the variable get's the string from jsx function but when I want to use it outside I get empty string again.

Also I get the alert outside evalScript first in order. Why this happens?

Does anyone know why this happens and how to fix this?

Best Regards

TOPICS
SDK

Views

7.1K

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 Employee , Jan 26, 2018 Jan 26, 2018

Votes

Translate

Translate
Adobe Employee ,
Jan 26, 2018 Jan 26, 2018

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
Explorer ,
Nov 13, 2018 Nov 13, 2018

Copy link to clipboard

Copied

bbb_999Could You please tell me how I can create callback on this event?

csInterface.evalScript('$._PPP_.registerProjectPanelSelectionChangedFxn()'); // Project panel selection changed

I want that the trackitem of currently selected clip will be in the input box of my Panel.

My goal is to create button on panel that if I push it, will change scale of currently selected clip.

Therefore I decide to take trackitem path from input box and send it to jsx.

May be it can be done with another algorythm?

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
Enthusiast ,
Nov 13, 2018 Nov 13, 2018

Copy link to clipboard

Copied

n.abola  wrote

bbb_999Could You please tell me how I can create callback on this event?

csInterface.evalScript('$._PPP_.registerProjectPanelSelectionChangedFxn()'); // Project panel selection changed

I want that the trackitem of currently selected clip will be in the input box of my Panel.

My goal is to create button on panel that if I push it, will change scale of currently selected clip.

Therefore I decide to take trackitem path from input box and send it to jsx.

May be it can be done with another algorythm?

csInterface.evalScript('$._PPP_.registerProjectPanelSelectionChangedFxn()', function( ResultsFromJsxContext ){

  //Command block here

});

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
Explorer ,
Nov 13, 2018 Nov 13, 2018

Copy link to clipboard

Copied

With this code You will get callback only the first time when execute this script.

But I need get callback on every changing of selection on timeline.

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
Enthusiast ,
Nov 13, 2018 Nov 13, 2018

Copy link to clipboard

Copied

n.abola  wrote

With this code You will get callback only the first time when execute this script.

But I need get callback on every changing of selection on timeline.

One approach: run your evalScript on an interval, JSX context testing timeline state with each call.

I've done it.  It works.

You do raise interesting questions for bbb_999

- What is going on behind-the-scenes with evalScript?  Is it wrapping an AJAX call to the JSX context?  Trade secret?

- Is it possible to set up a WebSocket between JS and JSX?

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
Adobe Employee ,
Nov 13, 2018 Nov 13, 2018

Copy link to clipboard

Copied

My goal is to create button on panel that if I push it, will change scale of currently selected clip.

Change it...to what? What's the entire workflow, you're trying to support?

Also, "Allow panels to register for notification when the timeline selection changes" is a pretty popular API feature request; I'll add your vote.

What is going on behind-the-scenes with evalScript?

Yes, carefully-defended trade secret...

[Looks both ways, leans in conspiratorially...]

It passes the script...to ExtendScript engine...where it's evaluated.

Sssssh!

Web socket connections are totally possible between panels, in JavaScript; I've not heard of anyone using a web socket connection, between JavaScript and ExtendScript.

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
Explorer ,
Nov 14, 2018 Nov 14, 2018

Copy link to clipboard

Copied

What's the entire workflow, you're trying to support?

I want that when I press hotkey "Q" it increases scale effect of currently selected clip on  timeline to +1.

And if I press hotkey "W" it decrease scale effect of currently selected clip on  timeline to -1.

I want to make it like this:

I understand that this palette uses another API, but it possible to do it with  ExtendScript + Autohotkey.

It is only 1 problem - get selected trackitem object index.

Now I do it like this:

C:\Program Files (x86)\Common Files\Adobe\CEP\extensions\test\index.html

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./lib/CSInterface.js"></script>
<script type="text/javascript">
var csInterface = new CSInterface();
csInterface
.registerKeyEventsInterest(JSON.stringify([
{"keyCode": 0x51},  //q
{"keyCode": 0x57}   //w
]));

function evalScriptCallback(result)
{
  
if (result !== "undefined")
      document
.getElementById("selected").value = result;
}

function keyDownInBody(event)
{
  
if (event.keyCode == 0x51)   //q
  
{
     
var ControlledEffect = "AE.ADBE Motion";   //effect matchName
     
var ControlledProperty = 1;   //effect property scale
     
var step = 1;   //increase/decrease value
      csInterface
.evalScript('var ControlledEffect = "' + ControlledEffect + '"; var ControlledProperty = ' + ControlledProperty + '; var step = ' + step + '; ' + document.getElementById("selected").value + '$._PPP_.ChangeEffectParameters()', evalScriptCallback);
  
}
  
else if (event.keyCode == 0x57)   //w
  
{
     
var ControlledEffect = "AE.ADBE Motion";   //effect matchName
     
var ControlledProperty = 1;   //effect property scale
     
var step = -1;   //increase/decrease value
      csInterface
.evalScript('var ControlledEffect = "' + ControlledEffect + '"; var ControlledProperty = ' + ControlledProperty + '; var step = ' + step + '; ' + document.getElementById("selected").value + '$._PPP_.ChangeEffectParameters()', evalScriptCallback);
  
}
}

</script>
</head>
<body onkeydown="keyDownInBody(event)">
<input type="text" id="selected" value="var SelectedTrack = 0; var SelectedClip = 0; var SelectedEffect = 0;">
</body>
</html>

C:\Program Files (x86)\Common Files\Adobe\CEP\extensions\test\PProPanel.jsx

$._PPP_={

ChangeEffectParameters: function()
{
  
var NowSelectedTrack = SelectedTrack; var NowSelectedClip = SelectedClip; var NowSelectedEffect = SelectedEffect;
  
try {
     
var videoTracks = app.project.activeSequence.videoTracks;
  
}
  
catch(err) {
      alert
("Error!\nNo active sequence!");
     
return
  
}
  
try {
     
if (videoTracks[SelectedTrack].clips[SelectedClip].isSelected())
        
var clip = videoTracks[SelectedTrack].clips[SelectedClip];
  
}
  
catch(err) {
  
}
  
if (!clip)
  
{
      exit_loops
:
     
for (var i=0 ; i< videoTracks.numTracks ; i++)
     
{
        
for (var k=0 ; k< videoTracks[i].clips.numItems ; k++)
        
{
           
if (videoTracks[i].clips[k].isSelected())
           
{
              
var NowSelectedTrack = i; var NowSelectedClip = k;
              
var clip = videoTracks[i].clips[k];
              
break exit_loops;
           
}
        
}
     
}       
  
}
  
if (!clip)
  
{
      alert
("Error!\nNo clip selected!");
     
return
  
}
  
  
var effects = clip.components;
  
try {
     
if (effects[SelectedEffect].matchName == ControlledEffect)
        
var effect = effects[SelectedEffect];
  
}
  
catch(err) {
  
}
  
if (!effect)
  
{
     
for (var l=0 ; l< effects.numItems ; l++)
     
{
        
if (effects[l].matchName == ControlledEffect)
        
{
           
var NowSelectedEffect = l;
           
var effect = effects[l];
           
break;
        
}
     
}
  
}
  
if (!effect)
  
{
      alert
("Error!\nNo such effect!");
     
return
  
}

  
var property = effect.properties[ControlledProperty];
  
if (property.isTimeVarying())
  
{
      alert
("Error!\nParameter has keyframes!");
     
return
  
}
  
var value = property.getValue();
  
property.setValue(value + step, true);
  
if (NowSelectedTrack == SelectedTrack && NowSelectedClip == SelectedClip && NowSelectedEffect == SelectedEffect)
     
return
  
else
     
return ('var SelectedTrack = ' + NowSelectedTrack + '; var SelectedClip = ' + NowSelectedClip + '; var SelectedEffect = ' + NowSelectedEffect + ';');
}

}

C:\Program Files (x86)\Common Files\Adobe\CEP\extensions\test\CSXS\manifest.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
/*************************************************************************
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2014 Adobe
* All Rights Reserved.
*
* NOTICE: Adobe permits you to use, modify, and distribute this file in
* accordance with the terms of the Adobe license agreement accompanying
* it. If you have received this file from a source other than Adobe,
* then your use, modification, or distribution of it requires the prior
* written permission of Adobe.
**************************************************************************/
-->
   
<ExtensionManifest Version="5.0" ExtensionBundleId="com.adobe.PProPanel" ExtensionBundleVersion="11.1"
ExtensionBundleName="Premiere Pro sample panel"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   
<ExtensionList>
       
<Extension Id="com.adobe.PProPanel" Version="10.3.0" />
   
</ExtensionList>
   
<ExecutionEnvironment>
       
<HostList>
           
<Host Name="PPRO" Version="9.0" />
       
</HostList>
       
<LocaleList>
           
<Locale Code="All" />
       
</LocaleList>
       
<RequiredRuntimeList>
           
<RequiredRuntime Name="CSXS" Version="6.0" />
       
</RequiredRuntimeList>
   
</ExecutionEnvironment>

   
<DispatchInfoList>
       
<Extension Id="com.adobe.PProPanel">
           
<DispatchInfo >
               
<Resources>
                   
<MainPath>./index.html</MainPath>
                   
<ScriptPath>./PProPanel.jsx</ScriptPath>
                   
<CEFCommandLine>
                       
<Parameter>--allow-file-access</Parameter>
                       
<Parameter>--allow-file-access-from-files</Parameter>
                   
</CEFCommandLine>
               
</Resources>
               
<Lifecycle>
                   
<AutoVisible>false</AutoVisible>
                   
<StartOn>
                       
<!-- Premiere Pro dispatches this event on startup -->
                       
<Event>com.adobe.csxs.events.ApplicationActivate</Event>
                   
</StartOn>
               
</Lifecycle>
               
<UI>
                   
<Type>Modeless</Type>
                   
<Menu>PProPanel (SDK sample panel)</Menu>
                   
<Geometry>
                       
<Size>
                           
<Height>300</Height>
                           
<Width>180</Width>
                       
</Size>
                   
</Geometry>
               
</UI>
           
</DispatchInfo>
       
</Extension>
   
</DispatchInfoList>
</ExtensionManifest>

Autohotkey script:

SleepDuration := 5
FirstPressDelay := 0.15

#InstallKeybdHook
#InstallMouseHook
#UseHook
DetectHiddenWindows, On

#If WinActive("ahk_exe Adobe Premiere Pro.exe") and WinExist("Script Alert ahk_exe Adobe Premiere Pro.exe")
q
::
w
::
return

#If WinActive("ahk_exe Adobe Premiere Pro.exe")
q
::
w
::
SetBatchLines -1
SetKeyDelay, -1, -1
If (A_PriorKey != "q") and (A_PriorKey != "w")
{
  
SetControlDelay -1
  
ControlClick, Chrome_WidgetWin_01, ahk_exe Adobe Premiere Pro.exe, Chrome Legacy Window,,, NA
   loop
  
{
     
ControlGetFocus, Focus, ahk_exe Adobe Premiere Pro.exe, Chrome Legacy Window
     
if (Focus = "Chrome_WidgetWin_01")
        
break
  
}
}
KeyWait, %A_ThisHotkey%, T%FirstPressDelay%
If ErrorLevel
{
  
DllCall("Winmm\timeBeginPeriod", UInt, 3)
   loop
  
{
     
if !GetKeyState(A_ThisHotKey, "P")
        
break
     
SendInput {%A_ThisHotKey%}
      loop
% SleepDuration
        
DllCall("Sleep", UInt, 1)
  
}
  
DllCall("Winmm\timeEndPeriod", UInt, 3)
}
Else
  
SendInput {%A_ThisHotKey%}

Now When we press hotkeys "Q" or "W" - selected clip on timiline will be scaled to +-1 point.

I have written autorun in manifest in hidden mode of my panel.

Autohotkey after pressing hotkey detects  what control is focused in Premiere and if it is not my panel it sends click on panel.

Then it sends hotkey.

SleepDuration - pause between sending hotkeys when hotkey is hold.

FirstPressDelay - time of first pressing hotkey needed for detecting - hotkey is hold or just pressed.

And the question is - will it be possible to get trackitem object index of selected clip without looping and checking for isSelected()?

PS I can not find code tag to format post, therefore I use tag quote.

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
Enthusiast ,
Jan 27, 2018 Jan 27, 2018

Copy link to clipboard

Copied

cs.evalScript() is an asyncronous call, meaning it will wait until it receives a reply from your jsx script before setting ‘result’ and executing the callback function your evalScript.

While asyncronous functions wait patiently before executing their callbacks, that ‘waiting’ does not halt execution of the next line of code, which in your case is the ‘outside’ alert.

So your code will execute your second ‘outside’ alert first and your first ‘in evalscript’ second.

More on asyncronous coding here Introduction to asynchronous JavaScript (Example) | hack.guides()

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
Enthusiast ,
Jan 28, 2018 Jan 28, 2018

Copy link to clipboard

Copied

klemenm  wrote

In evalScript function the variable get's the string from jsx function but when I want to use it outside I get empty string again.

Also I get the alert outside evalScript first in order. Why this happens?

Does anyone know why this happens and how to fix this?

As others have pointed out, CSInterface.evalScript is an asynchronous* function.

* There is currently a bug on Adobe apps in macOS that causes evalScript to run synchronously. This doesn't help you, however, because the callback still gets scheduled to occur after the current context completes.

Here's how your code is evaluated:

  1. Call to evalScript sends a request to process the code you send it.
  2. Your "outside" alert is triggered. The captured variable variable is still the empty string.
  3. The Panel (JS) processing (started via some callback, e.g. button click callback) completes.
  4. The ExtendScript (JSX) context is started and begins to process the request you sent it.
  5. The script you passed to ExtendScript (JSX) is processed, generating the return value you are interested in (coerces it to a string).
  6. The ExtendScript (JSX) context sends a request to process the string to the JS using the callback you specified.
  7. The panel (JS) context runs the callback that you provided to evalScript and only now will it have the chance to set the captured variable variable to the string that your JSX code produced. Your "inside" alert is triggered.

What you really want to do is run your "outside" alert after the "inside" code has had a chance to run. To do this you need to somehow get #2 to occur after #7. This is where the setTimeout function comes in handy. Try this:

(function () { 

    var cs = new CSInterface(); 

    var variable = ""; 

    cs.evalScript('"string"', function(result) { 

       variable = result; 

       alert("variable in evalScript =" + variable);  

    }); 

    setTimeout(() => {alert("variable in outside = " + variable);}, 0);

}());

Note that I got rid of the special JSX-side function that simply returns "string". Rather, I just made the evalScript simply return that directly.

The important part is line 8. That schedules the anonymous, inline function to be called at a later date (the 0 at the end means "as soon as possible" - if you had heavy script in your JSX [on applications running in Windows] then you might need to delay even further with larger numbers). Honestly, though, the correct thing to do is simply trigger another function call that makes use of that captured variable from within the function itself. Both the callback passed to evalScript and the one passed to setTimeout capture a reference to the same variable instance which means that when one changes, both do. It's merely a matter of determining which callback is triggered earlier.

I hope this helps!

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 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

Most of this topic went over my head. Is there a way to get information from the jsx file back to the js script in your html file? I am trying to use a folder picker in the form of:

var fPath = decodeURIComponent(Folder.selectDialog("Choose the output directory"));

I can get the path and alert from the jsx file but I cannot seem to set it to a variable to display to the user in a panel field. Is this possible? 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
Adobe Employee ,
Aug 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

Is there a way to get information from the jsx file back to the js script in your html file?

Yes; see PProPanel's usage of getUserName.

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 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

Hi, thanks so much for the reply. I am still having no luck with what I am trying to accomplish. So that function is similar to the one I have created. Using the one you show as an example, how would I get the userName (returned) variable to be persistent so that I could update a field in my panel with its value? 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
Adobe Employee ,
Aug 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

> Using the one you show as an example, how would I get the userName (returned) variable to be persistent so that I could update a field in my panel with its value?

If you look at the JavaScript side, you'll see that getUserName is called both from within the panel's OnLoaded() function, and when PProPanel is copying presets into the user's directory, and needs the user name.

In both cases, the returned name is passed to the callback function specified, when invoking the ExtendScript. That callback function displays the user's name in the panel.

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 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

Thank you again, all that you have posted help me understand better. I see what you are talking about now. I think my problem is that I do not understand how to work with the "when" thing are happening. I noticed that the examples are all when things are initialized, meaning when the script starts up. I am trying to do something after the script has already started. I would like to have a field and browse button and let a user of the script choose a directory, or even manually type on in. If I start my script reporting some system variable it is fine. However, I when I refer to that variable again it is always undefined. 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
Adobe Employee ,
Aug 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

I'll need a better understanding of the _entire_ workflow you're trying to support, from the user's perspective.

[day job address = b b b at adobe dot com]

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 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

Once that panel is up displaying the users name how could you refer to that property in the JavaScript file? Is there then an property that can be used again. I cannot seem to call it again. All I recieve is undefined.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
Adobe Employee ,
Aug 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

Take a look at this JavaScript function, in PProPanel; it receives the userName returned by the ExtendScript function, and modifies the innerHTML of the object displaying the user name, in the panel.

func.png

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 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

I see that and under stand, however when I try to do this

===jsx file ===

getPath: function() {

    fPath = decodeURIComponent(Folder.selectDialog("Choose the output directory"));

    //alert(fPath);

    return fPath;

},

===js file===

var mypath;

var userName;

var cs = new CSInterface();

function getFolder() {       

    mypath = cs.evalScript('$.runScript.getPath()');

    //document.getElementById('ppath').value = $.runScript.getPath();

   

}   

function newPath () {

    // Updates username with whatever ExtendScript function returns.

    var path_name        = document.getElementById("ppath");

    path_name.value    = mypath;

}

//cs.evalScript('$.runScript.getPath()'cs.evalScript('$.runScript.getPath()', newPath););                       

function runAll() {               

    cs.evalScript('$.runScript.meInOut()')

}

I cannot reffence the value to the choosen path?

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 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

I have changed the code so many times it might be off now. But my point is that after the first load of the panel I am not able to get the value of the  Folder.selectDialog("Choose the output directory"). 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
Enthusiast ,
Aug 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

The CSInterface.evalScript function does not return the value. It is intended to be an asynchronous call.

Instead, the callback you pass to evalScript is passed the value returned from the ExtendScript-side function.

Try this:

var cs = new CSInterface();

function getFolder() {      

    cs.evalScript('$.runScript.getPath()', onNewPath);

}

function onNewPath(path) {

    // Updates username with whatever ExtendScript function returns.

    var path_name   = document.getElementById("ppath");

    path_name.value = path;

}

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 05, 2019 Aug 05, 2019

Copy link to clipboard

Copied

LATEST

That worked like a charm... funny I thought I tried to do this already. The first time @bbb_999 sugested the code in the PProPanel's example (scratching my head ). However that is great to know. I really thank you guys for suggesting so many helpful things. What @bbb directed me to is a big help also in building better scripts. Once again @sberic Thank you so much!

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