OpenDocument writer: New table cell support with row and column spans (#6682)
Unit tests only verify column spans at this point. Co-authored-by: Nils Carlson <nils.carlson@ludd.ltu.se>
This commit is contained in:
parent
1f707da40f
commit
4f13c0e25e
2 changed files with 213 additions and 26 deletions
|
@ -32,11 +32,12 @@ import qualified Text.Pandoc.Builder as B
|
||||||
import Text.Pandoc.Logging
|
import Text.Pandoc.Logging
|
||||||
import Text.Pandoc.Options
|
import Text.Pandoc.Options
|
||||||
import Text.DocLayout
|
import Text.DocLayout
|
||||||
import Text.Pandoc.Shared (linesToPara, tshow)
|
import Text.Pandoc.Shared (linesToPara, tshow, blocksToInlines)
|
||||||
import Text.Pandoc.Templates (renderTemplate)
|
import Text.Pandoc.Templates (renderTemplate)
|
||||||
import qualified Text.Pandoc.Translations as Term (Term(Figure, Table))
|
import qualified Text.Pandoc.Translations as Term (Term(Figure, Table))
|
||||||
import Text.Pandoc.Writers.Math
|
import Text.Pandoc.Writers.Math
|
||||||
import Text.Pandoc.Writers.Shared
|
import Text.Pandoc.Writers.Shared
|
||||||
|
import qualified Text.Pandoc.Writers.AnnotatedTable as Ann
|
||||||
import Text.Pandoc.XML
|
import Text.Pandoc.XML
|
||||||
import Text.Printf (printf)
|
import Text.Printf (printf)
|
||||||
|
|
||||||
|
@ -371,9 +372,7 @@ blockToOpenDocument o bs
|
||||||
| BulletList b <- bs = setFirstPara >> bulletListToOpenDocument o b
|
| BulletList b <- bs = setFirstPara >> bulletListToOpenDocument o b
|
||||||
| OrderedList a b <- bs = setFirstPara >> orderedList a b
|
| OrderedList a b <- bs = setFirstPara >> orderedList a b
|
||||||
| CodeBlock _ s <- bs = setFirstPara >> preformatted s
|
| CodeBlock _ s <- bs = setFirstPara >> preformatted s
|
||||||
| Table _ bc s th tb tf
|
| Table a bc s th tb tf <- bs = setFirstPara >> table (Ann.toTable a bc s th tb tf)
|
||||||
<- bs = let (c, a, w, h, r) = toLegacyTable bc s th tb tf
|
|
||||||
in setFirstPara >> table c a w h r
|
|
||||||
| HorizontalRule <- bs = setFirstPara >> return (selfClosingTag "text:p"
|
| HorizontalRule <- bs = setFirstPara >> return (selfClosingTag "text:p"
|
||||||
[ ("text:style-name", "Horizontal_20_Line") ])
|
[ ("text:style-name", "Horizontal_20_Line") ])
|
||||||
| RawBlock f s <- bs = if f == Format "opendocument"
|
| RawBlock f s <- bs = if f == Format "opendocument"
|
||||||
|
@ -396,29 +395,32 @@ blockToOpenDocument o bs
|
||||||
orderedList a b = do (ln,pn) <- newOrderedListStyle (isTightList b) a
|
orderedList a b = do (ln,pn) <- newOrderedListStyle (isTightList b) a
|
||||||
inTags True "text:list" [ ("text:style-name", "L" <> tshow ln)]
|
inTags True "text:list" [ ("text:style-name", "L" <> tshow ln)]
|
||||||
<$> orderedListToOpenDocument o pn b
|
<$> orderedListToOpenDocument o pn b
|
||||||
table c a w h r = do
|
table :: PandocMonad m => Ann.Table -> OD m (Doc Text)
|
||||||
|
table (Ann.Table _ (Caption _ c) colspecs thead tbodies _) = do
|
||||||
tn <- length <$> gets stTableStyles
|
tn <- length <$> gets stTableStyles
|
||||||
pn <- length <$> gets stParaStyles
|
pn <- length <$> gets stParaStyles
|
||||||
let genIds = map chr [65..]
|
let genIds = map chr [65..]
|
||||||
name = "Table" <> tshow (tn + 1)
|
name = "Table" <> tshow (tn + 1)
|
||||||
columnIds = zip genIds w
|
(aligns, mwidths) = unzip colspecs
|
||||||
|
fromWidth (ColWidth w) | w > 0 = w
|
||||||
|
fromWidth _ = 0
|
||||||
|
widths = map fromWidth mwidths
|
||||||
|
columnIds = zip genIds widths
|
||||||
mkColumn n = selfClosingTag "table:table-column" [("table:style-name", name <> "." <> T.singleton (fst n))]
|
mkColumn n = selfClosingTag "table:table-column" [("table:style-name", name <> "." <> T.singleton (fst n))]
|
||||||
columns = map mkColumn columnIds
|
columns = map mkColumn columnIds
|
||||||
paraHStyles = paraTableStyles "Heading" pn a
|
paraHStyles = paraTableStyles "Heading" pn aligns
|
||||||
paraStyles = paraTableStyles "Contents" (pn + length (newPara paraHStyles)) a
|
paraStyles = paraTableStyles "Contents" (pn + length (newPara paraHStyles)) aligns
|
||||||
newPara = map snd . filter (not . isEmpty . snd)
|
newPara = map snd . filter (not . isEmpty . snd)
|
||||||
addTableStyle $ tableStyle tn columnIds
|
addTableStyle $ tableStyle tn columnIds
|
||||||
mapM_ addParaStyle . newPara $ paraHStyles ++ paraStyles
|
mapM_ addParaStyle . newPara $ paraHStyles ++ paraStyles
|
||||||
captionDoc <- if null c
|
captionDoc <- if null c
|
||||||
then return empty
|
then return empty
|
||||||
else inlinesToOpenDocument o c >>=
|
else inlinesToOpenDocument o (blocksToInlines c) >>=
|
||||||
if isEnabled Ext_native_numbering o
|
if isEnabled Ext_native_numbering o
|
||||||
then numberedTableCaption
|
then numberedTableCaption
|
||||||
else unNumberedCaption "TableCaption"
|
else unNumberedCaption "TableCaption"
|
||||||
th <- if all null h
|
th <- colHeadsToOpenDocument o (map fst paraHStyles) thead
|
||||||
then return empty
|
tr <- mapM (tableBodyToOpenDocument o (map fst paraStyles)) tbodies
|
||||||
else colHeadsToOpenDocument o (map fst paraHStyles) h
|
|
||||||
tr <- mapM (tableRowToOpenDocument o (map fst paraStyles)) r
|
|
||||||
let tableDoc = inTags True "table:table" [
|
let tableDoc = inTags True "table:table" [
|
||||||
("table:name" , name)
|
("table:name" , name)
|
||||||
, ("table:style-name", name)
|
, ("table:style-name", name)
|
||||||
|
@ -464,26 +466,54 @@ unNumberedCaption :: Monad m => Text -> Doc Text -> OD m (Doc Text)
|
||||||
unNumberedCaption style caption = return $ inParagraphTagsWithStyle style caption
|
unNumberedCaption style caption = return $ inParagraphTagsWithStyle style caption
|
||||||
|
|
||||||
colHeadsToOpenDocument :: PandocMonad m
|
colHeadsToOpenDocument :: PandocMonad m
|
||||||
=> WriterOptions -> [Text] -> [[Block]]
|
=> WriterOptions -> [Text] -> Ann.TableHead
|
||||||
-> OD m (Doc Text)
|
-> OD m (Doc Text)
|
||||||
colHeadsToOpenDocument o ns hs =
|
colHeadsToOpenDocument o ns (Ann.TableHead _ hs) =
|
||||||
inTagsIndented "table:table-header-rows" . inTagsIndented "table:table-row" . vcat <$>
|
case hs of
|
||||||
mapM (tableItemToOpenDocument o "TableHeaderRowCell") (zip ns hs)
|
[] -> return empty
|
||||||
|
(x:_) ->
|
||||||
|
let (Ann.HeaderRow _ _ c) = x
|
||||||
|
in inTagsIndented "table:table-header-rows" .
|
||||||
|
inTagsIndented "table:table-row" .
|
||||||
|
vcat <$> mapM (tableItemToOpenDocument o "TableHeaderRowCell") (zip ns c)
|
||||||
|
|
||||||
|
tableBodyToOpenDocument:: PandocMonad m
|
||||||
|
=> WriterOptions -> [Text] -> Ann.TableBody
|
||||||
|
-> OD m (Doc Text)
|
||||||
|
tableBodyToOpenDocument o ns tb =
|
||||||
|
let (Ann.TableBody _ _ _ r) = tb
|
||||||
|
in vcat <$> mapM (tableRowToOpenDocument o ns) r
|
||||||
|
|
||||||
tableRowToOpenDocument :: PandocMonad m
|
tableRowToOpenDocument :: PandocMonad m
|
||||||
=> WriterOptions -> [Text] -> [[Block]]
|
=> WriterOptions -> [Text] -> Ann.BodyRow
|
||||||
-> OD m (Doc Text)
|
-> OD m (Doc Text)
|
||||||
tableRowToOpenDocument o ns cs =
|
tableRowToOpenDocument o ns r =
|
||||||
inTagsIndented "table:table-row" . vcat <$>
|
let (Ann.BodyRow _ _ _ c ) = r
|
||||||
mapM (tableItemToOpenDocument o "TableRowCell") (zip ns cs)
|
in inTagsIndented "table:table-row" . vcat <$>
|
||||||
|
mapM (tableItemToOpenDocument o "TableRowCell") (zip ns c)
|
||||||
|
|
||||||
|
|
||||||
|
colspanAttrib :: ColSpan -> [(Text, Text)]
|
||||||
|
colspanAttrib cs =
|
||||||
|
case cs of
|
||||||
|
ColSpan 1 -> mempty
|
||||||
|
ColSpan n -> [("table:number-columns-spanned", tshow n)]
|
||||||
|
|
||||||
|
rowspanAttrib :: RowSpan -> [(Text, Text)]
|
||||||
|
rowspanAttrib rs =
|
||||||
|
case rs of
|
||||||
|
RowSpan 1 -> mempty
|
||||||
|
RowSpan n -> [("table:number-rows-spanned", tshow n)]
|
||||||
|
|
||||||
tableItemToOpenDocument :: PandocMonad m
|
tableItemToOpenDocument :: PandocMonad m
|
||||||
=> WriterOptions -> Text -> (Text,[Block])
|
=> WriterOptions -> Text -> (Text,Ann.Cell)
|
||||||
-> OD m (Doc Text)
|
-> OD m (Doc Text)
|
||||||
tableItemToOpenDocument o s (n,i) =
|
tableItemToOpenDocument o s (n,c) =
|
||||||
let a = [ ("table:style-name" , s )
|
let (Ann.Cell _colspecs _colnum (Cell _ _ rs cs i) ) = c
|
||||||
, ("office:value-type", "string" )
|
csa = colspanAttrib cs
|
||||||
]
|
rsa = rowspanAttrib rs
|
||||||
|
a = [ ("table:style-name" , s )
|
||||||
|
, ("office:value-type", "string" ) ] ++ csa ++ rsa
|
||||||
in inTags True "table:table-cell" a <$>
|
in inTags True "table:table-cell" a <$>
|
||||||
withParagraphStyle o n (map plainToPara i)
|
withParagraphStyle o n (map plainToPara i)
|
||||||
|
|
||||||
|
|
|
@ -117,3 +117,160 @@
|
||||||
(TableFoot ("",[],[])
|
(TableFoot ("",[],[])
|
||||||
[])]
|
[])]
|
||||||
```
|
```
|
||||||
|
```
|
||||||
|
% pandoc -f native -t opendocument --quiet
|
||||||
|
[Table ("",[],[]) (Caption Nothing
|
||||||
|
[])
|
||||||
|
[(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)
|
||||||
|
,(AlignDefault,ColWidth 6.25e-2)]
|
||||||
|
(TableHead ("",[],[])
|
||||||
|
[])
|
||||||
|
[(TableBody ("",[],[]) (RowHeadColumns 0)
|
||||||
|
[]
|
||||||
|
[Row ("",[],[])
|
||||||
|
[Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 8)
|
||||||
|
[Para [Strong [Str "Octet",Space,Str "no.",Space,Str "1"]]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 8)
|
||||||
|
[Para [Strong [Str "Octet",Space,Str "no.",Space,Str "2"]]]]
|
||||||
|
,Row ("",[],[])
|
||||||
|
[Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "16"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "15"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "14"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "13"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "12"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "11"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "10"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "9"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "8"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "7"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "6"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "5"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "4"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "3"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "2"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
|
||||||
|
[Para [Str "1"]]]
|
||||||
|
,Row ("",[],[])
|
||||||
|
[Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 8)
|
||||||
|
[Para [Str "Code",Space,Str "A"]]
|
||||||
|
,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 8)
|
||||||
|
[Para [Str "Code",Space,Str "B"]]]])]
|
||||||
|
(TableFoot ("",[],[])
|
||||||
|
[])]
|
||||||
|
^D
|
||||||
|
<table:table table:name="Table1" table:style-name="Table1">
|
||||||
|
<table:table-column table:style-name="Table1.A" />
|
||||||
|
<table:table-column table:style-name="Table1.B" />
|
||||||
|
<table:table-column table:style-name="Table1.C" />
|
||||||
|
<table:table-column table:style-name="Table1.D" />
|
||||||
|
<table:table-column table:style-name="Table1.E" />
|
||||||
|
<table:table-column table:style-name="Table1.F" />
|
||||||
|
<table:table-column table:style-name="Table1.G" />
|
||||||
|
<table:table-column table:style-name="Table1.H" />
|
||||||
|
<table:table-column table:style-name="Table1.I" />
|
||||||
|
<table:table-column table:style-name="Table1.J" />
|
||||||
|
<table:table-column table:style-name="Table1.K" />
|
||||||
|
<table:table-column table:style-name="Table1.L" />
|
||||||
|
<table:table-column table:style-name="Table1.M" />
|
||||||
|
<table:table-column table:style-name="Table1.N" />
|
||||||
|
<table:table-column table:style-name="Table1.O" />
|
||||||
|
<table:table-column table:style-name="Table1.P" />
|
||||||
|
<table:table-row>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string" table:number-columns-spanned="8">
|
||||||
|
<text:p text:style-name="Table_20_Contents"><text:span text:style-name="T1">Octet
|
||||||
|
no. 1</text:span></text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string" table:number-columns-spanned="8">
|
||||||
|
<text:p text:style-name="Table_20_Contents"><text:span text:style-name="T1">Octet
|
||||||
|
no. 2</text:span></text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
</table:table-row>
|
||||||
|
<table:table-row>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">16</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">15</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">14</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">13</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">12</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">11</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">10</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">9</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">8</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">7</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">6</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">5</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">4</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">3</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">2</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string">
|
||||||
|
<text:p text:style-name="Table_20_Contents">1</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
</table:table-row>
|
||||||
|
<table:table-row>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string" table:number-columns-spanned="8">
|
||||||
|
<text:p text:style-name="Table_20_Contents">Code A</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
<table:table-cell table:style-name="TableRowCell" office:value-type="string" table:number-columns-spanned="8">
|
||||||
|
<text:p text:style-name="Table_20_Contents">Code B</text:p>
|
||||||
|
</table:table-cell>
|
||||||
|
</table:table-row>
|
||||||
|
</table:table>
|
||||||
|
```
|
||||||
|
|
Loading…
Add table
Reference in a new issue