diff --git a/lisp/ox-html.el b/lisp/ox-html.el
index e1b9cf07b..3f67c5c50 100644
--- a/lisp/ox-html.el
+++ b/lisp/ox-html.el
@@ -68,6 +68,7 @@
(horizontal-rule . org-html-horizontal-rule)
(inline-src-block . org-html-inline-src-block)
(inlinetask . org-html-inlinetask)
+ (inner-template . org-html-inner-template)
(italic . org-html-italic)
(item . org-html-item)
(keyword . org-html-keyword)
@@ -1369,6 +1370,26 @@ INFO is a plist used as a communication channel."
(org-element-normalize-string postamble-contents)
"\n"))))))
+(defun org-html-inner-template (contents info)
+ "Return body of document string after HTML conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ (concat
+ (format "
\n" (nth 1 org-html-divs))
+ ;; Document title.
+ (format "
%s
\n"
+ (org-export-data (plist-get info :title) info))
+ ;; Table of contents.
+ (let ((depth (plist-get info :with-toc)))
+ (when depth (org-html-toc depth info)))
+ ;; Document contents.
+ contents
+ ;; Footnotes section.
+ (org-html-footnote-section info)
+ ;; Bibliography.
+ (org-html-bibliography)
+ "\n"))
+
(defun org-html-template (contents info)
"Return complete document string after HTML conversion.
CONTENTS is the transcoded contents string. INFO is a plist
@@ -1405,22 +1426,8 @@ holding export options."
(or link-home link-up))))
;; Preamble.
(org-html--build-preamble info)
- ;; Begin content.
- (format "\n" (nth 1 org-html-divs))
- ;; Document title.
- (format "
%s
\n"
- (org-export-data (plist-get info :title) info))
- ;; Table of contents.
- (let ((depth (plist-get info :with-toc)))
- (when depth (org-html-toc depth info)))
;; Document contents.
contents
- ;; Footnotes section.
- (org-html-footnote-section info)
- ;; Bibliography.
- (org-html-bibliography)
- ;; End content.
- "\n"
;; Postamble.
(org-html--build-postamble info)
;; Closing document.
diff --git a/lisp/ox.el b/lisp/ox.el
index d83c11bd6..0b32842e6 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -830,13 +830,15 @@ string, the type will be ignored, but the blank lines or white
spaces will be kept.
In addition to element and object types, one function can be
-associated to the `template' symbol and another one to the
-`plain-text' symbol.
+associated to the `template' (or `inner-template') symbol and
+another one to the `plain-text' symbol.
The former returns the final transcoded string, and can be used
to add a preamble and a postamble to document's body. It must
accept two arguments: the transcoded string and the property list
-containing export options.
+containing export options. A function associated to `template'
+will not be applied if export has option \"body-only\".
+A function associated to `inner-template' is always applied.
The latter, when defined, is to be called on every text not
recognized as an element or an object. It must accept two
@@ -1227,7 +1229,8 @@ The back-end could then be called with, for example:
;;
;; + `:translate-alist' :: Alist between element and object types and
;; transcoding functions relative to the current back-end.
-;; Special keys `template' and `plain-text' are also possible.
+;; Special keys `inner-template', `template' and `plain-text' are
+;; also possible.
;; - category :: option
;; - type :: alist (SYMBOL . FUNCTION)
;;
@@ -1286,8 +1289,8 @@ The back-end could then be called with, for example:
;; + `:with-latex' :: Non-nil means `latex-environment' elements and
;; `latex-fragment' objects should appear in export output. When
;; this property is set to `verbatim', they will be left as-is.
-;; - category :: option
-;; - symbol (`verbatim', nil, t)
+;; - category :: option
+;; - type :: symbol (`verbatim', nil, t)
;;
;; + `:with-plannings' :: Non-nil means transcoding should include
;; planning info.
@@ -2848,18 +2851,23 @@ Return code as a string."
(org-combine-plists
info (org-export-collect-tree-properties tree info)))
;; Eventually transcode TREE. Wrap the resulting string into
- ;; a template, if needed. Finally call final-output filter.
- (let ((body (org-element-normalize-string
- (or (org-export-data tree info) "")))
- (template (cdr (assq 'template
- (plist-get info :translate-alist)))))
+ ;; a template.
+ (let* ((body (org-element-normalize-string
+ (or (org-export-data tree info) "")))
+ (inner-template (cdr (assq 'inner-template
+ (plist-get info :translate-alist))))
+ (full-body (if (not (functionp inner-template)) body
+ (funcall inner-template body info)))
+ (template (cdr (assq 'template
+ (plist-get info :translate-alist)))))
;; Remove all text properties since they cannot be
- ;; retrieved from an external process, and return result.
+ ;; retrieved from an external process. Finally call
+ ;; final-output filter and return result.
(org-no-properties
(org-export-filter-apply-functions
(plist-get info :filter-final-output)
- (if (or (not (functionp template)) body-only) body
- (funcall template body info))
+ (if (or (not (functionp template)) body-only) full-body
+ (funcall template full-body info))
info))))))))
;;;###autoload
diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
index b27ded0dd..c67db4f7c 100644
--- a/testing/lisp/test-ox.el
+++ b/testing/lisp/test-ox.el
@@ -2092,6 +2092,50 @@ Another text. (ref:text)
info))))
+
+;;; Templates
+
+(ert-deftest test-org-export/inner-template ()
+ "Test `inner-template' translator specifications."
+ (should
+ (equal "Success!"
+ (let (org-export-registered-backends)
+ (org-export-define-backend test
+ ((inner-template . (lambda (contents info) "Success!"))
+ (headline . (lambda (h c i) "Headline"))))
+ (org-test-with-temp-text "* Headline"
+ (org-export-as 'test)))))
+ ;; Inner template is applied even in a "body-only" export.
+ (should
+ (equal "Success!"
+ (let (org-export-registered-backends)
+ (org-export-define-backend test
+ ((inner-template . (lambda (contents info) "Success!"))
+ (headline . (lambda (h c i) "Headline"))))
+ (org-test-with-temp-text "* Headline"
+ (org-export-as 'test nil nil 'body-only))))))
+
+(ert-deftest test-org-export/template ()
+ "Test `template' translator specifications."
+ (should
+ (equal "Success!"
+ (let (org-export-registered-backends)
+ (org-export-define-backend test
+ ((template . (lambda (contents info) "Success!"))
+ (headline . (lambda (h c i) "Headline"))))
+ (org-test-with-temp-text "* Headline"
+ (org-export-as 'test)))))
+ ;; Template is not applied in a "body-only" export.
+ (should-not
+ (equal "Success!"
+ (let (org-export-registered-backends)
+ (org-export-define-backend test
+ ((template . (lambda (contents info) "Success!"))
+ (headline . (lambda (h c i) "Headline"))))
+ (org-test-with-temp-text "* Headline"
+ (org-export-as 'test nil nil 'body-only))))))
+
+
;;; Topology