Избранное »

22.09.2014 – 07:27 | 2 комментария | 27 554 views

Здравствуйте все, кто работает в Индизайне!
Извещаем вас о том, что на youtube.com работает канал «InDesign Мастерская вёрстки». Там уже размещены более 70 видео с полным описанием как работать с программой DoTextOK. Другие интересные темы, касающиеся работы …

Читать полностью »
Работа в InDesign

Хитрости и секреты, приемы работы, уроки

Новая версия!

Особенности новой версии Индизайна

Плагины

Описание плагинов, информация о плагинах для работы с Adobe InDesign

Скрипты

Готовые к использованию скрипты для Adobe InDesign

Скриптинг

Описание языка, приёмов и методов программирования для Adobe InDesign

Home » Скриптинг, Скрипты

Сортировка нескольких диапазонов

Добавлено на 26.04.2010 – 16:44One Comment | 705 views

Наша любимая фирма Adobe Systems любезно предоставила нам скрипт SortParagraphs по сортировке абзацев. Но если надо отсортировать данные в нескольких разделах не затрагивая названия разделов, то этот скрипт мало помогает. Приходится вручную выделять абзацы каждого раздела и многократно запускать скрипт. Эта проблема для многих является актуальной и недавно на форуме по Индизайну rudtp.ru был задан такой вопрос:SortDiapazon

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

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

1
<const NameRubrParaStyle = "Рубрики"

Поскольку название стиля рубрик не будет меняться в процессе работы скрипта, то нет нужды определять его как переменную.
Да, еще ещё мы забыли отметить, что самым первым вашим действием должна быть подготовка текста к верстке с удалением лишних пробелов, пустых абзацев и т.д. Мы не будем останавливаться на этом, решений таких проблем существует достаточно много. Просто это надо сделать, и всё.
Создадим описание объекта, шаблон, по которому скрипт будет создавать объекты

2
3
4
5
6
function rubrica (paragraph)
{
this.paragraphR = paragraph;	
this.paragraphsInRub = [];
}

По этому шаблону наш объект типа rubrica будет содержать в себе объектную переменную, указывающую на абзац с названием рубрики и массив, куда будут заноситься объекты, указывающие на частные объявления в рубрике.
Используя прототипы добавим метод, при помощи которого будет заполняться этот массив

7
8
9
10
rubrica.prototype.addStyle = function(para)
{
	this.paragraphsInRub.push(para)
}

Поскольку в нашем тексте не одна рубрика с частными объявлениями, а много, то создадим коллекцию объектов-рубрик. Это обычный массив.

11
var myRubrics = [];

Этот массив объявлен вне всяких функций, глобально, и будет доступен для всех функций.

Далее надо сделать стандартные проверки — открыт ли документ, выделено ли что либо, с чем в дальнейшем работать скрипту и т.п. Эти действия запрограммируем в функции main(), из неё же будем вызывать и остальные рабочие функции. Для привязки к обрабатываемому материалу примем, что пользователь должен выделить черной стрелкой какой-либо фрейм.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
main();
function main(){
	if(app.documents.length != 0){
		if(app.selection.length > 0 && app.selection[0].constructor.name == "TextFrame"){	
			var myStory = app.selection[0].parentStory;
			prepareSort(myStory);
			sort()
			newData(myStory);
		}
		else{
			alert("Выделите  текстовый фрейм и запустите скрипт снова.");
		}
	}
	else{
		alert("No documents are open. Please open a document and try again.");
	}
} // main

Здесь в случае успешных проверок вызываются три основные функции: prepareSort(myStory), sort(), newData(myStory). Первая из них выполняет подготовку к сортировке, заполняя данными массив myRubrics, вторая собственно выполняет сортировку массива и третья выводит отсортированные данные в материал. Конечно перед этими функциями ещё надо поместить функцию подготовки текста (удаление пустых абзацев, пробелов и проч.), но мы договорились, что рассматривать ее не будем.
Функция заполнения коллекции myRubrics выглядит следующим образом:

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function prepareSort(myStory)
{
	var myParagraphs = myStory.paragraphs
// примочка на случай если абзац  начнется не с имени рубрики - эти абзацы пропускаем	
	var n=0
	while(myParagraphs[n].appliedParagraphStyle.name !=NameRubrParaStyle) {n++}
// конец примочки
	var j = 0;
	 for(var i = n; i < myParagraphs.length; i ++)
	 {
		if(myParagraphs[i].appliedParagraphStyle.name == NameRubrParaStyle) {
			var currentRub = new rubrica(myParagraphs[i])
			myRubrics[j++] = currentRub
		}
		else {
			currentRub.addStyle(myParagraphs[i])
		}
 
	} // for
 
} // prepareSort()

При заполнении массива myRubrics нам важно, чтобы первой обрабатываемой строкой было название рубрики. Мало ли что могут написать первой строкой, например, какой-либо общий заголовок или руководящее указание верстальщику. Это можно проверить по примененному к абзацу стилю. Если стиль не «Рубрики», то можно остановить работу программы и просить пользователя об удалении лишних начальных абзацев. В вышеприведенной функции такие данные просто пропускаются посредством процедуры while(myParagraphs[n].appliedParagraphStyle.name !=NameRubrParaStyle) {n++}.
Далее производится перебор всех абзацев в материале и если встречается абзац, оформленный стилем «Рубрики», то создается новый объект типа rubrica, а если стиль абзаца не «Рубрики», то этот абзац заносится в текущий объект типа rubrica, дополняя список объектов, указывающих на частные объявления. Затем объект заносится в коллекцию myRubrics.
В результате выполнения функции prepareSort() мы имеем заполненную коллекцию объектов, где каждый объект ссылается на название рубрики (.paragraphR) и на абзацы этой рубрики (.paragraphsInRub — массив). Теперь можно приступить к сортировке данных в коллекции.
Функция сортировки данных sort() сделана на основе скрипта сортировки абзацев SortParagraphs, который поставляется вместе с InDesign CS3. Собственно, ничего интересного.

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
function sort()
{
	var myItemMoved, myCounter, buf;
	for(var i =0; i < myRubrics.length; i++)
	{
		var myParagraphs = myRubrics[i].paragraphsInRub;
		do{
			myItemMoved = false;
			myCounter = 0;
			do{
				if(myRubrics[i].paragraphsInRub.[myCounter].contents > myRubrics[i].paragraphsInRub.[myCounter+1].contents){
					buf=myRubrics[i].paragraphsInRub.[myCounter]
					myRubrics[i].paragraphsInRub.[myCounter] = myRubrics[i].paragraphsInRub.[myCounter+1]
					myRubrics[i].paragraphsInRub.[myCounter+1] = buf;
					myItemMoved = true;
				}
				myCounter ++;
					}while (myCounter < myParagraphs.length-1);	
			myCounter = myParagraphs.length-1;
			do{
				if(myRubrics[i].paragraphsInRub.[myCounter].contents < myRubrics[i].paragraphsInRub.[myCounter-1].contents){
					buf = myRubrics[i].paragraphsInRub.[myCounter-1]
					myRubrics[i].paragraphsInRub.[myCounter-1] = myRubrics[i].paragraphsInRub.[myCounter]
					myRubrics[i].paragraphsInRub.[myCounter] = buf
					myItemMoved = true;
				}
				myCounter --;
			}while(myCounter > 1);
		}while(myItemMoved != false);		
	} // for
 
}

Функция по выводу отсортированных данных:

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
function newData(myStory)
{
	var currentT
	var myT = [];
	var n=0;
	for(var i =0; i < myRubrics.length; i++)
	{
		currentT = new myText
		currentT.pcontent = myRubrics[i].paragraphR.contents
		currentT.pstyle = myRubrics[i].paragraphR.appliedParagraphStyle
		myT[n++] = currentT
		for(var j=0; j<myRubrics[i].paragraphsInRub.length; j++)
		{
			currentT = new myText
			currentT.pcontent =myRubrics[i].paragraphsInRub[j].contents;
			currentT.pstyle = myRubrics[i].paragraphsInRub[j].appliedParagraphStyle
			myT[n++] = currentT
		}
 
	}// for*/
	var myParagraphs = myStory.paragraphs
	n=0
	while(myParagraphs[n].appliedParagraphStyle.name !=NameRubrParaStyle) {n++}
	for(var i=n; i< myT.length; i++)
	{
		n = myT[i].pcontent.length
		var s = myT[i].pcontent
		if(s[n-1] !="\r") 
		{
			myT[i].pcontent += '\r'
		}
		myParagraphs[i].contents = myT[i].pcontent
		myParagraphs[i].appliedParagraphStyle = myT[i].pstyle
	}
} // function

Попытки обойтись одной коллекцией myRubrics неизбежно сталкивались с потерей абзацного оформления текста. Названия рубрик теряли свой стиль. Возможно, этого можно избежать, если посидеть и хорошо подумать. Но пока приводится тот вариант, который получился на сегодняшний день. В результате был сделан еще один глобальный объект, куда перегрузились данные о всех абзацах и их форматировании, а потом этот объект выводился в верстку (о да простят автора сего творения гуру Батушев с Бутриным и Иванюшин иже с ними за такое безобразие, каюсь).
Это описание нового объекта было помещено перед функцией main()

function myText(pcontent, pstyle)
{
this.pcontent	= pcontent
this.pstyle = pstyle
}

Реальный объект по этому шаблону будет содержать текст абзаца и название стиля, которым оформлен этот абзац.
В первой части функции newData() создается коллекция таких объектов. Во второй — вывод их в материал.
Надо отметить одну особенность данных для сортировки: самый последний абзац в Story может не иметь знака окончания абзаца «\r», тогда перемещение его по тексту в результате сортировки приводит к слиянию двух абзацев с объявлениями. Поэтому этот абзац пришлось ловить и добавлять ему недостающий «\r». Это сделано частью скрипта
if(s[n-1] !=»\r»)
{
myT[i].pcontent += ‘\r’
}
Попытки избавиться от этой проблемы предпринимались и в функции sort(), но это приводило к потере начальной буквы одного из частных объявлений. Так все хитро завязано.
Ну вот и всё. Пока что этот набор функций для сортировки текстовых данных в многораздельном материале будем считать первой беттой, которая требует хорошего тестирования, шлифовки и доработки. Сделана-то она, честно говоря, «на скорую руку». Присылайте свои предложения, идеи, и может быть скоро появится хорошая программа. Первый камень заложен.

One Comment »

  • Mityura:

    Спасибо всем, кто откликнулся на эту тему!

    А вот что мне посоветовал эксперт Peter Kahrel для простейшей сортировки абзацев:

    myParagraphs = app.selection[0].parentStory.contents.split («\r»);
    app.selection[0].parentStory.contents = myParagraphs.sort ().join («\r»);

Оставить комментарий!

Вы должны быть в системе чтобы оставить комментарий.