39f41ef3cd9603dd0d7a1596a8482702a4bdde36
[org-mode.git] / contrib / lisp / ox-s5.el
blob39f41ef3cd9603dd0d7a1596a8482702a4bdde36
1 ;;; ox-s5.el --- S5 Presentation Back-End for Org Export Engine
3 ;; Copyright (C) 2011-2013 Rick Frankel
5 ;; Author: Rick Frankel <emacs at rickster dot com>
6 ;; Keywords: outlines, hypermedia, S5, wp
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation, either version 3 of the License, or
11 ;; (at your option) any later version.
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ;;; Commentary:
23 ;; This library implements an S5 Presentation back-end for the Org
24 ;; generic exporter.
26 ;; Installation
27 ;; ------------
28 ;; Get the s5 scripts from
29 ;; http://meyerweb.com/eric/tools/s5/
30 ;; (Note that the default s5 version is set for using the alpha, 1.2a2.
31 ;; Copy the ui dir to somewhere reachable from your published presentation
32 ;; The default (`org-s5-ui-url') is set to "ui" (e.g., in the
33 ;; same directory as the html file).
35 ;; Usage
36 ;; -----
37 ;; Follow the general instructions at the above website. To generate
38 ;; incremental builds, you can set the HTML_CONTAINER_CLASS on an
39 ;; object to "incremental" to make it build. If you want an outline to
40 ;; build, set the` INCREMENTAL property on the parent headline.
42 ;; To test it, run:
44 ;; M-x org-s5-export-as-html
46 ;; in an Org mode buffer. See ox.el and ox-html.el for more details
47 ;; on how this exporter works.
49 (require 'ox-html)
51 (org-export-define-derived-backend s5 html
52 :menu-entry
53 (?s "Export to S5 HTML Presentation"
54 ((?H "To temporary buffer" org-s5-export-as-html)
55 (?h "To file" org-s5-export-to-html)
56 (?o "To file and open"
57 (lambda (a s v b)
58 (if a (org-s5-export-to-html t s v b)
59 (org-open-file (org-s5-export-to-html nil s v b)))))))
60 :options-alist
61 ((:html-link-home "HTML_LINK_HOME" nil nil)
62 (:html-link-up "HTML_LINK_UP" nil nil)
63 (:html-mathjax "HTML_MATHJAX" nil "" space)
64 (:html-postamble nil "html-postamble" nil t)
65 (:html-preamble nil "html-preamble" nil t)
66 (:html-style-extra "HTML_STYLE" nil org-html-style-extra newline)
67 (:html-style-include-default "HTML_INCLUDE_DEFAULT" nil nil)
68 (:html-style-include-scripts "HTML_INCLUDE_SCRIPTS" nil nil)
69 (:s5-version "S5_VERSION" nil org-s5-version)
70 (:s5-theme-file "S5_THEME_FILE" nil org-s5-theme-file)
71 (:s5-ui-url "S5_UI_URL" nil org-s5-ui-url))
72 :translate-alist
73 ((headline . org-s5-headline)
74 (plain-list . org-s5-plain-list)
75 (template . org-s5-template)))
77 (defgroup org-export-s5 nil
78 "Options for exporting Org mode files to S5 HTML Presentations."
79 :tag "Org Export S5"
80 :group 'org-export-html)
82 (defcustom org-s5-version "1.2a2"
83 "Version of s5 being used (for version metadata.) Defaults to
84 s5 v2 alpha 2.
85 Can be overridden with S5_VERSION."
86 :group 'org-export-s5
87 :type 'string)
89 (defcustom org-s5-theme-file nil
90 "Url to S5 theme (slides.css) file. Can be overriden with the
91 S5_THEME_FILE property. If nil, defaults to
92 `org-s5-ui-url'/default/slides.css. If it starts with anything but
93 \"http\" or \"/\", it is used as-is. Otherwise the link in generated
94 relative to `org-s5-ui-url'.
95 The links for all other required stylesheets and scripts will be
96 generated relative to `org-s5-ui-url'/default."
97 :group 'org-export-s5
98 :type 'string)
100 (defcustom org-s5-ui-url "ui"
101 "Base url to directory containing S5 \"default\" subdirectory
102 and the \"s5-notes.html\" file.
103 Can be overriden with the S5_UI_URL property."
104 :group 'org-export-s5
105 :type 'string)
107 (defcustom org-s5-default-view 'slideshow
108 "Setting for \"defaultView\" meta info."
109 :group 'org-export-s5
110 :type '(choice (const slideshow) (const outline)))
112 (defcustom org-s5-control-visibility 'hidden
113 "Setting for \"controlVis\" meta info."
114 :group 'org-export-s5
115 :type '(choice (const hidden) (const visibile)))
117 (defcustom org-s5-footer-template
118 "<div id=\"footer\">
119 <h1>%author - %title</h1>
120 </div>"
121 "Format template to specify footer div. Completed using
122 `org-fill-template'.
123 Optional keys include %author, %email, %file, %title and %date.
124 Note that the div id must be \"footer\"."
125 :group 'org-export-s5
126 :type 'string)
128 (defcustom org-s5-header-template "<div id=\"header\"></div>"
129 "Format template to specify footer div. Completed using
130 `org-fill-template'.
131 Optional keys include %author, %email, %file, %title and %date.
132 Note that the div id must be \"header\"."
133 :group 'org-export-s5
134 :type 'string)
136 (defcustom org-s5-title-page-template
137 "<div class=\"slide title-page\">
138 <h1>%title</h1>
139 <h1>%author</h1>
140 <h1>%email</h1>
141 <h1>%date</h1>
142 </div>"
143 "Format template to specify title page div. Completed using
144 `org-fill-template'.
145 Optional keys include %author, %email, %file, %title and %date.
146 Note that the wrapper div must include the class \"slide\"."
147 :group 'org-export-s5
148 :type 'string)
151 (defun org-s5-toc (depth info)
152 (let* ((headlines (org-export-collect-headlines info depth))
153 (toc-entries
154 (loop for headline in headlines collect
155 (list (org-html-format-headline--wrap
156 headline info 'org-html-format-toc-headline)
157 (org-export-get-relative-level headline info)))))
158 (when toc-entries
159 (concat
160 "<div id=\"table-of-contents\" class=\"slide\">\n"
161 (format "<h1>%s</h1>\n"
162 (org-html--translate "Table of Contents" info))
163 "<div id=\"text-table-of-contents\">"
164 (org-html-toc-text toc-entries)
165 "</div>\n"
166 "</div>\n"))))
168 (defun org-s5--build-style (info)
169 (let* ((dir (plist-get info :s5-ui-url))
170 (theme (or (plist-get info :s5-theme-file) "default/slides.css")))
171 (mapconcat
172 'identity
173 (list
174 "<!-- style sheet links -->"
175 (mapconcat
176 (lambda (list)
177 (format
178 (concat
179 "<link rel='stylesheet' href='%s/default/%s' type='text/css'"
180 " media='%s' id='%s' />")
181 dir (nth 0 list) (nth 1 list) (nth 2 list)))
182 (list
183 '("outline.css" "screen" "outlineStyle")
184 '("print.css" "print" "slidePrint")
185 '("opera.css" "projection" "operaFix")) "\n")
186 (format (concat
187 "<link rel='stylesheet' href='%s' type='text/css'"
188 " media='screen' id='slideProj' />")
189 (if (string-match-p "^\\(http\\|/\\)" theme) theme
190 (concat dir "/" theme)))
191 "<!-- S5 JS -->"
192 (concat
193 "<script src='" dir
194 "/default/slides.js' type='text/javascript'></script>")) "\n")))
196 (defun org-s5--build-meta-info (info)
197 (concat
198 (org-html--build-meta-info info)
199 (format "<meta name=\"version\" content=\"S5 %s\" />"
200 (plist-get info :s5-version))
201 "<meta name='defaultView' content='slideshow' />\n"
202 "<meta name='controlVis' content='hidden' />"))
204 (defun org-s5-headline (headline contents info)
205 (let ((org-html-toplevel-hlevel 1))
206 (org-html-headline
207 (if (= 1 (+ (org-element-property :level headline)
208 (plist-get info :headline-offset)))
209 (org-element-put-property
210 headline :html-container-class
211 (mapconcat 'identity
212 (list
213 (org-element-property
214 :html-container-class headline)
215 "slide") " "))
216 headline) contents info)))
218 (defun org-s5-plain-list (plain-list contents info)
219 "Transcode a PLAIN-LIST element from Org to HTML.
220 CONTENTS is the contents of the list. INFO is a plist holding
221 contextual information.
222 If a containing headline has the property :incremental,
223 then the \"incremental\" class will be added to the to the list,
224 which will make the list into a \"build\"."
225 (let* ((type (org-element-property :type plain-list))
226 (tag (case type
227 (ordered "ol")
228 (unordered "ul")
229 (descriptive "dl"))))
230 (format "%s\n%s%s"
231 (format
232 "<%s class='org-%s%s'>" tag tag
233 (if (org-export-get-node-property :incremental plain-list t)
234 " incremental" ""))
235 contents (org-html-end-plain-list type))))
237 (defun org-s5-template-alist (info)
239 ("title" . ,(car (plist-get info :title)))
240 ("author" . ,(car (plist-get info :author)))
241 ("email" . ,(plist-get info :email))
242 ("date" . ,(substring (nth 0 (plist-get info :date)) 0 10))
243 ("file" . ,(plist-get info :input-file))))
245 (defun org-s5-template (contents info)
246 "Return complete document string after HTML conversion.
247 CONTENTS is the transcoded contents string. INFO is a plist
248 holding export options."
249 (mapconcat
250 'identity
251 (list
252 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
253 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
254 (format "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"%s\" xml:lang=\"%s\">"
255 (plist-get info :language) (plist-get info :language))
256 "<head>"
257 (org-s5--build-meta-info info)
258 (org-s5--build-style info)
259 (org-html--build-style info)
260 (org-html--build-mathjax-config info)
261 "</head>"
262 "<body>"
263 "<div class=\"layout\">"
264 "<div id=\"controls\"><!-- no edit --></div>"
265 "<div id=\"currentSlide\"><!-- no edit --></div>"
266 (org-fill-template
267 org-s5-header-template (org-s5-template-alist info))
268 (org-fill-template
269 org-s5-footer-template (org-s5-template-alist info))
270 "</div>"
271 (format "<div id=\"%s\" class=\"presentation\">" (nth 1 org-html-divs))
272 ;; title page
273 (org-fill-template
274 org-s5-title-page-template (org-s5-template-alist info))
275 (let ((depth (plist-get info :with-toc)))
276 (when depth (org-s5-toc depth info)))
277 contents
278 "</div>"
279 "</body>"
280 "</html>\n") "\n"))
282 (defun org-s5-export-as-html
283 (&optional async subtreep visible-only body-only ext-plist)
284 "Export current buffer to an HTML buffer.
286 If narrowing is active in the current buffer, only export its
287 narrowed part.
289 If a region is active, export that region.
291 A non-nil optional argument ASYNC means the process should happen
292 asynchronously. The resulting buffer should be accessible
293 through the `org-export-stack' interface.
295 When optional argument SUBTREEP is non-nil, export the sub-tree
296 at point, extracting information from the headline properties
297 first.
299 When optional argument VISIBLE-ONLY is non-nil, don't export
300 contents of hidden elements.
302 When optional argument BODY-ONLY is non-nil, only write code
303 between \"<body>\" and \"</body>\" tags.
305 EXT-PLIST, when provided, is a property list with external
306 parameters overriding Org default settings, but still inferior to
307 file-local settings.
309 Export is done in a buffer named \"*Org S5 Export*\", which
310 will be displayed when `org-export-show-temporary-export-buffer'
311 is non-nil."
312 (interactive)
313 (if async
314 (org-export-async-start
315 (lambda (output)
316 (with-current-buffer (get-buffer-create "*Org S5 Export*")
317 (erase-buffer)
318 (insert output)
319 (goto-char (point-min))
320 (nxml-mode)
321 (org-export-add-to-stack (current-buffer) 's5)))
322 `(org-export-as 's5 ,subtreep ,visible-only ,body-only ',ext-plist))
323 (let ((outbuf (org-export-to-buffer
324 's5 "*Org S5 Export*"
325 subtreep visible-only body-only ext-plist)))
326 ;; Set major mode.
327 (with-current-buffer outbuf (nxml-mode))
328 (when org-export-show-temporary-export-buffer
329 (switch-to-buffer-other-window outbuf)))))
331 (defun org-s5-export-to-html
332 (&optional async subtreep visible-only body-only ext-plist)
333 "Export current buffer to a S5 HTML file.
335 If narrowing is active in the current buffer, only export its
336 narrowed part.
338 If a region is active, export that region.
340 A non-nil optional argument ASYNC means the process should happen
341 asynchronously. The resulting file should be accessible through
342 the `org-export-stack' interface.
344 When optional argument SUBTREEP is non-nil, export the sub-tree
345 at point, extracting information from the headline properties
346 first.
348 When optional argument VISIBLE-ONLY is non-nil, don't export
349 contents of hidden elements.
351 When optional argument BODY-ONLY is non-nil, only write code
352 between \"<body>\" and \"</body>\" tags.
354 EXT-PLIST, when provided, is a property list with external
355 parameters overriding Org default settings, but still inferior to
356 file-local settings.
358 Return output file's name."
359 (interactive)
360 (let* ((extension (concat "." org-html-extension))
361 (file (org-export-output-file-name extension subtreep))
362 (org-export-coding-system org-html-coding-system))
363 (if async
364 (org-export-async-start
365 (lambda (f) (org-export-add-to-stack f 's5))
366 (let ((org-export-coding-system org-html-coding-system))
367 `(expand-file-name
368 (org-export-to-file
369 's5 ,file ,subtreep ,visible-only ,body-only ',ext-plist))))
370 (let ((org-export-coding-system org-html-coding-system))
371 (org-export-to-file
372 's5 file subtreep visible-only body-only ext-plist)))))
374 (defun org-s5-publish-to-html (plist filename pub-dir)
375 "Publish an org file to S5 HTML Presentation.
377 FILENAME is the filename of the Org file to be published. PLIST
378 is the property list for the given project. PUB-DIR is the
379 publishing directory.
381 Return output file name."
382 (org-publish-org-to 's5 filename ".html" plist pub-dir))
384 (provide 'ox-s5)