Copy link to clipboard
Copied
Hello all,
What happens with a linked list of objects when I use the Delete method on one of these objects ? The FrameMaker Scripting Guide does not say much about this, nor does the FDK reference guide. I have tried the following but it does not work as I expected:
doc = app.ActiveDoc;
theGraph = doc.FirstGraphicInDoc;
n = 0;
while ( theGraph.ObjectValid() ) {
tobedeleted = false;
if ( theGraph.constructor.name == "AFrame" ) {
theObject = theGraph.FirstGraphicInFrame;
if ( theObject.ObjectValid() )
if ( theObject.constructor.name == "TextFrame" )
tobedeleted = true;
}
if ( tobedeleted ) {
nextGraph = theGraph.NextGraphicInDoc;
theGraph.Delete();
n++
theGraph = nextGraph;
} else
theGraph = theGraph.NextGraphicInDoc;
}
alert ( n );
The document has 18 of the specified anchored frames (with embedded text frames), but the above code only deletes 5. If I just walk through the list and skip deleting the objects, the count goes up to 18, as expected. So there must be some crazy side effect of deleting an object from a linked list. But what exactly ?
How can I walk through a linked list and delete some objects from them without disrupting the linked list ?
Jang
I'll have to take some time to try your code and try to understand what is going on. In the meantime, another approach is to loop through the anchored frames save the objects that you want to delete in an array. Then, you can loop through the array and delete each object. It may be a bit less efficient, but each loop can be very simple.
var doc = app.ActiveDoc;
var graphic = doc.FirstGraphicInDoc;
var textFrame;
var toDelete = [ ];
while(graphic.ObjectValid()) {
if (graphic.constructor.name === "AFr
Copy link to clipboard
Copied
This is the only way I could get it to work until now. It is kind of silly to have to restart from the first graphic in the document after having deleted one graphic object from the list, but at least this one works.
doc = app.ActiveDoc;
n = 0;
brunning = true;
while ( brunning ) {
theGraph = doc.FirstGraphicInDoc;
bdeleted = false;
while ( theGraph.ObjectValid() && !bdeleted ) {
if ( theGraph.constructor.name == "AFrame" ) {
theObject = theGraph.FirstGraphicInFrame;
if ( theObject.ObjectValid() ) {
if ( theObject.constructor.name == "TextFrame" ) {
bdeleted = true;
theGraph.Delete();
n++;
}
}
}
theGraph = theGraph.NextGraphicInDoc;
}
if ( !bdeleted )
brunning = false;
}
alert ( n );
It seems to me that there should be a more efficient way of doing this, but I have not found it yet. If anyone has good ideas, please post them. And if Adobe techies are monitoring this list: there is an obvious lack of either clarity or support from the available Delete() method here.
Ciao again
Jang
Copy link to clipboard
Copied
Hi Jang,
You might find this tutorial useful:
http://frameexpert.com/tutorials/loopsandlinkedlists.htm
The code is FrameScript, but the concepts are the same in ExtendScript and the FDK. Please let me know if you have any questions or comments.
Rick
Copy link to clipboard
Copied
Hi Rick,
The method you describe is what I tried to use in ExtendScript, as shown in my first posting, but apparently deleting an object after first saving its forward pointer still invalidates the forward pointer in some mysterious way. My expectation is that ExtendScript is fiddling with pointers to structures in the background, i.e. not copying objects but only the pointers to those objects.
I found something like this when I tried to set a TextRange to contain a frame anchor.
myrange = new Textrange;
myrange.beg = myrange.end = anchor;
myrange.beg.offset = 0;
myrange.end.offset = 1;
Believe it or not, but after these lines, both offsets are 1. So I tried to unlink the beg and end textlocs in my textrange object:
myrange = new Textrange;
myrange.beg = anchor;
myrange.end = anchor;
myrange.beg.offset = 0;
myrange.end.offset = 1;
Still the same result. The code that does what I expected looks like this:
myrange = new Textrange;
myrange.beg.obj = anchor.obj;
myrange.end.obj = anchor.obj;
myrange.beg.offset = 0;
myrange.end.offset = 1;
Isn't this total madness ? But it does tell me that some pointer juggling is going on behind the scenes. I will have another go at the linked list member deletion code and post a solution if I can find one.
Ciao
Jang
Copy link to clipboard
Copied
I'll have to take some time to try your code and try to understand what is going on. In the meantime, another approach is to loop through the anchored frames save the objects that you want to delete in an array. Then, you can loop through the array and delete each object. It may be a bit less efficient, but each loop can be very simple.
var doc = app.ActiveDoc;
var graphic = doc.FirstGraphicInDoc;
var textFrame;
var toDelete = [ ];
while(graphic.ObjectValid()) {
if (graphic.constructor.name === "AFrame") {
textFrame = graphic.FirstGraphicInFrame;
if (textFrame.ObjectValid()) {
if (textFrame.constructor.name === "TextFrame") {
toDelete.push(graphic); // Store the frame in the array.
}
}
}
graphic = graphic.NextGraphicInDoc;
}
// Loop through the array of anchored frames and delete each one.
for (var i = 0; i < toDelete.length; i += 1) {
toDelete.Delete();
}
Copy link to clipboard
Copied
Hi Rick,
I had to process another set of anchored frames and could not be certain that I could throw all of them away, so I converted the script to use the second method you indicated: push the objects into a toDelete array and then process that array at the end of the scipt. Very elegant and effective. Thanks.
Ciao
Jang
Copy link to clipboard
Copied
Hi Jang,
I orginally developed this for deleting certain elements in a structured document, since these are in a tree and not a linked list and this is the only way to do it reliably.
Rick
Copy link to clipboard
Copied
Most of the element- and attribute level work in structured Frame I do with the FrameSLT Node Wizard Scripts now. Once you get the XPath expressions down, that is a very powerful tool. It is a little like scripting, but so much easier (because of the much smaller set of options, of course).
Ciao
Jang
Copy link to clipboard
Copied
I agree, FrameSLT is excellent. I am sure you have seen my blog post on FrameSLT:
http://frameautomation.com/2010/03/15/frameslt-a-great-framemaker-plugin/
Rick