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

Code to be evaluated! [012] Extract the Table Title! …

LEGEND ,
Dec 21, 2016 Dec 21, 2016

Copy link to clipboard

Copied

Hi Scripters,

Table Titles are included in the first row of each table and I want to "extract" them before the table using a para style "Title" applied to them!

Before:

Capture d’écran 2016-12-21 à 23.54.55.png

After:

Capture d’écran 2016-12-21 à 23.55.22.png

I've written the code below. Even if it totally works well, I'm not sure [as usual!] it's the more beautiful code we can read!

Thanks for your comments! 

app.doScript("main()", ScriptLanguage.javascript, undefined, UndoModes.ENTIRE_SCRIPT, "Extract Title! …");

function main()    

{

    var 

    myDoc = app.activeDocument,   

    myTables = myDoc.stories.everyItem().tables.everyItem().getElements();   

   

    for ( var T = 0 ; T < myTables.length; T++ )   

        {   

            myTables.storyOffset.paragraphs[0].duplicate(LocationOptions.after, myTables.storyOffset.paragraphs[0]);

            var myRows = myTables.rows;

            var R = myRows.length;

            while ( R -- )  if (R != 0)  myRows.remove();

            var myTitle = myTables.convertToText("\t", "\r");

            myTitle.appliedParagraphStyle = "Title";

        }

   

    myTables = myDoc.stories.everyItem().tables.everyItem().getElements();

    var T = myTables.length;

    while ( T-- )  myTables.rows[0].remove();

   

}

(^/)

TOPICS
Scripting

Views

681

Translate

Translate

Report

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 ,
Dec 21, 2016 Dec 21, 2016

Copy link to clipboard

Copied

Hi Obi-wan,

if you are sure that every table in your document has a title and you want to move it out of the table why don't you move just the text of cell one to an insertion point?

Example:

/*

    Preconditions:

    1. There are tables in the document

    2. All cells in the first row are merged to one cell

    3. The first row contains text

    4. The last character of that text is no paragraph sign

    5. There is a paragraph style named "Title"

*/

var doc = app.documents[0];

var tables = doc.stories.everyItem().tables.everyItem().getElements();

for(var n=tables.length-1;n>=0;n--)

{

    var index = tables.storyOffset.index;

    var story = tables.storyOffset.parentStory;

  

    tables.cells[0].insertionPoints[-1].contents = "\r";

    tables.cells[0].texts[0].move(LocationOptions.AT_BEGINNING , story.insertionPoints[index]);

    tables.rows[0].remove();

  

    story.insertionPoints[index].paragraphs[0].appliedParagraphStyle = "Title";

}

Regards,
Uwe

Votes

Translate

Translate

Report

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 ,
Dec 22, 2016 Dec 22, 2016

Copy link to clipboard

Copied

Uwe, Vlad and Loic,

Thanks for your interest! …

Uwe's code is obviously more interesting and more relevant (and more written too! )! Thanks for it!

I'm going to insert "if" statements in it to take in account these 2 points:

1/ if open doc and if no table.

2/ if the contents of the first row (merger or not [1-column table) is a table title (para style applied) - a necessary filter!

Imho, no need to verify if "Title" para style exists and if the last is not a para sign! It seems logical for me even if not always for users!

Do I need to use a try … catch for the first point?

(^/)

Votes

Translate

Translate

Report

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
Advisor ,
Dec 21, 2016 Dec 21, 2016

Copy link to clipboard

Copied

Uwe was faster.
Also, Obi, try your code on a document that has no tables!

Votes

Translate

Translate

Report

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
People's Champ ,
Dec 22, 2016 Dec 22, 2016

Copy link to clipboard

Copied

Obi,

Think I already advised you this but this simple line will save you efforts and energy:

if ( !app.documents.length) return;

myDoc = app.activeDocument

or you will have execution error at the very first moment your code will be run.

Also, in a loop, don't look at the length property but reference it before

var n = tables.length;

for ( i=0; i<n; i++ )…

If you want to acquire good practices.

Votes

Translate

Translate

Report

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 ,
Dec 22, 2016 Dec 22, 2016

Copy link to clipboard

Copied

Hi Loic,

About the second point, why is it a better practice? …

(^/)

Votes

Translate

Translate

Report

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
Advisor ,
Dec 22, 2016 Dec 22, 2016

Copy link to clipboard

Copied

About Loic's second point:

The theory is that you are caching the array's length so instead of accessing the length property each step in the loop you only access it once, thus speeding up the script.

However, that's the theory, in practice I never noticed any difference and I assume the ExtendScript engine does do some optimisations to the loops.

So I just use the for (var i=0; i<arr.length; i++) format.

Loic.Aigon​, do you have some data to show that it does make any difference?

Votes

Translate

Translate

Report

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
People's Champ ,
Dec 22, 2016 Dec 22, 2016

Copy link to clipboard

Copied

Because the script engine won't reach a property of an object (the length property of the array ) every loop. It will only read a value stored in memory. It might not be obvious for a small loop but with huge loops the difference can be sensitive.

Besides why would you want to force convert the collection into an array with

  1. var tables = doc.stories.everyItem().tables.everyItem().getElements(); 

A collection is an array like object so it does have a length property too and you can loop through the same way. Once again, unless you want to sue some specific arrays methods, it's useless to to so.

FWIW

Loic

Votes

Translate

Translate

Report

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
Advisor ,
Dec 22, 2016 Dec 22, 2016

Copy link to clipboard

Copied

About converting collections to arrays:

It actually makes a lot of difference and it can significantly speed up the script.

Iterating through a collection will make a request to the DOM for each member of the collection, in order to resolve the specifier.

Using the everyItem().getElements() to convert to an array will only touch the DOM once, and return an array of actual honest indesign objects, not specifiers, which results in a huge speed increase.

To illustrate, use the following code:

(function(){

var d=app.documents.add();

for (var i=0; i<100; i++){

  d.pages.add();

}

$.hiresTimer;

var p=d.pages;

for (var i=0; i<p.length;i++){

  $.write(p.name);

}

$.writeln('\r'+$.hiresTimer);

var p=d.pages.everyItem().getElements();

for (var i=0; i<p.length;i++){

  $.write(p.name);

}

$.writeln('\r'+$.hiresTimer);

}());

Votes

Translate

Translate

Report

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
People's Champ ,
Dec 22, 2016 Dec 22, 2016

Copy link to clipboard

Copied

var a  = new Array(10000);

var t = (new Date() ).getTime();

var i = 0;

var n = a.length;

for ( i = 0; i<a.length; i++ ) {

  a = new Date();

}

(new Date() ).getTime()-t;

> ~120

var a  = new Array(10000);

var t = (new Date() ).getTime();

var i = 0;

var n = a.length;

for ( i = 0; i<n; i++ ) {

  a = new Date();

}

(new Date() ).getTime()-t;

> ~75

Votes

Translate

Translate

Report

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 ,
Dec 22, 2016 Dec 22, 2016

Copy link to clipboard

Copied

… So, a double good practice is to:

• convert a collection to an array, using "everyItem().getElements()"

• define ~.length as a variable before using it n a loop

Right?

(^/)

Votes

Translate

Translate

Report

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
People's Champ ,
Dec 22, 2016 Dec 22, 2016

Copy link to clipboard

Copied

LATEST

Vamitul

It actually makes a lot of difference and it can significantly speed up the script.

That's a good one and I will certainly make mine from now on

Happy holidays !

Loic

Votes

Translate

Translate

Report

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