Ship more local files
[emacs.git] / .emacs.d / elisp / local / ox-reveal.el
1 ;;; ox-reveal.el --- reveal.js Presentation Back-End for Org Export Engine
2
3 ;; Copyright (C) 2013 Yujie Wen
4
5 ;; Author: Yujie Wen <yjwen.ty at gmail dot com>
6 ;; Created: 2013-04-27
7 ;; Version: 1.0
8 ;; Package-Requires: ((org "8.3"))
9 ;; Keywords: outlines, hypermedia, slideshow, presentation
10
11 ;; This file is not part of GNU Emacs.
12
13 ;;; Copyright Notice:
14
15 ;; This program is free software: you can redistribute it and/or modify
16 ;; it under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation, either version 3 of the License, or
18 ;; (at your option) any later version.
19
20 ;; This program is distributed in the hope that it will be useful,
21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ;; GNU General Public License for more details.
24
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
27
28 ;; Please see "Readme.org" for detail introductions.
29
30 ;; Pull request: Multiplex Support - Stephen Barrett <Stephen dot Barrewtt at scss dot tcd dot ie
31
32 ;;; Code:
33
34 (require 'ox-html)
35 (require 'cl)
36
37 (org-export-define-derived-backend 'reveal 'html
38
39 :menu-entry
40 '(?R "Export to reveal.js HTML Presentation"
41 ((?R "To file" org-reveal-export-to-html)
42 (?B "To file and browse" org-reveal-export-to-html-and-browse)
43 (?S "Current subtree to file" org-reveal-export-current-subtree)))
44
45 :options-alist
46 '((:reveal-control nil "reveal_control" org-reveal-control t)
47 (:reveal-progress nil "reveal_progress" org-reveal-progress t)
48 (:reveal-history nil "reveal_history" org-reveal-history t)
49 (:reveal-center nil "reveal_center" org-reveal-center t)
50 (:reveal-rolling-links nil "reveal_rolling_links" org-reveal-rolling-links t)
51 (:reveal-slide-number nil "reveal_slide_number" org-reveal-slide-number t)
52 (:reveal-keyboard nil "reveal_keyboard" org-reveal-keyboard t)
53 (:reveal-overview nil "reveal_overview" org-reveal-overview t)
54 (:reveal-width nil "reveal_width" org-reveal-width t)
55 (:reveal-height nil "reveal_height" org-reveal-height)
56 (:reveal-margin "REVEAL_MARGIN" nil org-reveal-margin t)
57 (:reveal-min-scale "REVEAL_MIN_SCALE" nil org-reveal-min-scale t)
58 (:reveal-max-scale "REVEAL_MAX_SCALE" nil org-reveal-max-scale t)
59 (:reveal-root "REVEAL_ROOT" nil org-reveal-root t)
60 (:reveal-trans "REVEAL_TRANS" nil org-reveal-transition t)
61 (:reveal-speed "REVEAL_SPEED" nil org-reveal-transition-speed t)
62 (:reveal-theme "REVEAL_THEME" nil org-reveal-theme t)
63 (:reveal-extra-css "REVEAL_EXTRA_CSS" nil org-reveal-extra-css newline)
64 (:reveal-extra-js "REVEAL_EXTRA_JS" nil org-reveal-extra-js nil)
65 (:reveal-hlevel "REVEAL_HLEVEL" nil nil t)
66 (:reveal-title-slide nil "reveal_title_slide" org-reveal-title-slide t)
67 (:reveal-slide-global-header nil "reveal_global_header" org-reveal-global-header t)
68 (:reveal-slide-global-footer nil "reveal_global_footer" org-reveal-global-footer t)
69 (:reveal-title-slide-background "REVEAL_TITLE_SLIDE_BACKGROUND" nil nil t)
70 (:reveal-title-slide-background-size "REVEAL_TITLE_SLIDE_BACKGROUND_SIZE" nil nil t)
71 (:reveal-title-slide-background-position "REVEAL_TITLE_SLIDE_BACKGROUND_POSITION" nil nil t)
72 (:reveal-title-slide-background-repeat "REVEAL_TITLE_SLIDE_BACKGROUND_REPEAT" nil nil t)
73 (:reveal-title-slide-background-transition "REVEAL_TITLE_SLIDE_BACKGROUND_TRANSITION" nil nil t)
74 (:reveal-default-slide-background "REVEAL_DEFAULT_SLIDE_BACKGROUND" nil nil t)
75 (:reveal-default-slide-background-size "REVEAL_DEFAULT_SLIDE_BACKGROUND_SIZE" nil nil t)
76 (:reveal-default-slide-background-position "REVEAL_DEFAULT_SLIDE_BACKGROUND_POSITION" nil nil t)
77 (:reveal-default-slide-background-repeat "REVEAL_DEFAULT_SLIDE_BACKGROUND_REPEAT" nil nil t)
78 (:reveal-default-slide-background-transition "REVEAL_DEFAULT_SLIDE_BACKGROUND_TRANSITION" nil nil t)
79 (:reveal-mathjax-url "REVEAL_MATHJAX_URL" nil org-reveal-mathjax-url t)
80 (:reveal-preamble "REVEAL_PREAMBLE" nil org-reveal-preamble t)
81 (:reveal-head-preamble "REVEAL_HEAD_PREAMBLE" nil org-reveal-head-preamble newline)
82 (:reveal-postamble "REVEAL_POSTAMBLE" nil org-reveal-postamble t)
83 (:reveal-multiplex-id "REVEAL_MULTIPLEX_ID" nil org-reveal-multiplex-id nil)
84 (:reveal-multiplex-secret "REVEAL_MULTIPLEX_SECRET" nil org-reveal-multiplex-secret nil)
85 (:reveal-multiplex-url "REVEAL_MULTIPLEX_URL" nil org-reveal-multiplex-url nil)
86 (:reveal-multiplex-socketio-url "REVEAL_MULTIPLEX_SOCKETIO_URL" nil org-reveal-multiplex-socketio-url nil)
87 (:reveal-slide-header "REVEAL_SLIDE_HEADER" nil org-reveal-slide-header t)
88 (:reveal-slide-footer "REVEAL_SLIDE_FOOTER" nil org-reveal-slide-footer t)
89 (:reveal-plugins "REVEAL_PLUGINS" nil nil t)
90 (:reveal-default-frag-style "REVEAL_DEFAULT_FRAG_STYLE" nil org-reveal-default-frag-style t)
91 (:reveal-single-file nil "reveal_single_file" org-reveal-single-file t)
92 (:reveal-init-script "REVEAL_INIT_SCRIPT" nil org-reveal-init-script space)
93 (:reveal-highlight-css "REVEAL_HIGHLIGHT_CSS" nil org-reveal-highlight-css nil)
94 )
95
96 :translate-alist
97 '((headline . org-reveal-headline)
98 (inner-template . org-reveal-inner-template)
99 (item . org-reveal-item)
100 (keyword . org-reveal-keyword)
101 (link . org-reveal-link)
102 (latex-environment . org-reveal-latex-environment)
103 (latex-fragment . (lambda (frag contents info)
104 (setq info (plist-put info :reveal-mathjax t))
105 (org-html-latex-fragment frag contents info)))
106 (plain-list . org-reveal-plain-list)
107 (quote-block . org-reveal-quote-block)
108 (section . org-reveal-section)
109 (src-block . org-reveal-src-block)
110 (special-block . org-reveal-special-block)
111 (template . org-reveal-template))
112
113 :filters-alist '((:filter-parse-tree . org-reveal-filter-parse-tree))
114 )
115
116 (defcustom org-reveal-root "./reveal.js"
117 "The root directory of reveal.js packages. It is the directory
118 within which js/reveal.js is."
119 :group 'org-export-reveal)
120
121 (defcustom org-reveal-hlevel 1
122 "The minimum level of headings that should be grouped into
123 vertical slides."
124 :group 'org-export-reveal
125 :type 'integer)
126
127 (defun org-reveal--get-hlevel (info)
128 "Get HLevel value safely.
129 If option \"REVEAL_HLEVEL\" is set, retrieve integer value from it,
130 else get value from custom variable `org-reveal-hlevel'."
131 (let ((hlevel-str (plist-get info :reveal-hlevel)))
132 (if hlevel-str (string-to-number hlevel-str)
133 org-reveal-hlevel)))
134
135 (defcustom org-reveal-title-slide 'auto
136 "Non-nil means insert a title slide.
137
138 When set to `auto', an automatic title slide is generated. When
139 set to a string, use this string as a format string for title
140 slide, where the following escaping elements are allowed:
141
142 %s stands for the title
143 %a stands for the author's name.
144 %e stands for the author's email.
145 %d stands for the date.
146 %% stands for a literal %."
147 :group 'org-export-reveal
148 :type '(choice (const :tag "No title slide" nil)
149 (const :tag "Auto title slide" 'auto)
150 (string :tag "Custom title slide")))
151
152 (defcustom org-reveal-transition
153 "default"
154 "Reveal transistion style."
155 :group 'org-export-reveal
156 :type 'string)
157
158 (defcustom org-reveal-transition-speed
159 "default"
160 "Reveal transistion speed."
161 :group 'org-export-reveal
162 :type 'string)
163
164 (defcustom org-reveal-theme
165 "moon"
166 "Reveal theme."
167 :group 'org-export-reveal
168 :type 'string)
169
170 (defcustom org-reveal-extra-js
171 ""
172 "URL to extra JS file."
173 :group 'org-export-reveal
174 :type 'string)
175
176 (defcustom org-reveal-extra-css
177 ""
178 "URL to extra css file."
179 :group 'org-export-reveal
180 :type 'string)
181
182
183 (defcustom org-reveal-multiplex-id ""
184 "The ID to use for multiplexing."
185 :group 'org-export-reveal
186 :type 'string)
187
188 (defcustom org-reveal-multiplex-secret ""
189 "The secret to use for master slide."
190 :group 'org-export-reveal
191 :type 'string)
192
193 (defcustom org-reveal-multiplex-url ""
194 "The url of the socketio server."
195 :group 'org-export-reveal
196 :type 'string)
197
198 (defcustom org-reveal-multiplex-socketio-url
199 ""
200 "the url of the socketio.js library"
201 :group 'org-export-reveal
202 :type 'string)
203
204 (defcustom org-reveal-control t
205 "Reveal control applet."
206 :group 'org-export-reveal
207 :type 'string)
208
209 (defcustom org-reveal-progress t
210 "Reveal progress applet."
211 :group 'org-export-reveal
212 :type 'boolean)
213
214 (defcustom org-reveal-history nil
215 "Reveal history applet."
216 :group 'org-export-reveal
217 :type 'boolean)
218
219 (defcustom org-reveal-center t
220 "Reveal center applet."
221 :group 'org-export-reveal
222 :type 'boolean)
223
224 (defcustom org-reveal-rolling-links nil
225 "Reveal use rolling links."
226 :group 'org-export-reveal
227 :type 'boolean)
228
229 (defcustom org-reveal-slide-number "c"
230 "Reveal showing slide numbers."
231 :group 'org-export-reveal
232 :type 'string)
233
234 (defcustom org-reveal-keyboard t
235 "Reveal use keyboard navigation."
236 :group 'org-export-reveal
237 :type 'boolean)
238
239 (defcustom org-reveal-overview t
240 "Reveal show overview."
241 :group 'org-export-reveal
242 :type 'boolean)
243
244 (defcustom org-reveal-width -1
245 "Slide width"
246 :group 'org-export-reveal
247 :type 'integer)
248
249 (defcustom org-reveal-height -1
250 "Slide height"
251 :group 'org-export-reveal
252 :type 'integer)
253
254 (defcustom org-reveal-margin "-1"
255 "Slide margin"
256 :group 'org-export-reveal
257 :type 'string)
258
259 (defcustom org-reveal-min-scale "-1"
260 "Minimum bound for scaling slide."
261 :group 'org-export-reveal
262 :type 'string)
263
264 (defcustom org-reveal-max-scale "-1"
265 "Maximum bound for scaling slide."
266 :group 'org-export-reveal
267 :type 'string)
268
269 (defcustom org-reveal-mathjax nil
270 "Obsolete. Org-reveal enable mathjax when it find latex
271 content."
272 :group 'org-export-reveal
273 :type 'boolean)
274
275 (defcustom org-reveal-mathjax-url
276 "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
277 "Default MathJax URL."
278 :group 'org-export-reveal
279 :type 'string)
280
281 (defcustom org-reveal-preamble nil
282 "Preamble contents."
283 :group 'org-export-reveal
284 :type 'string)
285
286 (defcustom org-reveal-head-preamble nil
287 "Preamble contents for head part."
288 :group 'org-export-reveal
289 :type 'string)
290
291 (defcustom org-reveal-postamble nil
292 "Postamble contents."
293 :group 'org-export-reveal
294 :type 'string)
295
296 (defcustom org-reveal-slide-header nil
297 "HTML content used as Reveal.js slide header"
298 :group 'org-export-reveal
299 :type 'string)
300
301 (defcustom org-reveal-global-header nil
302 "If non nil, slide header defined in org-reveal-slide-header
303 is displayed also on title and toc slide"
304 :group 'org-export-reveal
305 :type 'boolean)
306
307 (defcustom org-reveal-global-footer nil
308 "If non nil, slide footer defined in org-reveal-slide-footer
309 is displayed also on title and toc slide"
310 :group 'org-export-reveal
311 :type 'boolean)
312
313 (defcustom org-reveal-slide-footer nil
314 "HTML content used as Reveal.js slide footer"
315 :group 'org-export-reveal
316 :type 'string)
317
318 (defcustom org-reveal-default-frag-style nil
319 "Default fragment style."
320 :group 'org-export-reveal
321 :type 'string)
322
323 (defcustom org-reveal-plugins
324 '(classList markdown zoom notes)
325 "Default builtin plugins"
326 :group 'org-export-reveal
327 :type '(set
328 (const classList)
329 (const markdown)
330 (const highlight)
331 (const zoom)
332 (const notes)
333 (const search)
334 (const remotes)
335 (const multiplex)))
336
337 (defcustom org-reveal-external-plugins nil
338 "Additional third-party Plugins to load with reveal.
339 Each entry should contain a name and an expression of the form
340 \"{src: '%srelative/path/from/reveal/root', async:true/false,condition: jscallbackfunction(){}}\"
341 Note that some plugins have dependencies such as jquery; these must be included here as well,
342 BEFORE the plugins that depend on them."
343 :group 'org-export-reveal
344 :type 'alist)
345
346 (defcustom org-reveal-single-file nil
347 "Export presentation into one single HTML file, which embedded
348 JS scripts and pictures."
349 :group 'org-export-reveal
350 :type 'boolean)
351
352 (defcustom org-reveal-init-script nil
353 "Custom script that will be passed to Reveal.initialize."
354 :group 'org-export-reveal
355 :type 'string)
356
357 (defcustom org-reveal-highlight-css "%r/lib/css/zenburn.css"
358 "Hightlight.js CSS file."
359 :group 'org-export-reveal
360 :type 'string)
361
362 (defcustom org-reveal-note-key-char "n"
363 "If not nil, org-reveal-note-key-char's value is registered as
364 the key character to Org-mode's structure completion for
365 Reveal.js notes. When `<' followed by the key character are
366 typed and then the completion key is pressed, which is usually
367 `TAB', \"#+BEGIN_NOTES\" and \"#+END_NOTES\" is inserted.
368
369 The default value is \"n\". Set the variable to nil to disable
370 registering the completion"
371 :group 'org-export-reveal
372 :type 'string)
373
374 (defcustom org-reveal-klipsify-src nil
375 "Set to non-nil if you would like to make source code blocks editable in exported presentation."
376 :group 'org-export-reveal
377 :type 'boolean)
378
379 (defcustom org-reveal-klipse-css "https://storage.googleapis.com/app.klipse.tech/css/codemirror.css"
380 "Location of the codemirror css file for use with klipse."
381 :group 'org-export-reveal
382 :type 'string)
383
384 (defcustom org-reveal-klipse-js "https://storage.googleapis.com/app.klipse.tech/plugin_prod/js/klipse_plugin.min.js"
385 "location of the klipse js source code."
386 :group 'org-export-reveal
387 :type 'string)
388
389 (defvar org-reveal--last-slide-section-tag ""
390 "Variable to cache the section tag from the last slide. ")
391
392 (defun if-format (fmt val)
393 (if val (format fmt val) ""))
394
395 (defun frag-style (frag info)
396 "Return proper fragment string according to FRAG and the default fragment style.
397 FRAG is the fragment style set on element, INFO is a plist
398 holding contextual information."
399 (cond
400 ((string= frag t)
401 (let ((default-frag-style (plist-get info :reveal-default-frag-style)))
402 (if default-frag-style (format "fragment %s" default-frag-style)
403 "fragment")))
404 (t (format "fragment %s" frag))))
405
406 (defun frag-class (frag info)
407 "Return proper HTML string description of fragment style.
408 FRAG is the fragment style set on element, INFO is a plist
409 holding contextual information."
410 (and frag
411 (format " class=\"%s\"" (frag-style frag info))))
412
413 (defun org-reveal-special-block (special-block contents info)
414 "Transcode a SPECIAL-BLOCK element from Org to Reveal.
415 CONTENTS holds the contents of the block. INFO is a plist
416 holding contextual information.
417
418 If the block type is 'NOTES', transcode the block into a
419 Reveal.js slide note. Otherwise, export the block as by the HTML
420 exporter."
421 (let ((block-type (org-element-property :type special-block)))
422 (if (string= block-type "NOTES")
423 (format "<aside class=\"notes\">\n%s\n</aside>\n" contents)
424 (org-html-special-block special-block contents info))))
425
426 ;; Copied from org-html-headline and modified to embed org-reveal
427 ;; specific attributes.
428 (defun org-reveal-headline (headline contents info)
429 "Transcode a HEADLINE element from Org to HTML.
430 CONTENTS holds the contents of the headline. INFO is a plist
431 holding contextual information."
432 (unless (org-element-property :footnote-section-p headline)
433 (if (org-export-low-level-p headline info)
434 ;; This is a deep sub-tree: export it as in ox-html.
435 (org-html-headline headline contents info)
436 ;; Standard headline. Export it as a slide
437 (let* ((level (org-export-get-relative-level headline info))
438 (section-number (mapconcat #'number-to-string
439 (org-export-get-headline-number headline info)
440 "-"))
441 (preferred-id (or (org-element-property :CUSTOM_ID headline)
442 section-number
443 (org-element-property :ID headline)))
444 (hlevel (org-reveal--get-hlevel info))
445 (header (plist-get info :reveal-slide-header))
446 (header-div (when header (format "<div class=\"slide-header\">%s</div>\n" header)))
447 (footer (plist-get info :reveal-slide-footer))
448 (footer-div (when footer (format "<div class=\"slide-footer\">%s</div>\n" footer)))
449 (first-sibling (org-export-first-sibling-p headline info))
450 (last-sibling (org-export-last-sibling-p headline info))
451 (default-slide-background (plist-get info :reveal-default-slide-background))
452 (default-slide-background-size (plist-get info :reveal-default-slide-background-size))
453 (default-slide-background-position (plist-get info :reveal-default-slide-background-position))
454 (default-slide-background-repeat (plist-get info :reveal-default-slide-background-repeat))
455 (default-slide-background-transition (plist-get info :reveal-default-slide-background-transition))
456 (slide-section-tag (format "<section %s%s>\n"
457 (org-html--make-attribute-string
458 `(:id ,(format "slide-sec-%s" preferred-id)
459 :data-transition ,(org-element-property :REVEAL_DATA_TRANSITION headline)
460 :data-state ,(org-element-property :REVEAL_DATA_STATE headline)
461 :data-background ,(or (org-element-property :REVEAL_BACKGROUND headline)
462 default-slide-background)
463 :data-background-size ,(or (org-element-property :REVEAL_BACKGROUND_SIZE headline)
464 default-slide-background-size)
465 :data-background-position ,(or (org-element-property :REVEAL_BACKGROUND_POSITION headline)
466 default-slide-background-position)
467 :data-background-repeat ,(or (org-element-property :REVEAL_BACKGROUND_REPEAT headline)
468 default-slide-background-repeat)
469 :data-background-transition ,(or (org-element-property :REVEAL_BACKGROUND_TRANS headline)
470 default-slide-background-transition)))
471 (let ((extra-attrs (org-element-property :REVEAL_EXTRA_ATTR headline)))
472 (if extra-attrs (format " %s" extra-attrs) ""))))
473 (ret (concat
474 (if (or (/= level 1) (not first-sibling))
475 ;; Not the first heading. Close previou slide.
476 (concat
477 ;; Slide footer if any
478 footer-div
479 ;; Close previous slide
480 "</section>\n"
481 (if (<= level hlevel)
482 ;; Close previous vertical slide group.
483 "</section>\n")))
484 (if (<= level hlevel)
485 ;; Add an extra "<section>" to group following slides
486 ;; into vertical slide group. Transition override
487 ;; attributes are attached at this level, too.
488 (let ((attrs
489 (org-html--make-attribute-string
490 `(:data-transition ,(org-element-property :REVEAL_DATA_TRANSITION headline)))))
491 (if (string= attrs "")
492 "<section>\n"
493 (format "<section %s>\n" attrs))))
494 ;; Start a new slide.
495 (prog1
496 slide-section-tag
497 ;; Cache the current slide's section tag, except the id attr
498 (setq org-reveal--last-slide-section-tag
499 (replace-regexp-in-string "id\\s-*=\\s-*[\][\"].*?[\][\"]"
500 "" slide-section-tag)))
501 ;; Slide header if any.
502 header-div
503 ;; The HTML content of the headline
504 ;; Strip the <div> tags, if any
505 (let ((html (org-html-headline headline contents info)))
506 (if (string-prefix-p "<div" html)
507 ;; Remove the first <div> and the last </div> tags from html
508 (concat "<"
509 (mapconcat 'identity
510 (butlast (cdr (split-string html "<" t)))
511 "<"))
512 ;; Return the HTML content unchanged
513 html))
514 (if (and (= level 1)
515 (org-export-last-sibling-p headline info))
516 ;; Last head 1. Close all slides.
517 (concat
518 ;; Slide footer if any
519 footer-div
520 "</section>\n</section>\n")))))
521 ret))))
522
523 (defgroup org-export-reveal nil
524 "Options for exporting Orgmode files to reveal.js HTML pressentations."
525 :tag "Org Export Reveal"
526 :group 'org-export)
527
528 (defun org-reveal--read-file (file)
529 "Return the content of file"
530 (with-temp-buffer
531 (insert-file-contents-literally file)
532 (buffer-string)))
533
534 (defun org-reveal--file-url-to-path (url)
535 "Convert URL that points to local files to file path."
536 (replace-regexp-in-string
537 (if (string-equal system-type "windows-nt") "^file:///" "^file://")
538 "" url))
539
540 (defun org-reveal--css-label (in-single-file file-name style-id)
541 "Generate an HTML label for including a CSS file, if
542 IN-SINGLE-FILE is t, the content of FILE-NAME is embedded,
543 otherwise, a `<link>' label is generated."
544 (when (and file-name (not (string= file-name "")))
545 (if in-single-file
546 ;; Single-file
547 (let ((local-file-name (org-reveal--file-url-to-path file-name)))
548 (if (file-readable-p local-file-name)
549 (concat "<style type=\"text/css\">\n"
550 (org-reveal--read-file local-file-name)
551 "\n</style>\n")
552 ;; But file is not readable.
553 (error "Cannot read %s" file-name)))
554 ;; Not in-single-file
555 (concat "<link rel=\"stylesheet\" href=\"" file-name "\""
556 (if style-id (format " id=\"%s\"" style-id))
557 "/>\n"))))
558
559 (defun org-reveal-stylesheets (info)
560 "Return the HTML contents for declaring reveal stylesheets
561 using custom variable `org-reveal-root'."
562 (let* ((root-path (file-name-as-directory (plist-get info :reveal-root)))
563 (reveal-css (concat root-path "css/reveal.css"))
564 (theme (plist-get info :reveal-theme))
565 (theme-css (concat root-path "css/theme/" theme ".css"))
566 (extra-css (plist-get info :reveal-extra-css))
567 (in-single-file (plist-get info :reveal-single-file)))
568 (concat
569 ;; Default embedded style sheets
570 "<style type=\"text/css\">
571 .underline { text-decoration: underline; }
572 </style>
573 "
574 ;; stylesheets
575 (mapconcat (lambda (elem) (org-reveal--css-label in-single-file (car elem) (cdr elem)))
576 (append (list (cons reveal-css nil)
577 (cons theme-css "theme"))
578 (mapcar (lambda (a) (cons a nil))
579 (split-string extra-css "\n")))
580 "\n")
581
582 ;; Include CSS for highlight.js if necessary
583 (if (org-reveal--using-highlight.js info)
584 (format "<link rel=\"stylesheet\" href=\"%s\"/>"
585 (format-spec (plist-get info :reveal-highlight-css)
586 `((?r . ,(directory-file-name root-path))))))
587 ;; print-pdf
588 (if in-single-file ""
589 (format "
590 <!-- If the query includes 'print-pdf', include the PDF print sheet -->
591 <script>
592 if( window.location.search.match( /print-pdf/gi ) ) {
593 var link = document.createElement( 'link' );
594 link.rel = 'stylesheet';
595 link.type = 'text/css';
596 link.href = '%scss/print/pdf.css';
597 document.getElementsByTagName( 'head' )[0].appendChild( link );
598 }
599 </script>
600 "
601 root-path)))))
602
603 (defun org-reveal-mathjax-scripts (info)
604 "Return the HTML contents for declaring MathJax scripts"
605 (if (plist-get info :reveal-mathjax)
606 ;; MathJax enabled.
607 (format "<script type=\"text/javascript\" src=\"%s\"></script>\n"
608 (plist-get info :reveal-mathjax-url))))
609
610 (defun org-reveal-scripts (info)
611 "Return the necessary scripts for initializing reveal.js using
612 custom variable `org-reveal-root'."
613 (let* ((root-path (file-name-as-directory (plist-get info :reveal-root)))
614 (head-min-js (concat root-path "lib/js/head.min.js"))
615 (reveal-js (concat root-path "js/reveal.js"))
616 ;; Local files
617 (local-root-path (org-reveal--file-url-to-path root-path))
618 (local-head-min-js (concat local-root-path "lib/js/head.min.js"))
619 (local-reveal-js (concat local-root-path "js/reveal.js"))
620 (in-single-file (plist-get info :reveal-single-file)))
621 (concat
622 ;; reveal.js/lib/js/head.min.js
623 ;; reveal.js/js/reveal.js
624 (if (and in-single-file
625 (file-readable-p local-head-min-js)
626 (file-readable-p local-reveal-js))
627 ;; Embed scripts into HTML
628 (concat "<script>\n"
629 (org-reveal--read-file local-head-min-js)
630 "\n"
631 (org-reveal--read-file local-reveal-js)
632 "\n</script>")
633 ;; Fall-back to extern script links
634 (if in-single-file
635 ;; Tried to embed scripts but failed. Print a message about possible errors.
636 (error (concat "Cannot read "
637 (mapconcat 'identity
638 (delq nil (mapcar (lambda (file) (if (not (file-readable-p file)) file))
639 (list local-head-min-js local-reveal-js)))
640 ", "))))
641 (concat
642 "<script src=\"" head-min-js "\"></script>\n"
643 "<script src=\"" reveal-js "\"></script>\n"))
644 ;; plugin headings
645 "
646 <script>
647 // Full list of configuration options available here:
648 // https://github.com/hakimel/reveal.js#configuration
649 Reveal.initialize({
650 "
651 (format "
652 controls: %s,
653 progress: %s,
654 history: %s,
655 center: %s,
656 slideNumber: %s,
657 rollingLinks: %s,
658 keyboard: %s,
659 overview: %s,
660 "
661 (if (plist-get info :reveal-control) "true" "false")
662 (if (plist-get info :reveal-progress) "true" "false")
663 (if (plist-get info :reveal-history) "true" "false")
664 (if (plist-get info :reveal-center) "true" "false")
665 (let ((slide-number (plist-get info :reveal-slide-number)))
666 (if slide-number (format "'%s'" slide-number)
667 "false"))
668 (if (plist-get info :reveal-rolling-links) "true" "false")
669 (if (plist-get info :reveal-keyboard) "true" "false")
670 (if (plist-get info :reveal-overview) "true" "false"))
671
672 ;; slide width
673 (let ((width (plist-get info :reveal-width)))
674 (if (> width 0) (format "width: %d,\n" width) ""))
675
676 ;; slide height
677 (let ((height (plist-get info :reveal-height)))
678 (if (> height 0) (format "height: %d,\n" height) ""))
679
680 ;; slide margin
681 (let ((margin (string-to-number (plist-get info :reveal-margin))))
682 (if (>= margin 0) (format "margin: %.2f,\n" margin) ""))
683
684 ;; slide minimum scaling factor
685 (let ((min-scale (string-to-number (plist-get info :reveal-min-scale))))
686 (if (> min-scale 0) (format "minScale: %.2f,\n" min-scale) ""))
687
688 ;; slide maximux scaling factor
689 (let ((max-scale (string-to-number (plist-get info :reveal-max-scale))))
690 (if (> max-scale 0) (format "maxScale: %.2f,\n" max-scale) ""))
691
692 ;; thems and transitions
693 (format "
694 theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
695 transition: Reveal.getQueryHash().transition || '%s', // default/cube/page/concave/zoom/linear/fade/none
696 transitionSpeed: '%s',\n"
697 (plist-get info :reveal-trans)
698 (plist-get info :reveal-speed))
699
700 ;; multiplexing - depends on defvar 'client-multiplex'
701 (when (plist-get info :reveal-multiplex-id)
702 (format
703 "multiplex: {
704 secret: %s, // null if client
705 id: '%s', // id, obtained from socket.io server
706 url: '%s' // Location of socket.io server
707 },\n"
708 (if (eq client-multiplex nil)
709 (format "'%s'" (plist-get info :reveal-multiplex-secret))
710 (format "null"))
711 (plist-get info :reveal-multiplex-id)
712 (plist-get info :reveal-multiplex-url)))
713
714 ;; optional JS library heading
715 (if in-single-file ""
716 (concat
717 "
718 // Optional libraries used to extend on reveal.js
719 dependencies: [
720 "
721 ;; JS libraries
722 (let* ((builtins
723 '(classList (format " { src: '%slib/js/classList.js', condition: function() { return !document.body.classList; } }" root-path)
724 markdown (format " { src: '%splugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
725 { src: '%splugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }" root-path root-path)
726 highlight (format " { src: '%splugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }" root-path)
727 zoom (format " { src: '%splugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } }" root-path)
728 notes (format " { src: '%splugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }" root-path)
729 search (format " { src: '%splugin/search/search.js', async: true, condition: function() { return !!document.body.classList; } }" root-path)
730 remotes (format " { src: '%splugin/remotes/remotes.js', async: true, condition: function() { return !!document.body.classList; } }" root-path)
731 multiplex (format " { src: '%s', async: true },\n%s"
732 (plist-get info :reveal-multiplex-socketio-url)
733 ; following ensures that either client.js or master.js is included depending on defva client-multiplex value state
734 (if (not client-multiplex)
735 (progn
736 (if (plist-get info :reveal-multiplex-secret)
737 (setq client-multiplex t))
738 (format " { src: '%splugin/multiplex/master.js', async: true }" root-path))
739 (format " { src: '%splugin/multiplex/client.js', async: true }" root-path)))))
740 (builtin-codes
741 (mapcar
742 (lambda (p)
743 (eval (plist-get builtins p)))
744 (let ((buffer-plugins (condition-case e
745 (car (read-from-string (plist-get info :reveal-plugins)))
746 (end-of-file nil)
747 (wrong-type-argument nil))))
748 (or (and buffer-plugins (listp buffer-plugins) buffer-plugins)
749 org-reveal-plugins))))
750 (external-plugins
751 (cl-loop for (key . value) in org-reveal-external-plugins
752 collect (format value root-path )) )
753 (all-plugins (if external-plugins (append external-plugins builtin-codes) builtin-codes))
754 (extra-codes (plist-get info :reveal-extra-js))
755 (total-codes
756 (if (string= "" extra-codes) all-plugins (append (list extra-codes) all-plugins)) ))
757 (mapconcat 'identity total-codes ",\n"))
758 "]\n"
759 ))
760 (let ((init-script (plist-get info :reveal-init-script)))
761 (if init-script (concat (if in-single-file "" ",") init-script)))
762 "});\n</script>\n")))
763
764 (defun org-reveal-toc (depth info)
765 "Build a slide of table of contents."
766 (let ((toc (org-html-toc depth info)))
767 (when toc
768 (let ((toc-slide-with-header (plist-get info :reveal-slide-global-header))
769 (toc-slide-with-footer (plist-get info :reveal-slide-global-footer)))
770 (concat "<section id=\"table-of-contents\">\n"
771 (when toc-slide-with-header
772 (let ((header (plist-get info :reveal-slide-header)))
773 (when header (format "<div class=\"slide-header\">%s</div>\n" header))))
774 (replace-regexp-in-string "<a href=\"#" "<a href=\"#/slide-" toc)
775 (when toc-slide-with-footer
776 (let ((footer (plist-get info :reveal-slide-footer)))
777 (when footer (format "<div class=\"slide-footer\">%s</div>\n" footer))))
778 "</section>\n")))))
779
780 (defun org-reveal-inner-template (contents info)
781 "Return body of document string after HTML conversion.
782 CONTENTS is the transcoded contents string. INFO is a plist
783 holding export options."
784 (concat
785 ;; Table of contents.
786 (let ((depth (plist-get info :with-toc)))
787 (when (and depth
788 (not (plist-get info :reveal-subtree)))
789 (org-reveal-toc depth info)))
790 ;; Document contents.
791 contents))
792
793 (defun org-reveal-parse-token (key &optional value)
794 "Return HTML tags or perform SIDE EFFECT according to key.
795 Use the previous section tag as the tag of the split section. "
796 (case (intern key)
797 (split (format "</section>\n%s" org-reveal--last-slide-section-tag))))
798
799 (defun org-reveal-parse-keyword-value (value)
800 "According to the value content, return HTML tags to split slides."
801 (let ((tokens (mapcar
802 (lambda (x) (split-string x ":"))
803 (split-string value))))
804 (mapconcat
805 (lambda (x) (apply 'org-reveal-parse-token x))
806 tokens
807 "")))
808
809 ;; Copied from org-html-format-list-item. Overwrite HTML class
810 ;; attribute when there is attr_html attributes.
811 (defun org-reveal-format-list-item (contents type checkbox attributes info
812 &optional term-counter-id
813 headline)
814 "Format a list item into HTML."
815 (let ((attr-html (cond (attributes (format " %s" (org-html--make-attribute-string attributes)))
816 (checkbox (format " class=\"%s\"" (symbol-name checkbox)))
817 (t "")))
818 (checkbox (concat (org-html-checkbox checkbox info)
819 (and checkbox " ")))
820 (br (org-html-close-tag "br" nil info)))
821 (concat
822 (case type
823 (ordered
824 (let* ((counter term-counter-id)
825 (extra (if counter (format " value=\"%s\"" counter) "")))
826 (concat
827 (format "<li%s%s>" attr-html extra)
828 (when headline (concat headline br)))))
829 (unordered
830 (let* ((id term-counter-id)
831 (extra (if id (format " id=\"%s\"" id) "")))
832 (concat
833 (format "<li%s%s>" attr-html extra)
834 (when headline (concat headline br)))))
835 (descriptive
836 (let* ((term term-counter-id))
837 (setq term (or term "(no term)"))
838 ;; Check-boxes in descriptive lists are associated to tag.
839 (concat (format "<dt%s>%s</dt>"
840 attr-html (concat checkbox term))
841 (format "<dd%s>" attr-html)))))
842 (unless (eq type 'descriptive) checkbox)
843 (and contents (org-trim contents))
844 (case type
845 (ordered "</li>")
846 (unordered "</li>")
847 (descriptive "</dd>")))))
848
849 ;; Copied from org-html-item, changed to call
850 ;; org-reveal-format-list-item.
851 (defun org-reveal-item (item contents info)
852 "Transcode an ITEM element from Org to Reveal.
853 CONTENTS holds the contents of the item. INFO is a plist holding
854 contextual information."
855 (let* ((plain-list (org-export-get-parent item))
856 (type (org-element-property :type plain-list))
857 (counter (org-element-property :counter item))
858 (attributes (org-export-read-attribute :attr_html item))
859 ; (attributes (org-html--make-attribute-string (org-export-read-attribute :attr_html item)))
860 (checkbox (org-element-property :checkbox item))
861 (tag (let ((tag (org-element-property :tag item)))
862 (and tag (org-export-data tag info)))))
863 (org-reveal-format-list-item
864 contents type checkbox attributes info (or tag counter))))
865
866 (defun org-reveal-keyword (keyword contents info)
867 "Transcode a KEYWORD element from Org to Reveal,
868 and may change custom variables as SIDE EFFECT.
869 CONTENTS is nil. INFO is a plist holding contextual information."
870 (let ((key (org-element-property :key keyword))
871 (value (org-element-property :value keyword)))
872 (case (intern key)
873 (REVEAL (org-reveal-parse-keyword-value value))
874 (REVEAL_HTML value)
875 (HTML value))))
876 (defun org-reveal-embedded-svg (path)
877 "Embed the SVG content into Reveal HTML."
878 (with-temp-buffer
879 (insert-file-contents-literally path)
880 (let ((start (re-search-forward "<[ \t\n]*svg[ \t\n]"))
881 (end (re-search-forward "<[ \t\n]*/svg[ \t\n]*>")))
882 (concat "<svg " (buffer-substring-no-properties start end)))))
883
884 (defun org-reveal--format-image-data-uri (link path info)
885 "Generate the data URI for the image referenced by LINK."
886 (let* ((ext (downcase (file-name-extension path))))
887 (if (string= ext "svg")
888 (org-reveal-embedded-svg path)
889 (org-html-close-tag
890 "img"
891 (org-html--make-attribute-string
892 (org-combine-plists
893 (list :src
894 (concat
895 "data:image/"
896 ;; Image type
897 ext
898 ";base64,"
899 ;; Base64 content
900 (with-temp-buffer
901 (insert-file-contents-literally path)
902 (base64-encode-region 1 (point-max))
903 (buffer-string))))
904 ;; Get attribute list from parent element
905 ;; Copied from ox-html.el
906 (let* ((parent (org-export-get-parent-element link))
907 (link (let ((container (org-export-get-parent link)))
908 (if (and (eq (org-element-type container) 'link)
909 (org-html-inline-image-p link info))
910 container
911 link))))
912 (and (eq (org-element-map parent 'link 'identity info t) link)
913 (org-export-read-attribute :attr_html parent)))))
914 info))))
915
916 (defun org-reveal-link (link desc info)
917 "Transcode a LINK object from Org to Reveal. The result is
918 identical to ox-html expect for image links. When `org-reveal-single-file' is t,
919 the result is the Data URIs of the referenced image."
920 (let* ((want-embed-image (and (plist-get info :reveal-single-file)
921 (plist-get info :html-inline-images)
922 (string= "file" (org-element-property :type link))
923 (org-export-inline-image-p
924 link (plist-get info :html-inline-image-rules))))
925 (raw-path (org-element-property :path link))
926 (clean-path (org-reveal--file-url-to-path raw-path))
927 (can-embed-image (and want-embed-image
928 (file-readable-p clean-path))))
929 (if can-embed-image
930 (org-reveal--format-image-data-uri link clean-path info)
931 (if want-embed-image
932 (error "Cannot embed image %s" raw-path)
933 (replace-regexp-in-string "<a href=\"#" "<a href=\"#/slide-"
934 (org-html-link link desc info))))))
935
936 (defun org-reveal-latex-environment (latex-env contents info)
937 "Transcode a LaTeX environment from Org to Reveal.
938
939 LATEX-ENV is the Org element. CONTENTS is the contents of the environment. INFO is a plist holding contextual information "
940 (setq info (plist-put info :reveal-mathjax t))
941 (let ((attrs (org-export-read-attribute :attr_html latex-env)))
942 (format "<div%s>\n%s\n</div>\n"
943 (if attrs (concat " " (org-html--make-attribute-string attrs)) "")
944 (org-html-latex-environment latex-env contents info))))
945
946 (defun org-reveal-plain-list (plain-list contents info)
947 "Transcode a PLAIN-LIST element from Org to Reveal.
948
949 CONTENTS is the contents of the list. INFO is a plist holding
950 contextual information.
951
952 Extract and set `attr_html' to plain-list tag attributes."
953 (let ((tag (case (org-element-property :type plain-list)
954 (ordered "ol")
955 (unordered "ul")
956 (descriptive "dl")))
957 (attrs (org-export-read-attribute :attr_html plain-list)))
958 (format "<%s%s>\n%s\n</%s>"
959 tag
960 (if attrs (concat " " (org-html--make-attribute-string attrs)) "")
961 contents
962 tag
963 )))
964
965 (defun org-reveal--build-pre/postamble (type info)
966 "Return document preamble or postamble as a string, or nil."
967 (let ((section (plist-get info (intern (format ":reveal-%s" type))))
968 (spec (org-html-format-spec info)))
969 (when section
970 (let ((section-contents
971 (if (functionp (intern section)) (funcall (intern section) info)
972 ;; else section is a string.
973 (format-spec section spec))))
974 (when (org-string-nw-p section-contents)
975 (org-element-normalize-string section-contents))))))
976
977
978 (defun org-reveal-section (section contents info)
979 "Transcode a SECTION element from Org to Reveal.
980 CONTENTS holds the contents of the section. INFO is a plist
981 holding contextual information."
982 ;; Just return the contents. No "<div>" tags.
983 contents)
984
985 (defun org-reveal--using-highlight.js (info)
986 "Check whether highlight.js plugin is enabled."
987 (let ((reveal-plugins (condition-case e
988 (car (read-from-string (plist-get info :reveal-plugins)))
989 (end-of-file nil)
990 (wrong-type-argument nil))))
991 (memq 'highlight (or (and reveal-plugins (listp reveal-plugins) reveal-plugins)
992 org-reveal-plugins))))
993
994 (defun org-reveal-src-block (src-block contents info)
995 "Transcode a SRC-BLOCK element from Org to Reveal.
996 CONTENTS holds the contents of the item. INFO is a plist holding
997 contextual information."
998 (if (org-export-read-attribute :attr_html src-block :textarea)
999 (org-html--textarea-block src-block)
1000 (let* ((use-highlight (org-reveal--using-highlight.js info))
1001 (lang (org-element-property :language src-block))
1002 (caption (org-export-get-caption src-block))
1003 (code (if (not use-highlight)
1004 (org-html-format-code src-block info)
1005 (cl-letf (((symbol-function 'org-html-htmlize-region-for-paste)
1006 #'buffer-substring))
1007 (org-html-format-code src-block info))))
1008 (frag (org-export-read-attribute :attr_reveal src-block :frag))
1009 (code-attribs (or (org-export-read-attribute
1010 :attr_reveal src-block :code_attribs) ""))
1011 (label (let ((lbl (org-element-property :name src-block)))
1012 (if (not lbl) ""
1013 (format " id=\"%s\"" lbl))))
1014 (klipsify (and org-reveal-klipsify-src
1015 (member lang '("javascript" "js" "ruby" "scheme" "clojure" "php" "html"))))
1016 (langselector (cond ((or (string= lang "js") (string= lang "javascript")) "selector_eval_js")
1017 ((string= lang "clojure") "selector")
1018 ((string= lang "python") "selector_eval_python_client")
1019 ((string= lang "scheme") "selector_eval_scheme")
1020 ((string= lang "ruby") "selector_eval_ruby")
1021 ((string= lang "html") "selector_eval_html"))
1022 )
1023 )
1024 (if (not lang)
1025 (format "<pre %s%s>\n%s</pre>"
1026 (or (frag-class frag info) " class=\"example\"")
1027 label
1028 code)
1029 (if klipsify
1030 (concat
1031 "<iframe style=\"background-color:white;\" height=\"500px\" width= \"100%\" srcdoc='<html><body><pre><code "
1032 (if (string= lang "html" )"data-editor-type=\"html\" " "") "class=\"klipse\" "code-attribs ">
1033 " (if (string= lang "html")
1034 (replace-regexp-in-string "'" "&#39;"
1035 (replace-regexp-in-string "&" "&amp;"
1036 (replace-regexp-in-string "<" "&lt;"
1037 (replace-regexp-in-string ">" "&gt;"
1038 (cl-letf (((symbol-function 'org-html-htmlize-region-for-paste)
1039 #'buffer-substring))
1040 (org-html-format-code src-block info))))))
1041 (replace-regexp-in-string "'" "&#39;"
1042 code)) "
1043 </code></pre>
1044 <link rel= \"stylesheet\" type= \"text/css\" href=\"" org-reveal-klipse-css "\">
1045 <style>
1046 .CodeMirror { font-size: 2em; }
1047 </style>
1048 <script>
1049 window.klipse_settings = { " langselector ": \".klipse\" };
1050 </script>
1051 <script src= \"" org-reveal-klipse-js "\"></script></body></html>
1052 '>
1053 </iframe>")
1054 (format
1055 "<div class=\"org-src-container\">\n%s%s\n</div>"
1056 (if (not caption) ""
1057 (format "<label class=\"org-src-name\">%s</label>"
1058 (org-export-data caption info)))
1059 (if use-highlight
1060 (format "\n<pre%s%s><code class=\"%s\" %s>%s</code></pre>"
1061 (or (frag-class frag info) "")
1062 label lang code-attribs code)
1063 (format "\n<pre %s%s>%s</pre>"
1064 (or (frag-class frag info)
1065 (format " class=\"src src-%s\"" lang))
1066 label code)
1067 )))))))
1068
1069 (defun org-reveal-quote-block (quote-block contents info)
1070 "Transcode a QUOTE-BLOCK element from Org to Reveal.
1071 CONTENTS holds the contents of the block INFO is a plist holding
1072 contextual information."
1073 (format "<blockquote %s>\n%s</blockquote>"
1074 (frag-class (org-export-read-attribute :attr_reveal quote-block :frag) info)
1075 contents))
1076
1077
1078 (defun org-reveal--auto-title-slide-template (info)
1079 "Generate the automatic title slide template."
1080 (let* ((spec (org-html-format-spec info))
1081 (title (org-export-data (plist-get info :title) info))
1082 (author (cdr (assq ?a spec)))
1083 (email (cdr (assq ?e spec)))
1084 (date (cdr (assq ?d spec))))
1085 (concat
1086 (when (and (plist-get info :with-title)
1087 (org-string-nw-p title))
1088 (concat "<h1 class=\"title\">" title "</h1>"))
1089 (when (and (plist-get info :with-author)
1090 (org-string-nw-p author))
1091 (concat "<h2 class=\"author\">" author "</h2>"))
1092 (when (and (plist-get info :with-email)
1093 (org-string-nw-p email))
1094 (concat "<h2 class=\"email\">" email "</h2>"))
1095 (when (and (plist-get info :with-date)
1096 (org-string-nw-p date))
1097 (concat "<h2 class=\"date\">" date "</h2>"))
1098 (when (plist-get info :time-stamp-file)
1099 (concat "<p class=\"date\">"
1100 (org-html--translate "Created" info)
1101 ": "
1102 (format-time-string org-html-metadata-timestamp-format)
1103 "</p>")))))
1104
1105 (defun org-reveal-template (contents info)
1106 "Return complete document string after HTML conversion.
1107 contents is the transcoded contents string.
1108 info is a plist holding export options."
1109 (concat
1110 (format "<!DOCTYPE html>\n<html%s>\n<head>\n"
1111 (if-format " lang=\"%s\"" (plist-get info :language)))
1112 "<meta charset=\"utf-8\"/>\n"
1113 (if-format "<title>%s</title>\n" (org-export-data (plist-get info :title) info))
1114 (if-format "<meta name=\"author\" content=\"%s\"/>\n" (plist-get info :author))
1115 (if-format "<meta name=\"description\" content=\"%s\"/>\n" (plist-get info :description))
1116 (if-format "<meta name=\"keywords\" content=\"%s\"/>\n" (plist-get info :keywords))
1117 (org-reveal-stylesheets info)
1118 (org-reveal-mathjax-scripts info)
1119 (org-reveal--build-pre/postamble 'head-preamble info)
1120 (org-element-normalize-string (plist-get info :html-head))
1121 (org-element-normalize-string (plist-get info :html-head-extra))
1122 "</head>
1123 <body>\n"
1124 (org-reveal--build-pre/postamble 'preamble info)
1125 "<div class=\"reveal\">
1126 <div class=\"slides\">\n"
1127 ;; Title slides
1128 (let ((title-slide (plist-get info :reveal-title-slide)))
1129 (when (and title-slide (not (plist-get info :reveal-subtree)))
1130 (let ((title-slide-background (plist-get info :reveal-title-slide-background))
1131 (title-slide-background-size (plist-get info :reveal-title-slide-background-size))
1132 (title-slide-background-position (plist-get info :reveal-title-slide-background-position))
1133 (title-slide-background-repeat (plist-get info :reveal-title-slide-background-repeat))
1134 (title-slide-background-transition (plist-get info :reveal-title-slide-background-transition))
1135 (title-slide-with-header (plist-get info :reveal-slide-global-header))
1136 (title-slide-with-footer (plist-get info :reveal-slide-global-footer)))
1137 (concat "<section id=\"sec-title-slide\""
1138 (when title-slide-background
1139 (concat " data-background=\"" title-slide-background "\""))
1140 (when title-slide-background-size
1141 (concat " data-background-size=\"" title-slide-background-size "\""))
1142 (when title-slide-background-position
1143 (concat " data-background-position=\"" title-slide-background-position "\""))
1144 (when title-slide-background-repeat
1145 (concat " data-background-repeat=\"" title-slide-background-repeat "\""))
1146 (when title-slide-background-transition
1147 (concat " data-background-transition=\"" title-slide-background-transition "\""))
1148 ">"
1149 (when title-slide-with-header
1150 (let ((header (plist-get info :reveal-slide-header)))
1151 (when header (format "<div class=\"slide-header\">%s</div>\n" header))))
1152 (cond ((eq title-slide nil) nil)
1153 ((stringp title-slide) (format-spec title-slide (org-html-format-spec info)))
1154 ((eq title-slide 'auto) (org-reveal--auto-title-slide-template info)))
1155 "\n"
1156 (when title-slide-with-footer
1157 (let ((footer (plist-get info :reveal-slide-footer)))
1158 (when footer (format "<div class=\"slide-footer\">%s</div>\n" footer))))
1159 "</section>\n"))))
1160 contents
1161 "</div>
1162 </div>\n"
1163 (org-reveal--build-pre/postamble 'postamble info)
1164 (org-reveal-scripts info)
1165 "</body>
1166 </html>\n"))
1167
1168 (defun org-reveal-filter-parse-tree (tree backend info)
1169 "Do filtering before parsing TREE.
1170
1171 Tree is the parse tree being exported. BACKEND is the export
1172 back-end used. INFO is a plist-used as a communication channel.
1173
1174 Assuming BACKEND is `reveal'.
1175
1176 Each `attr_reveal' attribute is mapped to corresponding
1177 `attr_html' attributes."
1178 (let ((default-frag-style (plist-get info :reveal-default-frag-style)))
1179 (org-element-map tree (remq 'item org-element-all-elements)
1180 (lambda (elem) (org-reveal-append-frag elem default-frag-style))))
1181 ;; Return the updated tree.
1182 tree)
1183
1184 (defun org-reveal--update-attr-html (elem frag default-style &optional frag-index)
1185 "Update ELEM's attr_html attribute with reveal's
1186 fragment attributes."
1187 (let ((attr-html (org-element-property :attr_html elem)))
1188 (when (and frag (not (string= frag "none")))
1189 (push (cond ((string= frag t)
1190 (if default-style (format ":class fragment %s" default-style)
1191 ":class fragment"))
1192 (t (format ":class fragment %s" frag)))
1193 attr-html)
1194 (when frag-index
1195 (push (format ":data-fragment-index %s" frag-index) attr-html)))
1196 (org-element-put-property elem :attr_html attr-html)))
1197
1198 (defun org-reveal-append-frag (elem default-style)
1199 "Read org-reveal's fragment attribute from ELEM and append
1200 transformed fragment attribute to ELEM's attr_html plist."
1201 (let ((frag (org-export-read-attribute :attr_reveal elem :frag))
1202 (frag-index (org-export-read-attribute :attr_reveal elem :frag_idx)))
1203 (if frag
1204 (cond ((and (string= (org-element-type elem) 'plain-list)
1205 (char-equal (string-to-char frag) ?\())
1206 (let* ((frag-list (car (read-from-string frag)))
1207 (frag-list (if default-style
1208 (mapcar (lambda (s)
1209 "Replace t with default-style"
1210 (if (string= s t) default-style
1211 s))
1212 frag-list)
1213 frag-list))
1214 (items (org-element-contents elem)))
1215 (if frag-index
1216 (mapcar* 'org-reveal--update-attr-html
1217 items frag-list default-style (car (read-from-string frag-index)))
1218 (let* ((last-frag (car (last frag-list)))
1219 (tail-list (mapcar (lambda (a) last-frag)
1220 (number-sequence (+ (length frag-list) 1)
1221 (length items))))
1222 (default-style-list
1223 (mapcar (lambda (a) default-style)
1224 (number-sequence 1 (length items)))))
1225 (nconc frag-list tail-list)
1226 (mapcar* 'org-reveal--update-attr-html items frag-list default-style-list)))))
1227 (t (org-reveal--update-attr-html elem frag default-style frag-index)))
1228 elem)))
1229
1230 (defvar client-multiplex nil
1231 "used to cause generation of client html file for multiplex")
1232
1233 (defun org-reveal-export-to-html
1234 (&optional async subtreep visible-only body-only ext-plist)
1235 "Export current buffer to a reveal.js HTML file."
1236 (interactive)
1237 (let* ((extension (concat "." org-html-extension))
1238 (file (org-export-output-file-name extension subtreep))
1239 (clientfile (org-export-output-file-name (concat "_client" extension) subtreep)))
1240
1241 ; export filename_client HTML file if multiplexing
1242 (setq client-multiplex nil)
1243 (setq retfile (org-export-to-file 'reveal file
1244 async subtreep visible-only body-only ext-plist))
1245
1246 ; export the client HTML file if client-multiplex is set true
1247 ; by previous call to org-export-to-file
1248 (if (eq client-multiplex t)
1249 (org-export-to-file 'reveal clientfile
1250 async subtreep visible-only body-only ext-plist))
1251 (cond (t retfile))))
1252
1253 (defun org-reveal-export-to-html-and-browse
1254 (&optional async subtreep visible-only body-only ext-plist)
1255 "Export current buffer to a reveal.js and browse HTML file."
1256 (interactive)
1257 (browse-url-of-file (expand-file-name (org-reveal-export-to-html async subtreep visible-only body-only ext-plist))))
1258
1259 (defun org-reveal-export-current-subtree
1260 (&optional async subtreep visible-only body-only ext-plist)
1261 "Export current subtree to a Reveal.js HTML file."
1262 (interactive)
1263 (org-narrow-to-subtree)
1264 (let ((ret (org-reveal-export-to-html async subtreep visible-only body-only (plist-put ext-plist :reveal-subtree t))))
1265 (widen)
1266 ret))
1267
1268 ;;;###autoload
1269 (defun org-reveal-publish-to-reveal
1270 (plist filename pub-dir)
1271 "Publish an org file to Html.
1272
1273 FILENAME is the filename of the Org file to be published. PLIST
1274 is the property list for the given project. PUB-DIR is the
1275 publishing directory.
1276
1277 Return output file name."
1278 (org-publish-org-to 'reveal filename ".html" plist pub-dir))
1279
1280 ;; Register auto-completion for speaker notes.
1281 (when org-reveal-note-key-char
1282 (add-to-list 'org-structure-template-alist
1283 (list org-reveal-note-key-char "#+BEGIN_NOTES\n\?\n#+END_NOTES")))
1284
1285 (provide 'ox-reveal)
1286
1287 ;;; ox-reveal.el ends here