ox-s5: Small fix
[org-mode/org-tableheadings.git] / contrib / lisp / ox-s5.el
blobb0039192b41618628b7345d4f685a60821ede959
1 ;;; ox-s5.el --- S5 Presentation Back-End for Org Export Engine
3 ;; Copyright (C) 2011-2014 Rick Frankel
5 ;; Author: Rick Frankel <emacs at rickster dot com>
6 ;; Keywords: outlines, hypermedia, S5, wp
8 ;; This file is not part of GNU Emacs.
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
23 ;;; Commentary:
25 ;; This library implements an S5 Presentation back-end for the Org
26 ;; generic exporter.
28 ;; Installation
29 ;; ------------
30 ;; Get the s5 scripts from
31 ;; http://meyerweb.com/eric/tools/s5/
32 ;; (Note that the default s5 version is set for using the alpha, 1.2a2.
33 ;; Copy the ui dir to somewhere reachable from your published presentation
34 ;; The default (`org-s5-ui-url') is set to "ui" (e.g., in the
35 ;; same directory as the html file).
37 ;; Usage
38 ;; -----
39 ;; Follow the general instructions at the above website. To generate
40 ;; incremental builds, you can set the HTML_CONTAINER_CLASS on an
41 ;; object to "incremental" to make it build. If you want an outline to
42 ;; build, set the :INCREMENTAL property on the parent headline.
44 ;; To test it, run:
46 ;; M-x org-s5-export-as-html
48 ;; in an Org mode buffer. See ox.el and ox-html.el for more details
49 ;; on how this exporter works.
51 (require 'ox-html)
52 (eval-when-compile (require 'cl))
54 (org-export-define-derived-backend 's5 'html
55 :menu-entry
56 '(?s "Export to S5 HTML Presentation"
57 ((?H "To temporary buffer" org-s5-export-as-html)
58 (?h "To file" org-s5-export-to-html)
59 (?o "To file and open"
60 (lambda (a s v b)
61 (if a (org-s5-export-to-html t s v b)
62 (org-open-file (org-s5-export-to-html nil s v b)))))))
63 :options-alist
64 '((:html-link-home "HTML_LINK_HOME" nil nil)
65 (:html-link-up "HTML_LINK_UP" nil nil)
66 (:s5-postamble "S5_POSTAMBLE" nil org-s5-postamble newline)
67 (:s5-preamble "S5_PREAMBLE" nil org-s5-preamble newline)
68 (:html-head-include-default-style "HTML_INCLUDE_DEFAULT_STYLE" nil nil)
69 (:html-head-include-scripts "HTML_INCLUDE_SCRIPTS" nil nil)
70 (:s5-version "S5_VERSION" nil org-s5-version)
71 (:s5-theme-file "S5_THEME_FILE" nil org-s5-theme-file)
72 (:s5-ui-url "S5_UI_URL" nil org-s5-ui-url)
73 (:s5-default-view "S5_DEFAULT_VIEW" nil org-s5-default-view)
74 (:s5-control-visibility "S5_CONTROL_VISIBILITY" nil
75 org-s5-control-visibility))
76 :translate-alist
77 '((headline . org-s5-headline)
78 (plain-list . org-s5-plain-list)
79 (inner-template . org-s5-inner-template)
80 (template . org-s5-template)))
82 (defgroup org-export-s5 nil
83 "Options for exporting Org mode files to S5 HTML Presentations."
84 :tag "Org Export S5"
85 :group 'org-export-html)
87 (defcustom org-s5-version "1.2a2"
88 "Version of s5 being used (for version metadata.) Defaults to
89 s5 v2 alpha 2.
90 Can be overridden with S5_VERSION."
91 :group 'org-export-s5
92 :type 'string)
94 (defcustom org-s5-theme-file nil
95 "Url to S5 theme (slides.css) file. Can be overriden with the
96 S5_THEME_FILE property. If nil, defaults to
97 `org-s5-ui-url'/default/slides.css. If it starts with anything but
98 \"http\" or \"/\", it is used as-is. Otherwise the link in generated
99 relative to `org-s5-ui-url'.
100 The links for all other required stylesheets and scripts will be
101 generated relative to `org-s5-ui-url'/default."
102 :group 'org-export-s5
103 :type 'string)
105 (defcustom org-s5-ui-url "ui"
106 "Base url to directory containing S5 \"default\" subdirectory
107 and the \"s5-notes.html\" file.
108 Can be overriden with the S5_UI_URL property."
109 :group 'org-export-s5
110 :type 'string)
112 (defcustom org-s5-default-view 'slideshow
113 "Setting for \"defaultView\" meta info."
114 :group 'org-export-s5
115 :type '(choice (const slideshow) (const outline)))
117 (defcustom org-s5-control-visibility 'hidden
118 "Setting for \"controlVis\" meta info."
119 :group 'org-export-s5
120 :type '(choice (const hidden) (const visibile)))
122 (defvar org-s5--divs
123 '((preamble "div" "header")
124 (content "div" "content")
125 (postamble "div" "footer"))
126 "Alist of the three section elements for HTML export.
127 The car of each entry is one of 'preamble, 'content or 'postamble.
128 The cdrs of each entry are the ELEMENT_TYPE and ID for each
129 section of the exported document.
131 If you set `org-html-container-element' to \"li\", \"ol\" will be
132 uses as the content ELEMENT_TYPE, generating an XOXO format
133 slideshow.
135 Note that changing the preamble or postamble will break the
136 core S5 stylesheets.")
138 (defcustom org-s5-postamble "<h1>%a - %t</h1>"
139 "Preamble inserted into the S5 layout section.
140 When set to a string, use this string as the postamble.
142 When set to a function, apply this function and insert the
143 returned string. The function takes the property list of export
144 options as its only argument.
146 Setting the S5_POSTAMBLE option -- or the :s5-postamble in publishing
147 projects -- will take precedence over this variable.
149 Note that the default css styling will break if this is set to nil
150 or an empty string."
151 :group 'org-export-s5
152 :type '(choice (const :tag "No postamble" "&#x20;")
153 (string :tag "Custom formatting string")
154 (function :tag "Function (must return a string)")))
156 (defcustom org-s5-preamble "&#x20;"
157 "Peamble inserted into the S5 layout section.
159 When set to a string, use this string as the preamble.
161 When set to a function, apply this function and insert the
162 returned string. The function takes the property list of export
163 options as its only argument.
165 Setting S5_PREAMBLE option -- or the :s5-preamble in publishing
166 projects -- will take precedence over this variable.
168 Note that the default css styling will break if this is set to nil
169 or an empty string."
170 :group 'org-export-s5
171 :type '(choice (const :tag "No preamble" "&#x20;")
172 (string :tag "Custom formatting string")
173 (function :tag "Function (must return a string)")))
175 (defcustom org-s5-title-slide-template
176 "<h1>%t</h1>
177 <h2>%a</h2>
178 <h3>%e</h3>
179 <h4>%d</h4>"
180 "Format template to specify title page section.
181 See `org-html-postamble-format' for the valid elements which
182 can be included.
184 It will be wrapped in the element defined in the :html-container
185 property, and defaults to the value of `org-html-container-element',
186 and have the id \"title-slide\"."
187 :group 'org-export-s5
188 :type 'string)
190 (defun org-s5--format-toc-headline (headline info)
191 "Return an appropriate table of contents entry for HEADLINE.
192 Note that (currently) the S5 exporter does not support deep links,
193 so the table of contents is not \"active\".
194 INFO is a plist used as a communication channel."
195 (let* ((headline-number (org-export-get-headline-number headline info))
196 (section-number
197 (and (not (org-export-low-level-p headline info))
198 (org-export-numbered-headline-p headline info)
199 (concat (mapconcat 'number-to-string headline-number ".") ". ")))
200 (tags (and (eq (plist-get info :with-tags) t)
201 (org-export-get-tags headline info))))
202 (concat section-number
203 (org-export-data
204 (org-export-get-alt-title headline info) info)
205 (and tags "&nbsp;&nbsp;&nbsp;") (org-html--tags tags info))))
207 (defun org-s5-toc (depth info)
208 (let* ((headlines (org-export-collect-headlines info depth))
209 (toc-entries
210 (mapcar (lambda (headline)
211 (cons (org-s5--format-toc-headline headline info)
212 (org-export-get-relative-level headline info)))
213 (org-export-collect-headlines info depth))))
214 (when toc-entries
215 (concat
216 (format "<%s id='table-of-contents' class='slide'>\n"
217 (plist-get info :html-container))
218 (format "<h1>%s</h1>\n"
219 (org-html--translate "Table of Contents" info))
220 "<div id=\"text-table-of-contents\">"
221 (org-html--toc-text toc-entries)
222 "</div>\n"
223 (format "</%s>\n" (plist-get info :html-container))))))
225 (defun org-s5--build-head (info)
226 (let* ((dir (plist-get info :s5-ui-url))
227 (theme (or (plist-get info :s5-theme-file) "default/slides.css")))
228 (mapconcat
229 'identity
230 (list
231 "<!-- style sheet links -->"
232 (mapconcat
233 (lambda (list)
234 (format
235 (concat
236 "<link rel='stylesheet' href='%s/default/%s' type='text/css'"
237 " media='%s' id='%s' />")
238 dir (nth 0 list) (nth 1 list) (nth 2 list)))
239 (list
240 '("outline.css" "screen" "outlineStyle")
241 '("print.css" "print" "slidePrint")
242 '("opera.css" "projection" "operaFix")) "\n")
243 (format (concat
244 "<link rel='stylesheet' href='%s' type='text/css'"
245 " media='screen' id='slideProj' />")
246 (if (string-match-p "^\\(http\\|/\\)" theme) theme
247 (concat dir "/" theme)))
248 "<!-- S5 JS -->"
249 (concat
250 "<script src='" dir
251 "/default/slides.js' type='text/javascript'></script>")) "\n")))
253 (defun org-s5--build-meta-info (info)
254 (concat
255 (org-html--build-meta-info info)
256 (format "<meta name=\"version\" content=\"S5 %s\" />\n"
257 (plist-get info :s5-version))
258 (format "<meta name='defaultView' content='%s' />\n"
259 (plist-get info :s5-default-view))
260 (format "<meta name='controlVis' content='%s' />"
261 (plist-get info :s5-control-visibility))))
263 (defun org-s5-headline (headline contents info)
264 (let ((org-html-toplevel-hlevel 1)
265 (class (or (org-element-property :HTML_CONTAINER_CLASS headline) ""))
266 (level (org-export-get-relative-level headline info)))
267 (when (and (= 1 level) (not (string-match-p "\\<slide\\>" class)))
268 (org-element-put-property headline :HTML_CONTAINER_CLASS (concat class " slide")))
269 (org-html-headline headline contents info)))
271 (defun org-s5-plain-list (plain-list contents info)
272 "Transcode a PLAIN-LIST element from Org to HTML.
273 CONTENTS is the contents of the list. INFO is a plist holding
274 contextual information.
275 If a containing headline has the property :INCREMENTAL,
276 then the \"incremental\" class will be added to the to the list,
277 which will make the list into a \"build\"."
278 (let* ((type (org-element-property :type plain-list))
279 (tag (case type
280 (ordered "ol")
281 (unordered "ul")
282 (descriptive "dl"))))
283 (format "%s\n%s%s"
284 (format
285 "<%s class='org-%s%s'>" tag tag
286 (if (org-export-get-node-property :INCREMENTAL plain-list t)
287 " incremental" ""))
288 contents (org-html-end-plain-list type))))
290 (defun org-s5-inner-template (contents info)
291 "Return body of document string after HTML conversion.
292 CONTENTS is the transcoded contents string. INFO is a plist
293 holding export options."
294 (concat contents "\n"))
296 (defun org-s5-template (contents info)
297 "Return complete document string after HTML conversion.
298 CONTENTS is the transcoded contents string. INFO is a plist
299 holding export options."
300 (let ((org-html-divs
301 (if (equal (plist-get info :html-container) "li")
302 (append '((content "ol" "content")) org-s5--divs)
303 org-s5--divs))
304 (info (plist-put
305 (plist-put info :html-preamble (plist-get info :s5-preamble))
306 :html-postamble (plist-get info :s5-postamble))))
307 (mapconcat
308 'identity
309 (list
310 (org-html-doctype info)
311 (format "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"%s\" xml:lang=\"%s\">"
312 (plist-get info :language) (plist-get info :language))
313 "<head>"
314 (org-s5--build-meta-info info)
315 (org-s5--build-head info)
316 (org-html--build-head info)
317 (org-html--build-mathjax-config info)
318 "</head>"
319 "<body>"
320 "<div class=\"layout\">"
321 "<div id=\"controls\"><!-- no edit --></div>"
322 "<div id=\"currentSlide\"><!-- no edit --></div>"
323 (org-html--build-pre/postamble 'preamble info)
324 (org-html--build-pre/postamble 'postamble info)
325 "</div>"
326 (format "<%s id=\"%s\" class=\"presentation\">"
327 (nth 1 (assq 'content org-html-divs))
328 (nth 2 (assq 'content org-html-divs)))
329 ;; title page
330 (format "<%s id='title-slide' class='slide'>"
331 (plist-get info :html-container))
332 (format-spec org-s5-title-slide-template (org-html-format-spec info))
333 (format "</%s>" (plist-get info :html-container))
334 ;; table of contents.
335 (let ((depth (plist-get info :with-toc)))
336 (when depth (org-s5-toc depth info)))
337 contents
338 (format "</%s>" (nth 1 (assq 'content org-html-divs)))
339 "</body>"
340 "</html>\n") "\n")))
342 (defun org-s5-export-as-html
343 (&optional async subtreep visible-only body-only ext-plist)
344 "Export current buffer to an HTML buffer.
346 If narrowing is active in the current buffer, only export its
347 narrowed part.
349 If a region is active, export that region.
351 A non-nil optional argument ASYNC means the process should happen
352 asynchronously. The resulting buffer should be accessible
353 through the `org-export-stack' interface.
355 When optional argument SUBTREEP is non-nil, export the sub-tree
356 at point, extracting information from the headline properties
357 first.
359 When optional argument VISIBLE-ONLY is non-nil, don't export
360 contents of hidden elements.
362 When optional argument BODY-ONLY is non-nil, only write code
363 between \"<body>\" and \"</body>\" tags.
365 EXT-PLIST, when provided, is a property list with external
366 parameters overriding Org default settings, but still inferior to
367 file-local settings.
369 Export is done in a buffer named \"*Org S5 Export*\", which
370 will be displayed when `org-export-show-temporary-export-buffer'
371 is non-nil."
372 (interactive)
373 (org-export-to-buffer 's5 "*Org S5 Export*"
374 async subtreep visible-only body-only ext-plist (lambda () (nxml-mode))))
376 (defun org-s5-export-to-html
377 (&optional async subtreep visible-only body-only ext-plist)
378 "Export current buffer to a S5 HTML file.
380 If narrowing is active in the current buffer, only export its
381 narrowed part.
383 If a region is active, export that region.
385 A non-nil optional argument ASYNC means the process should happen
386 asynchronously. The resulting file should be accessible through
387 the `org-export-stack' interface.
389 When optional argument SUBTREEP is non-nil, export the sub-tree
390 at point, extracting information from the headline properties
391 first.
393 When optional argument VISIBLE-ONLY is non-nil, don't export
394 contents of hidden elements.
396 When optional argument BODY-ONLY is non-nil, only write code
397 between \"<body>\" and \"</body>\" tags.
399 EXT-PLIST, when provided, is a property list with external
400 parameters overriding Org default settings, but still inferior to
401 file-local settings.
403 Return output file's name."
404 (interactive)
405 (let* ((extension (concat "." org-html-extension))
406 (file (org-export-output-file-name extension subtreep))
407 (org-export-coding-system org-html-coding-system))
408 (org-export-to-file 's5 file
409 async subtreep visible-only body-only ext-plist)))
411 (defun org-s5-publish-to-html (plist filename pub-dir)
412 "Publish an org file to S5 HTML Presentation.
414 FILENAME is the filename of the Org file to be published. PLIST
415 is the property list for the given project. PUB-DIR is the
416 publishing directory.
418 Return output file name."
419 (org-publish-org-to 's5 filename ".html" plist pub-dir))
421 (provide 'ox-s5)
423 ;;; ox-s5.el ends here