Indesign JavaScript Создание текста и гиперссылок внутри книги в книге - очень медленно - PullRequest
2 голосов
/ 07 марта 2012
  1. Первый раз
  2. Первый раз пишу на JavaScript, хотя у меня есть опыт работы на других языках.

Я работаю в Adobe InDesign CS5.5. У меня есть несколько файлов в идентификационной книге, каждый из которых содержит различное количество «глав». Книга включает индексный файл с заголовками тем, которые ссылаются на главы в сокращенной форме (например, «ГЛАВА 125» становится «ch 125 no 3» - обратите внимание, что часть «нет х» не имеет значения). Цель моего сценария - создать ссылки между документами, которые добавят значительную функциональность при экспорте ID Book, скажем, в PDF. Пользователь сможет перейти от индекса к главе и наоборот. Я думаю, что сценарий и проблемы, с которыми я имею дело, были бы полезны для других, но я еще не нашел ни одной публикации для решения моей проблемы.

Все ссылки (например, "ch 125 no 1") в указателе на конкретную главу ("ГЛАВА 125") получают гиперссылку на местоположение главы этой главы. Эта часть скрипта работает отлично и работает быстро.

Другая половина вставит соответствующие заголовки темы в конце текста каждой главы и сделает эти абзацы ссылками на соответствующий заголовок темы в указателе. (Другими словами, они являются перекрестными ссылками, но не настоящими x-ref в терминах идентификаторов, потому что я хотел иметь больше контроля над ними, и мое чтение этой темы подсказало мне избегать истинных x-ref.) это заставляет меня биться головой об стену. Он работает часами, не заканчивая книгу из 200 глав. Обратите внимание, что для целей тестирования я просто вставляю один абзац текста в нужное место под каждой главой, а не все заголовки тем и ссылки. Из небольших наборов текста и из отладочных отпечатков на консоли я знаю, что скрипт выполняет работу, а не застревает в бесконечном цикле. Тем не менее, он работает слишком долго, и, если я прерву его, InDesign не отвечает, и мне придется убить его, поэтому он даже не может просмотреть частичные результаты.

Основано на поиске / чтении форумов: я отключил предварительную проверку; отключено автоматическое обновление номеров страниц книги; изменил настройки предварительного просмотра на отложенное. Я все еще подозреваю, что медлительность может быть связана с накладными расходами InDesign, но я не знаю, что еще попробовать.

Я смущен тем, каким ужасным может быть стиль этого кода JS, но в данный момент мне просто нужно, чтобы он работал, тогда я могу его уточнить.

var myBookFilePath = File.openDialog("Choose an InDesign Book File", "Indb files: *.indb");
var myOpenBook = app.open(myBookFilePath);
app.scriptPreferences.userInteractionLevel = UserInteractionLevels.neverInteract;

// Open up every file in the currently active Book
app.open(app.activeBook.bookContents.everyItem().fullName)

// TODO:  add error handling / user interaction here -- to pick which is Index file
var strIndexFilename = "Index.indd";
var objChapHeadsWeb = {};
var myDoc = app.documents.item(strIndexFilename);

$.writeln("\n\n~~~ " + myDoc.name + " ~~~");

// REMOVED CODE - check for existing hyperlinks, hyperlink sources/destinations
// loop to delete any pre-existing hyperlinks & associated objects
// works w/o any problems

// Ugly GREP to find the Main heading text (all caps entry and nothing beyond) in the index file
app.findGrepPreferences = NothingEnum.nothing;
app.changeGrepPreferences = NothingEnum.nothing;

/// GREP:  ^[\u\d \:\;\?\-\'\"\$\%\&\!\@\*\#\,\.\(\)]+[\u\d](?=\.|,)
app.findGrepPreferences.findWhat = "^[\\u\\d \\:\\;\\?\\-\\'\\\"\\$\\%\\&\\!\\@\\*\\#\\,\\.\\(\\)]+[\\u\\d](?=\\.|,)";
app.findGrepPreferences.appliedParagraphStyle = "Main";

var myFound = [];
myFound = myDoc.findGrep();
$.writeln("Found " + myFound.length + " Main headings.");

for (var i = 0; i < myFound.length; i++)   {
    myDoc.hyperlinkTextDestinations.add(myFound[i], { name: myFound[i].contents });
}

$.writeln("There are now " + myDoc.hyperlinkTextDestinations.count() + " destinations.");


myFound.length = 0;

for (var j = app.documents.count()-1; j >= 0; j--) {
    app.findGrepPreferences = NothingEnum.nothing;
    app.changeGrepPreferences = NothingEnum.nothing;

    // set the variable to the document we are working with
    myDoc = null;
    myDoc = app.documents[j];
    myFound.length = 0;

    if (myDoc.name === strIndexFilename) {
        continue;       // we don't want to look for chapter heads in the Index file, so skip it
    }

    $.writeln("\n\n~~~ " + myDoc.name + " ~~~");

// REMOVED CODE - check for existing hyperlinks, hyperlink sources/destinations
// loop to delete any pre-existing hyperlinks & associated objects
// works w/o any problems

    // Clear GREP prefs
    app.findGrepPreferences = NothingEnum.nothing;
    app.changeGrepPreferences = NothingEnum.nothing;

    app.findGrepPreferences.findWhat = "^CHAPTER \\d+";
    app.findGrepPreferences.appliedParagraphStyle = "chapter";

    myFound = myDoc.findGrep();
    var strTemp = "";
    $.writeln("Found " + myFound.length + " chapter headings.");

    for (var m = 0; m < myFound.length; m++)   {
        strTemp = myFound[m].contents;

        objChapHeadsWeb[strTemp] = {};
        objChapHeadsWeb[strTemp].withinDocName = myDoc.name;
        objChapHeadsWeb[strTemp].hltdChHead = 
            myDoc.hyperlinkTextDestinations.add(myFound[m], {name:strTemp});
        objChapHeadsWeb[strTemp].a_strIxMains = [];
        objChapHeadsWeb[strTemp].a_hltdIxMains = [];
        objChapHeadsWeb[strTemp].nextKeyName = "";

        objChapHeadsWeb[strTemp].nextKeyName = 
            ((m < myFound.length-1) ? myFound[m+1].contents : String(""));
    }

    $.writeln("There are now " + myDoc.hyperlinkTextDestinations.count() + " destinations.");
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  Find the "ch" (chapter) references in the index file, link them
//      back to the corresponding text anchors for the chapter heads
//      in the text.
// 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
myDoc = app.documents.item(strIndexFilename);   // work with the Index file

app.findGrepPreferences = NothingEnum.nothing;
app.changeGrepPreferences = NothingEnum.nothing;

// GREP to find the "ch" (chapter) references in the index file
// like ch 151 no 1 OR ch 12 no 3
app.findGrepPreferences.findWhat = "(ch\\s+\\d+\\s+no\\s+\\d+)";

var strExpandedChap = "";
var strWorkingMainHd = "";
var arrFoundChapRefs = [];
var myHyperlinkSource;
var myHyperlinkDest;

for (var x = 0; x < myDoc.hyperlinkTextDestinations.count(); x++)   {
    strWorkingMainHd = "";
    arrFoundChapRefs.length = 0;

    // the special case, where we are working with the ultimate hyperlinkTextDestination obj
    if (x === myDoc.hyperlinkTextDestinations.count()-1) {
        // This is selecting text from the start of one MAIN heading...
        myDoc.hyperlinkTextDestinations[x].destinationText.select();
        // This next line will extend the selection to the end of the story,
        //      which should also be the end of the document
        myDoc.selection[0].parentStory.insertionPoints[-1].select(SelectionOptions.ADD_TO);
    }
    // the regular case...
    else  {
        // This is selecting text from the start of one MAIN heading...
        myDoc.hyperlinkTextDestinations[x].destinationText.select();
        // ... to the start of the next MAIN heading
        myDoc.hyperlinkTextDestinations[x+1].destinationText.select(SelectionOptions.ADD_TO);
    }

    strWorkingMainHd = myDoc.hyperlinkTextDestinations[x].name;
    //arrFoundChapRefs = myDoc.selection[0].match(/(ch\s+)(\d+)(\s+no\s+\d+)/g);  //NOTE:  global flag

    arrFoundChapRefs = myDoc.selection[0].findGrep();

    for(y = 0; y < arrFoundChapRefs.length; y++)    {
        myHyperlinkSource = null;
        myHyperlinkDest = null;
        strExpandedChap = "";

        strExpandedChap = arrFoundChapRefs[y].contents.replace(/ch\s+/, "CHAPTER ");
        strExpandedChap = strExpandedChap.replace(/\s+no\s+\d+/, "");

        // if we found the chapter head corresponding to our chapter ref in the index
        //      then it is time to create a link
        if (strExpandedChap in objChapHeadsWeb)    {
            objChapHeadsWeb[strExpandedChap].a_strIxMains.push(strWorkingMainHd);
            objChapHeadsWeb[strExpandedChap].a_hltdIxMains.push(myDoc.hyperlinkTextDestinations[x]);

            myHyperlinkSource = myDoc.hyperlinkTextSources.add(arrFoundChapRefs[y]);
            myHyperlinkDest = objChapHeadsWeb[strExpandedChap].hltdChHead;

            myDoc.hyperlinks.add(myHyperlinkSource, myHyperlinkDest);
        }   else    {
            $.writeln("Couldn't find chapter head " + strExpandedChap);
        }
    }
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOW TIME FOR THE HARD PART...
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
myDoc = null;
var strWorkingMainHd = "";
var nextKey = "";
var myParentStory = null;
var myCharIndex = 0;
var myCompareChar = null;
var myLeftmostBound = 0;
var myCurrentPara = null;

for (var key in objChapHeadsWeb)   {
    myDoc = app.documents.item(objChapHeadsWeb[key].withinDocName);
    myCompareChar = null;   //recent addition
    $.writeln("Working on " + key + ".");   //debugging

    nextKey = objChapHeadsWeb[key].nextKeyName;

    objChapHeadsWeb[key].hltdChHead.destinationText.select();
    myLeftmostBound = myDoc.selection[0].index;
    myParentStory = myDoc.selection[0].parentStory;

    if( (nextKey === "") || (myDoc.name !== objChapHeadsWeb[nextKey].withinDocName) )
    {
        //// Need to find end of story instead of beginning of next chapter
        //myDoc.selection[0].parentStory.insertionPoints[-1].select(SelectionOptions.ADD_TO);
        myParentStory.insertionPoints[-1].select();
        //myCharIndex = myDoc.selection[0].index;           /recently commented out

        myCharIndex = myDoc.selection[0].index - 1;     //testing new version
        myCompareChar = myParentStory.characters.item(myCharIndex);     //recenttly added/relocated from below
    }   else    {
        /////
        //objChapHeadsWeb[nextKey].hltdChHead.destinationText.select(SelectionOptions.ADD_TO);
        objChapHeadsWeb[nextKey].hltdChHead.destinationText.select();

        //myParentStory.characters.item(myDoc.selection[0].index -1).select();

        myParentStory.characters.item(myDoc.selection[0].index -2).select();  //temp test *****

        myCharIndex = myDoc.selection[0].index;
        myCompareChar = myParentStory.characters.item(myCharIndex);

        if (myCompareChar.contents === "\uFEFF") {
            $.writeln("Message from inside the \\uFEFF check.");     //debugging

            myParentStory.characters.item(myDoc.selection[0].index -1).select();

            myCharIndex = myDoc.selection[0].index;
            myCompareChar = myParentStory.characters.item(myCharIndex);
        }

        if( (myCompareChar.contents !== SpecialCharacters.PAGE_BREAK) &&
            (myCompareChar.contents !== SpecialCharacters.ODD_PAGE_BREAK) &&
            (myCompareChar.contents !== SpecialCharacters.EVEN_PAGE_BREAK) &&
            (myCompareChar.contents !== SpecialCharacters.COLUMN_BREAK) &&
            (myCompareChar.contents !== SpecialCharacters.FRAME_BREAK)) 
        {
            $.writeln("Possible error finding correct insertion point for " + objChapHeadsWeb[key].hltdChHead.name + ".");
        }
    }

    if(myCharIndex <= myLeftmostBound)  {   // this shouldn't ever happen
        alert("Critical error finding IX Marker insertion point for " + objChapHeadsWeb[key].hltdChHead.name + ".");
    }

    if(myCompareChar.contents !== "\r") {
        myDoc.selection[0].insertionPoints[-1].contents = "\r";
    }

    myDoc.selection[0].insertionPoints[-1].contents = "TESTING text insertion for:  " + objChapHeadsWeb[key].hltdChHead.name + "\r";
    myDoc.selection[0].insertionPoints.previousItem(myDoc.selection[0].insertionPoints[-1]).select();

//myDoc.selection[0].insertionPoints[-1].contents = "<Now I'm here!>";

    myCurrentPara = myDoc.selection[0].paragraphs[0];

    myCurrentPara.appliedParagraphStyle = myDoc.paragraphStyles.item("IX Marker");

    // TODO:
    //      need error handling for when style doesn't already exist in the document
}   // end big for loop


//TODO:  add error handling support to carry on if user cancels
//close each open file; user should be prompted to save changed files by default

app.scriptPreferences.userInteractionLevel = UserInteractionLevels.interactWithAll;
app.documents.everyItem().close();

// Cleanup
app.findGrepPreferences = NothingEnum.nothing;
app.changeGrepPreferences = NothingEnum.nothing;

Ответы [ 2 ]

0 голосов
/ 29 апреля 2016

Могу я предложить несколько улучшений, которые могут немного ускорить процесс.Прежде всего, у вас есть множество глобальных переменных, которые вы можете сконцентрировать в гораздо меньшем количестве областей, используя функции.Наличие множества глобальных переменных сопряжено с большими затратами с точки зрения производительности.

Как только это будет сказано, я не буду открывать каждый документ книги сразу, а буду обрабатывать их один за другим.Имейте в виду, что вызовы grep очень дороги, поэтому вы можете попытаться взглянуть на свои шаблоны.

Другим примером является широкое использование команды $ .writeln.Избегайте этого, особенно внутри петель.Предпочитаю легко установить библиотеку отчетов.

Наконец, я попытался переписать ваш код «лучше», но было сложно создать весь сценарий с четким пониманием ваших потребностей и отсутствием файлов для обработки.Но я надеюсь, что следующий фрагмент поможет вам начать переписывать код и заявить о значительных улучшениях во времени.

var debug = true;

var log = function(msg) {
	
	var l = File (Folder.desktop+"/log.txt" );
	
	if ( !debug ) return;
	
	l.open('a');
	l.write(msg);
	l.close();
};

var main = function() {
	
	var bookFile, uil = app.scriptPreferences.userIntercationLevel;
	
	log("The party has started");
	
	bookFile = File.openDialog("Choose an InDesign Book File", "Indb files: *.indb");
	
	if (!bookFile) return;
	app.scriptPreferences.userInteractionLevel = UserInteractionLevels.NEVER_INTERACT;
	
	try {
		processBookFile ( bookFile );
	}
	catch(err) {
		alert(err.line+"///"+err.message);
	}

	app.scriptPreferences.userInteractionLevel = uil;
};

function processBookFile ( bookFile ) {
	var book = app.open ( bookFile ),
	bks = book.bookContents,
	n = bks.length;
	
	while ( n-- ) {
		File(bks[n].name)!="Index.indd" && processBookContent ( bks[n] );
	}
}

function processBookContent ( bookContent ) {
	var bcf = bookContent.fullName,
	doc = app.open ( bcf, debug );
	
	//DEAL WITH HEADINGS
	processHeadings ( doc );
	
	//DEAL WITH CHAPTERS
	processHeadings ( doc );
	
	//add hyperlinks
	addHyperlinks( doc);
}



function processHeadings (doc){
	var props = {
		findWhat : "^[\\u\\d \\:\\;\\?\\-\\'\\\"\\$\\%\\&\\!\\@\\*\\#\\,\\.\\(\\)]+[\\u\\d](?=\\.|,)",
		appliedParagraphStyle : "Main"
	},
	found = findGrep(doc, props),
	n = found.length;
	
	while ( n-- ) {
		doc.hyperlinkTextDestinations.add(doc, { name: found[i].contents });
	}
};

function processChapters (doc ) {
	var props = {
		findWhat : "^CHAPTER \\d+",
		appliedParagraphStyle : "chapter"
	},
	found = findGrep(doc, props),
	n = found.length;
	
	while ( n-- ) {
		doc.hyperlinkTextDestinations.add(found[n], found[n].contents);
	}
}

function findGrep(doc, props){
	app.findGrepPreferences = app.changeGrepPreferences = null;	
	app.findGrepPreferences.properties = props;
	return doc.findGrep();
}

function addHyperlinks (doc){
	//a logic of yours
};


main();
0 голосов
/ 28 апреля 2016

Попробуйте открыть все файлы перекрестных ссылок, ссылки на них.

...