Skip to main content
bluebeezle
Inspiring
November 29, 2017
Answered

Getting the parent element with JSFL

  • November 29, 2017
  • 4 replies
  • 5154 views

This seems like the simplest thing in the world, but I can't figure out a simple way how, if I'm currently in a symbol, to get access to the element that IS the current symbol I have open, on the timeline of the symbol that the current symbol is in.

The way I've done it until now is really clunky. There has to be a better way. Currently, I use document.exitEditMode() to exit into the parent timeline, and use document.selection[0] to access the currently selected element. Is there a way to do this without exiting the symbol?

This topic has been closed for replies.
Correct answer JoãoCésar17023019

Wow! This is nice!

I never thought I could get only the keyframes.

It will certainly lower the number of iterations. I did a small modification based on what you've done.

Instead of just j++ I've modified to j += timeline.layers.frames.startFrame + timeline.layers.frames.duration.

Please let me know if it can be even better.

function getParent(docArray)

{

    for (var i = 0; i < docArray.length; i++)

    {

        if (docArray.libraryItem.timeline == fl.getDocumentDOM().getTimeline() && docArray.selected)

            return docArray;

    }

   

    return fl.getDocumentDOM().timelines[0];

}

function getAll(timeline)

{

    var array = [];

    var count = 0;

   

    getAll2(timeline);

   

    function getAll2(timeline)

    {

        for (var i = 0; i < timeline.layers.length; i++)

        {           

            for (var j = 0; j < timeline.layers.frames.length; j += timeline.layers.frames.startFrame + timeline.layers.frames.duration)

            {

                for (var k = 0; k < timeline.layers.frames.elements.length; k++)

                {

                    var element = timeline.layers.frames.elements;

                    count++;                   

                   

                    if (element.instanceType == "symbol")

                    {

                        array.push(element);

                        getAll2(element.libraryItem.timeline);

                    }                   

                    else

                        continue;

                }           

            }

        }   

    }

   

    return array;

}

fl.trace(getParent(getAll(fl.getDocumentDOM().timelines[0])));

fl.trace(getParent(getAll(fl.getDocumentDOM().timelines[0])).name);

Regards,

JC

4 replies

Participating Frequently
November 25, 2024

var ele = fl.getDocument().getSelection[0];

var eleTimeline = ele.libraryItem.timeline;

JoãoCésar17023019
Community Expert
Community Expert
December 7, 2017

I think I've finally found the solution for this.

Basically I created a function to get ALL symbols of the entire document, no matter how nested or on what frame they are. This function returns a array with all these elements.

Then I call a function to check if the elements of this array has a timeline that is equal to the current symbol's timeline AND if the current element is selected. This is because all elements in edit mode has to have their parent selected.

Please run various tests and tell me if this works and if there is some problem.

Please notice that some actions will only get updated when you exit de edit mode. For example, if you rotate the parent symbol, you will only see it when you exit the edit mode.

function getParent(docArray)

{

    for (var i = 0; i < docArray.length; i++)

    {

        if (docArray.libraryItem.timeline == fl.getDocumentDOM().getTimeline() && docArray.selected)

            return docArray;

    }

   

    return fl.getDocumentDOM().timelines[0];

}

function getAll(timeline)

{

    var array = [];

   

    getAll2(timeline);

   

    function getAll2(timeline)

    {

        for (var i = 0; i < timeline.layers.length; i++)

        {           

            for (var j = 0; j < timeline.layers.frames.length; j++)

            {

                for (var k = 0; k < timeline.layers.frames.elements.length; k++)

                {

                    var element = timeline.layers.frames.elements;

                   

                    if (element.instanceType == "symbol")

                    {

                        array.push(element);

                        getAll2(element.libraryItem.timeline);

                    }                   

                    else

                        continue;

                }           

            }

        }   

    }

   

    return array;

}

fl.trace(getParent(getAll(fl.getDocumentDOM().timelines[0])));

fl.trace(getParent(getAll(fl.getDocumentDOM().timelines[0])).name);

Regards,

JC

chrisgelles
Inspiring
December 7, 2017

@JoãoCésar:

Just curious...won't this script grab the elements on EVERY frame in a timeline, not just keyframes?

So, I think you'd get sub-arrays with a number of items equal to the frame length of the timeline.
Right?

If that's the case, you could add something like this (see below) to get the elements from just the keyframes:

function getLayerKeys(thisLayer){ //input: a layer object, output: returns array of frame indexes containing keyframes.

var tot_fr = thisLayer.frameCount;

var i=0;

var stFrame;

var durr;

var keyFrIdx = [];

var outArray = [];

while(i<tot_fr){

keyFrIdx.push(i);

stFrame = thisLayer.frames.startFrame;

durr = thisLayer.frames.duration;

i = stFrame + durr;

}

outArray = keyFrIdx;

return outArray;

}

JoãoCésar17023019
Community Expert
JoãoCésar17023019Community ExpertCorrect answer
Community Expert
December 7, 2017

Wow! This is nice!

I never thought I could get only the keyframes.

It will certainly lower the number of iterations. I did a small modification based on what you've done.

Instead of just j++ I've modified to j += timeline.layers.frames.startFrame + timeline.layers.frames.duration.

Please let me know if it can be even better.

function getParent(docArray)

{

    for (var i = 0; i < docArray.length; i++)

    {

        if (docArray.libraryItem.timeline == fl.getDocumentDOM().getTimeline() && docArray.selected)

            return docArray;

    }

   

    return fl.getDocumentDOM().timelines[0];

}

function getAll(timeline)

{

    var array = [];

    var count = 0;

   

    getAll2(timeline);

   

    function getAll2(timeline)

    {

        for (var i = 0; i < timeline.layers.length; i++)

        {           

            for (var j = 0; j < timeline.layers.frames.length; j += timeline.layers.frames.startFrame + timeline.layers.frames.duration)

            {

                for (var k = 0; k < timeline.layers.frames.elements.length; k++)

                {

                    var element = timeline.layers.frames.elements;

                    count++;                   

                   

                    if (element.instanceType == "symbol")

                    {

                        array.push(element);

                        getAll2(element.libraryItem.timeline);

                    }                   

                    else

                        continue;

                }           

            }

        }   

    }

   

    return array;

}

fl.trace(getParent(getAll(fl.getDocumentDOM().timelines[0])));

fl.trace(getParent(getAll(fl.getDocumentDOM().timelines[0])).name);

Regards,

JC

JoãoCésar17023019
Community Expert
Community Expert
December 1, 2017

Hi,

Well, at least for me it's not a trivial thing... I've tested a lot of solutions but none has worked. The exitEditMode seems to be the only obvious way.

function getParent()

{

    var doc = fl.getDocumentDOM();

    var current;

   

    doc.exitEditMode();

    current = doc.selection[0];

   

    if (!current)

        return;

   

    doc.enterEditMode('inPlace');

   

    fl.trace("current: " + current + ", current.name: " + current.name);

}

getParent();

The process is unnoticeable for the user. So I think it's a valid solution.

And Adobe should insert a parent property. It will certainly make your lives easier.

Regards,

JC

chrisgelles
Inspiring
December 6, 2017

I think I see what you're after.

You want to be able to "dive into" a symbol on the stage, accessing its timeline, do a certain thing, then, affect the instance in the timeline you originally accessed it through.

The sad thing about JSFL is that all of the information it can access is new each time you initiate the script.

So, I suggest altering your workflow slightly.

Use a command to "dive into" selected items rather than double-clicking.

I've found tremendous improvement in workflow by making a command to do this. (When I'm hot-keying my way through a scene, double-clicking a precise location on the stage is a real nuisance). Secondly, by using a command, you can add extra functionality (which is what you need).

As you dive into your symbol to edit it, you can also have the command record your starting location (the parent timeline, the frame number, etc) into a temporary text file in the location of your choosing. I'd use the config directory since it's already defined as a property of the fl object. Adobe Flash Professional * fl.configURI

Record the symbol object's information, the frame you're on, etc.

Once you write that text file, you've essentially left a bookmark for yourself.

When you're inside the embedded symbol, you can then run a second script which will get the "bookmarked" timeline information you recorded to that text file. Then, you can do whatever you want.

bluebeezle
Inspiring
December 7, 2017

no, I don't need to run any script twice, or more than one script. diving into the symbol is done manually. at no point do I need the script to dive into any symbol. Using JSFL, I want to be able to get access to the instance object I manually dived into on the parent timeline.

also, the timeline object only gives me access to the currently open timeline. I need the timeline of the timeline that the symbol instance is sitting on. it looks like the only way to do that is the clunky method I mentioned.

kglad
Community Expert
Community Expert
November 29, 2017

how did you get to symbol editing?  via the library symbol (and you want the library name) or via a timeline instance and you want the instance name?  or something else?

bluebeezle
Inspiring
November 30, 2017

I'm talking about if you dive into nested symbols from the timeline rather than opening them through the library. I want to get the instance that I dove into to open the currently open symbol. not just the name, but the actual object.

kglad
Community Expert
Community Expert
November 30, 2017

i don't understand your work-flow.

you have a fla that you want to manipulate using jsfl, correct?

you create a jsfl file and you run it from a fla (commands>run>..), correct?