Absatzformate zuweisen mit einer State Machine

Das Problem

Im Satz hat man es immer wieder mit Listen zu tun wie diesen:

Ausgangslage

Entweder ist da ein Listenpunkt, oder zwei oder viele. Je nachdem müssen den einzelnen Punkten verschiedene Abstände zugewiesen werden, damit das Listing sauber vom umgebenden Fließtext getrennt ist.

erwünschter Zustand

Wie man sieht, brauchen wir vier Absatzformate, je nach Situation.

Die Schleife

Wenn wir n Absätze haben, die in einem Textfluss aneinandergereit sind, dann ist der normale Denkansatz, dass wir die in einer Schleife durchgehen.

Das bedeutet dann, dass wir einen Absatz zur Zeit inspizieren und entscheiden müssen, was wir mit diesem Absatz anstellen wollen, in dieesm Kontext: ob wir ihm ein Absatzformat zuweisen wollen und wenn ja, welches.

Wenn wir also zum Beispiel diesen Absatz unter der Lupe haben…

analysierter Absatz

… dann wissen wir erst mal nur, dass der Absatz zum Listing gehört. Aber welches der vier Absatzformate sollen wir zuweisen?

Dazu müssten wir die Absätze davor und danach irgendwie mit berücksichtigen, was sehr schnell sehr unübersichtlich wird.

Kontextabsätze

Die Fallunterscheidungen

Welche Situationen/Statusse kann es denn geben?

A) Wir sind nicht im Listing und betreten einen Absatz, der auch nicht zum Listing gehört

kein Listing

B) Wir „betreten“ das Listing

Listing Eingang

C) Wir sind mitten im Listing

Listing Eingang

D) Wir verlassen das Listing

Listing Eingang

Statusse und Statusübergänge

Auf den ersten Blick brauchen wir also vier Statusse:


var NO_LISTING = 0, ENTER_LISTING = 1, IN_LISTING = 2, LEAVE_LISTING = 3;
var state = NO_LISTING;

Die konkreten Werte für NO_LISTING etc sind egal, sie müssen nur verschieden sein.

Gehen wir mal die mittlere Spalte durch. Startzustand ist NO_LISTING.

Erster Absatz

erster

  • Kein Listing,
  • wir kommen aus NO_LISTING,
  • wir bleiben in NO_LISTING

Zweiter Absatz

zweiter

  • Ist Listing
  • wir kommen aus NO_LISTING
  • wir ändern den Status daher auf ENTER_LISTING und
  • weisen das Absatzformat für einen einzelnen Listing-Punkt zu.

Dritter Absatz

dritter

  • Ist Listing
  • wir kommen aus ENTER_LISTING
  • wir korrigieren das Absatzformat vom *vorigen* Absatz auf START
  • wir weisen *diesem* Absatz das Basis-Listing Format zu
  • wir ändern den Status auf IN_LISTING

Vierter Absatz

vierter

  • Kein Listing
  • wir kommen aus IN_LISTING
  • wir korrigieren das Absatzformat vom *vorigen* Absatz auf END
  • wir belassen *diesen* Absatz wie er ist
  • wir ändern den Status auf NO_CODE

In der linken Spalte gibt es einen anderen Übergang im dritten Absatz:

  • Kein Listing
  • wir kommen aus ENTER_LISTING
  • wir ändern den Status in NO_CODE

Damit haben wir die gesamte Logik erfasst.

Mein Code-Fragment, um das alles für InDesign umzusetzen, sieht so aus:


var NO_CODE = 0,
ENTER_CODE = 1,
IN_CODE = 2;
var crnt_state = NO_CODE;

var paras = story.paragraphs.everyItem().getElements();
for ( var np = 0; np < paras.length; np++ ) { var prev_para = (np > 0) ? paras[np-1] : null;
var para = paras[np];
var dieser_p = check_af( para ); // check_af checkt, ob der Absatz Listing ist oder nicht

if ( dieser_p ) {
if ( crnt_state == NO_CODE ) {
crnt_state = ENTER_CODE;
para.applyParagraphStyle( af_single, true );
} else if ( crnt_state == ENTER_CODE ) {
crnt_state = IN_CODE;
prev_para.applyParagraphStyle( af_start, true );
para.applyParagraphStyle( af_base, true );
} else if ( crnt_state == IN_CODE ) {
para.applyParagraphStyle( af_base, true ); // sicherheitshalber AF auf base setzen
}
} else {
if ( crnt_state == IN_CODE ) {
prev_para.applyParagraphStyle( af_end, true );
}
crnt_state = NO_CODE;
}
}

It’s a Feature, not a Script

Es sei darauf hingewiesen, dass ab CC2019 genau dieses Problem mit den Listing-Absatzformaten auch von Haus aus gelöst ist.

Absatzpalette