# HG changeset patch
# User František Kučera <franta-hg@frantovo.cz>
# Date 1318791346 -7200
# Node ID b51ab80c7a9d276cf40bac071ef0c59981c9d4f1
# Parent  1f9e5757caf4eea300fe86d68418071e130637ca
Drupal: XSL pro vytváření <p>odstavců</p> z textu přímo uvnitř html/body
hranice mezi odstavci se poznají podle prázdného řádku (případně podle blokového elementu).
Naopak inline elementy jsou zahrnuty do odstavce. Příklad

První odstavec.
Druhý řádek téhož odstavce.

Druhý odstavec obsahující <em>nějaký inline element</em>.
Stále jsme v druhém odstavci.

Třetí odstavec…
<p>skutečný odstavec, jak to má být</p>
Toto už je čtvrtý resp. pátý odstavec, přestože tu nebyl žádný prázdný řádek.

diff -r 1f9e5757caf4 -r b51ab80c7a9d helpers/mimeXhtmlPart-make-paragraphs.xsl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/helpers/mimeXhtmlPart-make-paragraphs.xsl	Sun Oct 16 20:55:46 2011 +0200
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="2.0"
+	xmlns="http://www.w3.org/1999/xhtml"
+	xmlns:h="http://www.w3.org/1999/xhtml"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:fn="http://www.w3.org/2005/xpath-functions"
+	xmlns:svg="http://www.w3.org/2000/svg"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema"
+	xmlns:o="https://trac.frantovo.cz/odstavcovac-TODO-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-/wiki/xmlns/odstavcovac"
+	exclude-result-prefixes="fn h xs">
+	<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
+	
+	
+	<!-- Celý dokument -->
+	<xsl:template match="/">
+		<html>
+			<head>
+				<style type="text/css">
+					.mešuge {
+						background-color: #afa;
+						border: 1px solid #55f;
+					}
+				</style>
+			</head>
+
+			<body>
+			
+				<xsl:variable name="prvníKolo">
+					<xsl:apply-templates select="h:html/h:body/node()" mode="prvníKolo"/>
+				</xsl:variable>
+				
+				<xsl:variable name="druhéKolo">
+					<xsl:apply-templates select="$prvníKolo" mode="druhéKolo"/>
+				</xsl:variable>
+				
+				<xsl:apply-templates select="$druhéKolo" mode="třetíKolo"/>
+				
+			</body>
+		</html>
+	</xsl:template>
+    
+    
+    <!-- Mezi odstavci je prázdný řádek, můžou být mezery/tabulátory. -->
+	<xsl:variable name="oddělovač" select="'\n\s*\n\s*'"/>
+    
+	
+	<!-- Funkce: zda jde o XHTML inline element – může se vyskytovat uvnitř odstavců. -->
+	<xsl:template name="inlineElement" as="xs:boolean">
+		<xsl:param name="prvek"/>
+		<xsl:sequence select="
+			$prvek/name() = 'a' or						
+			$prvek/name() = 'abbr' or						
+			$prvek/name() = 'acronym' or						
+			$prvek/name() = 'b' or						
+			$prvek/name() = 'br' or						
+			$prvek/name() = 'cite' or						
+			$prvek/name() = 'code' or						
+			$prvek/name() = 'em' or						
+			$prvek/name() = 'i' or						
+			$prvek/name() = 'img' or						
+			$prvek/name() = 'q' or
+			$prvek/name() = 'span' or
+			$prvek/name() = 'strong' or
+			$prvek/name() = 'sub' or
+			$prvek/name() = 'sup' or
+			$prvek/name() = 'tt' or
+			$prvek/name() = 'u' or
+			$prvek/name() = 'var'
+			"/>
+		<!-- …případně další, pokud je budeme chtít podporovat. -->
+	</xsl:template>
+	
+	
+	<!-- Funkce: zda je prvek začátkem odstavce. -->
+	<xsl:template name="začátekOdstavce" as="xs:boolean">
+		<xsl:param name="prvek"/>
+		
+		<xsl:variable name="inlineElement" as="xs:boolean">
+			<xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$prvek"/></xsl:call-template>
+		</xsl:variable>
+		
+		<xsl:variable name="předchůdce" select="$prvek/preceding-sibling::node()[1]"/>
+		
+		<xsl:variable name="inlineElementPředchůdce" as="xs:boolean">
+			<xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$předchůdce"/></xsl:call-template>
+		</xsl:variable>
+		
+		<xsl:variable name="textovýUzel" select="boolean($prvek/self::text())"/>
+				
+		<xsl:sequence select="
+			($inlineElement or $textovýUzel) 
+			and 
+			(
+				($inlineElementPředchůdce and matches($prvek, concat('^', $oddělovač, '.*')))
+				or
+				not($inlineElementPředchůdce)
+				or
+				not($předchůdce)
+			)
+			and
+			(
+				not($předchůdce/self::text())
+				or
+				matches($předchůdce/self::text(), concat('.*', $oddělovač, '$'))
+			)
+			"/>
+	</xsl:template>
+	
+	
+	<!--
+		V prvním kole zavřeme volný text a inline elementy do značek <o:odstavec typ=""/>,
+		kde typ může být "začátek", což značí, že se jedná o první část budoucího odstavce <p/>.
+	-->
+	<xsl:template match="text()" mode="prvníKolo">
+	
+		<xsl:variable name="začátekOdstavce" as="xs:boolean">
+			<xsl:call-template name="začátekOdstavce">
+				<xsl:with-param name="prvek" select="."/>
+			</xsl:call-template>
+		</xsl:variable>
+		
+		<xsl:for-each select="fn:tokenize(., $oddělovač)">
+			<xsl:element name="o:odstavec">
+				<xsl:if test="$začátekOdstavce or not(position() = 1)">
+					<xsl:attribute name="typ">začátek</xsl:attribute>
+				</xsl:if>
+				<xsl:value-of select="."/>
+			</xsl:element>
+		</xsl:for-each>
+	
+	</xsl:template>
+	
+	<!-- 
+		Inline elementy zavíráme do <o:odstavec typ=""/>,
+		ostatní vkládáme, jak jsou.
+	-->
+	<xsl:template match="*" mode="prvníKolo">
+	
+		<xsl:variable name="inlineElement" as="xs:boolean">
+			<xsl:call-template name="inlineElement">
+				<xsl:with-param name="prvek" select="."/>
+			</xsl:call-template>
+		</xsl:variable>
+		
+		<xsl:choose>
+			<!-- TODO: zvláštní šablona (match="…") pro inline elementy místo větvení? -->
+			<xsl:when test="$inlineElement">
+				<xsl:variable name="začátekOdstavce" as="xs:boolean">
+					<xsl:call-template name="začátekOdstavce">
+						<xsl:with-param name="prvek" select="."/>
+					</xsl:call-template>
+				</xsl:variable>
+				<xsl:element name="o:odstavec">
+					<xsl:if test="$začátekOdstavce">
+						<xsl:attribute name="typ">začátek</xsl:attribute>
+					</xsl:if>
+					<xsl:copy-of select="."/>
+				</xsl:element>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:copy-of select="."/>
+			</xsl:otherwise>		
+		</xsl:choose>
+	
+	</xsl:template>
+	
+	<!-- V druhém kole spojíme jednotlivé části odstavců. -->
+	<xsl:template match="o:odstavec[@typ='začátek']" mode="druhéKolo">
+		<o:odstavec>
+			<xsl:call-template name="spojOdstavce">
+				<xsl:with-param name="část" select="."/>
+			</xsl:call-template>
+		</o:odstavec>
+	</xsl:template>
+	<!-- Následující části odstavce přeskočíme – postará se o ně vnitřní smyčka volaná z předchozí šablony. -->
+	<xsl:template match="o:odstavec" mode="druhéKolo"/>
+	<!-- Neinline (blokové) elementy vložíme, jak jsou. -->
+	<xsl:template match="*" mode="druhéKolo">
+		<xsl:copy-of select="."/>
+	</xsl:template>
+	
+	
+	<!--
+		Za první část (parametr, <o:odstavec typ="začátek"/>) resp. její vnitřek
+		připojíme (rekurze) všechny další části téhož odstavce (oddělíme mezerou).
+		Konec odstavce poznáme tak, že následovník je něco jiného než <o:odstavec/> nebo má atribut typ="začátek".
+	-->
+	<xsl:template name="spojOdstavce">
+		<xsl:param name="část"/>
+		<xsl:copy-of select="$část/child::node()"/>
+		<xsl:variable name="následovník" select="$část/following-sibling::node()[1]"/>
+		<xsl:if test="$následovník/name() = 'o:odstavec' and not($následovník/@typ = 'začátek')">
+			<xsl:text> </xsl:text>
+			<xsl:call-template name="spojOdstavce">
+				<xsl:with-param name="část" select="$následovník"/>
+			</xsl:call-template>
+		</xsl:if>
+	</xsl:template>
+	
+	
+	<!-- Ve třetím kole smažeme prázdné mešuge odstavce. -->
+	<xsl:template mode="třetíKolo" match="o:odstavec[
+		count(child::node()) = 0 
+		or 
+		(
+			count(child::node()) = 1 
+			and
+			text()
+			and
+			matches(text(), '^\s*$')
+		)
+		]">
+		<xsl:text> </xsl:text>	
+	</xsl:template>
+	<!-- Převedeme z <o:odstavec/> na <p/> -->
+	<xsl:template match="o:odstavec" mode="třetíKolo">
+		<p class="mešuge">
+			<xsl:copy-of select="child::node()"/>
+		</p>
+	</xsl:template>
+	<!-- Všechno ostatní zkopírujeme, jak je. -->
+	<xsl:template match="*" mode="třetíKolo">
+		<xsl:copy-of select="."/>
+	</xsl:template>
+	
+	
+</xsl:stylesheet>
diff -r 1f9e5757caf4 -r b51ab80c7a9d helpers/mimeXhtmlPart.xsl
--- a/helpers/mimeXhtmlPart.xsl	Fri Oct 14 17:50:35 2011 +0200
+++ b/helpers/mimeXhtmlPart.xsl	Sun Oct 16 20:55:46 2011 +0200
@@ -72,7 +72,7 @@
 					/** TODO: smazat */
 					.mešuge {
 						background-color: #afa;
-						border: 1px solid #5f5;
+						border: 1px solid #55f;
 					}
 				</style>
 			</head>
@@ -162,19 +162,26 @@
 						Textový uzel → budeme dělat odstavce
 						(rekurzivně se opět zavolá šablona zpracujTělo)
 					-->
-					<xsl:call-template name="dělejOdstavceX">
+					<xsl:call-template name="dělejOdstavce">
 						<xsl:with-param name="blokTextu" select="$prvek"/>
 						<xsl:with-param name="vnořeno" select="$vnořeno"/>
 					</xsl:call-template>
-					<!-- TODO: někdy zpracujTělo dalšího prvku -->
 					
+					<!-- 
 					<xsl:variable name="navázat" as="xs:boolean">
 						<xsl:call-template name="navázat">
 							<xsl:with-param name="blokTextu" select="$prvek"/>
 						</xsl:call-template>
 					</xsl:variable>
 					
-					<xsl:if test="not($navázat)">[not(navázat)]</xsl:if>
+					Někdy zpracujTělo dalšího prvku 
+					<xsl:if test="not($navázat)">[další:]
+						<xsl:call-template name="zpracujTělo">
+							<xsl:with-param name="prvek" select="$prvek/following-sibling::node()[1]"/>
+							<xsl:with-param name="vnořeno" select="$vnořeno"/>
+						</xsl:call-template>
+					</xsl:if>
+					-->
 					
 				</xsl:when>
 				<xsl:otherwise>
@@ -192,7 +199,7 @@
 		</xsl:if>
 	</xsl:template>
 	
-	<xsl:variable name="oddělovač" select="'\n\s+\n\s+'"/>
+	<xsl:variable name="oddělovač" select="'\n\s*\n\s*'"/>
 	
 	<xsl:template name="navázat" as="xs:boolean">
 		<xsl:param name="blokTextu"/>
@@ -217,7 +224,7 @@
 		"/>
 	</xsl:template>
 	
-	<xsl:template name="dělejOdstavceX">
+	<xsl:template name="dělejOdstavce">
 		<xsl:param name="blokTextu"/>
 		<xsl:param name="vnořeno" select="false()"/>
 		
@@ -230,90 +237,55 @@
 		</xsl:variable>
 		
 		<xsl:for-each select="fn:tokenize($blokTextu, $oddělovač)">
-			<xsl:if test="normalize-space(.)">
+			<!-- TODO: ošetřit prázdné odstavce -->
+			<xsl:if test="normalize-space(.) or true()">
 				<xsl:choose>
 					<xsl:when test="$vnořeno">
-						<xsl:value-of select="."/>
-						<xsl:if test="$navázat and position() = last()">
-							<xsl:call-template name="zpracujTělo">
-								<xsl:with-param name="prvek" select="$dalšíUzel"/>
-							</xsl:call-template>
-						</xsl:if>
-					</xsl:when>
-					<xsl:otherwise>
-						<p class="mešuge">
+						[
 							<xsl:value-of select="."/>
 							<xsl:if test="$navázat and position() = last()">
+								→
 								<xsl:call-template name="zpracujTělo">
 									<xsl:with-param name="prvek" select="$dalšíUzel"/>
 									<xsl:with-param name="vnořeno" select="true()"/>
 								</xsl:call-template>
 							</xsl:if>
+						]
+						[Avril:]
+						<xsl:if test="not($navázat) and position() = last()">
+							a→
+								<xsl:call-template name="zpracujTělo">
+									<xsl:with-param name="prvek" select="$dalšíUzel"/>
+									<xsl:with-param name="vnořeno" select="true()"/>
+								</xsl:call-template>
+						</xsl:if>
+					</xsl:when>
+					<xsl:otherwise>
+						<p class="mešuge">
+						{
+							<xsl:value-of select="."/>
+							<xsl:if test="$navázat and position() = last()">
+								s→
+								<xsl:call-template name="zpracujTělo">
+									<xsl:with-param name="prvek" select="$dalšíUzel"/>
+									<xsl:with-param name="vnořeno" select="true()"/>
+								</xsl:call-template>
+							</xsl:if>
+						}
 						</p>
+						[sk8:]
+						<xsl:if test="not($navázat) and position() = last()">
+							→
+								<xsl:call-template name="zpracujTělo">
+									<xsl:with-param name="prvek" select="$dalšíUzel"/>
+									<xsl:with-param name="vnořeno" select="false()"/>
+								</xsl:call-template>
+						</xsl:if>
 					</xsl:otherwise>
 				</xsl:choose>
 			</xsl:if>
 		</xsl:for-each>
 		
-		<xsl:if test="not($navázat)">
-			<xsl:call-template name="zpracujTělo">
-				<xsl:with-param name="prvek" select="$dalšíUzel"/>
-			</xsl:call-template>
-		</xsl:if>
-	</xsl:template>
-	
-	
-	
-	
-	
-	
-	<xsl:template name="dělejOdstavce">
-		<xsl:param name="blokTextu"/>
-		<xsl:variable name="oddělovač" select="'\n\s+\n\s+'"/>
-		<xsl:for-each select="fn:tokenize(., $oddělovač)">
-			<xsl:if test="normalize-space(.)">
-				<p class="mešuge">
-					<xsl:value-of select="."/>
-					<!-- 
-						Toto je poslední odstavec bloku textu 
-						a blok nekončí dvěma konci řádku → 
-						může za ním následovat značka (např. odkaz nebo tučné písmo)
-						vnořená do téhož odstavce
-					-->
-					<xsl:if test="
-						position() = last() and
-						not(fn:matches($blokTextu, concat('.*', $oddělovač ,'$')))
-						">
-						<xsl:variable name="n" select="$blokTextu/following-sibling::*[1]"/>
-						<xsl:variable name="nn" select="$n/name()"/>
-						<!--
-							Za blokem textu nenásleduje značka, která nemůže být uvnitř odstavce.
-						-->
-						<xsl:if test="not(
-								$nn = 'p' or
-								$nn = 'div' or								
-								$nn = 'h1' or								
-								$nn = 'h2' or								
-								$nn = 'h3' or								
-								$nn = 'h4' or								
-								$nn = 'h5' or								
-								$nn = 'h6' or								
-								$nn = 'pre' or								
-								$nn = 'table' or								
-								$nn = 'blockquote' or								
-								$nn = 'hr'								
-							)">
-							<xsl:apply-templates select="$n"/>
-						</xsl:if>
-						
-						<xsl:call-template name="zpracujTělo">
-							<xsl:with-param name="prvek" select="$blokTextu/following-sibling::node()[1]"/>
-						</xsl:call-template>
-				
-					</xsl:if>
-				</p>				
-			</xsl:if>
-		</xsl:for-each>
 	</xsl:template>