Copy link to clipboard
Copied
Hi all. I'm new here and new to scripting. Been reading a lot and watching some videos but it still hasn't quite clicked. I'm am trying to write a script that will apply a hypertext marker to a specific paragraph format, and customize each marker with a specific newlink command based on the contents of the paragraph. For example, the following paragraph, which has the format CaptionFigure, would need a hypertext marker called newlink f3 to correspond with Figure F3:
Figure F3. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec non pretiu
Figure F4 will have newlink f4, Figure F5 will have newlink f5, and so on.
There are sometimes up to 50 or 60 figures in a document, thus I’m looking to streamline it with ExtendScript. I found this code to apply a marker to a paragraph format in the forum (thanks mrsjackharkness) and modified it, and it works great. Now I need help with the next step, to customize the marker.
var doc = app.ActiveDoc;
var flow = doc.MainFlowInDoc;
var tframe = flow.FirstTextFrameInFlow;
var pgf = tframe.FirstPgf;
var target1 = doc.GetNamedObject(Constants.FO_PgfFmt, "CaptionFigure");
var target2 = doc.GetNamedObject(Constants.FO_PgfFmt, "CaptionTable");
while (pgf.ObjectValid()) {
if (pgf.Name == target1.Name) {
createMarker (doc, pgf, 0, "Hypertext", "Newlink f");
}
else if (pgf.Name == target2.Name) {
createMarker (doc, pgf, 0, "Hypertext", "Newlink t");
}
pgf = pgf.NextPgfInDoc;
}
function createMarker(doc, pgf, offset, type, text) {
var tLoc = new TextLoc(pgf, offset);
var marker = doc.NewAnchoredObject(Constants.FO_Marker, tLoc);
var markerType = doc.GetNamedObject(Constants.FO_MarkerType, type);
marker.MarkerTypeId = markerType;
marker.MarkerText = text;
return 1;
}
Any advice will be much appreciated. Please and thank you!
Julie
myersjh91 and I worked on this on the phone. Here is our complete solution. fonrig's solution should work too, but using regular expressions made this work for both Figure and Table captions.
...#target framemaker
main ();
function main () {
var doc;
doc = app.ActiveDoc;
if (doc.ObjectValid () === 1) {
processDoc (doc);
}
else {
alert ("There is no active document.","www.frameexpert.com");
}
}
function processDoc (doc) {
var pgfRegex, pgf;
// Turn of
Copy link to clipboard
Copied
You can use the PgfNumber property of your caption paragraph. So, assuming your Autonumber formatting for the caption paragraph is: "F<+n> ", PgfNumber will return F1 , F2 , F3 , ..., Fn for each instance of the caption paragraph.
You can then extract the figure number from that string, for example inside your function createMarker, you can add:
var myPgfNumber = pgf.PgfNumber // This returns F1, F2, etc.
var figNumber = myPgfNumber.substr(1); // this extracts the number 1, 2, ..., 99, etc.
marker.MarkerText = text + figNumber; // adds figure number to your marker, i.e. Newlink f1, Newlink f2, etc.
Hope this makes sense...
Copy link to clipboard
Copied
H Julie,
Foring's response seems like a reasonable approach, if you are using autonumbers and that is what you were asking in the first place. Your question is a bit vague, though... can you clarify that is what you need help with? That you want to parse out the figure number from the paragraph, for use in the marker text? It seems like that is the case, which means maybe you have the answer.
Russ
Copy link to clipboard
Copied
I do want to parse out the figure number from the paragraph but the paragraphs are not autonumbered and are not part of the main flow of the document. I tried just adding "+ i++" (and ++i) to the function [createMarker (doc, pgf, 0, "Hypertext", "Newlink f" + i++); ]. It worked except for figure F1, which didn't number in the right order (showed up as F4), so I don't think this is the correct approach.
Copy link to clipboard
Copied
Is there any way you can post a sample FrameMaker document? You can send it to me directly if you want to: rick at frameexpert dot com. Thanks.
Copy link to clipboard
Copied
I'll send one. Thanks!
Copy link to clipboard
Copied
myersjh91 and I worked on this on the phone. Here is our complete solution. fonrig's solution should work too, but using regular expressions made this work for both Figure and Table captions.
#target framemaker
main ();
function main () {
var doc;
doc = app.ActiveDoc;
if (doc.ObjectValid () === 1) {
processDoc (doc);
}
else {
alert ("There is no active document.","www.frameexpert.com");
}
}
function processDoc (doc) {
var pgfRegex, pgf;
// Turn off the displaying property to speed the script and prevent flicker.
if (app.Displaying === 1) {
app.Displaying = 0;
}
// Match both CaptionFigure and CaptionTable paragraph formats.
pgfRegex = /^(CaptionFigure|CaptionTable)$/;
pgf = doc.FirstPgfInDoc;
while (pgf.ObjectValid () === 1) {
if (pgfRegex.test (pgf.Name) === true) {
processNewlinkPgf (pgf, doc);
}
pgf = pgf.NextPgfInDoc;
}
// Restore the document's display and refresh the screen.
if (app.Displaying === 0) {
app.Displaying = 1;
doc.Redisplay ();
}
}
function processNewlinkPgf (pgf, doc) {
var num, marker;
num = getFigOrTableNum (pgf);
if (num) {
// See if a newlink marker already exists in the paragraph.
marker = getMarker (pgf, "Hypertext", "newlink");
if (marker) {
// Update the existing marker's text.
marker.MarkerText = "newlink " + num;
}
else { // No existing marker; create a new one.
createMarker (doc, pgf, 0, "Hypertext", "newlink " + num);
}
}
else {
Console ("Couldn't find number: " + pgf.Name);
}
}
function getMarker (pgf, markerType, text) {
var markers = [], marker, textList, i;
textList = pgf.GetText (Constants.FTI_MarkerAnchor);
for (i = 0; i < textList.len; i += 1) {
marker = textList.obj;
if (marker.MarkerTypeId.Name === markerType) {
if (marker.MarkerText.indexOf (text) > -1) {
return marker;
}
}
}
}
function createMarker(doc, pgf, offset, type, text) {
var tLoc = new TextLoc(pgf, offset);
var marker = doc.NewAnchoredObject(Constants.FO_Marker, tLoc);
var markerType = doc.GetNamedObject(Constants.FO_MarkerType, type);
marker.MarkerTypeId = markerType;
marker.MarkerText = text;
return 1;
}
function getFigOrTableNum (pgf) {
var regex, pgfText, match;
regex = /(?:Table|Figure) ([FT]\d+)/;
pgfText = getText (pgf, doc);
if (regex.test (pgfText) === true) {
match = pgfText.match (regex);
return (match[1].toLowerCase ());
}
}
function getText (textObj, doc) {
// Gets the text from the text object.
var text = "", textItems, i;
// Get a list of the strings in the text object or text range.
if (textObj.constructor.name !== "TextRange") {
textItems = textObj.GetText(Constants.FTI_String);
} else {
textItems = doc.GetTextForRange(textObj, Constants.FTI_String);
}
// Concatenate the strings.
for (i = 0; i < textItems.len; i += 1) {
text += (textItems.sdata);
}
return text; // Return the text
}
Copy link to clipboard
Copied
frameexpert​,
Thank you so much for your time on the phone today and for your expertise. This will save us so much time, especially on the very long documents we often have.
~Julie
Copy link to clipboard
Copied
Impressive response Rick! Thanks for all your help. I learn something new with each one of your solutions!
Copy link to clipboard
Copied
Thank you very much. As you can see, I like to use a lot of functions and generalize them as much as possible so I can reuse them. I should have recorded our meeting so you could see how we built it up from a handful of lines to the working script. Maybe I will next time. Thanks again!
Copy link to clipboard
Copied
I had a feeling that a regex would be involved. Therefore, I was glad to see that Rick was not on vacation. Every occasional time I need one of those, it's back to the tutorial.
Russ
Copy link to clipboard
Copied
I read Jeffrey Friedl's "Mastering Regular Expressions" years ago, and it really got me liking regular expressions. It is one of the best computer books I have ever read. Regular expressions and xml technologies are two of my favorite things to work with as a programmer.
Copy link to clipboard
Copied
I just found this great site for testing and explaining regular expressions. It's pretty simple (which is what I need) but it helped me modify the code above to capture more types of captions. https://regex101.com/r/cU5lC2/1
Copy link to clipboard
Copied
// Parse figure number from figure caption text. Caption is not AutoNumbered
function parseCaption(pgf){
// Caption format: Figure F3. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec non pretiu
var figNumber = ''; // Initialize
var caption = getText(pgf); // Gets text content from paragraph
// Parse text to extract figure number
var firstSpace = caption.indexOf(" ", 7); // Gets first space position after second "F" in Figure FX._
figNumber = caption.substr(8, firstSpace - 9); // Grabs all text between "F" and period "." = Figure number
return figNumber;
}
//Returns text stored in a Text Object ********************************
function getText(textObj) {
var objText = '';
// Get a list of strings from the object.
var textItems = textObj.GetText(Constants.FTI_String); // Text only
// Concatenate strings in array
for (var i = 0; i < textItems.len; i += 1) {
objText += (textItems.sdata);
}
return objText;
} // end function
You can use it as:
createMarker (doc, pgf, 0, "Hypertext", "Newlink f" + parseCaption(pgf));
Copy link to clipboard
Copied
Thank you!
Copy link to clipboard
Copied
Thank you for replying. Unfortunately, the captions/figures are in independent text frames separate from the main flow and they are not autonumbered. I think I need the script to read the text that goes with the markers, and if the text says Figure F1, it needs to add the "1" to the marker.