ePub


Creating ePubDocuments With Scripts III

Tuesday, January 22, 2013

Our last blog introduced you to a script that creates the framework for your ePub document. Here, we start another script that will populate the document and style the text. Each page for our sample document will have a similar structure consisting of three paragraphs:

  • headline - paragraph style "Headline1"
  • body text - paragraph style "Text"
  • empty paragraph for anchoring image - paragraph style "CenterImage"

The text contents will be imported from a plain text file with paragraphs defined by ending line returns reading, in part, as follows:

My Crazy Cat¶
This is a story about one crazy cat whose personality seems to change with each day of the week.¶
¶
Monday¶
My cat carefully plans his week while lazying around the house all day.¶
¶

And so on. Of course, depending on your text editor, you probably will not see the paragraph returns. We added the paragraph return character here just for illustration.

The interesting part of this script involves how the paragraphs are styled.

Because the styling repeats in a consistent pattern, it can use a unique looping algorithm that involves a modulus operation.

Modulus

The mathematical operation modulus is similar to division with the exception that it returns only the remainder of a division operation, for example.
24 modulus 3 = 0
25 modulus 3 = 1

The symbol for modulus in AppleScript is mod; in ExtendScript it is the percent sign (%).

Looping Algorithm

For demonstration, try the following script snippet:

AppleScript

set paraCount to 9 --number of paragraphs in text flow
set applyParastyleList to {"Headline1", "Text", "CenterImage"} --names of styles
set styleLen to length of applyParastyleList
repeat with i from 1 to paraCount
	set parastyleIndex to ((i + paraCount - 1) mod styleLen) + 1
	set styleName to item parastyleIndex of applyParastyleList
	display alert "paragraph style is now " & item parastyleIndex of applyParastyleList
end repeat

ExtendScript

var paraCount = 9; //number of paragraphs in text flow
var applyParastyleList = ["Headline1", "Text", "CenterImage"]; //names of styles to be applied
var styleLen = applyParastyleList.length;
for (var i = 0; i < paraCount; i ++) {
        var tempIndex = ((i + paraCount) % styleLen) ; 
        var styleName = applyParastyles[tempIndex];
        alert ("Paragraph style is now "  + applyParastyleList[tempIndex]
       paraList[i].appliedParagraphStyle = docRef.paragraphStyles.item(styleName);
}

In the script, references to the document's paragraph styles are stored in a list (array) variable. This is returned from the getParagraphStyles subroutine.

AppleScript

tell application "Adobe InDesign CS6"
set docRef to document 1
set parastyleList to my getParagraphStyles (docRef)
end tell

(*Handler returns list of names for paragraph styles in document*)
on getParagraphStyles(docRef)
	tell application "Adobe InDesign CS6"
		tell docRef
			set allNames to name of paragraph styles
		end tell
	end tell
	set parastyleList to rest of allNames --discard the first style 
	set item 1 of parastyleList to "No Style" --rename the style that is now first
	return parastyleList
end getParagraphStyles

ExtendScript

//calls function
var docRef = app.documents.item(0);
var parastyleList = getParagraphStyles(docRef);

/*Function returns list of names for paragraph styles in document*/
   var localstyleList = docRef.paragraphStyles.everyItem().name;
  var localstyleLen = localstyleList.length;
  localstyleList = localstyleList.slice(2, localstyleLen); //remove first two items from array
  localstyleList.unshift("No Style"); //add this item as the first item
  return localstyleList;
}

The list of available paragraph styles is passed to a custom dialog which allows the user to select, in order, the paragraph styles to use. The custom dialog provides five drop downs from which to choose the style for each of the paragraphs. For our sample document only the first three drop downs will be used. The others will default to "No Style".

The styles are then applied to the paragraphs using our looping algorithm. This is done in the placeText subroutine that places the text inside the top/left margin for the first page of the document.

(*Places text for file defined by fileRef and styles the text using a list of paragraph styles*)
on placeText(docRef, fileRef, applyParastyles)
	set styleLen to length of applyParastyles
	tell application "Adobe InDesign CS6"
		--set text import preferences
		set origImportPrefs to text import preferences
		tell text import preferences
			set strip returns between lines to false
			set strip returns between paragraphs to false
			set use typographers quotes to true
			set convert spaces into tabs to false
		end tell
		--get page and place point for placing the text
		set pageRef to page 1 of docRef
		tell margin preferences of pageRef
			set mTop to top
			set mLeft to left
		end tell
		set placePt to {mLeft, mTop}
		--place the file
		tell pageRef to place file fileRef place point placePt with autoflowing without showing options
		--get an object reference list of the paragraphs in the story
		set paraList to object reference of paragraphs of story -1 of docRef
		set paraCount to (length of paraList)
		--adjust the number of paragraphs
		if paraCount mod styleLen > 0 then
			set paraCount to (paraCount div styleLen) * styleLen
		end if
		--repeat through the paragraphs and apply the styles
		tell docRef
			repeat with i from 1 to paraCount
				set parastyleIndex to ((i + paraCount - 1) mod styleLen) + 1
				set styleName to item parastyleIndex of applyParastyles
				set thisPara to item i of paraList
				set applied paragraph style of thisPara to paragraph style styleName
			end repeat
			--check for overflow condition for text frame on page 1
			if overflows of text frame 1 of page 1 = true then
				set next text frame of text frame 1 of page 1 to text frame 1 of page 2
			end if
		end tell
		--return text import preferences to original settings
		set text import preferences to origImportPrefs
	end tell
end placeText

ExtendScript

/*Places text for the file defined; styles the text using list of paragraph styles*/
function placeText (docRef, fileRef, applyParastyles){
    var styleLen = applyParastyles.length;
    //set text import preferences
    var origImportPrefs = app.textImportPreferences.properties;
    with (app.textImportPreferences) {
    stripReturnsBetweenLines = false;
    stripReturnsBetweenParagraphs = false;
    useTypographersQuotes = true;
    convertSpacesIntoTabs = false;
    }
    //define page and place point for text import
    var pageRef = docRef.pages.item(0);
    var mTop = pageRef.marginPreferences.top;
    var mLeft = pageRef.marginPreferences.left;
    var placePt = [mLeft, mTop];
    //place the file; parameters: file, place point, layer reference, showing options, autoflow
    pageRef.place(fileRef, placePt, undefined, false, true);
    //get array of paragraphs in story placed
    var paraList = docRef.stories.item(-1).paragraphs;
    //adjust the number of paragraphs
    var paraCount = paraList.length;
    if (paraCount % styleLen > 0) {
        paraCount = (Math.floor(paraCount/styleLen)) * styleLen;
    }
    //style the paragraphs using the looping algorithm
    for (var i = 0; i < paraCount; i ++) {
        var tempIndex = ((i + paraCount) % styleLen) ;
        var styleName = applyParastyles[tempIndex];
       paraList[i].appliedParagraphStyle = docRef.paragraphStyles.item(styleName);
     }
    //check for overflow condition for text frame on page 1
    if (pageRef.textFrames.item(0).overflows == true) {
        var nextPage = docRef.pages.item(1);
        pageRef.textFrames.item(0).nextTextFrame = nextPage.textFrames.item(0);
    }
    //reset text import preferences
    app.textImportPreferences.properties = origImportPrefs;
}

A procedure within this subroutine needs explanation. We need to make sure that the number of paragraphs to be styled conform to the number of styles being used. Otherwise an error with be raised if the script attempts to style a paragraph that does not exist. Some text editors will throw away the last paragraph of a story if it is empty. For our example, this is prevented by using end of story characters (hash characters) for the last paragraph.

The subroutine makes sure there is an evenly-divisible number of paragraphs by rounding the number of paragraphs (paraCount). This might result in the paragraphs on the last page being unstyled. Users would then need to style this page manually. Optionally, you could add paragraphs until the count is evenly divisible.

At first glance, going to all of this trouble to write a script to create one document, might seem to be counter-productive. On the other hand, consider the fact that most pages in a fixed layout will not require any more than five paragraphs. The order of styling for the pages is controlled by the paragraph style list (array). The paragraph that will hold the image is identified by an index value. Suppose you want to have the image for page 1 follow the second paragraph, but to follow the third paragraph on subsequent pages. Allow for empty paragraphs to shift the position, and remove empty paragraphs after images have been placed.

For example, allow for five paragraphs with the following pattern: {"Headline1", "Text", "Text", "CenterImage", "Text"}. When you want the text to follow the second paragraph, you make the second paragraph of the page an empty paragraph. When it needs to follow the third paragraph, both the first and second paragraphs have content. It works, believe me.

Tune in next week as we place the images for our pages.

Trackback Link
http://www.yourscriptdoctor.com/BlogRetrieve.aspx?BlogID=15847&PostID=817824&A=Trackback
Trackbacks
Post has no trackbacks.