Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
7

Cut text by frame and paste

Explorer ,
Feb 29, 2024 Feb 29, 2024

I'm looking for a script that cuts part or parts of a text and pastes it into new text boxes below. trying to find a script code that I'm doing this, but I've had no success. Can someone help me. The objective is for this "sentence" text to reference the bold text above.
Captura de tela 2024-02-29 113224.pngCaptura de tela 2024-02-29 113228.png

TOPICS
Feature request , How to , Scripting
1.2K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 01, 2024 Mar 01, 2024

Hi @eusoujpg, can you show us what your raw text looks like? For example, does every second line have the secondary "sentences"? Or are there two separate stories and the paragraphs from one match the instances of bold text in the other? I really have no idea how your job is structured, so I couldn't say whether a script would be good for it, I'm afraid.

- Mark

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 01, 2024 Mar 01, 2024

The document is part of a material for schools. In the raw material, in DOC, the editor writes a sentence. Below, she will write some texts (quotes) that refer to the bold texts. Example:

The dog chases the cat.
...........singular
Obs: ( . = space )

Below the "dog" text, for example, there will be a dimension called "singular". And so on. Did you understand?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 01, 2024 Mar 01, 2024

Hi @eusoujpg, I've written a script for this challenge!

 

Please try it out and let me know how it goes. Just select your text, or text frame and run script. If you have trouble getting it to work, please download the attached demo.indd and try script with that first.

- Mark

demo.gif

Here is the result using the same demo, but including styles for labels, tokens and sentences and also I've turned on the `removeLabelParagraphs` option (so my sentence paragraph style has enough space after to accommodate the label). It is a very good idea to use styles in cases like this. (The numbering and shading are just for demonstration of course.)

demo2.gif

 

/**
 * @file Connect Labels And Tokens.js
 *
 * Script will anchor "label" text to "token" text,
 * where paragraphs alternate between having
 * "tokens" and "labels".
 *
 * As configured by `settings` object:
 * "Labels" are text delimited by runs of 4 or more spaces.
 * "Tokens" are text in Bold font style.
 * Object style is applied to labels (if available).
 *
 * @author m1b
 * @discussion https://community.adobe.com/t5/indesign-discussions/cut-text-by-frame-and-paste/m-p/14457128
 */
function main() {

    // user settings
    var settings = {

        // name of label object style (optional)
        labelObjectStyleName: 'Label',

        // name of token character style (optional)
        tokenCharacterStyleName: 'Token',

        // name of sentence paragraph style (optional)
        sentenceParagraphStyleName: 'Sentence',

        // tokens are bold text in sentences
        tokenFindPreferences: { fontStyle: 'Bold' },

        // labels are delimited by runs of 4 or more spaces
        labelFindPreferences: { findWhat: '(?<=\\h{4})(\\S.*?)(?=\\h{4}|\\h*\\r)' },

        removeLabelParagraphs: true,

    };

    var doc = app.activeDocument;

    if (0 === doc.selection.length)
        return alert('Please select a text frame or text and try again.');

    // expand the settings object
    settings.doc = doc;
    settings.text = doc.selection[0];
    settings.labelStyle = getThing(doc.allObjectStyles, 'name', settings.labelObjectStyleName);
    settings.tokenStyle = getThing(doc.allCharacterStyles, 'name', settings.tokenCharacterStyleName);
    settings.sentenceStyle = getThing(doc.allParagraphStyles, 'name', settings.sentenceParagraphStyleName);

    // connect the labels
    var labels = connectLabelsToTokens(settings);

    alert((!labels || 0 === labels.length)
        ? 'No labels were connected.'
        : 'Connected ' + labels.length + ' labels.'
    );

};

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Connect Labels');


/**
 * Connects "labels" to "tokens".
 *
 * Creates anchored text frames containing
 * "label" text, positioned centrally beneath
 * the "token" text.
 *
 * The `text` parameter must include paragraphs
 * where a paragraph of "labels" is always preceded
 * by a paragraph of 'tokens'.
 *
 * @author m1b
 * @version 2024-03-03
 * @param {Object} options
 * @param {Document} options.doc - an Indesign Document.
 * @param {Text|TextFrame|TextColumn} options.text - a DOM object with multiple paragraphs of alternating content.
 * @param {Object} options.tokenFindPreferences - an object containing valid findGrepPreferences properties.
 * @param {Object} options.labelFindPreferences - an object containing valid findGrepPreferences properties.
 * @param {ObjectStyle} [options.labelStyle] - an object style to apply to each label text frame (default: none).
 * @param {CharacterStyle} [options.tokenStyle] - a character style to apply to each token found (default: none).
 * @returns {Array<{label: token:}>}
 */
function connectLabelsToTokens(options) {

    options = options || {};
    app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;

    // extra width of label frames, in points
    const LABEL_SIDE_MARGIN = 10;

    var doc = options.doc,
        paragraphs = getWholeParagraphs(options.text),
        didAddCarriageReturn = false,
        connections = [];

    if (
        undefined == paragraphs
        || 0 === paragraphs.length
    )
        return;

    if ('\u000D' != paragraphs[paragraphs.length - 1].characters.lastItem().contents) {
        // add a carriage return to last paragraph, to make things easier with findGrep
        paragraphs[paragraphs.length - 1].characters.lastItem().contents += '\u000D';
        // update the reference
        paragraphs[paragraphs.length - 1] = paragraphs[paragraphs.length - 1].characters.firstItem().paragraphs[0];
        didAddCarriageReturn = true;
    }

    paragraphLoop:
    for (var i = paragraphs.length - 1, para, labels, sentence, tokens; i >= 0; i--) {

        para = paragraphs[i];

        if (!para.isValid)
            continue paragraphLoop;

        // find labels
        setUpFindGrepPreferences(options.labelFindPreferences)
        labels = para.findGrep();

        if (labels.length == 0)
            // no labels here
            continue paragraphLoop;

        // get the sentence paragraph for this label paragraph
        sentence = labels[0]
            .parentStory.characters
            .previousItem(labels[0].paragraphs[0].characters[0])
            .paragraphs[0];

        if (!sentence.isValid)
            continue paragraphLoop;

        // find tokens in the sentence
        setUpFindGrepPreferences(options.tokenFindPreferences)
        tokens = sentence.findGrep();

        if (tokens.length == 0)
            // no tokens here
            continue paragraphLoop;

        if (options.sentenceStyle)
            sentence.applyParagraphStyle(options.sentenceStyle, true);

        tokenLoop:
        for (var j = tokens.length - 1, token, label, ip, center, frame, halfLabel; j >= 0; j--) {

            token = tokens[j];
            label = labels[j];

            if (!token || !label)
                continue tokenLoop;

            if (options.tokenStyle)
                token.applyCharacterStyle(options.tokenStyle, false);

            halfLabel = ((label.endHorizontalOffset - label.horizontalOffset) / 2) + LABEL_SIDE_MARGIN;
            center = token.horizontalOffset + (token.endHorizontalOffset - token.horizontalOffset) / 2;

            // this is where the label frame will be anchored
            ip = token.insertionPoints.lastItem();

            frame = doc.textFrames.add({
                geometricBounds: [
                    /* top */     label.baseline - label.ascent,
                    /* left */    center - halfLabel,
                    /* bottom */  label.baseline + label.descent,
                    /* right */   center + halfLabel],
            });

            // put text in the new frame
            labels.pop().duplicate(LocationOptions.AFTER, frame.insertionPoints[0]);

            // anchor the frame
            frame.anchoredObjectSettings.insertAnchoredObject(ip, AnchorPosition.ANCHORED);

            // apply object style, if specified
            if (options.labelStyle)
                frame.applyObjectStyle(options.labelStyle, true);

            // position the frame
            frame.anchoredObjectSettings.horizontalReferencePoint = AnchoredRelativeTo.ANCHOR_LOCATION;
            frame.anchoredObjectSettings.anchorXoffset = frame.parent.horizontalOffset - center - halfLabel;

            connections.push({ label: frame, token: token });

        }

        if (options.removeLabelParagraphs)
            para.remove();
        else
            para.contents = '\r';

    }

    if (didAddCarriageReturn)
        options.text.parentStory.characters.lastItem().remove();

    if (connections.length)
        return connections;

};

/**
 * Returns a thing with matching property.
 * @param {Array|collection} things - the things to look through, eg. PageItems.
 * @param {String} key - the property name, eg. 'name'.
 * @param {*} value - the value to match.
 * @returns {*} - the thing.
 */
function getThing(things, key, value) {

    for (var i = 0; i < things.length; i++)
        if (things[i][key] == value)
            return things[i];

};

/**
 * Sets up Indesign's findGrep using `props`.
 * @param {Object} props - the properties to apply.
 */
function setUpFindGrepPreferences(props) {

    app.findGrepPreferences = NothingEnum.NOTHING;

    for (var key in props)
        if (app.findGrepPreferences.hasOwnProperty(key))
            app.findGrepPreferences[key] = props[key];

};


/**
 * Returns array of whole paragraphs
 * that each end in carriage return;
 * @author m1b
 * @version 2024-03-03
 * @param {Text} text - Indesign DOM object with paragraphs.
 * @returns {Array<Paragraph>}
 */
function getWholeParagraphs(text) {

    if (undefined == text)
        return;

    if (text.hasOwnProperty('text'))
        text = text.text;

    if (
        !text.hasOwnProperty('paragraphs')
        || text.paragraphs.length < 1
    )
        return;

    return text.paragraphs.everyItem().getElements();

};

 

 

 

 

Edit 2024-03-03: improved getWholeParagraphs and fixed bug where if `text` was the last insertionPoint of a Story. Also added optional character style for "tokens" and better handling of object styling.

Edit 2024-03-03: added optional paragraph style for "sentences", option to remove "labels" paragraphs, and added gif showing use of styles.

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 04, 2024 Mar 04, 2024

I really appreciate your dedication for doing this. It will help me a lot with the material I'm doing. Furthermore, I will be able to study a lot of the code you created, bringing great ideas. I'm very happy.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 04, 2024 Mar 04, 2024
LATEST

Very glad it helped!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Mar 01, 2024 Mar 01, 2024

@eusoujpg 

 

So you want for texts "sentence #" to stay in the same place - but as separate TextFrames?

 

Is there a Char / ParaStyle applied to the "sentence #" - because, how script should be able to find what you want to "extract"?

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 04, 2024 Mar 04, 2024

Yes, the code posted by M1b has already helped me a lot. Then I will read all the reflections and suggestions given here. It is very rich in information and will be very useful to me. thank you very much

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines