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

[Tutorial] After Effects ExtendScript Script Writing

Advocate ,
Apr 20, 2013 Apr 20, 2013

Copy link to clipboard

Copied

Hi all, just wanted to share a new tutorial series I have launched today that I think a lot of you may find helpful.

We've all posted here in this forum looking for help with scripting. There are many reasons why too. One of which that keeps making the rounds is the lack of documentation for ExtendScript. When I first started scripting for After Effects five years ago, the CS3 guide is all there was and it did contain the proper information, but as a newbie I was unable to understand the guide to get any real help from it. I didn't know Javascript then and I was super frustrated. Asking questions and searching forums like this was my only option really. No real training existed, that I'm aware of, that truly covered how to use ExtendScript. That is, until now. I have spent the better part of my weekends over the past year recording this training series to give the After Effects community a decent collection of information in one place to help get people started in scripting. This series comes in at over ten hours in length and is being released in segments on a weekly basis as of today. There is a lot to cover in ExtendScript and I do cover much of it. I'm unable to hit 100% of it as I too am still learning some of the more advanced aspects of it. I do cover however the basics of Javascript, looping through project items, creating folders, creating comps, creating layers, reading various project information, building GUI's, creating/reading txt documents, etc...

If you are a newbie looking to learn ExtendScript, a frustrated artist who's confused by programming, a script developer looking for more info, then at one point or another I believe this series will help you.

The first three episodes begin here:

http://provideocoalition.com/news/video/after-effects-extendscript-training-ep-1-2-3

Keep an eye out for more posts each week. thanks, and I hope you find this resource useful.

-David Torno

TOPICS
Scripting

Views

27.5K

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
Advocate ,
Aug 03, 2013 Aug 03, 2013

Copy link to clipboard

Copied

The series is getting closer to the end with only one more episode left after this. Episode 18 covers populating a multi-column listbox, assigning onClick events to buttons, and we also retrieve a full list of all effects used on all layers in your project. Plus functions to create a tab delimited text file, sort and remove duplicate array information, populate a listbox, and more.

Episode 18:     (Dockable list of all effects used in project and export to text document)

http://provideocoalition.com/pvcexclusive/video/after-effects-extendscript-training-ep-18

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 ,
Sep 15, 2013 Sep 15, 2013

Copy link to clipboard

Copied

Hi David,

I'm following your tutorial series and currently working on ep12, building a GUI.

I can't work out why, but when I set up the code for a dockable panel, nothing displays in the panel. Everything works correctly in Extenscript Toolkit, or in AE if I run the script as a floating panel from the "run script file" command.

I thought it might be a CC thing, but it doesn't work in CS6 either. I'm sure I'm just messing something up, but wondered if you (or anyone else) could point me in the right direction?

Here's my code:

{

 

function myScript(thisObj){

    function myScript_buildUI(thisObj){

        var myPanel = (thisObj instanceof Panel) ? thisObj : new Window("palette","My window name", undefined, {resizeable:true});

     

        res =   "group{orientation:'row',\

                        groupOne: Group{orientation:'stack',\

                            myButton: Button{text:'Button Visible Name'},\

                        },\

               },\

                    }";

       

      

        myPanel.grp = myPanel.add(res);

       

       

        return myPanel;

    }

    var myScriptPal = myScript_buildUI(thisObj);

   

    if((myScriptPal != null) && (myScriptPal instanceof Window)){

        myScriptPal.center();

        myScriptPal.show();

    }

}

myScript(this); 

    

}

Thanks for any help!

Ben

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
Advocate ,
Sep 15, 2013 Sep 15, 2013

Copy link to clipboard

Copied

Three things...

1) You have one too many closing braces in your resource string. "},\". Delete the second to last one.

2) You also need to tell the script to layout itself. Add this just before your "return myPanel;" line.

     myPanel.layout.layout(true);

     return myPanel;

3) Also if you want your UI elements to resize with your panel as you adjust it's size, you'll need a few more lines too.

     myPanel.grp.minimumSize = myPanel.grp.size;     //Makes your starting panel size fit all elements.

     myPanel.layout.resize();     //Resizes layout

     myPanel.onResizing = myPanel.onResize = function () {this.layout.resize();}     //Resizes everything with panel

     myPanel.layout.layout(true);     //Updates layout to show elements.

     return myPanel;     //Returns final result of myPanel


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 ,
Sep 16, 2013 Sep 16, 2013

Copy link to clipboard

Copied

Awesome, thanks David.

I had to move the myPanel.layout.layout(true); line to before the resize code to get it to work, but that function is really useful.

I don't know why, but there's something really satisfying about getting a button to appear in a window... it's the little things. Small steps!

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
Advocate ,
Sep 18, 2013 Sep 18, 2013

Copy link to clipboard

Copied

Glad it worked out for you. Yes having a button show is an odd sense of accomplishment. Plus it's fun to just click the hell out of it while it is there. Wait until you are dealing with dozens of control elements. It gets really fun when you get anything to work the first time around. The coding has to start somewhere and one button showing up is a great step in the right direction. 😉

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 ,
Sep 18, 2013 Sep 18, 2013

Copy link to clipboard

Copied

Hey David,

One more question...

If I wanted to add say a listItem to a ListBox from another function in my code, what would be the best way to set that up? How would I get access to "myPanel" from outside the function it is created in?

All the nested functions are getting me confused.

Thanks!

Ben

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 ,
Sep 18, 2013 Sep 18, 2013

Copy link to clipboard

Copied

I know you directed the question to David, but thought I'd share with you how I've done it. 

I have done it two ways, and it is a matter of style.  You can create a global variable, and when you create your "myPanel" just set that global variable to that panel, and you'll be able to access on the control objects via that global variable.  I've also passed around the "myPanel" object from one function to another.  So if you want to access the "myPanel" object locally in a function, use a parameter in your function declaration and when you call the function, just pass the "myPanel" object.

Hope that 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
Explorer ,
Sep 18, 2013 Sep 18, 2013

Copy link to clipboard

Copied

Thanks Arie!

It actually seems really obvious now. I was trying to pass the object around in a function like your second method, but couldn't get it to work. The global variable seems to work nicely though.

Really appreciate your help 🙂

And David, sorry that I inadvertently hijacked this thread with my troubleshooting questions.


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
Advocate ,
Sep 18, 2013 Sep 18, 2013

Copy link to clipboard

Copied

Arie is spot on. I use the pass through method mostly myself, but either will do.

And David, sorry that I inadvertently hijacked this thread with my troubleshooting questions.

Keeps bringing my tutorial info up for the eyes to see. No complaints 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
New Here ,
Jul 20, 2014 Jul 20, 2014

Copy link to clipboard

Copied

Hi David,

Many thanks for your tutorial series. This is really big great job!

But I not understand how can I add dynamic code to my UI panels?

Here's my code:

{

    var a = "It's working!";

function myScript(thisObj){

        function myScript_buildUI(thisObj){

                var myPanel = (thisObj instanceof Panel) ? thisObj : new Window("palette", "AE вещает ёпт", undefined);

                res = "group{orientation:'row', alligment:['fill','fill'], alignChildren:['fill','fill'],\

                                groupOne: Group{orientation:'column', alligment:['fill','fill'], alignChildren:['fill','fill'],\

                                    myImage: Image{text:'nothing', image:'~/Desktop/joy.png'}, alligment:['fill','top'],\

                                    myButton: Button{text:'Ok'}, alligment:['fill','top'],\

                                },\

                                groupTwo: Group{orientation:'column',\

                                    myStaticText: StaticText{text:'Пора играть в Diablo III - Даже AE тебе говорит епт'}, alligment:['fill','top'],\

                                    mySlider: Slider{text:'slider', value:'50'}, alligment:['fill','top'],\

                                },\

                          }";

                myPanel.grp = myPanel.add(res);

         

                // размер окна

                myPanel.layout.layout(true);

                myPanel.grp.minimumSize = myPanel.grp.size;

         

                //изменяемый размер панелей

                myPanel.layout.resize();

                myPanel.onResizing = myPanel.onResize = function(){this.layout.resize()};

         

                return myPanel;

            }

        var myScriptPal = myScript_buildUI(thisObj);

 

        if((myScriptPal != null) && (myScriptPal instanceof Window)){

            myScriptPal.center();

            myScriptPal.show();

        }

    }

myScript(this);

}

I'll try to explain. I want click on my "Ok" Button and she say

alert(a);

The question is, how do I make dynamic elements in this code. I don't understand where I should insert this code. How to program for example - myButton. Should I turn to the "res" files or not? And how it work?


And another question, in AE CC version my window isn't dockable and {resizable: true} don't work too. I want put my window inside AE panels...

win.png


Sorry for my English. Thanks for your time David.


Update: I'll create myButton.onClick function, but it doesn't work... Script in the button work fine, i'll check.

function myScript(thisObj){

        function myScript_buildUI(thisObj){

                var myPanel = (thisObj instanceof Panel) ? thisObj : new Window("palette", "AE вещает ёпт", undefined);

                res = "group{orientation:'row', alligment:['fill','fill'], alignChildren:['fill','fill'],\

                                groupOne: Group{orientation:'column', alligment:['fill','fill'], alignChildren:['fill','fill'],\

                                    myImage: Image{text:'nothing', image:'~/Desktop/joy.png'}, alligment:['fill','top'],\

                                    myButton: Button{text:'Ok'}, alligment:['fill','top'],\

                                },\

                                groupTwo: Group{orientation:'column',\

                                    myStaticText: StaticText{text:'Пора играть в Diablo III - Даже AE тебе говорит епт'}, alligment:['fill','top'],\

                                    mySlider: Slider{text:'slider', value:'50'}, alligment:['fill','top'],\

                                },\

                          }";

                myPanel.grp = myPanel.add(res);

                // размер окна

                myPanel.layout.layout(true);

                myPanel.grp.minimumSize = myPanel.grp.size;

               

                //изменяемый размер панелей

                myPanel.layout.resize();

                myPanel.onResizing = myPanel.onResize = function(){this.layout.resize()};

               

                return myPanel;

               

                myButton.onClick = function(){

                            myComp = app.project.item(1);

                            mySolid = myComp.layers.addSolid([1.0,1.0,0], "my square", 50, 50, 1);

                    };  

               

            }

       

        var myScriptPal = myScript_buildUI(thisObj);

       

        if((myScriptPal != null) && (myScriptPal instanceof Window)){

            myScriptPal.center();

            myScriptPal.show();

        }

    } 

myScript(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
Advocate ,
Jul 25, 2014 Jul 25, 2014

Copy link to clipboard

Copied

I don't understand where I should insert this code. How to program for example - myButton. Should I turn to the "res" files or not? And how it work?

You need to move your "myButton code" to just after the "myPanel.grp = myPanel.add(res);" line.

myPanel.grp = myPanel.add(res);

myPanel.grp.groupOne.myButton.onClick = function(){

  alert("TEST");     //This will alert whatever string or value you pass into it.

  myComp = app.project.item(1);

  mySolid = myComp.layers.addSolid([1.0,1.0,0], "my square", 50, 50, 1);

};

// размер окна

myPanel.layout.layout(true);

  myComp = app.project.item(1);

Just as a heads up, this piece of code you wrote will only work on the first item in your project window since you have defined it to use only "item(1)". If the first item is not a composition, your code will fail when trying to add a solid. You can change it to look for the selected items to make it more open and then check that the selections are comps then add the solids.

myPanel.grp.groupOne.myButton.onClick = function(){

     var sel = app.project.selection;

     var selLength = sel.length;

     var mySolid;

     for(var i=1; i<=selLength; i++){

          myComp = app.project.item(i);

          if(myComp instanceof CompItem){     //checks to see if item is a comp

               mySolid = myComp.layers.addSolid([1.0,1.0,0], "my square", 50, 50, 1);

          }

     }

};


And another question, in AE CC version my window isn't dockable and {resizable: true} don't work too. I want put my window inside AE panels...

For it to be resizeable you need to add the "{resizeable:true}" to your Window code.

var myPanel = (thisObj instanceof Panel) ? thisObj : new Window("palette", "AE вещает ёпт", undefined, {resizeable:true});

This will only make a floating window resizeable. A docked panel already has this functionality, so it is ignored. If you are wanting the control elements in your window to resize with the window or panel, then you would change the "alignment" and "alignChildren" properties in the res string. You have your child elements set to always remain at the top currently, so they will never slide downwards below there maximum size.

groupOne: Group{orientation:'column', alligment:['fill','fill'], alignChildren:['fill','fill'],\

     myImage: Image{text:'nothing', image:'~/Desktop/Alert.png'}, alligment:['fill','top'],\

Here's an updated version of your code:

{   

function myScript(thisObj){

     function myScript_buildUI(thisObj){

          var myPanel = (thisObj instanceof Panel) ? thisObj : new Window("palette", "AE вещает ёпт", undefined, {resizeable:true});

          res = "group{orientation:'row', alligment:['fill','fill'], alignChildren:['fill','fill'],\

               groupOne: Group{orientation:'column', alligment:['fill','fill'], alignChildren:['fill','fill'],\

                    myImage: Image{text:'nothing', image:'~/Desktop/Alert.png'}, alligment:['fill','top'],\

                    myButton: Button{text:'Ok'}, alligment:['fill','top'],\

               },\

               groupTwo: Group{orientation:'column', alligment:['fill','fill'], alignChildren:['fill','fill'],\

                    myStaticText: StaticText{text:'Пора играть в Diablo III - Даже AE тебе говорит епт'}, alligment:['fill','top'],\

                    mySlider: Slider{text:'slider', value:'50'}, alligment:['fill','top'],\

               },\

          }";

   

          myPanel.grp = myPanel.add(res);

          myPanel.grp.groupOne.myButton.onClick = function(){

                var sel = app.project.selection;

                var selLength = sel.length;

                var mySolid;

                for(var i=1; i<=selLength; i++){

                      myComp = app.project.item(i);

                      if(myComp instanceof CompItem){     //checks to see if item is a comp

                            mySolid = myComp.layers.addSolid([1.0,1.0,0], "my square", 50, 50, 1);

                      }

                }

          };

          // размер окна

          myPanel.layout.layout(true);

          myPanel.grp.minimumSize = myPanel.grp.size;

        

          //изменяемый размер панелей

          myPanel.layout.resize();

          myPanel.onResizing = myPanel.onResize = function(){this.layout.resize()};

        

          return myPanel;

        

          }

   

     var myScriptPal = myScript_buildUI(thisObj);

   

     if((myScriptPal != null) && (myScriptPal instanceof Window)){

          myScriptPal.center();

          myScriptPal.show();

     }

     }   

myScript(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 ,
Dec 13, 2014 Dec 13, 2014

Copy link to clipboard

Copied

Hi Dave,

I know you posted a while ago but I have really enjoyed your tutorial series.

I am currently trying to make my own script and am running into some walls.

I want to generate an AE comp based on a drop down menu and check boxes.

Right now I know how to create the GUI panel as well as have buttons execute functions .onclick but not involve any true false style statements.

I want to be able to choose a template from a dropdown menu for a comp and then have "horizontal" and "vertical" check mark boxes and then a "generate" button. So basically if both checkboxes are ticked it, on click it would generate a 1280 x 720 comp and a 720 x 1280 comp.

Would love some help if at all possible.

Much appreciated and thanks again for the great tutorial series!!!!

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
Advocate ,
Feb 23, 2015 Feb 23, 2015

Copy link to clipboard

Copied

Ben,

I want to be able to choose a template from a dropdown menu for a comp

This would be an onChange for the Dropdown. Also you could create the template simply by selecting the option in your dropdown, instead of adding additional checkboxes. Not fully understanding your layout or setup, but you could use this for example...

myDropdown.onChange = function(){

     switch(myDropdown.selection.text){

          case Template1:

               //Code to create Template1

               break;

          case Template2:

               //Code to create Template2

               break;

          case Template3:

               //Code to create Template3

               break;

          default:

               //Do nothing

               break;

     }

}

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 ,
Aug 25, 2015 Aug 25, 2015

Copy link to clipboard

Copied

Great tutorial series David! Got my first dockable script up and running with a fancy icon button as icing on the cake.

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
Advocate ,
Aug 26, 2015 Aug 26, 2015

Copy link to clipboard

Copied

Hahaha, congrats to you, and thanks for the kind words.

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
New Here ,
Apr 07, 2016 Apr 07, 2016

Copy link to clipboard

Copied

For many years know, I wait for some software company to come out with an alternative to AE. I would quit using Adobe products instantly. Sometime, I find generous, dedicated people like you, that make me think that the real value of Adobe are it's user. I'm convinced your efforts, have or will be rewarded in some way.

Thanks a lot for all these great tutorials.

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
Advocate ,
Apr 07, 2016 Apr 07, 2016

Copy link to clipboard

Copied

Thank you vladblindu‌ Adobe definitely has it's quirks, and like all relationships in life there are plenty of ups and downs. The After Effects user base I have found to be the strongest, and most helpful group around. I am glad you have found my tutorial resources helpful, I still remember back in 2006 when I was struggling to make things happen in After Effects. I always said that if I ever figure this stuff out, I was gonna share with others going through the same struggle. Stick with it, and you will find that a lot of amazing things can be created with After Effects, even with it's hurdles. The scripting helps ease the pain a little, but it too has it's own quirks.

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
New Here ,
Apr 07, 2016 Apr 07, 2016

Copy link to clipboard

Copied

You are very polite to use the word "quirks". I have a little knowledge about coding, still I was on the verge of giving up AE scripting several times. Despite the fact that I consider javascript a mess compared to a decent scripting language like Python, using such a language for anything else than web dev indeed a "very poorly chosen option" (I try to keep the polite attitude going)

I managed to set up a PyCharm based environment, with a grunt task runner to concatenate different files.

I also put some "node.js" features like require or module.export between two specific comments, which grunt takes out before concatenating so I can write test with mocha.

I build a library of pollyFills to add the many missing features of the language, which "is based" on ECMA-262, without anybody telling you that based doesn't mean included. Vital things like indexOf or Object.keys() are missing and many more.

There is no (or maybe I couldn't find anything except Peter Kahrel's guide) decent Adobe issued documentation regarding the UI.

The Script Editor is a mess.(This is why I had to invent the PyCharm solution. webStorm would be better I think, but this is what I have at hand right now.)

Finally, in terms of tutorials and support for this crucial enhancement, all you can find are your tutorials, which are wonderful, but should have been done by Adobe first, and only after have user tutorials for more specific situations.

To conclude, when you request such an amount of money for your products, you break backwards compatibility every year to squeeze money from your users pocket or you move your app online, because it's obvious the squeezing gets even better, "quirks" is definitely a very gentle word, but it fits perfectly someone so generous to offer his time and knowledge to other as yourself.

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
Advocate ,
Apr 07, 2016 Apr 07, 2016

Copy link to clipboard

Copied

Not that it's any easier, in fact it's just as difficult (in my opinion), but the new CEP Extensions do offer more up-to-date Javascript access. Still Javascript mind you, but at least more expected options are available. I've had no time to put any real focus on learning CEP setups/debugging, but it may help ease the ExtendScript pain a little.

I do agree though, Python would have been a better choice, and more inline with nearly all other professional software. I do miss "Useful Things" from back in the day, it was python based 3rd party software that allowed a lot more access to AE at the time, but a complete overhaul of AE broke that permanently sadly.


"quirks" is definitely a very gentle word, but it fits perfectly someone so generous to offer his time and knowledge to other as yourself.

Thank you sir.

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
Contributor ,
Apr 07, 2016 Apr 07, 2016

Copy link to clipboard

Copied

I strongly second Vlad's praise. A year ago, knowing nothing about Extend Script, I dove into your series and now we're about to release version 1.0 of an Extend Script product. Can't thank you enough, David! Your generosity is rare.

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
Advocate ,
Apr 07, 2016 Apr 07, 2016

Copy link to clipboard

Copied

Thank you tardigrade01‌. I'm happy it helped out.

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
New Here ,
May 03, 2016 May 03, 2016

Copy link to clipboard

Copied

Hi David,
First of all thank you for the best tutorials you helped me a lot.

I only have one question is it possible to get your scripts? (that you write in tutorials), because I made way too many mistakes rewriting them and some of them some of them do not 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
Advocate ,
May 05, 2016 May 05, 2016

Copy link to clipboard

Copied

You are very welcome. Glad it has been helpful for you. The examples I use in the tutorials are mostly unavailable. I say mostly only because bits of them have been made available in other script releases I've made here and there since that series was recorded. The primary reason I don't normally supply the code already typed up is because I believe that hands on learning is the most effective learning. Yes, mistakes will be made, but that is part of the learning process.

If there are any specific hurdles you are encountering I would be more than happy to help explain a possible solution.

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
New Here ,
May 05, 2016 May 05, 2016

Copy link to clipboard

Copied

I have a problem with tutorial 17.  When i run the script I get an error in line 53 "TypeError: undefined is not an object"
My script:

var fx, log, proj, curComp, folderLoc, selections, selectionsLength, curSelection, propData, headerName, lName;

fx=new Array();

log=new Array();

proj= app.project;

curComp=proj.activeItem;

folderLoc= Folder.selectDialog ("Select folder to save to.");

if(curComp instanceof CompItem){

    selections= collectSelections(curComp);

    selectionsLength= selections.length;

    for(var s=0; 0<selectionsLength; s++){

        fx.length= 0;

        curSelection= selections;

        propData= propRecurse(curSelection,"",fx);

        if(propData!=null){

            headerName=curSelection.name;

            writeDoc(curSelection.name+"\t"+curSelection.matchName+"\r\r"+propData,headerName,folderLoc);

            }else{

                lName=grabParentLayer(curSelection);

                if(lName==null){

                    lName=curSelection.name;

                    }

                log[log.length]=lName+"_"+curSelection.name+"_"+curSelection.propertyIndex;

            }

        }

    if(log.length>0){

        alert ("The fallowing selections had no sub properties.\r\rLegend:\"Layer_PropName_Index\"\r\r"+log.toString().replace(new RegExp(",","g"),"\r"));

    }

writeLn("Process complete.");

}

function collectSelections(compInput){

    try{

        var myCollection, myLayers, myLayersLength, myProperties, myPropertiesLength, curProp, curLayer;

        myCollection=new Array ();

        myLayers =compInput.selectedLayers;

        myLayersLength=myLayers.length;

        myProperties=compInput.selectedProperties;

        myPropertiesLength=myProperties.length;

        for(var p=0;p<myPropertiesLength;p++){

            curProp=myProperties

;

            myCollection.push(curProp);

            }

        for(var l=0;l<myLayersLength;l++){

            curLayer=myLayers;

            if(curLayer.selectedProperties==0){

                myCollection.push(curLayer);

                }

            }

        return myCollection;

        }catch(err){alert(err.line.toString()+"\r"+err.toString());}

}

function propRecurse(a, indent, fx){

    try{

        var propLength = a.numProperties;

        for(var l=1;l<propLength;l++){

            fx.push(indent +"("+ a.property(l).propertyIndex +")"+a.property(l).name+"\t"+a.property(l).matchName);

            if(a.property(l).numProperties>0){

                propRecurse(a.property(l), indent+ "\t", fx);

                }

            }

        if(fx.length>0){

            var j=fx.join("--");

            var r= j.replace(new RegExp("--","g"),"\r");

            return r;

            }else{

                return null;

                }

        }catch(err){alert(err.line.toString()+"\r"+err.toString());}

}

function writeDoc(contents,fileName,folderLocation){

    try{

        var slash, finalName,doc,inc,fileSuffix;

        fileSuffix="_PropData.txt";

        slash=(osCheck()=="PC")? "\\":"/";

        if(folderLocation==null){

            folderLocation="~"+slash+"Desktop";

            }

        finalName=fileName+fileSuffix;

        doc=new File(folderLocation.toString()+slash+finalName);

        if(!doc.exists){

            doc.open("w");

            doc.write(contents);

            doc.close();

            }else{

                inc= suffixInc(fileName);

                writeDoc(contents,inc,folderLocation);

                }

            if(doc.exists){

                writeLn("File saved");

                }

           

        }catch(err){alert(err.line.toString()+"\r"+err.toString());}

}

function grabParentLayer(prop){

    try{

        var result=null;

        if(prop!=null){

            if(prop.toString().indexOf("Layer")!=(-1)){

                result=prop.name;

                }else{

                    grabParentLayer(prop.parentProperty);

                    }

                return result;

            }else{

                 return result;

                }

        }catch(err){alert(err.line.toString()+"\r"+err.toString());}

}

function suffixInc(oldName){

    try{

        var old=oldName.split("_");

        var oldLength=old.length;

        var tail=old[old.length-1];

        var newName;

        if(oldLength>1&&isNaN(tail)==false){

            for(var i=1; i<999;i++){

                if(i>tail){

                    old.splce(old.length-1);

                    newName=old.join("_").toString()+"_"+i.toString();

                    break;

                    }

                }

            }else{

                return oldName+"_1";

                }

            return newName;

        }catch(err){alert(err.line.toString()+"\r"+err.toString());}

}

function osCheck (){

    var userOS=null;

    var win=$.os.indexOf("Windows");

    win !=(-1)? userOS="PC": userOS="MAC";

    return userOS;

    }

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
Advocate ,
May 06, 2016 May 06, 2016

Copy link to clipboard

Copied

OwnLT, I have not found the exact cause of the issue, but it does seem to be located during the propRecurse function. The function is returning null after getting your data, and I believe that is what trips up the remaining code after calling propRecurse. I'll dig deeper when I have more time and let you know if I find the cause.

function propRecurse(a, indent, fx){

    try{

        var propLength = a.numProperties;

        for(var l=1;l<propLength;l++){

            fx.push(indent +"("+ a.property(l).propertyIndex +")"+a.property(l).name+"\t"+a.property(l).matchName);

            if(a.property(l).numProperties>0){

                propRecurse(a.property(l), indent+ "\t", fx);

                }

            }

        if(fx.length>0){

            var j=fx.join("--");

            var r= j.replace(new RegExp("--","g"),"\r");

            return r;

            }else{

                return null;

                }

        }catch(err){alert(err.line.toString()+"\r"+err.toString());}

}

Another issue I saw was that you have a broken variable call in this line

writeDoc(curSelection.name+"\t"+curSelection.matchName+"\r\r"+propData,headerName,folderL oc);

your variable is declared as folderLoc, but you typed it as folderL oc in the line above.

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