Wednesday, February 22, 2012

Opening a File with User Interaction

The easiest way to open a file is with SimpleOpen(). This is the analog to SimpleSave() discussed here.

If you do the open interactively, you do not need to know the file's location. You simply let the user locate the proper file.

The following script passes an empty string for the fileName parameter. FrameMaker assumes the file is the last one opened.

var doc;
doc = SimpleOpen("", true);


To open a file without user interaction, you need to pass it is full pathname and false for the second parameter. 

Monday, February 20, 2012

Working with Book Components

You might be tempted to think of FrameMaker books as containing documents. In fact, they contain book components which reference the files that when opened become FrameMaker documents.

To work with all of the documents in a book, you must traverse the list of book components and open each component in turn.

The list of book components is an ordered list. You can start with the FirstComponentInBook. Having found that component, you can use its NextComponentInBook property to find the next book component.

It is also possible to traverse a books components from last to first. In this case you start with LastComponentInBook and use the component's PrevComponentInBook property to move up the list.

The following code snippet shows how you to traverse a book's components from first to last. 

component =book.FirstComponentInBook;
while(component.ObjectValid() ){
    doSomething();
    component =  component.NextComponentInBook;
}

Working with the Active book

The ActiveBook is an exact analog of the ActiveDoc. It refers to the book that has the user focus.

There can be an active book or an active document but not both at the same time. It is also possible that there is neither an active book nor an active document. 

When working with either an active book or an active document, you should check for the possibility that what you are seeking does not exist.

var doc, book;

book  = app.ActiveBook;
if (book.ObjectValid()) {
    Alert("Active book found", Constants.FF_ALERT_CONTINUE_NOTE);
} else {
    doc = app.ActiveDoc;
    if (doc.ObjectValid()) {
        Alert("Active document found", Constants.FF_ALERT_CONTINUE_NOTE);
    } else {
         Alert("No active document or book found", Constants.FF_ALERT_CONTINUE_NOTE);
    } 
}


Saturday, February 4, 2012

Converting Font Style Names to Font Angle Index Values

If your script queries a text property such as font angle, the value you get back is a number and not a name. For example, the following code snippet asks what is the font angle at the text location (tLoc) specified. That information is returned as an integer.

textProp =  doc.GetTextPropVal(tLoc, Constants.FP_FontAngle);
angleIndex = textProp.propVal.ival; //integer value

The integer value angleIndex is an index into an array containing the possible font angle values available in the current FrameMaker session. Use the app (session) property FontAngleNames to get this array of strings.

angleNames = app.FontAngleNames;

Here is that data structure as viewed in the ExtendScript DataBrowser:

The following script converts an angle name to its corresponding index in the angleNames array.

function findAngleIndex(angleName) {
    var angleNames, index;
    angleNames = app.FontAngleNames;
    for (index = 1; index < angleNames.len; index += 1) {
        if (angleNames[index] === angleName) {
            break;
        }
    }
    if (index === angleNames.len) {
        index = null;
    }
    return (index);
}

var index;

index = findAngleIndex("Italic");
Alert(index, Constants.FF_ALERT_CONTINUE_NOTE);


The output is as shown here:

Monday, January 30, 2012

Text Item and Line Ends

Understanding exactly what text items are produced when you call GetText() is critical to writing correct scripts. I have been looking at when you get a FTI_CharPropsChange notification upon calling GetText(). In particular, I am interested in what happens at line ends.

Each of the examples below show what happens when you run a simple script that prints a set of requested text items including changes in character properties and line ends to the Console. Each file tested has one "word" consisting of the digits from 0 through 9. In each case three of the digits have been italicized using the Format>Style menu.

I was expecting to see, among other things, an indicator of where any changes in the italic properties of the text begin and end. The problem I have found occurs when the italic text is at the end of a line. In such cases, I do not get the second FTI_CharPropsChange indicator I am expecting. This behavior deviates from what I knew to be the case in the FDK in earlier versions of FrameMaker. I have not yet tried this in the FM 10 FDK.

var doc, mainflow, tItems;

doc = app.ActiveDoc;
mainflow = doc.MainFlowInDoc;
tItems = mainflow.GetText(Constants.FTI_CharPropsChange | Constants.FTI_TextObjId | Constants.FTI_LineEnd);
PrintTextItems(tItems);


Here is a case that goes as expected, yielding a change indicator before and after the italicized text.



Now look at what happens when the italic text is at the end of the line. Here I get only the initial indicator. In my view, this is acceptable as this this a special end of flow case. There is no non-italic character after the italic "9".






If a carriage return is added after the italic "9", I expect but do not get the second character properties change indicator. Note that end of paragraph symbols are selectable and this one is not italic.




Finally, lets use a soft return as our final character. Once again, there is only the beginning indicator.


I bring all this up not to be picky but because this change/bug complicates working with GetText(). If have I have missed something, please let me know.

Sunday, January 29, 2012

Customizing a Save Operation

The following script uses the Save() method to alter the format in which a file is saved. Using this method requires more code than SimpleSave() but offers a whole range of customization options. It takes three pages in the Scripting Guide to document the possibilities. Whatever changes you want to make, however, can be accomplished by following the model shown here:
  • Use GetSaveDefaultParams() to get a list of parameters whose default settings can be altered.
  • Use  new PropVals() to create an empty parameter list to be used to return information about the Save() operation.
  • Use GetPropIndex() to locate one or more of these properties of interest.
  • Reset that properties value in the parameter list.
  • Call Save() passing in the save as name, and the two parameter lists. 
The critical function is shown here:

function saveAsPdf(doc) {
    var saveParams, name, i, baseName, status, fullName;
    name = doc.Name;
    baseName = dropSuffix(name);//drops everything from last period
    fullName = baseName + ".pdf";
    saveParams = GetSaveDefaultParams();
    returnParams = new PropVals(); 
    i = GetPropIndex(saveParams, Constants.FS_FileType);
    saveParams[i].propVal.ival =Constants.FV_SaveFmtPdf;
    doc.Save(fullName, saveParams, returnParams);
    i = GetPropIndex(returnParams, Constants.FS_SaveNativeError);
    status = returnParams[i].propVal.ival;
    if (status === Constants.FE_Success) {
        return (true);
    } else {
        return (false);
    }
}

Friday, January 27, 2012

Creating a Marker (Correction to previous post)

When you create a marker you  need to specify the marker type identifier. If you are using an built-in type, use the name found in the English user interface.


Use GetNamedObject() to get this identifier. Use the appropriate marker type name. (This is a document and not a session property because of the fact that new types can be added to a given document.)

function createMarker(doc, pgf, offset, type, text) {
    var tLoc, marker, markerType;
    tLoc = new TextLoc(pgf, offset);
    marker = doc.NewAnchoredObject(Constants.FO_Marker, tLoc);
    markerType = doc.GetNamedObject(Constants.FO_MarkerType, type);
    marker.MarkerTypeId = markerType;
    marker.MarkerText = text;
    return 1;
}


You only need to  set the marker type properties for a built-in type if you want to change them. For example, add the following line of code to change the type name as displayed in the user interface.

markerType.Name = "My glossary";