campaign: minimize the flags a little more
[gnupg-doc.git] / web / share / ox-gpgweb.el
1 ;;; ox-gpgweb.el --- HTML for gnupg.org Back-End for Org Export Engine
2
3 ;; Copyright (C) 2011-2014 Free Software Foundation, Inc.
4
5 ;; Author: Carsten Dominik <carsten at orgmode dot org>
6 ;;      Jambunathan K <kjambunathan at gmail dot com>
7 ;; Keywords: outlines, hypermedia, calendar, wp
8
9 ;; This file is part of GNU Emacs.
10
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
15
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
23
24 ;;; Commentary:
25
26 ;; This library implements a HTML back-end for Org generic exporter.
27 ;; See Org manual for more information.  This is a simplified version
28 ;; of the standard HTML backend to be used for the gnupg.org website.
29
30 ;;; Code:
31
32 ;;; Dependencies
33
34 (require 'ox)
35 (require 'ox-publish)
36 (require 'format-spec)
37 (eval-when-compile (require 'cl) (require 'table nil 'noerror))
38
39 \f
40 ;;; Function Declarations
41
42 (declare-function htmlize-region "ext:htmlize" (beg end))
43
44 ;;; Define Back-End
45
46 (org-export-define-backend 'gpgweb
47   '((bold . org-gpgweb-bold)
48     (center-block . org-gpgweb-center-block)
49     (clock . org-gpgweb-clock)
50     (code . org-gpgweb-code)
51     (drawer . org-gpgweb-drawer)
52     (dynamic-block . org-gpgweb-dynamic-block)
53     (entity . org-gpgweb-entity)
54     (example-block . org-gpgweb-example-block)
55     (export-block . org-gpgweb-export-block)
56     (export-snippet . org-gpgweb-export-snippet)
57     (fixed-width . org-gpgweb-fixed-width)
58     (footnote-definition . org-gpgweb-footnote-definition)
59     (footnote-reference . org-gpgweb-footnote-reference)
60     (headline . org-gpgweb-headline)
61     (horizontal-rule . org-gpgweb-horizontal-rule)
62     (inline-src-block . org-gpgweb-inline-src-block)
63     (inlinetask . org-gpgweb-inlinetask)
64     (inner-template . org-gpgweb-inner-template)
65     (italic . org-gpgweb-italic)
66     (item . org-gpgweb-item)
67     (keyword . org-gpgweb-keyword)
68     (latex-environment . org-gpgweb-latex-environment)
69     (latex-fragment . org-gpgweb-latex-fragment)
70     (line-break . org-gpgweb-line-break)
71     (link . org-gpgweb-link)
72     (node-property . org-gpgweb-node-property)
73     (paragraph . org-gpgweb-paragraph)
74     (plain-list . org-gpgweb-plain-list)
75     (plain-text . org-gpgweb-plain-text)
76     (planning . org-gpgweb-planning)
77     (property-drawer . org-gpgweb-property-drawer)
78     (quote-block . org-gpgweb-quote-block)
79     (radio-target . org-gpgweb-radio-target)
80     (section . org-gpgweb-section)
81     (special-block . org-gpgweb-special-block)
82     (src-block . org-gpgweb-src-block)
83     (statistics-cookie . org-gpgweb-statistics-cookie)
84     (strike-through . org-gpgweb-strike-through)
85     (subscript . org-gpgweb-subscript)
86     (superscript . org-gpgweb-superscript)
87     (table . org-gpgweb-table)
88     (table-cell . org-gpgweb-table-cell)
89     (table-row . org-gpgweb-table-row)
90     (target . org-gpgweb-target)
91     (timestamp . org-gpgweb-timestamp)
92     (underline . org-gpgweb-underline)
93     (verbatim . org-gpgweb-verbatim)
94     (verse-block . org-gpgweb-verse-block))
95   :export-block "HTML"
96   :filters-alist '((:filter-final-output . org-gpgweb-final-function))
97   :menu-entry
98   '(?G "Export for http://gnupg.org"
99        ((?H "As HTML buffer" org-gpgweb-export-as-html)
100         (?h "As HTML file" org-gpgweb-export-to-html)
101         (?o "As HTML file and open"
102             (lambda (a s v b)
103               (if a (org-gpgweb-export-to-html t s v b)
104                 (org-open-file (org-gpgweb-export-to-html nil s v b)))))))
105   :options-alist
106   '(
107     (:html-html5-fancy nil "html5-fancy" org-gpgweb-html5-fancy)
108     (:html-link-home "HTML_LINK_HOME" nil org-gpgweb-link-home)
109     (:html-link-up "HTML_LINK_UP" nil org-gpgweb-link-up)
110     (:html-mathjax "HTML_MATHJAX" nil "" space)
111     (:html-html5-fancy nil "html5-fancy" org-gpgweb-html5-fancy)
112     (:html-checkbox-type nil nil org-gpgweb-checkbox-type)
113     (:html-extension nil nil org-gpgweb-extension)
114     (:html-home/up-format nil nil org-gpgweb-home/up-format)
115     (:html-inline-image-rules nil nil org-gpgweb-inline-image-rules)
116     (:html-link-org-files-as-html nil nil org-gpgweb-link-org-files-as-html)
117     (:html-mathjax-options nil nil org-gpgweb-mathjax-options)
118     (:html-mathjax-template nil nil org-gpgweb-mathjax-template)
119     (:html-table-align-individual-fields
120      nil nil org-gpgweb-table-align-individual-fields)
121     (:html-table-caption-above nil nil org-gpgweb-table-caption-above)
122     (:html-table-data-tags nil nil org-gpgweb-table-data-tags)
123     (:html-table-header-tags nil nil org-gpgweb-table-header-tags)
124     (:html-table-use-header-tags-for-first-column
125      nil nil org-gpgweb-table-use-header-tags-for-first-column)
126     (:html-tag-class-prefix nil nil org-gpgweb-tag-class-prefix)
127     (:html-todo-kwd-class-prefix nil nil org-gpgweb-todo-kwd-class-prefix)
128     (:html-toplevel-hlevel nil nil org-gpgweb-toplevel-hlevel)
129     (:html-inline-images nil nil org-gpgweb-inline-images)
130     (:html-table-attributes nil nil org-gpgweb-table-default-attributes)
131     (:html-table-row-tags nil nil org-gpgweb-table-row-tags)
132     (:html-xml-declaration nil nil org-gpgweb-xml-declaration)
133     ;; Redefine regular options.
134     (:with-latex nil "tex" org-gpgweb-with-latex)
135     ;; Retrieve LaTeX header for fragments.
136     (:latex-header "LATEX_HEADER" nil nil newline)))
137
138 \f
139 ;;; Internal Variables
140
141 (defvar org-gpgweb-format-table-no-css)
142 (defvar htmlize-buffer-places)  ; from htmlize.el
143
144 (defvar org-gpgweb--pre/postamble-class "status"
145   "CSS class used for pre/postamble")
146
147 (defconst org-gpgweb-html5-elements
148   '("article" "aside" "audio" "canvas" "details" "figcaption"
149     "figure" "footer" "header" "menu" "meter" "nav" "output"
150     "progress" "section" "video")
151   "New elements in html5.
152
153 For blocks that should contain headlines, use the HTML_CONTAINER
154 property on the headline itself.")
155
156 (defconst org-gpgweb-special-string-regexps
157   '(("\\\\-" . "&#x00ad;")              ; shy
158     ("---\\([^-]\\)" . "&#x2014;\\1")   ; mdash
159     ("--\\([^-]\\)" . "&#x2013;\\1")    ; ndash
160     ("\\.\\.\\." . "&#x2026;"))         ; hellip
161   "Regular expressions for special string conversion.")
162
163
164 \f
165 ;;; User Configuration Variables
166
167 ;;;; Headline
168
169 (defconst org-gpgweb-toplevel-hlevel 2
170   "The <H> level for level 1 headings in HTML export.
171 This is also important for the classes that will be wrapped around headlines
172 and outline structure.  If this variable is 1, the top-level headlines will
173 be <h1>, and the corresponding classes will be outline-1, section-number-1,
174 and outline-text-1.  If this is 2, all of these will get a 2 instead.
175 The default for this variable is 2, because we use <h1> for formatting the
176 document title.")
177
178 ;;;; LaTeX
179
180 (defconst org-gpgweb-with-latex org-export-with-latex
181   "Non-nil means process LaTeX math snippets.
182
183 When set, the exporter will process LaTeX environments and
184 fragments.
185
186 This option can also be set with the +OPTIONS line,
187 e.g. \"tex:mathjax\".  Allowed values are:
188
189 nil            Ignore math snippets.
190 `verbatim'     Keep everything in verbatim
191 `dvipng'       Process the LaTeX fragments to images.  This will also
192                include processing of non-math environments.
193 `imagemagick'  Convert the LaTeX fragments to pdf files and use
194                imagemagick to convert pdf files to png files.
195 `mathjax'      Do MathJax preprocessing and arrange for MathJax.js to
196                be loaded.
197 t              Synonym for `mathjax'.")
198
199 ;;;; Links :: Generic
200
201 (defconst org-gpgweb-link-org-files-as-html t
202   "Non-nil means make file links to `file.org' point to `file.html'.
203 When `org-mode' is exporting an `org-mode' file to HTML, links to
204 non-html files are directly put into a href tag in HTML.
205 However, links to other Org-mode files (recognized by the
206 extension `.org.) should become links to the corresponding html
207 file, assuming that the linked `org-mode' file will also be
208 converted to HTML.
209 When nil, the links still point to the plain `.org' file.")
210
211 ;;;; Links :: Inline images
212
213 (defconst org-gpgweb-inline-images t
214   "Non-nil means inline images into exported HTML pages.
215 This is done using an <img> tag.  When nil, an anchor with href is used to
216 link to the image.")
217
218 (defconst org-gpgweb-inline-image-rules
219   '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
220     ("http" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
221     ("https" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'"))
222   "Rules characterizing image files that can be inlined into HTML.
223 A rule consists in an association whose key is the type of link
224 to consider, and value is a regexp that will be matched against
225 link's path.")
226
227 ;;;; Plain Text
228
229 (defvar org-gpgweb-protect-char-alist
230   '(("&" . "&amp;")
231     ("<" . "&lt;")
232     (">" . "&gt;"))
233   "Alist of characters to be converted by `org-gpgweb-protect'.")
234
235 ;;;; Src Block
236
237 (defconst org-gpgweb-htmlize-output-type nil
238   "Output type to be used by htmlize when formatting code snippets.
239 Choices are `css' to export the CSS selectors only,`inline-css'
240 to export the CSS attribute values inline in the HTML or `nil' to
241 export plain text.")
242
243 (defconst org-gpgweb-htmlize-font-prefix "org-"
244   "The prefix for CSS class names for htmlize font specifications.")
245
246 ;;;; Table
247
248 (defconst org-gpgweb-table-default-attributes
249   '(:border "2" :cellspacing "0" :cellpadding "6" :rules "groups" :frame "hsides")
250   "Default attributes and values which will be used in table tags.
251 This is a plist where attributes are symbols, starting with
252 colons, and values are strings.
253
254 When exporting to HTML5, these values will be disregarded.")
255
256 (defconst org-gpgweb-table-header-tags '("<th scope=\"%s\"%s>" . "</th>")
257   "The opening and ending tags for table header fields.
258 This is customizable so that alignment options can be specified.
259 The first %s will be filled with the scope of the field, either row or col.
260 The second %s will be replaced by a style entry to align the field.
261 See also the variable `org-gpgweb-table-use-header-tags-for-first-column'.
262 See also the variable `org-gpgweb-table-align-individual-fields'.")
263
264 (defconst org-gpgweb-table-data-tags '("<td%s>" . "</td>")
265   "The opening and ending tags for table data fields.
266 This is customizable so that alignment options can be specified.
267 The first %s will be filled with the scope of the field, either row or col.
268 The second %s will be replaced by a style entry to align the field.
269 See also the variable `org-gpgweb-table-align-individual-fields'.")
270
271 (defconst org-gpgweb-table-row-tags '("<tr>" . "</tr>")
272   "The opening and ending tags for table rows.
273 This is customizable so that alignment options can be specified.
274 Instead of strings, these can be Lisp forms that will be
275 evaluated for each row in order to construct the table row tags.
276
277 During evaluation, these variables will be dynamically bound so that
278 you can reuse them:
279
280        `row-number': row number (0 is the first row)
281   `rowgroup-number': group number of current row
282  `start-rowgroup-p': non-nil means the row starts a group
283    `end-rowgroup-p': non-nil means the row ends a group
284         `top-row-p': non-nil means this is the top row
285      `bottom-row-p': non-nil means this is the bottom row
286
287 For example:
288
289 \(setq org-gpgweb-table-row-tags
290       (cons '(cond (top-row-p \"<tr class=\\\"tr-top\\\">\")
291                    (bottom-row-p \"<tr class=\\\"tr-bottom\\\">\")
292                    (t (if (= (mod row-number 2) 1)
293                           \"<tr class=\\\"tr-odd\\\">\"
294                         \"<tr class=\\\"tr-even\\\">\")))
295             \"</tr>\"))
296
297 will use the \"tr-top\" and \"tr-bottom\" classes for the top row
298 and the bottom row, and otherwise alternate between \"tr-odd\" and
299 \"tr-even\" for odd and even rows.")
300
301 (defconst org-gpgweb-table-align-individual-fields t
302   "Non-nil means attach style attributes for alignment to each table field.
303 When nil, alignment will only be specified in the column tags, but this
304 is ignored by some browsers (like Firefox, Safari).  Opera does it right
305 though.")
306
307 (defconst org-gpgweb-table-use-header-tags-for-first-column nil
308   "Non-nil means format column one in tables with header tags.
309 When nil, also column one will use data tags.")
310
311 (defconst org-gpgweb-table-caption-above t
312   "When non-nil, place caption string at the beginning of the table.
313 Otherwise, place it near the end.")
314
315 ;;;; Tags
316
317 (defconst org-gpgweb-tag-class-prefix ""
318   "Prefix to class names for TODO keywords.
319 Each tag gets a class given by the tag itself, with this prefix.
320 The default prefix is empty because it is nice to just use the keyword
321 as a class name.  But if you get into conflicts with other, existing
322 CSS classes, then this prefix can be very useful.")
323
324 ;;;; Template :: Generic
325
326 (defconst org-gpgweb-extension "html"
327   "The extension for exported HTML files.")
328
329 (defconst org-gpgweb-xml-declaration
330   '(("html" . "<?xml version=\"1.0\" encoding=\"%s\"?>")
331     ("php" . "<?php echo \"<?xml version=\\\"1.0\\\" encoding=\\\"%s\\\" ?>\"; ?>"))
332   "The extension for exported HTML files.
333 %s will be replaced with the charset of the exported file.
334 This may be a string, or an alist with export extensions
335 and corresponding declarations.
336
337 This declaration only applies when exporting to XHTML.")
338
339 (defconst org-gpgweb-doctype "xhtml-strict"
340   "Document type definition to use for exported HTML files.")
341
342 (defconst org-gpgweb-html5-fancy nil
343   "Non-nil means using new HTML5 elements.
344 This variable is ignored for anything other than HTML5 export.
345
346 For compatibility with Internet Explorer, it's probably a good
347 idea to download some form of the html5shiv (for instance
348 https://code.google.com/p/html5shiv/) and add it to your
349 HTML_HEAD_EXTRA, so that your pages don't break for users of IE
350 versions 8 and below.")
351
352 (defconst org-gpgweb-container-element "div"
353   "HTML element to use for wrapping top level sections.")
354
355 (defconst org-gpgweb-checkbox-types
356   '((unicode .
357      ((on . "&#x2611;") (off . "&#x2610;") (trans . "&#x2610;")))
358     (ascii .
359      ((on . "<code>[X]</code>")
360       (off . "<code>[&#xa0;]</code>")
361       (trans . "<code>[-]</code>")))
362     (html .
363           ((on . "<input type='checkbox' checked='checked' />")
364           (off . "<input type='checkbox' />")
365           (trans . "<input type='checkbox' />"))))
366   "Alist of checkbox types.
367 The cdr of each entry is an alist list three checkbox types for
368 HTML export: `on', `off' and `trans'.
369
370 The choices are:
371   `unicode' Unicode characters (HTML entities)
372   `ascii'   ASCII characters
373   `html'    HTML checkboxes
374
375 Note that only the ascii characters implement tri-state
376 checkboxes. The other two use the `off' checkbox for `trans'.")
377
378 (defconst org-gpgweb-checkbox-type 'ascii
379   "The type of checkboxes to use for HTML export.
380 See `org-gpgweb-checkbox-types' for for the values used for each
381 option.")
382
383
384 ;;;; Template :: Mathjax
385
386 (defconst org-gpgweb-mathjax-options
387   '((path  "http://orgmode.org/mathjax/MathJax.js")
388     (scale "100")
389     (align "center")
390     (indent "2em")
391     (mathml nil))
392   "Options for MathJax setup.
393
394 path        The path where to find MathJax
395 scale       Scaling for the HTML-CSS backend, usually between 100 and 133
396 align       How to align display math: left, center, or right
397 indent      If align is not center, how far from the left/right side?
398 mathml      Should a MathML player be used if available?
399             This is faster and reduces bandwidth use, but currently
400             sometimes has lower spacing quality.  Therefore, the default is
401             nil.  When browsers get better, this switch can be flipped.
402
403 You can also customize this for each buffer, using something like
404
405 #+MATHJAX: scale:\"133\" align:\"right\" mathml:t path:\"/MathJax/\"")
406
407 (defconst org-gpgweb-mathjax-template
408   "<script type=\"text/javascript\" src=\"%PATH\"></script>
409 <script type=\"text/javascript\">
410 <!--/*--><![CDATA[/*><!--*/
411     MathJax.Hub.Config({
412         // Only one of the two following lines, depending on user settings
413         // First allows browser-native MathML display, second forces HTML/CSS
414         :MMLYES: config: [\"MMLorHTML.js\"], jax: [\"input/TeX\"],
415         :MMLNO: jax: [\"input/TeX\", \"output/HTML-CSS\"],
416         extensions: [\"tex2jax.js\",\"TeX/AMSmath.js\",\"TeX/AMSsymbols.js\",
417                      \"TeX/noUndefined.js\"],
418         tex2jax: {
419             inlineMath: [ [\"\\\\(\",\"\\\\)\"] ],
420             displayMath: [ ['$$','$$'], [\"\\\\[\",\"\\\\]\"], [\"\\\\begin{displaymath}\",\"\\\\end{displaymath}\"] ],
421             skipTags: [\"script\",\"noscript\",\"style\",\"textarea\",\"pre\",\"code\"],
422             ignoreClass: \"tex2jax_ignore\",
423             processEscapes: false,
424             processEnvironments: true,
425             preview: \"TeX\"
426         },
427         showProcessingMessages: true,
428         displayAlign: \"%ALIGN\",
429         displayIndent: \"%INDENT\",
430
431         \"HTML-CSS\": {
432              scale: %SCALE,
433              availableFonts: [\"STIX\",\"TeX\"],
434              preferredFont: \"TeX\",
435              webFont: \"TeX\",
436              imageFont: \"TeX\",
437              showMathMenu: true,
438         },
439         MMLorHTML: {
440              prefer: {
441                  MSIE:    \"MML\",
442                  Firefox: \"MML\",
443                  Opera:   \"HTML\",
444                  other:   \"HTML\"
445              }
446         }
447     });
448 /*]]>*///-->
449 </script>"
450   "The MathJax setup for XHTML files.")
451
452 (defconst org-gpgweb-link-up ""
453   "Where should the \"UP\" link of exported HTML pages lead?")
454
455 (defconst org-gpgweb-link-home ""
456   "Where should the \"HOME\" link of exported HTML pages lead?")
457
458 (defconst org-gpgweb-home/up-format
459   "<div id=\"org-div-home-and-up\">
460  <a accesskey=\"h\" href=\"%s\"> UP </a>
461  |
462  <a accesskey=\"H\" href=\"%s\"> HOME </a>
463 </div>"
464   "Snippet used to insert the HOME and UP links.
465 This is a format string, the first %s will receive the UP link,
466 the second the HOME link.  If both `org-gpgweb-link-up' and
467 `org-gpgweb-link-home' are empty, the entire snippet will be
468 ignored.")
469
470 ;;;; Todos
471
472 (defconst org-gpgweb-todo-kwd-class-prefix ""
473   "Prefix to class names for TODO keywords.
474 Each TODO keyword gets a class given by the keyword itself, with this prefix.
475 The default prefix is empty because it is nice to just use the keyword
476 as a class name.  But if you get into conflicts with other, existing
477 CSS classes, then this prefix can be very useful.")
478
479 \f
480 ;;; Internal Functions
481
482 (defun org-gpgweb-xhtml-p (info)
483   (member org-gpgweb-doctype '("xhtml-strict" "xhtml" "xhtml5")))
484
485 (defun org-gpgweb-html5-p (info)
486   (member org-gpgweb-doctype '("html5" "xhtml5" "<!doctype html>")))
487
488 (defun org-gpgweb-close-tag (tag attr info)
489   (concat "<" tag " " attr
490           (if (org-gpgweb-xhtml-p info) " />" ">")))
491
492 (defun org-gpgweb--make-attribute-string (attributes)
493   "Return a list of attributes, as a string.
494 ATTRIBUTES is a plist where values are either strings or nil. An
495 attributes with a nil value will be omitted from the result."
496   (let (output)
497     (dolist (item attributes (mapconcat 'identity (nreverse output) " "))
498       (cond ((null item) (pop output))
499             ((symbolp item) (push (substring (symbol-name item) 1) output))
500             (t (let ((key (car output))
501                      (value (replace-regexp-in-string
502                              "\"" "&quot;" (org-gpgweb-encode-plain-text item))))
503                  (setcar output (format "%s=\"%s\"" key value))))))))
504
505 (defun org-gpgweb--wrap-image (contents info &optional caption label)
506   "Wrap CONTENTS string within an appropriate environment for images.
507 INFO is a plist used as a communication channel.  When optional
508 arguments CAPTION and LABEL are given, use them for caption and
509 \"id\" attribute."
510   (let ((html5-fancy (and (org-gpgweb-html5-p info)
511                           (plist-get info :html-html5-fancy))))
512     (format (if html5-fancy "\n<figure%s>%s%s\n</figure>"
513               "\n<div%s class=\"figure\">%s%s\n</div>")
514             ;; ID.
515             (if (not (org-string-nw-p label)) ""
516               (format " id=\"%s\"" (org-export-solidify-link-text label)))
517             ;; Contents.
518             (format "\n<p>%s</p>" contents)
519             ;; Caption.
520             (if (not (org-string-nw-p caption)) ""
521               (format (if html5-fancy "\n<figcaption>%s</figcaption>"
522                         "\n<p>%s</p>")
523                       caption)))))
524
525 (defun org-gpgweb--format-image (source attributes info)
526   "Return \"img\" tag with given SOURCE and ATTRIBUTES.
527 SOURCE is a string specifying the location of the image.
528 ATTRIBUTES is a plist, as returned by
529 `org-export-read-attribute'.  INFO is a plist used as
530 a communication channel."
531   (if (string= "svg" (file-name-extension source))
532       (org-gpgweb--svg-image source attributes info)
533     (org-gpgweb-close-tag
534      "img"
535      (org-gpgweb--make-attribute-string
536       (org-combine-plists
537        (list :src source
538              :alt (if (string-match-p "^ltxpng/" source)
539                       (org-gpgweb-encode-plain-text
540                        (org-find-text-property-in-string 'org-latex-src source))
541                     (file-name-nondirectory source)))
542        attributes))
543      info)))
544
545 (defun org-gpgweb--svg-image (source attributes info)
546   "Return \"object\" appropriate for embedding svg file SOURCE
547 with assoicated ATTRIBUTES. INFO is a plist used as a
548 communication channel.
549
550 The special attribute \"fallback\" can be used to specify a fallback
551 image file to use if the object embedding is not supported."
552   (let ((fallback (plist-get attributes :fallback))
553         (attrs (org-gpgweb--make-attribute-string
554                 (plist-put attributes :fallback nil))))
555   (format "<object type=\"image/svg+xml\" data=\"%s\" %s>\n%s</object>"
556           source attrs
557           (if fallback
558               (org-gpgweb-close-tag
559                "img" (format "src=\"%s\" %s" fallback attrs) info)
560             "Sorry, your browser does not support SVG."))))
561
562 (defun org-gpgweb--textarea-block (element)
563   "Transcode ELEMENT into a textarea block.
564 ELEMENT is either a src block or an example block."
565   (let* ((code (car (org-export-unravel-code element)))
566          (attr (org-export-read-attribute :attr_html element)))
567     (format "<p>\n<textarea cols=\"%s\" rows=\"%s\">\n%s</textarea>\n</p>"
568             (or (plist-get attr :width) 80)
569             (or (plist-get attr :height) (org-count-lines code))
570             code)))
571
572 (defun org-gpgweb--has-caption-p (element &optional info)
573   "Non-nil when ELEMENT has a caption affiliated keyword.
574 INFO is a plist used as a communication channel.  This function
575 is meant to be used as a predicate for `org-export-get-ordinal' or
576 a value to `org-gpgweb-standalone-image-predicate'."
577   (org-element-property :caption element))
578
579 ;;;; Table
580
581 (defun org-gpgweb-htmlize-region-for-paste (beg end)
582   "Convert the region between BEG and END to HTML, using htmlize.el.
583 This is much like `htmlize-region-for-paste', only that it uses
584 the settings define in the org-... variables."
585   (let* ((htmlize-output-type org-gpgweb-htmlize-output-type)
586          (htmlize-css-name-prefix org-gpgweb-htmlize-font-prefix)
587          (htmlbuf (htmlize-region beg end)))
588     (unwind-protect
589         (with-current-buffer htmlbuf
590           (buffer-substring (plist-get htmlize-buffer-places 'content-start)
591                             (plist-get htmlize-buffer-places 'content-end)))
592       (kill-buffer htmlbuf))))
593
594 (defun org-gpgweb--make-string (n string)
595   "Build a string by concatenating N times STRING."
596   (let (out) (dotimes (i n out) (setq out (concat string out)))))
597
598 (defun org-gpgweb-fix-class-name (kwd)  ; audit callers of this function
599   "Turn todo keyword KWD into a valid class name.
600 Replaces invalid characters with \"_\"."
601   (save-match-data
602     (while (string-match "[^a-zA-Z0-9_]" kwd)
603       (setq kwd (replace-match "_" t t kwd))))
604   kwd)
605
606 (defun org-gpgweb-footnote-section (info)
607   "Format the footnote section.
608 INFO is a plist used as a communication channel."
609   (let* ((fn-alist (org-export-collect-footnote-definitions
610                     (plist-get info :parse-tree) info))
611          (fn-alist
612           (loop for (n type raw) in fn-alist collect
613                 (cons n (if (eq (org-element-type raw) 'org-data)
614                             (org-trim (org-export-data raw info))
615                           (format "<p>%s</p>"
616                                   (org-trim (org-export-data raw info))))))))
617     (when fn-alist
618       (format "<div id=\"footnotes\">
619 <h2 class=\"footnotes\">%s: </h2>
620 <div id=\"text-footnotes\">
621 %s
622 </div>
623 </div>"
624        (org-gpgweb--translate "Footnotes" info)
625        (format
626         "\n%s\n"
627         (mapconcat
628          (lambda (fn)
629            (let ((n (car fn)) (def (cdr fn)))
630              (format
631               "<div class=\"footdef\">%s %s</div>\n"
632               (format
633                "<sup>%s</sup>"
634                (org-gpgweb--anchor
635                 (format "fn.%d" n)
636                 n
637                 (format " class=\"footnum\" href=\"#fnr.%d\"" n)
638                 info))
639               def)))
640          fn-alist
641          "\n"))))))
642
643 \f
644 ;;; Template
645
646 (defun org-gpgweb--build-meta-info (info)
647   "Return meta tags for exported document.
648 INFO is a plist used as a communication channel."
649   (let ((protect-string
650          (lambda (str)
651            (replace-regexp-in-string
652             "\"" "&quot;" (org-gpgweb-encode-plain-text str))))
653         (title (org-export-data (plist-get info :title) info))
654         (author (and (plist-get info :with-author)
655                      (let ((auth (plist-get info :author)))
656                        (and auth
657                             ;; Return raw Org syntax, skipping non
658                             ;; exportable objects.
659                             (org-element-interpret-data
660                              (org-element-map auth
661                                  (cons 'plain-text org-element-all-objects)
662                                'identity info))))))
663         (description (plist-get info :description))
664         (keywords (plist-get info :keywords))
665         (charset (or (and (fboundp 'coding-system-get)
666                           (coding-system-get 'utf-8 'mime-charset))
667                      "iso-8859-1")))
668     (concat
669      (format "<title>%s</title>\n" title)
670      (when (plist-get info :time-stamp-file)
671        (format-time-string
672          (concat "<!-- "
673                  (plist-get info :html-metadata-timestamp-format)
674                  " -->\n")))
675      (format
676       (if (org-gpgweb-html5-p info)
677           (org-gpgweb-close-tag "meta" " charset=\"%s\"" info)
678         (org-gpgweb-close-tag
679          "meta" " http-equiv=\"Content-Type\" content=\"text/html;charset=%s\""
680          info))
681       charset) "\n"
682      (org-gpgweb-close-tag "meta" " name=\"generator\" content=\"Org-mode\"" info)
683      "\n"
684      (and (org-string-nw-p author)
685           (concat
686            (org-gpgweb-close-tag "meta"
687                                (format " name=\"author\" content=\"%s\""
688                                        (funcall protect-string author))
689                                info)
690            "\n"))
691      (and (org-string-nw-p description)
692           (concat
693            (org-gpgweb-close-tag "meta"
694                                (format " name=\"description\" content=\"%s\"\n"
695                                        (funcall protect-string description))
696                                info)
697            "\n"))
698      (and (org-string-nw-p keywords)
699           (concat
700            (org-gpgweb-close-tag "meta"
701                                (format " name=\"keywords\" content=\"%s\""
702                                        (funcall protect-string keywords))
703                                info)
704            "\n")))))
705
706 (defun org-gpgweb--build-mathjax-config (info)
707   "Insert the user setup into the mathjax template.
708 INFO is a plist used as a communication channel."
709   (when (and (memq (plist-get info :with-latex) '(mathjax t))
710              (org-element-map (plist-get info :parse-tree)
711                  '(latex-fragment latex-environment) 'identity info t))
712     (let ((template (plist-get info :html-mathjax-template))
713           (options (plist-get info :html-mathjax-options))
714           (in-buffer (or (plist-get info :html-mathjax) ""))
715           name val (yes "   ") (no "// ") x)
716       (mapc
717        (lambda (e)
718          (setq name (car e) val (nth 1 e))
719          (if (string-match (concat "\\<" (symbol-name name) ":") in-buffer)
720              (setq val (car (read-from-string
721                              (substring in-buffer (match-end 0))))))
722          (if (not (stringp val)) (setq val (format "%s" val)))
723          (if (string-match (concat "%" (upcase (symbol-name name))) template)
724              (setq template (replace-match val t t template))))
725        options)
726       (setq val (nth 1 (assq 'mathml options)))
727       (if (string-match (concat "\\<mathml:") in-buffer)
728           (setq val (car (read-from-string
729                           (substring in-buffer (match-end 0))))))
730       ;; Exchange prefixes depending on mathml setting.
731       (if (not val) (setq x yes yes no no x))
732       ;; Replace cookies to turn on or off the config/jax lines.
733       (if (string-match ":MMLYES:" template)
734           (setq template (replace-match yes t t template)))
735       (if (string-match ":MMLNO:" template)
736           (setq template (replace-match no t t template)))
737       ;; Return the modified template.
738       (org-element-normalize-string template))))
739
740 (defun org-gpgweb-inner-template (contents info)
741   "Return body of document string after HTML conversion.
742 CONTENTS is the transcoded contents string.  INFO is a plist
743 holding export options."
744   (concat
745    ;; Table of contents.
746    (let ((depth (plist-get info :with-toc)))
747      (when depth (org-gpgweb-toc depth info)))
748    ;; Document contents.
749    contents
750    ;; Footnotes section.
751    (org-gpgweb-footnote-section info)))
752
753 (defun org-gpgweb--translate (s info)
754   "Translate string S according to specified language.
755 INFO is a plist used as a communication channel."
756   (org-export-translate s :html info))
757
758 ;;;; Anchor
759
760 (defun org-gpgweb--anchor (id desc attributes info)
761   "Format a HTML anchor."
762   (let* ((attributes (concat (and id (format " id=\"%s\"" id))
763                              attributes)))
764     (format "<a%s>%s</a>" attributes (or desc ""))))
765
766 ;;;; Todo
767
768 (defun org-gpgweb--todo (todo info)
769   "Format TODO keywords into HTML."
770   (when todo
771     (format "<span class=\"%s %s%s\">%s</span>"
772             (if (member todo org-done-keywords) "done" "todo")
773             (plist-get info :html-todo-kwd-class-prefix)
774             (org-gpgweb-fix-class-name todo)
775             todo)))
776
777 ;;;; Tags
778
779 (defun org-gpgweb--tags (tags info)
780   "Format TAGS into HTML.
781 INFO is a plist containing export options."
782   (when tags
783     (format "<span class=\"tag\">%s</span>"
784             (mapconcat
785              (lambda (tag)
786                (format "<span class=\"%s\">%s</span>"
787                        (concat (plist-get info :html-tag-class-prefix)
788                                (org-gpgweb-fix-class-name tag))
789                        tag))
790              tags "&#xa0;"))))
791
792 ;;;; Src Code
793
794 (defun org-gpgweb-fontify-code (code lang)
795   "Color CODE with htmlize library.
796 CODE is a string representing the source code to colorize.  LANG
797 is the language used for CODE, as a string, or nil."
798   (when code
799     (cond
800      ;; Case 1: No lang.  Possibly an example block.
801      ((not lang)
802       ;; Simple transcoding.
803       (org-gpgweb-encode-plain-text code))
804      ;; Case 2: No htmlize or an inferior version of htmlize
805      ((not (and (require 'htmlize nil t) (fboundp 'htmlize-region-for-paste)))
806       ;; Emit a warning.
807       (message "Cannot fontify src block (htmlize.el >= 1.34 required)")
808       ;; Simple transcoding.
809       (org-gpgweb-encode-plain-text code))
810      ;; Case 3: plain text explicitly set
811      ((not org-gpgweb-htmlize-output-type)
812       ;; Simple transcoding.
813       (org-gpgweb-encode-plain-text code))
814      (t
815       ;; Map language
816       (setq lang (or (assoc-default lang org-src-lang-modes) lang))
817       (let* ((lang-mode (and lang (intern (format "%s-mode" lang)))))
818         (cond
819          ;; Case 1: Language is not associated with any Emacs mode
820          ((not (functionp lang-mode))
821           ;; Simple transcoding.
822           (org-gpgweb-encode-plain-text code))
823          ;; Case 2: Default.  Fontify code.
824          (t
825           ;; htmlize
826           (setq code (with-temp-buffer
827                        ;; Switch to language-specific mode.
828                        (funcall lang-mode)
829                        ;; Disable fci-mode if present
830                        (when (and (fboundp 'fci-mode)
831                                   (require 'fill-column-indicator nil 'noerror))
832                          (fci-mode -1))
833                        (insert code)
834                        ;; Fontify buffer.
835                        (font-lock-ensure)
836                        ;; Remove formatting on newline characters.
837                        (save-excursion
838                          (let ((beg (point-min))
839                                (end (point-max)))
840                            (goto-char beg)
841                            (while (progn (end-of-line) (< (point) end))
842                              (put-text-property (point) (1+ (point)) 'face nil)
843                              (forward-char 1))))
844                        (org-src-mode)
845                        (set-buffer-modified-p nil)
846                        ;; Htmlize region.
847                        (org-gpgweb-htmlize-region-for-paste
848                         (point-min) (point-max))))
849           ;; Strip any enclosing <pre></pre> tags.
850           (let* ((beg (and (string-match "\\`<pre[^>]*>\n*" code) (match-end 0)))
851                  (end (and beg (string-match "</pre>\\'" code))))
852             (if (and beg end) (substring code beg end) code)))))))))
853
854 (defun org-gpgweb-do-format-code
855   (code &optional lang refs retain-labels num-start)
856   "Format CODE string as source code.
857 Optional arguments LANG, REFS, RETAIN-LABELS and NUM-START are,
858 respectively, the language of the source code, as a string, an
859 alist between line numbers and references (as returned by
860 `org-export-unravel-code'), a boolean specifying if labels should
861 appear in the source code, and the number associated to the first
862 line of code."
863   (let* ((code-lines (org-split-string code "\n"))
864          (code-length (length code-lines))
865          (num-fmt
866           (and num-start
867                (format "%%%ds: "
868                        (length (number-to-string (+ code-length num-start))))))
869          (code (org-gpgweb-fontify-code code lang)))
870     (org-export-format-code
871      code
872      (lambda (loc line-num ref)
873        (setq loc
874              (concat
875               ;; Add line number, if needed.
876               (when num-start
877                 (format "<span class=\"linenr\">%s</span>"
878                         (format num-fmt line-num)))
879               ;; Transcoded src line.
880               loc
881               ;; Add label, if needed.
882               (when (and ref retain-labels) (format " (%s)" ref))))
883        ;; Mark transcoded line as an anchor, if needed.
884        (if (not ref) loc
885          (format "<span id=\"coderef-%s\" class=\"coderef-off\">%s</span>"
886                  ref loc)))
887      num-start refs)))
888
889 (defun org-gpgweb-format-code (element info)
890   "Format contents of ELEMENT as source code.
891 ELEMENT is either an example block or a src block.  INFO is
892 a plist used as a communication channel."
893   (let* ((lang (org-element-property :language element))
894          ;; Extract code and references.
895          (code-info (org-export-unravel-code element))
896          (code (car code-info))
897          (refs (cdr code-info))
898          ;; Does the src block contain labels?
899          (retain-labels (org-element-property :retain-labels element))
900          ;; Does it have line numbers?
901          (num-start (case (org-element-property :number-lines element)
902                       (continued (org-export-get-loc element info))
903                       (new 0))))
904     (org-gpgweb-do-format-code code lang refs retain-labels num-start)))
905
906 \f
907 ;;; Tables of Contents
908
909 (defun org-gpgweb-toc (depth info)
910   "Build a table of contents.
911 DEPTH is an integer specifying the depth of the table.  INFO is a
912 plist used as a communication channel.  Return the table of
913 contents as a string, or nil if it is empty."
914   (let ((toc-entries
915          (mapcar (lambda (headline)
916                    (cons (org-gpgweb--format-toc-headline headline info)
917                          (org-export-get-relative-level headline info)))
918                  (org-export-collect-headlines info depth)))
919         (outer-tag (if (and (org-gpgweb-html5-p info)
920                             (plist-get info :html-html5-fancy))
921                        "nav"
922                      "div")))
923     (when toc-entries
924       (concat (format "<%s id=\"table-of-contents\">\n" outer-tag)
925               (let ((top-level (plist-get info :html-toplevel-hlevel)))
926                 (format "<h%d>%s</h%d>\n"
927                         top-level
928                         (org-gpgweb--translate "Table of Contents" info)
929                         top-level))
930               "<div id=\"text-table-of-contents\">"
931               (org-gpgweb--toc-text toc-entries)
932               "</div>\n"
933               (format "</%s>\n" outer-tag)))))
934
935 (defun org-gpgweb--toc-text (toc-entries)
936   "Return innards of a table of contents, as a string.
937 TOC-ENTRIES is an alist where key is an entry title, as a string,
938 and value is its relative level, as an integer."
939   (let* ((prev-level (1- (cdar toc-entries)))
940          (start-level prev-level))
941     (concat
942      (mapconcat
943       (lambda (entry)
944         (let ((headline (car entry))
945               (level (cdr entry)))
946           (concat
947            (let* ((cnt (- level prev-level))
948                   (times (if (> cnt 0) (1- cnt) (- cnt)))
949                   rtn)
950              (setq prev-level level)
951              (concat
952               (org-gpgweb--make-string
953                times (cond ((> cnt 0) "\n<ul>\n<li>")
954                            ((< cnt 0) "</li>\n</ul>\n")))
955               (if (> cnt 0) "\n<ul>\n<li>" "</li>\n<li>")))
956            headline)))
957       toc-entries "")
958      (org-gpgweb--make-string (- prev-level start-level) "</li>\n</ul>\n"))))
959
960 (defun org-gpgweb--format-toc-headline (headline info)
961   "Return an appropriate table of contents entry for HEADLINE.
962 INFO is a plist used as a communication channel."
963   (let* ((headline-number (org-export-get-headline-number headline info))
964          (todo (and (plist-get info :with-todo-keywords)
965                     (let ((todo (org-element-property :todo-keyword headline)))
966                       (and todo (org-export-data todo info)))))
967          (todo-type (and todo (org-element-property :todo-type headline)))
968          (priority (and (plist-get info :with-priority)
969                         (org-element-property :priority headline)))
970          (text (org-export-data-with-backend
971                 (org-export-get-alt-title headline info)
972                 ;; Create an anonymous back-end that will ignore any
973                 ;; footnote-reference, link, radio-target and target
974                 ;; in table of contents.
975                 (org-export-create-backend
976                  :parent 'gpgweb
977                  :transcoders '((footnote-reference . ignore)
978                                 (link . (lambda (object c i) c))
979                                 (radio-target . (lambda (object c i) c))
980                                 (target . ignore)))
981                 info))
982          (tags (and (eq (plist-get info :with-tags) t)
983                     (org-export-get-tags headline info))))
984     (format "<a href=\"#%s\">%s</a>"
985             ;; Label.
986             (org-export-solidify-link-text
987              (or (org-element-property :CUSTOM_ID headline)
988                  (concat "sec-"
989                          (mapconcat #'number-to-string headline-number "-"))))
990             ;; Body.
991             (concat
992              (and (not (org-export-low-level-p headline info))
993                   (org-export-numbered-headline-p headline info)
994                   (concat (mapconcat #'number-to-string headline-number ".")
995                           ". "))
996              (apply 'org-gpgweb-format-headline-function
997                      todo todo-type priority text tags :section-number nil)))))
998
999 (defun org-gpgweb-list-of-listings (info)
1000   "Build a list of listings.
1001 INFO is a plist used as a communication channel.  Return the list
1002 of listings as a string, or nil if it is empty."
1003   (let ((lol-entries (org-export-collect-listings info)))
1004     (when lol-entries
1005       (concat "<div id=\"list-of-listings\">\n"
1006               (let ((top-level (plist-get info :html-toplevel-hlevel)))
1007                 (format "<h%d>%s</h%d>\n"
1008                         top-level
1009                         (org-gpgweb--translate "List of Listings" info)
1010                         top-level))
1011               "<div id=\"text-list-of-listings\">\n<ul>\n"
1012               (let ((count 0)
1013                     (initial-fmt (format "<span class=\"listing-number\">%s</span>"
1014                                          (org-gpgweb--translate "Listing %d:" info))))
1015                 (mapconcat
1016                  (lambda (entry)
1017                    (let ((label (org-element-property :name entry))
1018                          (title (org-trim
1019                                  (org-export-data
1020                                   (or (org-export-get-caption entry t)
1021                                       (org-export-get-caption entry))
1022                                   info))))
1023                      (concat
1024                       "<li>"
1025                       (if (not label)
1026                           (concat (format initial-fmt (incf count)) " " title)
1027                         (format "<a href=\"#%s\">%s %s</a>"
1028                                 (org-export-solidify-link-text label)
1029                                 (format initial-fmt (incf count))
1030                                 title))
1031                       "</li>")))
1032                  lol-entries "\n"))
1033               "\n</ul>\n</div>\n</div>"))))
1034
1035 (defun org-gpgweb-list-of-tables (info)
1036   "Build a list of tables.
1037 INFO is a plist used as a communication channel.  Return the list
1038 of tables as a string, or nil if it is empty."
1039   (let ((lol-entries (org-export-collect-tables info)))
1040     (when lol-entries
1041       (concat "<div id=\"list-of-tables\">\n"
1042               (let ((top-level (plist-get info :html-toplevel-hlevel)))
1043                 (format "<h%d>%s</h%d>\n"
1044                         top-level
1045                         (org-gpgweb--translate "List of Tables" info)
1046                         top-level))
1047               "<div id=\"text-list-of-tables\">\n<ul>\n"
1048               (let ((count 0)
1049                     (initial-fmt (format "<span class=\"table-number\">%s</span>"
1050                                          (org-gpgweb--translate "Table %d:" info))))
1051                 (mapconcat
1052                  (lambda (entry)
1053                    (let ((label (org-element-property :name entry))
1054                          (title (org-trim
1055                                  (org-export-data
1056                                   (or (org-export-get-caption entry t)
1057                                       (org-export-get-caption entry))
1058                                   info))))
1059                      (concat
1060                       "<li>"
1061                       (if (not label)
1062                           (concat (format initial-fmt (incf count)) " " title)
1063                         (format "<a href=\"#%s\">%s %s</a>"
1064                                 (org-export-solidify-link-text label)
1065                                 (format initial-fmt (incf count))
1066                                 title))
1067                       "</li>")))
1068                  lol-entries "\n"))
1069               "\n</ul>\n</div>\n</div>"))))
1070
1071 \f
1072 ;;; Transcode Functions
1073
1074 ;;;; Bold
1075
1076 (defun org-gpgweb-bold (bold contents info)
1077   "Transcode BOLD from Org to HTML.
1078 CONTENTS is the text with bold markup.  INFO is a plist holding
1079 contextual information."
1080   (format "<b>%s</b>" contents))
1081
1082 ;;;; Center Block
1083
1084 (defun org-gpgweb-center-block (center-block contents info)
1085   "Transcode a CENTER-BLOCK element from Org to HTML.
1086 CONTENTS holds the contents of the block.  INFO is a plist
1087 holding contextual information."
1088   (format "<div class=\"center\">\n%s</div>" contents))
1089
1090 ;;;; Clock
1091
1092 (defun org-gpgweb-clock (clock contents info)
1093   "Transcode a CLOCK element from Org to HTML.
1094 CONTENTS is nil.  INFO is a plist used as a communication
1095 channel."
1096   (format "<p>
1097 <span class=\"timestamp-wrapper\">
1098 <span class=\"timestamp-kwd\">%s</span> <span class=\"timestamp\">%s</span>%s
1099 </span>
1100 </p>"
1101           org-clock-string
1102           (org-translate-time
1103            (org-element-property :raw-value
1104                                  (org-element-property :value clock)))
1105           (let ((time (org-element-property :duration clock)))
1106             (and time (format " <span class=\"timestamp\">(%s)</span>" time)))))
1107
1108 ;;;; Code
1109
1110 (defun org-gpgweb-code (code contents info)
1111   "Transcode CODE from Org to HTML.
1112 CONTENTS is nil.  INFO is a plist holding contextual
1113 information."
1114   (format "<code>%s</code>"
1115           (org-gpgweb-encode-plain-text (org-element-property :value code))))
1116
1117 ;;;; Drawer
1118
1119 (defun org-gpgweb-drawer (drawer contents info)
1120   "Transcode a DRAWER element from Org to HTML.
1121 CONTENTS holds the contents of the block.  INFO is a plist
1122 holding contextual information."
1123   (funcall (lambda (name contents) contents)
1124            (org-element-property :drawer-name drawer)
1125            contents))
1126
1127 ;;;; Dynamic Block
1128
1129 (defun org-gpgweb-dynamic-block (dynamic-block contents info)
1130   "Transcode a DYNAMIC-BLOCK element from Org to HTML.
1131 CONTENTS holds the contents of the block.  INFO is a plist
1132 holding contextual information.  See `org-export-data'."
1133   contents)
1134
1135 ;;;; Entity
1136
1137 (defun org-gpgweb-entity (entity contents info)
1138   "Transcode an ENTITY object from Org to HTML.
1139 CONTENTS are the definition itself.  INFO is a plist holding
1140 contextual information."
1141   (org-element-property :html entity))
1142
1143 ;;;; Example Block
1144
1145 (defun org-gpgweb-example-block (example-block contents info)
1146   "Transcode a EXAMPLE-BLOCK element from Org to HTML.
1147 CONTENTS is nil.  INFO is a plist holding contextual
1148 information."
1149   (if (org-export-read-attribute :attr_html example-block :textarea)
1150       (org-gpgweb--textarea-block example-block)
1151     (format "<pre class=\"example\">\n%s</pre>"
1152             (org-gpgweb-format-code example-block info))))
1153
1154 ;;;; Export Snippet
1155
1156 (defun org-gpgweb-export-snippet (export-snippet contents info)
1157   "Transcode a EXPORT-SNIPPET object from Org to HTML.
1158 CONTENTS is nil.  INFO is a plist holding contextual
1159 information."
1160   (when (eq (org-export-snippet-backend export-snippet) 'html)
1161     (org-element-property :value export-snippet)))
1162
1163 ;;;; Export Block
1164
1165 (defun org-gpgweb-export-block (export-block contents info)
1166   "Transcode an EXPORT-BLOCK element from Org to HTML.
1167 CONTENTS is nil.  INFO is a plist holding contextual information."
1168   (when (string= (org-element-property :type export-block) "HTML")
1169     (org-remove-indentation (org-element-property :value export-block))))
1170
1171 ;;;; Fixed Width
1172
1173 (defun org-gpgweb-fixed-width (fixed-width contents info)
1174   "Transcode a FIXED-WIDTH element from Org to HTML.
1175 CONTENTS is nil.  INFO is a plist holding contextual information."
1176   (format "<pre class=\"example\">\n%s</pre>"
1177           (org-gpgweb-do-format-code
1178            (org-remove-indentation
1179             (org-element-property :value fixed-width)))))
1180
1181 ;;;; Footnote Reference
1182
1183 (defun org-gpgweb-footnote-reference (footnote-reference contents info)
1184   "Transcode a FOOTNOTE-REFERENCE element from Org to HTML.
1185 CONTENTS is nil.  INFO is a plist holding contextual information."
1186   (concat
1187    ;; Insert separator between two footnotes in a row.
1188    (let ((prev (org-export-get-previous-element footnote-reference info)))
1189      (when (eq (org-element-type prev) 'footnote-reference)
1190         "<sup>, </sup>"))
1191    (let* ((n (org-export-get-footnote-number footnote-reference info))
1192           (id (format "fnr.%d%s"
1193                       n
1194                       (if (org-export-footnote-first-reference-p
1195                            footnote-reference info)
1196                           ""
1197                         ".100"))))
1198      (format
1199       "<sup>%s</sup>"
1200       (org-gpgweb--anchor
1201        id n (format " class=\"footref\" href=\"#fn.%d\"" n) info)))))
1202
1203 ;;;; Headline
1204
1205 (defun org-gpgweb-headline (headline contents info)
1206   "Transcode a HEADLINE element from Org to HTML.
1207 CONTENTS holds the contents of the headline.  INFO is a plist
1208 holding contextual information."
1209   (let* ((numberedp (org-export-numbered-headline-p headline info))
1210          (level (+ (org-export-get-relative-level headline info)
1211                    (1- (plist-get info :html-toplevel-hlevel))))
1212          (todo (and (plist-get info :with-todo-keywords)
1213                     (let ((todo (org-element-property :todo-keyword headline)))
1214                       (and todo (org-export-data todo info)))))
1215          (todo-type (and todo (org-element-property :todo-type headline)))
1216          (priority (and (plist-get info :with-priority)
1217                         (org-element-property :priority headline)))
1218          (text (org-export-data (org-element-property :title headline) info))
1219          (tags (and (plist-get info :with-tags)
1220                     (org-export-get-tags headline info)))
1221          (full-text (org-gpgweb-format-headline-function
1222                              todo todo-type priority text tags info))
1223          (contents (or contents "")))
1224     (cond
1225      ;; Case 1: This is a footnote section: ignore it.
1226      ((org-element-property :footnote-section-p headline) nil)
1227      ;; Case 2: This is a deep sub-tree: export it as a list item.
1228      ;;         Also export as items headlines for which no section
1229      ;;         format has been found.
1230      ((org-export-low-level-p headline info)
1231       ;; Build the real contents of the sub-tree.
1232       (let* ((type (if numberedp 'ordered 'unordered))
1233              (itemized-body (org-gpgweb-format-list-item
1234                              contents type nil info nil full-text)))
1235         (concat (and (org-export-first-sibling-p headline info)
1236                      (org-gpgweb-begin-plain-list type))
1237                 itemized-body
1238                 (and (org-export-last-sibling-p headline info)
1239                      (org-gpgweb-end-plain-list type)))))
1240      ;; Case 3: Standard headline.  Export it as a section.
1241      (t
1242       (let* ((numbers (org-export-get-headline-number headline info))
1243              (section-number (mapconcat #'number-to-string numbers "-"))
1244              (ids (remq nil
1245                         (list (org-element-property :CUSTOM_ID headline)
1246                               (concat "sec-" section-number)
1247                               (org-element-property :ID headline))))
1248              (preferred-id (car ids))
1249              (extra-ids (cdr ids))
1250              (extra-class (org-element-property :HTML_CONTAINER_CLASS headline))
1251              (first-content (car (org-element-contents headline))))
1252         (format "<h%d id=\"%s\">%s%s</h%d>\n%s\n"
1253                 ; h?
1254                 level
1255                 ; id=?
1256                 preferred-id
1257                 ; insert anchors
1258                 (mapconcat
1259                  (lambda (x)
1260                    (let ((id (org-export-solidify-link-text
1261                               (if (org-uuidgen-p x) (concat "ID-" x)
1262                                 x))))
1263                      (org-gpgweb--anchor id nil nil info)))
1264                  extra-ids "")
1265                 ; text of header
1266                 (concat
1267                  (and numberedp
1268                       (format
1269                        "<span class=\"section-number-%d\">%s</span> "
1270                        level
1271                        (mapconcat #'number-to-string numbers ".")))
1272                  full-text)
1273                 ; /h?
1274                 level
1275                 ; the content of the section
1276                 contents))))))
1277
1278 (defun org-gpgweb-format-headline-function
1279   (todo todo-type priority text tags info)
1280   "Function to format headline text.
1281
1282 This function will be called with six arguments:
1283 TODO      the todo keyword (string or nil).
1284 TODO-TYPE the type of todo (symbol: `todo', `done', nil)
1285 PRIORITY  the priority of the headline (integer or nil)
1286 TEXT      the main headline text (string).
1287 TAGS      the tags (string or nil).
1288 INFO      the export options (plist).
1289
1290 The function result will be used in the section format string."
1291   (let ((todo (org-gpgweb--todo todo info))
1292         (tags (org-gpgweb--tags tags info)))
1293     (concat todo (and todo " ") text (and tags "&#xa0;&#xa0;&#xa0;") tags)))
1294
1295 ;;;; Horizontal Rule
1296
1297 (defun org-gpgweb-horizontal-rule (horizontal-rule contents info)
1298   "Transcode an HORIZONTAL-RULE  object from Org to HTML.
1299 CONTENTS is nil.  INFO is a plist holding contextual information."
1300   (org-gpgweb-close-tag "hr" nil info))
1301
1302 ;;;; Inline Src Block
1303
1304 (defun org-gpgweb-inline-src-block (inline-src-block contents info)
1305   "Transcode an INLINE-SRC-BLOCK element from Org to HTML.
1306 CONTENTS holds the contents of the item.  INFO is a plist holding
1307 contextual information."
1308   (let* ((org-lang (org-element-property :language inline-src-block))
1309          (code (org-element-property :value inline-src-block)))
1310     (let ((lang (org-element-property :language inline-src-block))
1311           (code (org-gpgweb-format-code inline-src-block info))
1312           (label (let ((lbl (org-element-property :name inline-src-block)))
1313                    (if (not lbl) ""
1314                        (format " id=\"%s\""
1315                                (org-export-solidify-link-text lbl))))))
1316       (format "<code class=\"src src-%s\"%s>%s</code>" lang label code))))
1317
1318 ;;;; Inlinetask
1319
1320 (defun org-gpgweb-inlinetask (inlinetask contents info)
1321   "Transcode an INLINETASK element from Org to HTML.
1322 CONTENTS holds the contents of the block.  INFO is a plist
1323 holding contextual information."
1324   (let* ((todo (and (plist-get info :with-todo-keywords)
1325                     (let ((todo (org-element-property :todo-keyword inlinetask)))
1326                       (and todo (org-export-data todo info)))))
1327          (todo-type (and todo (org-element-property :todo-type inlinetask)))
1328          (priority (and (plist-get info :with-priority)
1329                         (org-element-property :priority inlinetask)))
1330          (text (org-export-data (org-element-property :title inlinetask) info))
1331          (tags (and (plist-get info :with-tags)
1332                     (org-export-get-tags inlinetask info))))
1333     (funcall org-gpgweb-format-inlinetask-function
1334              todo todo-type priority text tags contents)))
1335
1336 (defun org-gpgweb-format-inlinetask-function
1337   (todo todo-type priority text tags contents info)
1338   "Function called to format an inlinetask in HTML code.
1339
1340 The function must accept seven parameters:
1341   TODO      the todo keyword, as a string
1342   TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
1343   PRIORITY  the inlinetask priority, as a string
1344   NAME      the inlinetask name, as a string.
1345   TAGS      the inlinetask tags, as a list of strings.
1346   CONTENTS  the contents of the inlinetask, as a string.
1347   INFO      the export options, as a plist
1348
1349 The function should return the string to be exported."
1350   (format "<div class=\"inlinetask\">\n<b>%s</b>%s\n%s</div>"
1351           (org-gpgweb-format-headline-function
1352            todo todo-type priority text tags info)
1353           (org-gpgweb-close-tag "br" nil info)
1354           contents))
1355
1356 ;;;; Italic
1357
1358 (defun org-gpgweb-italic (italic contents info)
1359   "Transcode ITALIC from Org to HTML.
1360 CONTENTS is the text with italic markup.  INFO is a plist holding
1361 contextual information."
1362   (format "<i>%s</i>" contents))
1363
1364 ;;;; Item
1365
1366 (defun org-gpgweb-checkbox (checkbox info)
1367   "Format CHECKBOX into HTML.
1368 INFO is a plist holding contextual information.  See
1369 `org-gpgweb-checkbox-type' for customization options."
1370   (cdr (assq checkbox
1371              (cdr (assq (plist-get info :html-checkbox-type)
1372                         org-gpgweb-checkbox-types)))))
1373
1374 (defun org-gpgweb-format-list-item (contents type checkbox info
1375                                              &optional term-counter-id
1376                                              headline)
1377   "Format a list item into HTML."
1378   (let ((class (if checkbox
1379                    (format " class=\"%s\""
1380                            (symbol-name checkbox)) ""))
1381         (checkbox (concat (org-gpgweb-checkbox checkbox info)
1382                           (and checkbox " ")))
1383         (br (org-gpgweb-close-tag "br" nil info)))
1384     (concat
1385      (case type
1386        (ordered
1387         (let* ((counter term-counter-id)
1388                (extra (if counter (format " value=\"%s\"" counter) "")))
1389           (concat
1390            (format "<li%s%s>" class extra)
1391            (when headline (concat headline br)))))
1392        (unordered
1393         (let* ((id term-counter-id)
1394                (extra (if id (format " id=\"%s\"" id) "")))
1395           (concat
1396            (format "<li%s%s>" class extra)
1397            (when headline (concat headline br)))))
1398        (descriptive
1399         (let* ((term term-counter-id))
1400           (setq term (or term "(no term)"))
1401           ;; Check-boxes in descriptive lists are associated to tag.
1402           (concat (format "<dt%s>%s</dt>"
1403                           class (concat checkbox term))
1404                   "<dd>"))))
1405      (unless (eq type 'descriptive) checkbox)
1406      contents
1407      (case type
1408        (ordered "</li>")
1409        (unordered "</li>")
1410        (descriptive "</dd>")))))
1411
1412 (defun org-gpgweb-item (item contents info)
1413   "Transcode an ITEM element from Org to HTML.
1414 CONTENTS holds the contents of the item.  INFO is a plist holding
1415 contextual information."
1416   (let* ((plain-list (org-export-get-parent item))
1417          (type (org-element-property :type plain-list))
1418          (counter (org-element-property :counter item))
1419          (checkbox (org-element-property :checkbox item))
1420          (tag (let ((tag (org-element-property :tag item)))
1421                 (and tag (org-export-data tag info)))))
1422     (org-gpgweb-format-list-item
1423      contents type checkbox info (or tag counter))))
1424
1425 ;;;; Keyword
1426
1427 (defun org-gpgweb-keyword (keyword contents info)
1428   "Transcode a KEYWORD element from Org to HTML.
1429 CONTENTS is nil.  INFO is a plist holding contextual information."
1430   (let ((key (org-element-property :key keyword))
1431         (value (org-element-property :value keyword)))
1432     (cond
1433      ((string= key "HTML") value)
1434      ((string= key "TOC")
1435       (let ((value (downcase value)))
1436         (cond
1437          ((string-match "\\<headlines\\>" value)
1438           (let ((depth (or (and (string-match "[0-9]+" value)
1439                                 (string-to-number (match-string 0 value)))
1440                            (plist-get info :with-toc))))
1441             (org-gpgweb-toc depth info)))
1442          ((string= "listings" value) (org-gpgweb-list-of-listings info))
1443          ((string= "tables" value) (org-gpgweb-list-of-tables info))))))))
1444
1445 ;;;; Latex Environment
1446
1447 (defun org-gpgweb-format-latex (latex-frag processing-type info)
1448   "Format a LaTeX fragment LATEX-FRAG into HTML.
1449 PROCESSING-TYPE designates the tool used for conversion.  It is
1450 a symbol among `mathjax', `dvipng', `imagemagick', `verbatim' nil
1451 and t.  See `org-gpgweb-with-latex' for more information.  INFO is
1452 a plist containing export properties."
1453   (let ((cache-relpath "") (cache-dir ""))
1454     (unless (eq processing-type 'mathjax)
1455       (let ((bfn (or (buffer-file-name)
1456                      (make-temp-name
1457                       (expand-file-name "latex" temporary-file-directory))))
1458             (latex-header
1459              (let ((header (plist-get info :latex-header)))
1460                (and header
1461                     (concat (mapconcat
1462                              (lambda (line) (concat "#+LATEX_HEADER: " line))
1463                              (org-split-string header "\n")
1464                              "\n")
1465                             "\n")))))
1466         (setq cache-relpath
1467               (concat "ltxpng/"
1468                       (file-name-sans-extension
1469                        (file-name-nondirectory bfn)))
1470               cache-dir (file-name-directory bfn))
1471         ;; Re-create LaTeX environment from original buffer in
1472         ;; temporary buffer so that dvipng/imagemagick can properly
1473         ;; turn the fragment into an image.
1474         (setq latex-frag (concat latex-header latex-frag))))
1475     (with-temp-buffer
1476       (insert latex-frag)
1477       (org-format-latex cache-relpath cache-dir nil "Creating LaTeX Image..."
1478                         nil nil processing-type)
1479       (buffer-string))))
1480
1481 (defun org-gpgweb-latex-environment (latex-environment contents info)
1482   "Transcode a LATEX-ENVIRONMENT element from Org to HTML.
1483 CONTENTS is nil.  INFO is a plist holding contextual information."
1484   (let ((processing-type (plist-get info :with-latex))
1485         (latex-frag (org-remove-indentation
1486                      (org-element-property :value latex-environment)))
1487         (attributes (org-export-read-attribute :attr_html latex-environment)))
1488     (case processing-type
1489       ((t mathjax)
1490        (org-gpgweb-format-latex latex-frag 'mathjax info))
1491       ((dvipng imagemagick)
1492        (let ((formula-link
1493               (org-gpgweb-format-latex latex-frag processing-type info)))
1494          (when (and formula-link (string-match "file:\\([^]]*\\)" formula-link))
1495            ;; Do not provide a caption or a name to be consistent with
1496            ;; `mathjax' handling.
1497            (org-gpgweb--wrap-image
1498             (org-gpgweb--format-image
1499              (match-string 1 formula-link) attributes info) info))))
1500       (t latex-frag))))
1501
1502 ;;;; Latex Fragment
1503
1504 (defun org-gpgweb-latex-fragment (latex-fragment contents info)
1505   "Transcode a LATEX-FRAGMENT object from Org to HTML.
1506 CONTENTS is nil.  INFO is a plist holding contextual information."
1507   (let ((latex-frag (org-element-property :value latex-fragment))
1508         (processing-type (plist-get info :with-latex)))
1509     (case processing-type
1510       ((t mathjax)
1511        (org-gpgweb-format-latex latex-frag 'mathjax info))
1512       ((dvipng imagemagick)
1513        (let ((formula-link
1514               (org-gpgweb-format-latex latex-frag processing-type info)))
1515          (when (and formula-link (string-match "file:\\([^]]*\\)" formula-link))
1516            (org-gpgweb--format-image (match-string 1 formula-link) nil info))))
1517       (t latex-frag))))
1518
1519 ;;;; Line Break
1520
1521 (defun org-gpgweb-line-break (line-break contents info)
1522   "Transcode a LINE-BREAK object from Org to HTML.
1523 CONTENTS is nil.  INFO is a plist holding contextual information."
1524   (concat (org-gpgweb-close-tag "br" nil info) "\n"))
1525
1526 ;;;; Link
1527
1528 (defun org-gpgweb-inline-image-p (link info)
1529   "Non-nil when LINK is meant to appear as an image.
1530 INFO is a plist used as a communication channel.  LINK is an
1531 inline image when it has no description and targets an image
1532 file (see `org-gpgweb-inline-image-rules' for more information), or
1533 if its description is a single link targeting an image file."
1534   (if (not (org-element-contents link))
1535       (org-export-inline-image-p
1536        link (plist-get info :html-inline-image-rules))
1537     (not
1538      (let ((link-count 0))
1539        (org-element-map (org-element-contents link)
1540            (cons 'plain-text org-element-all-objects)
1541          (lambda (obj)
1542            (case (org-element-type obj)
1543              (plain-text (org-string-nw-p obj))
1544              (link (if (= link-count 1) t
1545                      (incf link-count)
1546                      (not (org-export-inline-image-p
1547                            obj (plist-get info :html-inline-image-rules)))))
1548              (otherwise t)))
1549          info t)))))
1550
1551 (defvar org-gpgweb-standalone-image-predicate)
1552 (defun org-gpgweb-standalone-image-p (element info)
1553   "Non-nil if ELEMENT is a standalone image.
1554
1555 INFO is a plist holding contextual information.
1556
1557 An element or object is a standalone image when
1558
1559   - its type is `paragraph' and its sole content, save for white
1560     spaces, is a link that qualifies as an inline image;
1561
1562   - its type is `link' and its containing paragraph has no other
1563     content save white spaces.
1564
1565 Bind `org-gpgweb-standalone-image-predicate' to constrain paragraph
1566 further.  For example, to check for only captioned standalone
1567 images, set it to:
1568
1569   \(lambda (paragraph) (org-element-property :caption paragraph))"
1570   (let ((paragraph (case (org-element-type element)
1571                      (paragraph element)
1572                      (link (org-export-get-parent element)))))
1573     (and (eq (org-element-type paragraph) 'paragraph)
1574          (or (not (fboundp 'org-gpgweb-standalone-image-predicate))
1575              (funcall org-gpgweb-standalone-image-predicate paragraph))
1576          (catch 'exit
1577            (let ((link-count 0))
1578              (org-element-map (org-element-contents paragraph)
1579                  (cons 'plain-text org-element-all-objects)
1580                #'(lambda (obj)
1581                    (when (case (org-element-type obj)
1582                            (plain-text (org-string-nw-p obj))
1583                            (link (or (> (incf link-count) 1)
1584                                      (not (org-gpgweb-inline-image-p obj info))))
1585                            (otherwise t))
1586                      (throw 'exit nil)))
1587                info nil 'link)
1588              (= link-count 1))))))
1589
1590 (defun org-gpgweb-link (link desc info)
1591   "Transcode a LINK object from Org to HTML.
1592
1593 DESC is the description part of the link, or the empty string.
1594 INFO is a plist holding contextual information.  See
1595 `org-export-data'."
1596   (let* ((link-org-files-as-html-maybe
1597           (function
1598            (lambda (raw-path info)
1599              "Treat links to `file.org' as links to `file.html', if needed."
1600              (cond
1601               ((string= ".org" (downcase (file-name-extension raw-path ".")))
1602                (concat (file-name-sans-extension raw-path) "."
1603                         org-gpgweb-extension))
1604               (t raw-path)))))
1605          (type (org-element-property :type link))
1606          (raw-path (org-element-property :path link))
1607          ;; Ensure DESC really exists, or set it to nil.
1608          (desc (org-string-nw-p desc))
1609          (path
1610           (cond
1611            ((member type '("http" "https" "ftp" "mailto"))
1612              ;(org-link-escape-browser
1613              ; (org-link-unescape (concat type ":" raw-path))))
1614              (concat type ":" raw-path))
1615            ((string= type "file")
1616             ;; Treat links to ".org" files as ".html".
1617             (setq raw-path
1618                   (funcall link-org-files-as-html-maybe raw-path info))
1619             ;; If file path is absolute, prepend it with protocol
1620             ;; component - "file:".
1621             ;(cond
1622             ; ((file-name-absolute-p raw-path)
1623             ;  (setq raw-path (concat "file:" raw-path))))
1624             ;; Add search option, if any.  A search option can be
1625             ;; relative to a custom-id or a headline title.  Append
1626             ;; a hash sign to any unresolved option, as it might point
1627             ;; to a target.
1628             (let ((option (org-element-property :search-option link)))
1629               (cond ((not option) raw-path)
1630                     ((eq (aref option 0) ?#) (concat raw-path option))
1631                     (t
1632                      (let ((destination
1633                             (org-publish-resolve-external-fuzzy-link
1634                              (org-element-property :path link) option)))
1635                        (concat raw-path
1636                                (if (not destination) (concat "#" option)
1637                                  (concat "#sec-"
1638                                          (mapconcat #'number-to-string
1639                                                     destination "-")))))))))
1640            (t raw-path)))
1641          ;; Extract attributes from parent's paragraph.  HACK: Only do
1642          ;; this for the first link in parent (inner image link for
1643          ;; inline images).  This is needed as long as attributes
1644          ;; cannot be set on a per link basis.
1645          (attributes-plist
1646           (let* ((parent (org-export-get-parent-element link))
1647                  (link (let ((container (org-export-get-parent link)))
1648                          (if (and (eq (org-element-type container) 'link)
1649                                   (org-gpgweb-inline-image-p link info))
1650                              container
1651                            link))))
1652             (and (eq (org-element-map parent 'link 'identity info t) link)
1653                  (org-export-read-attribute :attr_html parent))))
1654          (attributes
1655           (let ((attr (org-gpgweb--make-attribute-string attributes-plist)))
1656             (if (org-string-nw-p attr) (concat " " attr) "")))
1657          protocol)
1658     (cond
1659      ;; Image file.
1660      ((and (plist-get info :html-inline-images)
1661            (org-export-inline-image-p
1662             link (plist-get info :html-inline-image-rules)))
1663       (org-gpgweb--format-image path attributes-plist info))
1664      ;; Radio target: Transcode target's contents and use them as
1665      ;; link's description.
1666      ((string= type "radio")
1667       (let ((destination (org-export-resolve-radio-link link info)))
1668         (when destination
1669           (format "<a href=\"#%s\"%s>%s</a>"
1670                   (org-export-solidify-link-text
1671                    (org-element-property :value destination))
1672                   attributes desc))))
1673      ;; Links pointing to a headline: Find destination and build
1674      ;; appropriate referencing command.
1675      ((member type '("custom-id" "fuzzy" "id"))
1676       (let ((destination (if (string= type "fuzzy")
1677                              (org-export-resolve-fuzzy-link link info)
1678                            (org-export-resolve-id-link link info))))
1679         (case (org-element-type destination)
1680           ;; ID link points to an external file.
1681           (plain-text
1682            (let ((fragment (concat "ID-" path))
1683                  ;; Treat links to ".org" files as ".html", if needed.
1684                  (path (funcall link-org-files-as-html-maybe
1685                                 destination info)))
1686              (format "<a href=\"%s#%s\"%s>%s</a>"
1687                      path fragment attributes (or desc destination))))
1688           ;; Fuzzy link points nowhere.
1689           ((nil)
1690            (format "<i>%s</i>"
1691                    (or desc
1692                        (org-export-data
1693                         (org-element-property :raw-link link) info))))
1694           ;; Link points to a headline.
1695           (headline
1696            (let ((href
1697                   ;; What href to use?
1698                   (cond
1699                    ;; Case 1: Headline is linked via it's CUSTOM_ID
1700                    ;; property.  Use CUSTOM_ID.
1701                    ((string= type "custom-id")
1702                     (org-element-property :CUSTOM_ID destination))
1703                    ;; Case 2: Headline is linked via it's ID property
1704                    ;; or through other means.  Use the default href.
1705                    ((member type '("id" "fuzzy"))
1706                     (format "sec-%s"
1707                             (mapconcat 'number-to-string
1708                                        (org-export-get-headline-number
1709                                         destination info) "-")))
1710                    (t (error "Shouldn't reach here"))))
1711                  ;; What description to use?
1712                  (desc
1713                   ;; Case 1: Headline is numbered and LINK has no
1714                   ;; description.  Display section number.
1715                   (if (and (org-export-numbered-headline-p destination info)
1716                            (not desc))
1717                       (mapconcat 'number-to-string
1718                                  (org-export-get-headline-number
1719                                   destination info) ".")
1720                     ;; Case 2: Either the headline is un-numbered or
1721                     ;; LINK has a custom description.  Display LINK's
1722                     ;; description or headline's title.
1723                     (or desc (org-export-data (org-element-property
1724                                                :title destination) info)))))
1725              (format "<a href=\"#%s\"%s>%s</a>"
1726                      (org-export-solidify-link-text href) attributes desc)))
1727           ;; Fuzzy link points to a target or an element.
1728           (t
1729            (let* ((path (org-export-solidify-link-text path))
1730                   (org-gpgweb-standalone-image-predicate 'org-gpgweb--has-caption-p)
1731                   (number (cond
1732                            (desc nil)
1733                            ((org-gpgweb-standalone-image-p destination info)
1734                             (org-export-get-ordinal
1735                              (org-element-map destination 'link
1736                                'identity info t)
1737                              info 'link 'org-gpgweb-standalone-image-p))
1738                            (t (org-export-get-ordinal
1739                                destination info nil 'org-gpgweb--has-caption-p))))
1740                   (desc (cond (desc)
1741                               ((not number) "No description for this link")
1742                               ((numberp number) (number-to-string number))
1743                               (t (mapconcat 'number-to-string number ".")))))
1744              (format "<a href=\"#%s\"%s>%s</a>" path attributes desc))))))
1745      ;; Coderef: replace link with the reference name or the
1746      ;; equivalent line number.
1747      ((string= type "coderef")
1748       (let ((fragment (concat "coderef-" path)))
1749         (format "<a href=\"#%s\"%s%s>%s</a>"
1750                 fragment
1751                 (org-trim
1752                  (format (concat "class=\"coderef\""
1753                                  " onmouseover=\"CodeHighlightOn(this, '%s');\""
1754                                  " onmouseout=\"CodeHighlightOff(this, '%s');\"")
1755                          fragment fragment))
1756                 attributes
1757                 (format (org-export-get-coderef-format path desc)
1758                         (org-export-resolve-coderef path info)))))
1759      ;; Link type is handled by a special function.
1760      ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
1761       (funcall protocol (org-link-unescape path) desc 'gpgweb))
1762      ;; External link with a description part.
1763      ((and path desc) (format "<a href=\"%s\"%s>%s</a>" path attributes desc))
1764      ;; External link without a description part.
1765      (path (format "<a href=\"%s\"%s>%s</a>" path attributes path))
1766      ;; No path, only description.  Try to do something useful.
1767      (t (format "<i>%s</i>" desc)))))
1768
1769 ;;;; Node Property
1770
1771 (defun org-gpgweb-node-property (node-property contents info)
1772   "Transcode a NODE-PROPERTY element from Org to HTML.
1773 CONTENTS is nil.  INFO is a plist holding contextual
1774 information."
1775   (format "%s:%s"
1776           (org-element-property :key node-property)
1777           (let ((value (org-element-property :value node-property)))
1778             (if value (concat " " value) ""))))
1779
1780 ;;;; Paragraph
1781
1782 (defun org-gpgweb-paragraph (paragraph contents info)
1783   "Transcode a PARAGRAPH element from Org to HTML.
1784 CONTENTS is the contents of the paragraph, as a string.  INFO is
1785 the plist used as a communication channel."
1786   (let* ((parent (org-export-get-parent paragraph))
1787          (parent-type (org-element-type parent))
1788          (style '((footnote-definition " class=\"footpara\"")))
1789          (attributes (org-gpgweb--make-attribute-string
1790                       (org-export-read-attribute :attr_html paragraph)))
1791          (extra (or (cadr (assoc parent-type style)) "")))
1792     (cond
1793      ((and (eq (org-element-type parent) 'item)
1794            (= (org-element-property :begin paragraph)
1795               (org-element-property :contents-begin parent))
1796            (not (org-element-map (org-export-get-parent parent) 'item
1797                   (lambda (item)
1798                     (let ((contents (org-element-contents item)))
1799                       (and contents
1800                            (or (cdr contents)
1801                                (not (eq (org-element-type (car contents))
1802                                         'paragraph))))))
1803                   info 'first-match 'item)))
1804       ;; Leading paragraph in a list item have no tags if every
1805       ;; element of the containing list is only a single paragraph.
1806       contents)
1807      ((org-gpgweb-standalone-image-p paragraph info)
1808       ;; Standalone image.
1809       (let ((caption
1810              (let ((raw (org-export-data
1811                          (org-export-get-caption paragraph) info))
1812                    (org-gpgweb-standalone-image-predicate
1813                     'org-gpgweb--has-caption-p))
1814                (if (not (org-string-nw-p raw)) raw
1815                  (concat
1816                   "<span class=\"figure-number\">"
1817                   (format (org-gpgweb--translate "Figure %d:" info)
1818                           (org-export-get-ordinal
1819                            (org-element-map paragraph 'link
1820                              'identity info t)
1821                            info nil 'org-gpgweb-standalone-image-p))
1822                   "</span> " raw))))
1823             (label (org-element-property :name paragraph)))
1824         (org-gpgweb--wrap-image contents info caption label)))
1825      ;; Regular paragraph.
1826      (t (format "<p%s%s>\n%s</p>"
1827                 (if (org-string-nw-p attributes)
1828                     (concat " " attributes) "")
1829                 extra contents)))))
1830
1831 ;;;; Plain List
1832
1833 ;; FIXME Maybe arg1 is not needed because <li value="20"> already sets
1834 ;; the correct value for the item counter
1835 (defun org-gpgweb-begin-plain-list (type &optional arg1)
1836   "Insert the beginning of the HTML list depending on TYPE.
1837 When ARG1 is a string, use it as the start parameter for ordered
1838 lists."
1839   (case type
1840     (ordered
1841      (format "<ol%s>"
1842              (if arg1 (format " start=\"%d\"" arg1) "")))
1843     (unordered "<ul>")
1844     (descriptive "<dl>")))
1845
1846 (defun org-gpgweb-end-plain-list (type)
1847   "Insert the end of the HTML list depending on TYPE."
1848   (case type
1849     (ordered "</ol>")
1850     (unordered "</ul>")
1851     (descriptive "</dl>")))
1852
1853 (defun org-gpgweb-plain-list (plain-list contents info)
1854   "Transcode a PLAIN-LIST element from Org to HTML.
1855 CONTENTS is the contents of the list.  INFO is a plist holding
1856 contextual information."
1857   (let* (arg1 ;; (assoc :counter (org-element-map plain-list 'item
1858          (type (org-element-property :type plain-list)))
1859     (format "%s\n%s%s"
1860             (org-gpgweb-begin-plain-list type)
1861             contents (org-gpgweb-end-plain-list type))))
1862
1863 ;;;; Plain Text
1864
1865 (defun org-gpgweb-convert-special-strings (string)
1866   "Convert special characters in STRING to HTML."
1867   (let ((all org-gpgweb-special-string-regexps)
1868         e a re rpl start)
1869     (while (setq a (pop all))
1870       (setq re (car a) rpl (cdr a) start 0)
1871       (while (string-match re string start)
1872         (setq string (replace-match rpl t nil string))))
1873     string))
1874
1875 (defun org-gpgweb-encode-plain-text (text)
1876   "Convert plain text characters from TEXT to HTML equivalent.
1877 Possible conversions are set in `org-gpgweb-protect-char-alist'."
1878   (mapc
1879    (lambda (pair)
1880      (setq text (replace-regexp-in-string (car pair) (cdr pair) text t t)))
1881    org-gpgweb-protect-char-alist)
1882   text)
1883
1884 (defun org-gpgweb-plain-text (text info)
1885   "Transcode a TEXT string from Org to HTML.
1886 TEXT is the string to transcode.  INFO is a plist holding
1887 contextual information."
1888   (let ((output text))
1889     ;; Protect following characters: <, >, &.
1890     (setq output (org-gpgweb-encode-plain-text output))
1891     ;; Handle smart quotes.  Be sure to provide original string since
1892     ;; OUTPUT may have been modified.
1893     (when (plist-get info :with-smart-quotes)
1894       (setq output (org-export-activate-smart-quotes output :html info text)))
1895     ;; Handle special strings.
1896     (when (plist-get info :with-special-strings)
1897       (setq output (org-gpgweb-convert-special-strings output)))
1898     ;; Handle break preservation if required.
1899     (when (plist-get info :preserve-breaks)
1900       (setq output
1901             (replace-regexp-in-string
1902              "\\(\\\\\\\\\\)?[ \t]*\n"
1903              (concat (org-gpgweb-close-tag "br" nil info) "\n") output)))
1904     ;; Return value.
1905     output))
1906
1907
1908 ;; Planning
1909
1910 (defun org-gpgweb-planning (planning contents info)
1911   "Transcode a PLANNING element from Org to HTML.
1912 CONTENTS is nil.  INFO is a plist used as a communication
1913 channel."
1914   (let ((span-fmt "<span class=\"timestamp-kwd\">%s</span> <span class=\"timestamp\">%s</span>"))
1915     (format
1916      "<p><span class=\"timestamp-wrapper\">%s</span></p>"
1917      (mapconcat
1918       'identity
1919       (delq nil
1920             (list
1921              (let ((closed (org-element-property :closed planning)))
1922                (when closed
1923                  (format span-fmt org-closed-string
1924                          (org-translate-time
1925                           (org-element-property :raw-value closed)))))
1926              (let ((deadline (org-element-property :deadline planning)))
1927                (when deadline
1928                  (format span-fmt org-deadline-string
1929                          (org-translate-time
1930                           (org-element-property :raw-value deadline)))))
1931              (let ((scheduled (org-element-property :scheduled planning)))
1932                (when scheduled
1933                  (format span-fmt org-scheduled-string
1934                          (org-translate-time
1935                           (org-element-property :raw-value scheduled)))))))
1936       " "))))
1937
1938 ;;;; Property Drawer
1939
1940 (defun org-gpgweb-property-drawer (property-drawer contents info)
1941   "Transcode a PROPERTY-DRAWER element from Org to HTML.
1942 CONTENTS holds the contents of the drawer.  INFO is a plist
1943 holding contextual information."
1944   (and nil
1945        (org-string-nw-p contents)
1946        (format "<pre class=\"example\">\n%s</pre>" contents)))
1947
1948 ;;;; Quote Block
1949
1950 (defun org-gpgweb-quote-block (quote-block contents info)
1951   "Transcode a QUOTE-BLOCK element from Org to HTML.
1952 CONTENTS holds the contents of the block.  INFO is a plist
1953 holding contextual information."
1954   (format "<blockquote>\n%s</blockquote>" contents))
1955
1956 ;;;; Section
1957
1958 (defun org-gpgweb-section (section contents info)
1959   "Transcode a SECTION element from Org to HTML.
1960 CONTENTS holds the contents of the section.  INFO is a plist
1961 holding contextual information."
1962   (let ((parent (org-export-get-parent-headline section)))
1963     ;; Before first headline: no container, just return CONTENTS.
1964     (if (not parent) contents
1965       ;; Get div's class and id references.
1966       (let* ((class-num (+ (org-export-get-relative-level parent info)
1967                            (1- (plist-get info :html-toplevel-hlevel))))
1968              (section-number
1969               (mapconcat
1970                'number-to-string
1971                (org-export-get-headline-number parent info) "-")))
1972         ;; Build return value.
1973         (format "<div class=\"outline-text-%d\" id=\"text-%s\">\n%s</div>"
1974                 class-num
1975                 (or (org-element-property :CUSTOM_ID parent) section-number)
1976                 contents)))))
1977
1978 ;;;; Radio Target
1979
1980 (defun org-gpgweb-radio-target (radio-target text info)
1981   "Transcode a RADIO-TARGET object from Org to HTML.
1982 TEXT is the text of the target.  INFO is a plist holding
1983 contextual information."
1984   (let ((id (org-export-solidify-link-text
1985              (org-element-property :value radio-target))))
1986     (org-gpgweb--anchor id text nil info)))
1987
1988 ;;;; Special Block
1989
1990 (defun org-gpgweb-special-block (special-block contents info)
1991   "Transcode a SPECIAL-BLOCK element from Org to HTML.
1992 CONTENTS holds the contents of the block.  INFO is a plist
1993 holding contextual information."
1994   (if (org-export-raw-special-block-p special-block info)
1995       (org-remove-indentation (org-element-property :raw-value special-block))
1996     (let* ((block-type (downcase (org-element-property :type special-block)))
1997            (contents (or contents ""))
1998            (html5-fancy (and (org-gpgweb-html5-p info)
1999                              (plist-get info :html-html5-fancy)
2000                              (member block-type org-gpgweb-html5-elements)))
2001            (attributes (org-export-read-attribute :attr_html special-block)))
2002       (unless html5-fancy
2003         (let ((class (plist-get attributes :class)))
2004           (setq attributes (plist-put attributes :class
2005                                       (if class (concat class " " block-type)
2006                                         block-type)))))
2007       (setq attributes (org-gpgweb--make-attribute-string attributes))
2008       (when (not (equal attributes ""))
2009         (setq attributes (concat " " attributes)))
2010       (if html5-fancy
2011           (format "<%s%s>\n%s</%s>" block-type attributes contents block-type)
2012         (format "<div%s>\n%s\n</div>" attributes contents)))))
2013
2014 ;;;; Src Block
2015
2016 (defun org-gpgweb-src-block (src-block contents info)
2017   "Transcode a SRC-BLOCK element from Org to HTML.
2018 CONTENTS holds the contents of the item.  INFO is a plist holding
2019 contextual information."
2020   (if (org-export-read-attribute :attr_html src-block :textarea)
2021       (org-gpgweb--textarea-block src-block)
2022     (let ((lang (org-element-property :language src-block))
2023           (caption (org-export-get-caption src-block))
2024           (code (org-gpgweb-format-code src-block info))
2025           (label (let ((lbl (org-element-property :name src-block)))
2026                    (if (not lbl) ""
2027                      (format " id=\"%s\""
2028                              (org-export-solidify-link-text lbl))))))
2029       (if (not lang) (format "<pre class=\"example\"%s>\n%s</pre>" label code)
2030         (format
2031          "<div class=\"org-src-container\">\n%s%s\n</div>"
2032          (if (not caption) ""
2033            (format "<label class=\"org-src-name\">%s</label>"
2034                    (org-export-data caption info)))
2035          (format "\n<pre class=\"src src-%s\"%s>%s</pre>" lang label code))))))
2036
2037 ;;;; Statistics Cookie
2038
2039 (defun org-gpgweb-statistics-cookie (statistics-cookie contents info)
2040   "Transcode a STATISTICS-COOKIE object from Org to HTML.
2041 CONTENTS is nil.  INFO is a plist holding contextual information."
2042   (let ((cookie-value (org-element-property :value statistics-cookie)))
2043     (format "<code>%s</code>" cookie-value)))
2044
2045 ;;;; Strike-Through
2046
2047 (defun org-gpgweb-strike-through (strike-through contents info)
2048   "Transcode STRIKE-THROUGH from Org to HTML.
2049 CONTENTS is the text with strike-through markup.  INFO is a plist
2050 holding contextual information."
2051   (format "<del>%s</del>" contents))
2052
2053 ;;;; Subscript
2054
2055 (defun org-gpgweb-subscript (subscript contents info)
2056   "Transcode a SUBSCRIPT object from Org to HTML.
2057 CONTENTS is the contents of the object.  INFO is a plist holding
2058 contextual information."
2059   (format "<sub>%s</sub>" contents))
2060
2061 ;;;; Superscript
2062
2063 (defun org-gpgweb-superscript (superscript contents info)
2064   "Transcode a SUPERSCRIPT object from Org to HTML.
2065 CONTENTS is the contents of the object.  INFO is a plist holding
2066 contextual information."
2067   (format "<sup>%s</sup>" contents))
2068
2069 ;;;; Table Cell
2070
2071 (defun org-gpgweb-table-cell (table-cell contents info)
2072   "Transcode a TABLE-CELL element from Org to HTML.
2073 CONTENTS is nil.  INFO is a plist used as a communication
2074 channel."
2075   (let* ((table-row (org-export-get-parent table-cell))
2076          (table (org-export-get-parent-table table-cell))
2077          (cell-attrs
2078           (if (not (plist-get info :html-table-align-individual-fields)) ""
2079             (format (if (and (boundp 'org-gpgweb-format-table-no-css)
2080                              org-gpgweb-format-table-no-css)
2081                         " align=\"%s\"" " class=\"%s\"")
2082                     (org-export-table-cell-alignment table-cell info)))))
2083     (when (or (not contents) (string= "" (org-trim contents)))
2084       (setq contents "&#xa0;"))
2085     (cond
2086      ((and (org-export-table-has-header-p table info)
2087            (= 1 (org-export-table-row-group table-row info)))
2088       (let ((header-tags (plist-get info :html-table-header-tags)))
2089         (concat "\n" (format (car header-tags) "col" cell-attrs)
2090                 contents
2091                 (cdr header-tags))))
2092      ((and (plist-get info :html-table-use-header-tags-for-first-column)
2093            (zerop (cdr (org-export-table-cell-address table-cell info))))
2094       (let ((header-tags (plist-get info :html-table-header-tags)))
2095         (concat "\n" (format (car header-tags) "row" cell-attrs)
2096                 contents
2097                 (cdr header-tags))))
2098      (t (let ((data-tags (plist-get info :html-table-data-tags)))
2099           (concat "\n" (format (car data-tags) cell-attrs)
2100                   contents
2101                   (cdr data-tags)))))))
2102
2103 ;;;; Table Row
2104
2105 (defun org-gpgweb-table-row (table-row contents info)
2106   "Transcode a TABLE-ROW element from Org to HTML.
2107 CONTENTS is the contents of the row.  INFO is a plist used as a
2108 communication channel."
2109   ;; Rules are ignored since table separators are deduced from
2110   ;; borders of the current row.
2111   (when (eq (org-element-property :type table-row) 'standard)
2112     (let* ((rowgroup-number (org-export-table-row-group table-row info))
2113            (row-number (org-export-table-row-number table-row info))
2114            (start-rowgroup-p
2115             (org-export-table-row-starts-rowgroup-p table-row info))
2116            (end-rowgroup-p
2117             (org-export-table-row-ends-rowgroup-p table-row info))
2118            ;; `top-row-p' and `end-rowgroup-p' are not used directly
2119            ;; but should be set so that `org-gpgweb-table-row-tags' can
2120            ;; use them (see the docstring of this variable.)
2121            (top-row-p (and (equal start-rowgroup-p '(top))
2122                            (equal end-rowgroup-p '(below top))))
2123            (bottom-row-p (and (equal start-rowgroup-p '(above))
2124                               (equal end-rowgroup-p '(bottom above))))
2125            (rowgroup-tags
2126             (cond
2127              ;; Case 1: Row belongs to second or subsequent rowgroups.
2128              ((not (= 1 rowgroup-number))
2129               '("<tbody>" . "\n</tbody>"))
2130              ;; Case 2: Row is from first rowgroup.  Table has >=1 rowgroups.
2131              ((org-export-table-has-header-p
2132                (org-export-get-parent-table table-row) info)
2133               '("<thead>" . "\n</thead>"))
2134              ;; Case 2: Row is from first and only row group.
2135              (t '("<tbody>" . "\n</tbody>")))))
2136       (concat
2137        ;; Begin a rowgroup?
2138        (when start-rowgroup-p (car rowgroup-tags))
2139        ;; Actual table row
2140        (concat "\n" (eval (car (plist-get info :html-table-row-tags)))
2141                contents
2142                "\n"
2143                (eval (cdr (plist-get info :html-table-row-tags))))
2144        ;; End a rowgroup?
2145        (when end-rowgroup-p (cdr rowgroup-tags))))))
2146
2147 ;;;; Table
2148
2149 (defun org-gpgweb-table-first-row-data-cells (table info)
2150   "Transcode the first row of TABLE.
2151 INFO is a plist used as a communication channel."
2152   (let ((table-row
2153          (org-element-map table 'table-row
2154            (lambda (row)
2155              (unless (eq (org-element-property :type row) 'rule) row))
2156            info 'first-match))
2157         (special-column-p (org-export-table-has-special-column-p table)))
2158     (if (not special-column-p) (org-element-contents table-row)
2159       (cdr (org-element-contents table-row)))))
2160
2161 (defun org-gpgweb-table--table.el-table (table info)
2162   "Format table.el tables into HTML.
2163 INFO is a plist used as a communication channel."
2164   (when (eq (org-element-property :type table) 'table.el)
2165     (require 'table)
2166     (let ((outbuf (with-current-buffer
2167                       (get-buffer-create "*org-export-table*")
2168                     (erase-buffer) (current-buffer))))
2169       (with-temp-buffer
2170         (insert (org-element-property :value table))
2171         (goto-char 1)
2172         (re-search-forward "^[ \t]*|[^|]" nil t)
2173         (table-generate-source 'html outbuf))
2174       (with-current-buffer outbuf
2175         (prog1 (org-trim (buffer-string))
2176           (kill-buffer) )))))
2177
2178 (defun org-gpgweb-table (table contents info)
2179   "Transcode a TABLE element from Org to HTML.
2180 CONTENTS is the contents of the table.  INFO is a plist holding
2181 contextual information."
2182   (case (org-element-property :type table)
2183     ;; Case 1: table.el table.  Convert it using appropriate tools.
2184     (table.el (org-gpgweb-table--table.el-table table info))
2185     ;; Case 2: Standard table.
2186     (t
2187      (let* ((label (org-element-property :name table))
2188             (caption (org-export-get-caption table))
2189             (number (org-export-get-ordinal
2190                      table info nil 'org-gpgweb--has-caption-p))
2191             (attributes
2192              (org-gpgweb--make-attribute-string
2193               (org-combine-plists
2194                (and label (list :id (org-export-solidify-link-text label)))
2195                (and (not (org-gpgweb-html5-p info))
2196                     (plist-get info :html-table-attributes))
2197                (org-export-read-attribute :attr_html table))))
2198             (alignspec
2199              (if (and (boundp 'org-gpgweb-format-table-no-css)
2200                       org-gpgweb-format-table-no-css)
2201                  "align=\"%s\"" "class=\"%s\""))
2202             (table-column-specs
2203              (function
2204               (lambda (table info)
2205                 (mapconcat
2206                  (lambda (table-cell)
2207                    (let ((alignment (org-export-table-cell-alignment
2208                                      table-cell info)))
2209                      (concat
2210                       ;; Begin a colgroup?
2211                       (when (org-export-table-cell-starts-colgroup-p
2212                              table-cell info)
2213                         "\n<colgroup>")
2214                       ;; Add a column.  Also specify it's alignment.
2215                       (format "\n%s"
2216                               (org-gpgweb-close-tag
2217                                "col" (concat " " (format alignspec alignment)) info))
2218                       ;; End a colgroup?
2219                       (when (org-export-table-cell-ends-colgroup-p
2220                              table-cell info)
2221                         "\n</colgroup>"))))
2222                  (org-gpgweb-table-first-row-data-cells table info) "\n")))))
2223        (format "<table%s>\n%s\n%s\n%s</table>"
2224                (if (equal attributes "") "" (concat " " attributes))
2225                (if (not caption) ""
2226                  (format (if (plist-get info :html-table-caption-above)
2227                              "<caption class=\"t-above\">%s</caption>"
2228                            "<caption class=\"t-bottom\">%s</caption>")
2229                          (concat
2230                           "<span class=\"table-number\">"
2231                           (format (org-gpgweb--translate "Table %d:" info) number)
2232                           "</span> " (org-export-data caption info))))
2233                (funcall table-column-specs table info)
2234                contents)))))
2235
2236 ;;;; Target
2237
2238 (defun org-gpgweb-target (target contents info)
2239   "Transcode a TARGET object from Org to HTML.
2240 CONTENTS is nil.  INFO is a plist holding contextual
2241 information."
2242   (let ((id (org-export-solidify-link-text
2243              (org-element-property :value target))))
2244     (org-gpgweb--anchor id nil nil info)))
2245
2246 ;;;; Timestamp
2247
2248 (defun org-gpgweb-timestamp (timestamp contents info)
2249   "Transcode a TIMESTAMP object from Org to HTML.
2250 CONTENTS is nil.  INFO is a plist holding contextual
2251 information."
2252   (let ((value (org-gpgweb-plain-text
2253                 (org-timestamp-translate timestamp) info)))
2254     (format "<span class=\"timestamp-wrapper\"><span class=\"timestamp\">%s</span></span>"
2255             (replace-regexp-in-string "--" "&#x2013;" value))))
2256
2257 ;;;; Underline
2258
2259 (defun org-gpgweb-underline (underline contents info)
2260   "Transcode UNDERLINE from Org to HTML.
2261 CONTENTS is the text with underline markup.  INFO is a plist
2262 holding contextual information."
2263   (format "<span class=\"underline\">%s</span>" contents))
2264
2265 ;;;; Verbatim
2266
2267 (defun org-gpgweb-verbatim (verbatim contents info)
2268   "Transcode VERBATIM from Org to HTML.
2269 CONTENTS is nil.  INFO is a plist holding contextual
2270 information."
2271   (format "<code>%s</code>"
2272          (org-gpgweb-encode-plain-text (org-element-property :value verbatim))))
2273
2274 ;;;; Verse Block
2275
2276 (defun org-gpgweb-verse-block (verse-block contents info)
2277   "Transcode a VERSE-BLOCK element from Org to HTML.
2278 CONTENTS is verse block contents.  INFO is a plist holding
2279 contextual information."
2280   ;; Replace each newline character with line break.  Also replace
2281   ;; each blank line with a line break.
2282   (setq contents (replace-regexp-in-string
2283                   "^ *\\\\\\\\$" (format "%s\n" (org-gpgweb-close-tag "br" nil info))
2284                   (replace-regexp-in-string
2285                    "\\(\\\\\\\\\\)?[ \t]*\n"
2286                    (format "%s\n" (org-gpgweb-close-tag "br" nil info)) contents)))
2287   ;; Replace each white space at beginning of a line with a
2288   ;; non-breaking space.
2289   (while (string-match "^[ \t]+" contents)
2290     (let* ((num-ws (length (match-string 0 contents)))
2291            (ws (let (out) (dotimes (i num-ws out)
2292                             (setq out (concat out "&#xa0;"))))))
2293       (setq contents (replace-match ws nil t contents))))
2294   (format "<p class=\"verse\">\n%s</p>" contents))
2295
2296 \f
2297 ;;; Filter Functions
2298
2299 (defun org-gpgweb-final-function (contents backend info)
2300   "Filter to indent the HTML and convert HTML entities."
2301   (with-temp-buffer
2302     (insert contents)
2303     (buffer-substring-no-properties (point-min) (point-max))))
2304
2305 \f
2306 ;;; End-user functions
2307
2308 ;;;###autoload
2309 (defun org-gpgweb-export-as-html
2310   (&optional async subtreep visible-only body-only ext-plist)
2311   "Export current buffer to an HTML buffer.
2312
2313 If narrowing is active in the current buffer, only export its
2314 narrowed part.
2315
2316 If a region is active, export that region.
2317
2318 A non-nil optional argument ASYNC means the process should happen
2319 asynchronously.  The resulting buffer should be accessible
2320 through the `org-export-stack' interface.
2321
2322 When optional argument SUBTREEP is non-nil, export the sub-tree
2323 at point, extracting information from the headline properties
2324 first.
2325
2326 When optional argument VISIBLE-ONLY is non-nil, don't export
2327 contents of hidden elements.
2328
2329 The optional argument BODY-ONLY is ignored.
2330
2331 EXT-PLIST, when provided, is a property list with external
2332 parameters overriding Org default settings, but still inferior to
2333 file-local settings.
2334
2335 Export is done in a buffer named \"*Org HTML Export*\", which
2336 will be displayed when `org-export-show-temporary-export-buffer'
2337 is non-nil."
2338   (interactive)
2339   (org-export-to-buffer 'gpgweb "*Org GPGWEB Export*"
2340     async subtreep visible-only t ext-plist
2341     (lambda () (set-auto-mode t))))
2342
2343 ;;;###autoload
2344 (defun org-gpgweb-convert-region-to-html ()
2345   "Assume the current region has org-mode syntax, and convert it to HTML.
2346 This can be used in any buffer.  For example, you can write an
2347 itemized list in org-mode syntax in an HTML buffer and use this
2348 command to convert it."
2349   (interactive)
2350   (org-export-replace-region-by 'gpgweb))
2351
2352 ;;;###autoload
2353 (defun org-gpgweb-export-to-html
2354   (&optional async subtreep visible-only body-only ext-plist)
2355   "Export current buffer to a HTML file.
2356
2357 If narrowing is active in the current buffer, only export its
2358 narrowed part.
2359
2360 If a region is active, export that region.
2361
2362 A non-nil optional argument ASYNC means the process should happen
2363 asynchronously.  The resulting file should be accessible through
2364 the `org-export-stack' interface.
2365
2366 When optional argument SUBTREEP is non-nil, export the sub-tree
2367 at point, extracting information from the headline properties
2368 first.
2369
2370 When optional argument VISIBLE-ONLY is non-nil, don't export
2371 contents of hidden elements.
2372
2373 When optional argument BODY-ONLY is non-nil, only write code
2374 between \"<body>\" and \"</body>\" tags.
2375
2376 EXT-PLIST, when provided, is a property list with external
2377 parameters overriding Org default settings, but still inferior to
2378 file-local settings.
2379
2380 Return output file's name."
2381   (interactive)
2382   (let* ((extension (concat "." (or (plist-get ext-plist :html-extension)
2383                                     org-gpgweb-extension
2384                                     "html")))
2385          (file (org-export-output-file-name extension subtreep))
2386          (org-export-coding-system 'utf-8))
2387     (org-export-to-file 'gpgweb file
2388       async subtreep visible-only body-only ext-plist)))
2389
2390 ;;;###autoload
2391 (defun org-gpgweb-publish-to-html (plist filename pub-dir)
2392   "Publish an org file to HTML.
2393
2394 FILENAME is the filename of the Org file to be published.  PLIST
2395 is the property list for the given project.  PUB-DIR is the
2396 publishing directory.
2397
2398 Return output file name."
2399   (org-publish-org-to 'gpgweb filename
2400                       (concat "." (or (plist-get plist :html-extension)
2401                                       org-gpgweb-extension
2402                                       "html"))
2403                       plist pub-dir))
2404
2405
2406 (provide 'ox-gpgweb)
2407
2408 ;; Local variables:
2409 ;; generated-autoload-file: "org-loaddefs.el"
2410 ;; End:
2411
2412 ;;; ox-gpgweb.el ends here