Copy link to clipboard
Copied
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?
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
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
Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
I have a symbol sitting on my timeline here.
I dive into it manually by double clicking to edit in place. You can see it reads Scene 1>Symbol 1 on the top left here.
I then want to be able to run a .jsfl script that will give me access to the instance selected in the FIRST image. Is there a way to do that without using document.exitEditMode() and accessing the currently selected object with document.selection[0]? It's not relevant, but I run my JSFLs from a custom toolbar I created.
Copy link to clipboard
Copied
Depending on the type of element you have selected, it may have a .parent property that you can read.
Copy link to clipboard
Copied
fl.trace(fl.getDocumentDOM().getTimeline().parent);
Gives me "undefined".
Copy link to clipboard
Copied
Ah, a timeline object. Does this provide what you need?
Adobe Flash Professional * timeline.name
If not, well... using two or three lines of code to get a reference is about the least clunky thing I've ever had to do in JSFL. It is not an elegant API. If you can get it to do what you want at all, consider yourself lucky.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
Oh, that's much easier! I thought you wanted to edit the timeline of the "host" or "parent" timeline.
You just need to know the name of the symbol in the library that you want to access.
So, if your keyframe has one element, element[0], and that element is the symbol you're interested in editing, find its library item and that library item's name:
element[0].libraryItem.name
Having that information, I made a function a while back to give me access to the timeline object of that element.
First, define some basic variables:
var curr_doc = fl.getDocumentDOM().library;
var curr_lib = curr_doc.library;
Then, this function returns the timeline object:
function getTL(TimelineName){
var the_tl = Items[curr_lib.findItemIndex(TimelineName)].timeline;
return the_tl;
}
So, you'd run:
mySymbolTimeline = getTL(theSymbolLibraryName);
And, then, "mySymbolTimeline" will have all the same properties you'd use to work with "current timeline."
Copy link to clipboard
Copied
I don't think you're quite understanding what I'm asking. I want the element (i.e. tline.layers[0].frames[0].elements[0]) that I double clicked to edit in place the symbol that I currently have open. That means I need access to the timeline ABOVE the one that's currently open. When I run the script, I wouldn't know what that timeline is, since I only have the nested timeline open right now. It's also possible that multiple instances of this opened symbol exist on that parent timeline. even on the same frame. all with different properties (position, rotation, etc), so getting access to the right one is important.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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;
}
Copy link to clipboard
Copied
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
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
Copy link to clipboard
Copied
bluebeezle​...
Just curious if we're getting close to what you're after.
So far, I'm not entirely sure I'm clear on what you'd like to do to the symbol instance in the parent timeline.
And, then, if there are multiple instances, I don't know how to be certain that you're editing the correct one.
Or, if you want to do this to all of them.
At a guess, is this something to do with the element transformations?
Copy link to clipboard
Copied
yup, that works! I was really thinking something so basic would be more built in, but this works great. thanks!
@chrisgelles so, my need for this has come up a couple times. The most recent one is a way of getting the globalized transform matrix of the currently open symbol, yes. The other is that I have a script that exports from within the currently open symbol, but it needs to make changes to the file for each export. So I copy the file multiple times before performing the function on each of them. That means I have to dive back into the symbol that was open in the original file (or at least have access to its timeline) in each of the copies of the file. So I need to find the path from the main timeline down to the nested symbol by recording the list of indices for frame and element numbers.
As I mentioned before, I'd found a workaround with the exitEditMode feature in the meantime, but I figured something so basic would have had a proprietary solution that I was just missing.
Copy link to clipboard
Copied
var ele = fl.getDocument().getSelection[0];
var eleTimeline = ele.libraryItem.timeline;