1

What I'm trying to do

  1. Find all instances of paragraphs with a certain paragraph style.
  2. Cut the paragraphs and create a text frame where each group of paragraphs was.
  3. Apply an object style to the new text frame.
  4. Copy the cut text into the new text frame.
  5. Convert the new text frame to an interactive text field

Why I'm trying to do it

I have a document with a bunch of blank lines printed in it so users can fill in their notes. I accomplish this with carriage returns that have a Ruled paragraph that adds a full width paragraph underline. I want to also create an interactive PDF that has form fields for users to add their notes digitally. My hope is that I can take my current document, run a script on it, and export a PDF ready to go.

What isn't working

Currently, my javascript creates a new text box for each paragraph. But I have multiple lines for print users to add notes, and only need one text field for digital users. So I need a way to select all instances of multiple paragraphs with the same paragraph style.

My code

var myDoc = app.activeDocument; // The open document: the scene of the action
var myParas = app.selection[0].parentStory.paragraphs; // The collection of paragraphs
var myParaCount = app.selection[0].parentStory.paragraphs.length; // The number of paragraphs in the story


// Make a reference to the paragraph style for captions
var paraStyleSelect = app.activeDocument.paragraphStyleGroups.item("Main").paragraphStyles.item("Ruled");
var objectStyleSelect = app.activeDocument.objectStyles.item("Fillable Form");

// Loop to make the change on every paragraph that has the selected style
for (i = myParaCount - 2; i >= 0; i--) {
  if (myParas[i].appliedParagraphStyle == paraStyleSelect) {
    var myNewTextFrame = myParas[i + 1].insertionPoints[0].textFrames.add(); // Make a new text frame
    myNewTextFrame.appliedObjectStyle = objectStyleSelect;
    myParas[i].move(LocationOptions.AT_BEGINNING, myNewTextFrame.insertionPoints[0]); // Move the paragraph into the new text frame at the first insertion point
    
    // Convert text box to fillable form text field
    app.select(myNewTextFrame);
    var convertToTextField = app.menuActions.itemByName("$ID/$$$/Command/TextField");  // Menu command "Convert To Text Field":
    // If available:
    if (convertToTextField.enabled) {
      convertToTextField.invoke();
    };
  }
}
alert("High five!"); 

2 Answers 2

1

Here's some edits to your script which hopefully solves your problem:

var myDoc = app.activeDocument; // The open document: the scene of the action
var myParas = app.selection[0].parentStory.paragraphs; // The collection of paragraphs
var myParaCount = app.selection[0].parentStory.paragraphs.length; // The number of paragraphs in the story

// Make a reference to the paragraph style for captions
var paraStyleSelect = app.activeDocument.paragraphStyleGroups.item("Main").paragraphStyles.item("Ruled");
var objectStyleSelect = app.activeDocument.objectStyles.item("Fillable Form");

// Temporary text frame
var tempTextFrame = myDoc.pages[0].textFrames.add();
var tempTextFrameParas = tempTextFrame.parentStory.paragraphs;

// Loop to make the change on every paragraph that has the selected style
for (i = myParaCount - 2; i >= 0; i--) {
  if (myParas[i].appliedParagraphStyle == paraStyleSelect) {
    // Check if the previous paragraph also has the selected style
    if (myParas[i - 1].appliedParagraphStyle == paraStyleSelect) {
      // Move previous paragraph to temporary text frame
      myParas[i].move(LocationOptions.AT_BEGINNING, tempTextFrame.insertionPoints[0]);
    } else {
      // Move current paragraph to temporary text frame
      myParas[i].move(LocationOptions.AT_BEGINNING, tempTextFrame.insertionPoints[0]);
      
      // Remove the last character from temporary text frame if it's a paragraph break
      var lastChar = tempTextFrameParas[tempTextFrameParas.length - 1].characters.lastItem()
      if (lastChar.contents === "\r") {
        lastChar.remove()
      }
 
      // Make a new text frame
      var myNewTextFrame = myParas[i + 1].insertionPoints[0].textFrames.add();
      myNewTextFrame.appliedObjectStyle = objectStyleSelect;

      // Move all paragraphs from temporary text frame to new text frame
      for (j = tempTextFrameParas.length - 1; j >= 0; j--) {
        tempTextFrameParas[j].move(LocationOptions.AT_BEGINNING, myNewTextFrame.insertionPoints[0]);
      }
        
      // Convert text box to fillable form text field
      app.select(myNewTextFrame);
      var convertToTextField = app.menuActions.itemByName("$ID/$$$/Command/TextField");  // Menu command "Convert To Text Field":
      // If available:
      if (convertToTextField.enabled) {
        convertToTextField.invoke();
      };
    }
  }
}

// Remove temporary text frame
tempTextFrame.remove()

alert("High five!");

Before the loop we make a temporary text frame to contain the paragraphs we encounter along the way.

Inside the loop, if we encounter a paragraph with the wanted paragraph style, we check if the previous paragraph also has this style. If it does, we move the previous paragraph to the temporary text frame.

When there no longer exists a previous paragraph with the wanted style, we move the current paragraph to the temporary text frame and remove the last character if it's a line break. (I just noticed this might become a problem.)

After making a new text frame for the text field, we move the paragraphs currently in the temporary text frame to the new text frame.

After the loop the temporary text frame is deleted.

7
  • This is helpful, but I'm not wanting to delete multiple paragraphs; I'm wanting to cut multiple paragraphs into the new text box. I'm assuming I need to create a new var that can be multiple paragraphs, but I'm unsure how to do that.
    – Ian
    Mar 28 at 14:19
  • Ah OK, I see you mention that, but you also say the lines are blank so that confused me. Why do you want the blank lines pasted inside the text frames? Just to get the horizontal rules?
    – Wolff
    Mar 28 at 14:50
  • I think you could make a temporary text frame. I'll see if I can make it work.
    – Wolff
    Mar 28 at 14:54
  • I want to maintain the paragraphs because some responses only require a few lines of ruled blanks, whereas others require quite a few lines. I've got the object style set to auto-height so that it'll be as tall as the contained lines of blank ruled paragraphs.
    – Ian
    Mar 28 at 15:39
  • I'm part of the way there! I created an array and looped through previous paragraphs that are the same paragraph style, adding the array.
    – Ian
    Mar 28 at 15:40
0

Ended up using an array to capture multiple paragraphs.

There are a few other modifications I made as well, just so it's a bit more user-friendly.

// Original code by Jonathan Leathwood
// https://creativepro.com/topic/using-javascript-to-move-paragraphs-to-anchored-objects/
//
//DESCRIPTION:Cuts all paragraphs of a certain paragraph style, reinserts them as text anchors, and applies an object style

var myDoc = app.activeDocument; // The open document: the scene of the action

if (app.selection[0] instanceof TextFrame) {

  var myParas = app.selection[0].parentStory.paragraphs; // The collection of paragraphs
  var myParaCount = app.selection[0].parentStory.paragraphs.length; // The number of paragraphs in the story
  var myCapture = []; // Create an array to store selected paragraphs

  myResult = confirm("This script requires a paragraph style named Main > Ruled, another paragraph style named Main > Fillable Form, and an object style named Fillable Form. Do you have those set up?");
  if (!myResult) {
    exit();
  }

  // Make a reference to the paragraph style
  var paraStyleSelect = app.activeDocument.paragraphStyleGroups.item("Main").paragraphStyles.item("Ruled");
  var paraStyleNew = app.activeDocument.paragraphStyleGroups.item("Main").paragraphStyles.item("Fillable Form");
  var objectStyleSelect = app.activeDocument.objectStyles.item("Fillable Form");

  // Loop to make the change on every paragraph that has the selected style
  for (i = myParaCount - 2; i >= 0; i--) {
    if (myParas[i].appliedParagraphStyle == paraStyleSelect) {

      myCapture.push(myParas[i]);

      var j = i - 1;
      while (myParas[j].appliedParagraphStyle == paraStyleSelect) {
        myCapture.push(myParas[j]);
        j--;
      }

      myParas[i + 1].insertionPoints[0].contents = "\r"; // Add a new hard return i.e. a new paragraph
      myParas[i + 1].appliedParagraphStyle = paraStyleNew; // i + 1 is now that newly created paragraph
      var myNewTextFrame = myParas[i + 1].insertionPoints[0].textFrames.add(); // Make a new text frame

      for (var k = 0; k < myCapture.length; k++) {
        myCapture[k].move(LocationOptions.AT_BEGINNING, myNewTextFrame.insertionPoints[0]); // Move the paragraph into the new text frame at the first insertion point
      }

      // Convert text box to fillable form text field
      app.select(myNewTextFrame);
      var convertToTextField = app.menuActions.itemByName("$ID/$$$/Command/TextField");  // Menu command "Convert To Text Field":
      // If available:
      if (convertToTextField.enabled) {
        convertToTextField.invoke();
        app.selection[0].applyObjectStyle(objectStyleSelect, true, true);
        app.selection[0].multiline = true;
        app.selection[0].appliedFont = "Georgia";
      };
    }
  }
  alert("High five!");

} else {
  alert("Please select a text frame and try again.");
  exit();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.