Function: org-odt-table
org-odt-table is a byte-compiled function defined in ox-odt.el.gz.
Signature
(org-odt-table TABLE CONTENTS INFO)
Documentation
Transcode a TABLE element from Org to ODT.
CONTENTS is the contents of the table. INFO is a plist holding contextual information.
Use org-odt--table to typeset the table. Handle details
pertaining to indentation here.
Source Code
;; Defined in /usr/src/emacs/lisp/org/ox-odt.el.gz
(defun org-odt-table (table contents info)
"Transcode a TABLE element from Org to ODT.
CONTENTS is the contents of the table. INFO is a plist holding
contextual information.
Use `org-odt--table' to typeset the table. Handle details
pertaining to indentation here."
(let* ((--element-preceded-by-table-p
(lambda (element info)
(cl-loop for el in (org-export-get-previous-element element info t)
thereis (org-element-type-p el 'table))))
(--walk-list-genealogy-and-collect-tags
(lambda (table info)
(let* ((genealogy (org-element-lineage table))
;; FIXME: This will fail when the table is buried
;; inside non-list parent greater element, like
;; special block. The parent block will not be
;; closed properly.
;; Example:
;; 1. List item
;; - Sub-item
;; #+begin_textbox
;; | Table |
;; #+end_textbox
(list-genealogy
(when (org-element-type-p (car genealogy) 'item)
(cl-loop for el in genealogy
when (org-element-type-p el '(item plain-list))
collect el)))
(llh-genealogy
(apply #'nconc
(cl-loop
for el in genealogy
when (and (org-element-type-p el 'headline)
(org-export-low-level-p el info))
collect
(list el
(assq 'headline
(org-element-contents
(org-element-parent el)))))))
parent-list)
(nconc
;; Handle list genealogy.
(cl-loop
for el in list-genealogy collect
(cl-case (org-element-type el)
(plain-list
(setq parent-list el)
(cons "</text:list>"
(format "\n<text:list text:style-name=\"%s\" %s>"
(cl-case (org-element-property :type el)
(ordered "OrgNumberedList")
(unordered "OrgBulletedList")
(descriptive-1 "OrgDescriptionList")
(descriptive-2 "OrgDescriptionList"))
"text:continue-numbering=\"true\"")))
(item
(cond
((not parent-list)
(if (funcall --element-preceded-by-table-p table info)
'("</text:list-header>" . "<text:list-header>")
'("</text:list-item>" . "<text:list-header>")))
((funcall --element-preceded-by-table-p
parent-list info)
'("</text:list-header>" . "<text:list-header>"))
(t '("</text:list-item>" . "<text:list-item>"))))))
;; Handle low-level headlines.
(cl-loop for el in llh-genealogy
with step = 'item collect
(cl-case step
(plain-list
(setq step 'item) ; Flip-flop
(setq parent-list el)
(cons "</text:list>"
(format "\n<text:list text:style-name=\"%s\" %s>"
(if (org-export-numbered-headline-p
el info)
"OrgNumberedList"
"OrgBulletedList")
"text:continue-numbering=\"true\"")))
(item
(setq step 'plain-list) ; Flip-flop
(cond
((not parent-list)
(if (funcall --element-preceded-by-table-p table info)
'("</text:list-header>" . "<text:list-header>")
'("</text:list-item>" . "<text:list-header>")))
((let ((section? (org-export-get-previous-element
parent-list info)))
(and section?
(org-element-type-p section? 'section)
(assq 'table (org-element-contents section?))))
'("</text:list-header>" . "<text:list-header>"))
(t
'("</text:list-item>" . "<text:list-item>"))))))))))
(close-open-tags (funcall --walk-list-genealogy-and-collect-tags
table info)))
;; OpenDocument schema does not permit table to occur within a
;; list item.
;; One solution - the easiest and lightweight, in terms of
;; implementation - is to put the table in an indented text box
;; and make the text box part of the list-item. Unfortunately if
;; the table is big and spans multiple pages, the text box could
;; overflow. In this case, the following attribute will come
;; handy.
;; ,---- From OpenDocument-v1.1.pdf
;; | 15.27.28 Overflow behavior
;; |
;; | For text boxes contained within text document, the
;; | style:overflow-behavior property specifies the behavior of text
;; | boxes where the containing text does not fit into the text
;; | box.
;; |
;; | If the attribute's value is clip, the text that does not fit
;; | into the text box is not displayed.
;; |
;; | If the attribute value is auto-create-new-frame, a new frame
;; | will be created on the next page, with the same position and
;; | dimensions of the original frame.
;; |
;; | If the style:overflow-behavior property's value is
;; | auto-create-new-frame and the text box has a minimum width or
;; | height specified, then the text box will grow until the page
;; | bounds are reached before a new frame is created.
;; `----
;; Unfortunately, LibreOffice-3.4.6 doesn't honor
;; auto-create-new-frame property and always resorts to clipping
;; the text box. This results in table being truncated.
;; So we solve the problem the hard (and fun) way using list
;; continuations.
;; The problem only becomes more interesting if you take in to
;; account the following facts:
;;
;; - Description lists are simulated as plain lists.
;; - Low-level headlines can be listified.
;; - In Org mode, a table can occur not only as a regular list
;; item, but also within description lists and low-level
;; headlines.
;; See `org-odt--translate-description-lists' for how this is
;; tackled.
(concat "\n"
;; Discontinue the list.
(mapconcat 'car close-open-tags "\n")
;; Put the table in an indented section.
(let* ((table (org-odt--table table contents info))
(level (/ (length (mapcar 'car close-open-tags)) 2))
(style (format "OrgIndentedSection-Level-%d" level)))
(when table (org-odt-format-section table style)))
;; Continue the list.
(mapconcat 'cdr (nreverse close-open-tags) "\n"))))