|
;;; org-re-reveal.el --- Org export to reveal.js presentations -*- lexical-binding: t; -*-
|
|
|
|
;; SPDX-License-Identifier: GPL-3.0-or-later
|
|
;; Copyright (C) 2013-2018 Yujie Wen and contributors to org-reveal, see:
|
|
;; https://github.com/yjwen/org-reveal/commits/master
|
|
;; Copyright (C) 2017-2019 Jens Lechtenbörger
|
|
;; Copyright (C) 2019 Naoya Yamashita <conao3@gmail.com>
|
|
;; Copyright (C) 2019 Ayush Goyal <perfectayush@gmail.com>
|
|
|
|
;; URL: https://gitlab.com/oer/org-re-reveal
|
|
;; Version: 2.12.0
|
|
;; Package-Requires: ((emacs "24.4") (org "8.3") (htmlize "1.34"))
|
|
;; Keywords: tools, outlines, hypermedia, slideshow, presentation, OER
|
|
|
|
;; This file is not part of GNU Emacs.
|
|
|
|
;;; License:
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
;; (at your option) any later version.
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with GNU Emacs; see the file COPYING.
|
|
;; If not, see http://www.gnu.org/licenses/ or write to the
|
|
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
;; Boston, MA 02110-1301, USA.
|
|
|
|
;;; Commentary:
|
|
;; This package provides Org export functionality to generate HTML
|
|
;; presentations with the presentation framework reveal.js.
|
|
;;
|
|
;; Quickstart:
|
|
;; 0. Install reveal.js: https://revealjs.com/
|
|
;; 1. Activate org-re-reveal.
|
|
;; (a) Place this directory into your load path or install it from MELPA
|
|
;; (https://melpa.org/#/getting-started).
|
|
;; (b) Load package manually ("M-x load-library" followed by
|
|
;; "org-re-reveal") or place "(require 'org-re-reveal)" into your
|
|
;; ~/.emacs and restart or customize org-export-backends by adding
|
|
;; the symbol re-reveal.
|
|
;; 2. Load an Org file and export it to HTML.
|
|
;; (a) Make sure that reveal.js is available in your current directory
|
|
;; (e.g., as sub-directory or symbolic link).
|
|
;; (b) Load "Readme.org" (coming with org-re-reveal).
|
|
;; (c) Export to HTML: Press "C-c C-e v v" (write HTML file) or
|
|
;; "C-c C-e v b" (write HTML file and open in browser)
|
|
;; See "Readme.org" for introduction, details, and features added to
|
|
;; org-reveal.
|
|
;;
|
|
;; Note that emacs-reveal offers a project that embeds org-re-reveal,
|
|
;; reveal.js, and various reveal.js plugins:
|
|
;; https://gitlab.com/oer/emacs-reveal
|
|
;; Its howto, generated from Org source file in GitLab CI environment:
|
|
;; https://oer.gitlab.io/emacs-reveal-howto/howto.html
|
|
;;
|
|
;; The package org-re-reveal grew out of a forked version of org-reveal
|
|
;; when upstream development stopped:
|
|
;; https://github.com/yjwen/org-reveal/issues/349
|
|
;; https://github.com/yjwen/org-reveal/issues/342
|
|
|
|
;;; Code:
|
|
|
|
(require 'ox-html)
|
|
(require 'cl-lib) ; cl-mapcar and autoloads for:
|
|
; cl-loop, cl-letf, cl-assert, cl-case, cl-every,
|
|
; cl-delete-duplicates, cl-remove-if
|
|
(require 'subr-x) ; string-trim
|
|
(require 'url-parse)
|
|
(require 'url-util)
|
|
|
|
(defvar org-re-reveal-keys) ; Silence byte compiler
|
|
|
|
(defun org-re-reveal-define-backend ()
|
|
"Define the back-end for export as reveal.js presentation."
|
|
(org-export-define-derived-backend 're-reveal 'html
|
|
|
|
:menu-entry
|
|
`(,(nth 0 org-re-reveal-keys) "Export to reveal.js HTML Presentation"
|
|
((,(nth 1 org-re-reveal-keys)
|
|
"To file" org-re-reveal-export-to-html)
|
|
(,(nth 2 org-re-reveal-keys)
|
|
"To file and browse" org-re-reveal-export-to-html-and-browse)
|
|
(,(nth 3 org-re-reveal-keys)
|
|
"Current subtree to file" org-re-reveal-export-current-subtree)))
|
|
|
|
:options-alist ; See org-export-options-alist for meaning of parts.
|
|
'((:reveal-center nil "reveal_center" org-re-reveal-center t)
|
|
(:reveal-control nil "reveal_control" org-re-reveal-control t)
|
|
(:reveal-defaulttiming nil "reveal_defaulttiming" org-re-reveal-defaulttiming t)
|
|
(:reveal-fragmentinurl nil "reveal_fragmentinurl" org-re-reveal-fragmentinurl t)
|
|
(:reveal-generate-ids nil "reveal_generate_ids" org-re-reveal-generate-custom-ids t)
|
|
(:reveal-hashonebasedindex nil "reveal_hashonebasedindex" org-re-reveal-hashonebasedindex t)
|
|
(:reveal-height nil "reveal_height" org-re-reveal-height t)
|
|
(:reveal-history nil "reveal_history" org-re-reveal-history t)
|
|
(:reveal-inter-presentation-links nil "reveal_inter_presentation_links" org-re-reveal-inter-presentation-links t)
|
|
(:reveal-keyboard nil "reveal_keyboard" org-re-reveal-keyboard t)
|
|
(:reveal-klipsify-src nil "reveal_klipsify_src" org-re-reveal-klipsify-src t)
|
|
(:reveal-mousewheel nil "reveal_mousewheel" org-re-reveal-mousewheel t)
|
|
(:reveal-overview nil "reveal_overview" org-re-reveal-overview t)
|
|
(:reveal-pdfseparatefragments nil "reveal_pdfseparatefragments" org-re-reveal-pdfseparatefragments t)
|
|
(:reveal-progress nil "reveal_progress" org-re-reveal-progress t)
|
|
(:reveal-rolling-links nil "reveal_rolling_links" org-re-reveal-rolling-links t)
|
|
(:reveal-single-file nil "reveal_single_file" org-re-reveal-single-file t)
|
|
(:reveal-slide-global-footer nil "reveal_global_footer" org-re-reveal-global-footer t)
|
|
(:reveal-slide-global-header nil "reveal_global_header" org-re-reveal-global-header t)
|
|
(:reveal-slide-number nil "reveal_slide_number" org-re-reveal-slide-number t)
|
|
(:reveal-slide-toc-footer nil "reveal_toc_footer" org-re-reveal-toc-footer t)
|
|
(:reveal-subtree-with-title-slide nil "reveal_subtree_with_title_slide" org-re-reveal-subtree-with-title-slide t)
|
|
(:reveal-width nil "reveal_width" org-re-reveal-width t)
|
|
(:reveal-academic-title "REVEAL_ACADEMIC_TITLE" nil nil t)
|
|
(:reveal-codemirror-config "REVEAL_CODEMIRROR_CONFIG" nil org-re-reveal-klipse-codemirror newline)
|
|
(:reveal-default-frag-style "REVEAL_DEFAULT_FRAG_STYLE" nil org-re-reveal-default-frag-style t)
|
|
(:reveal-default-slide-background "REVEAL_DEFAULT_SLIDE_BACKGROUND" nil nil t)
|
|
(:reveal-default-slide-background-position "REVEAL_DEFAULT_SLIDE_BACKGROUND_POSITION" nil nil t)
|
|
(:reveal-default-slide-background-repeat "REVEAL_DEFAULT_SLIDE_BACKGROUND_REPEAT" nil nil t)
|
|
(:reveal-default-slide-background-size "REVEAL_DEFAULT_SLIDE_BACKGROUND_SIZE" nil nil t)
|
|
(:reveal-default-slide-background-transition "REVEAL_DEFAULT_SLIDE_BACKGROUND_TRANSITION" nil nil t)
|
|
(:reveal-external-plugins "REVEAL_EXTERNAL_PLUGINS" nil org-re-reveal-external-plugins t)
|
|
(:reveal-extra-attr "REVEAL_EXTRA_ATTR" nil org-re-reveal-extra-attr nil)
|
|
(:reveal-extra-css "REVEAL_EXTRA_CSS" nil org-re-reveal-extra-css newline)
|
|
(:reveal-extra-js "REVEAL_EXTRA_JS" nil org-re-reveal-extra-js nil)
|
|
(:reveal-extra-options "REVEAL_EXTRA_OPTIONS" nil org-re-reveal-extra-options t)
|
|
(:reveal-extra-scripts "REVEAL_EXTRA_SCRIPTS" nil org-re-reveal-extra-scripts nil)
|
|
(:reveal-head-preamble "REVEAL_HEAD_PREAMBLE" nil org-re-reveal-head-preamble newline)
|
|
(:reveal-highlight-css "REVEAL_HIGHLIGHT_CSS" nil org-re-reveal-highlight-css nil)
|
|
(:reveal-highlight-url "REVEAL_HIGHLIGHT_URL" nil org-re-reveal-highlight-url nil)
|
|
(:reveal-hlevel "REVEAL_HLEVEL" nil nil t)
|
|
(:reveal-init-script "REVEAL_INIT_SCRIPT" nil org-re-reveal-init-script space)
|
|
(:reveal-klipse-css-url "REVEAL_KLIPSE_CSS_URL" nil org-re-reveal-klipse-css t)
|
|
(:reveal-klipse-extra-config "REVEAL_KLIPSE_EXTRA_CONFIG" nil org-re-reveal-klipse-extra-config newline)
|
|
(:reveal-klipse-js-url "REVEAL_KLIPSE_JS_URL" nil org-re-reveal-klipse-js t)
|
|
(:reveal-klipse-setup "REVEAL_KLIPSE_SETUP" nil org-re-reveal-klipse-setup t)
|
|
(:reveal-margin "REVEAL_MARGIN" nil org-re-reveal-margin t)
|
|
(:reveal-mathjax-url "REVEAL_MATHJAX_URL" nil org-re-reveal-mathjax-url t)
|
|
(:reveal-max-scale "REVEAL_MAX_SCALE" nil org-re-reveal-max-scale t)
|
|
(:reveal-min-scale "REVEAL_MIN_SCALE" nil org-re-reveal-min-scale t)
|
|
(:reveal-miscinfo "REVEAL_MISCINFO" nil nil t)
|
|
(:reveal-multiplex-id "REVEAL_MULTIPLEX_ID" nil org-re-reveal-multiplex-id nil)
|
|
(:reveal-multiplex-secret "REVEAL_MULTIPLEX_SECRET" nil org-re-reveal-multiplex-secret nil)
|
|
(:reveal-multiplex-socketio-url "REVEAL_MULTIPLEX_SOCKETIO_URL" nil org-re-reveal-multiplex-socketio-url nil)
|
|
(:reveal-multiplex-url "REVEAL_MULTIPLEX_URL" nil org-re-reveal-multiplex-url nil)
|
|
(:reveal-plugins "REVEAL_PLUGINS" nil org-re-reveal-plugins t)
|
|
(:reveal-postamble "REVEAL_POSTAMBLE" nil org-re-reveal-postamble t)
|
|
(:reveal-preamble "REVEAL_PREAMBLE" nil org-re-reveal-preamble t)
|
|
(:reveal-root "REVEAL_ROOT" nil org-re-reveal-root t)
|
|
(:reveal-script-files "REVEAL_SCRIPT_FILES" nil org-re-reveal-script-files t)
|
|
(:reveal-slide-footer "REVEAL_SLIDE_FOOTER" nil org-re-reveal-slide-footer t)
|
|
(:reveal-slide-header "REVEAL_SLIDE_HEADER" nil org-re-reveal-slide-header t)
|
|
(:reveal-speed "REVEAL_SPEED" nil org-re-reveal-transition-speed t)
|
|
(:reveal-talk-qr-code "REVEAL_TALK_QR_CODE" nil nil t)
|
|
(:reveal-talk-url "REVEAL_TALK_URL" nil nil t)
|
|
(:reveal-theme "REVEAL_THEME" nil org-re-reveal-theme t)
|
|
(:reveal-title-slide "REVEAL_TITLE_SLIDE" nil org-re-reveal-title-slide newline)
|
|
(:reveal-title-slide-background "REVEAL_TITLE_SLIDE_BACKGROUND" nil nil t)
|
|
(:reveal-title-slide-background-position "REVEAL_TITLE_SLIDE_BACKGROUND_POSITION" nil nil t)
|
|
(:reveal-title-slide-background-repeat "REVEAL_TITLE_SLIDE_BACKGROUND_REPEAT" nil nil t)
|
|
(:reveal-title-slide-background-size "REVEAL_TITLE_SLIDE_BACKGROUND_SIZE" nil nil t)
|
|
(:reveal-title-slide-background-transition "REVEAL_TITLE_SLIDE_BACKGROUND_TRANSITION" nil nil t)
|
|
(:reveal-title-slide-state "REVEAL_TITLE_SLIDE_STATE" nil nil t)
|
|
(:reveal-title-slide-timing "REVEAL_TITLE_SLIDE_TIMING" nil nil t)
|
|
(:reveal-toc-slide-class "REVEAL_TOC_SLIDE_CLASS" nil nil t)
|
|
(:reveal-toc-slide-state "REVEAL_TOC_SLIDE_STATE" nil nil t)
|
|
(:reveal-toc-slide-title "REVEAL_TOC_SLIDE_TITLE" nil org-re-reveal-toc-slide-title t)
|
|
(:reveal-trans "REVEAL_TRANS" nil org-re-reveal-transition t))
|
|
|
|
:translate-alist
|
|
'((headline . org-re-reveal-headline)
|
|
(inner-template . org-re-reveal-inner-template)
|
|
(item . org-re-reveal-item)
|
|
(keyword . org-re-reveal-keyword)
|
|
(link . org-re-reveal-link)
|
|
(latex-environment . org-re-reveal-latex-environment)
|
|
(latex-fragment . (lambda (frag contents info)
|
|
(setq info (plist-put info :reveal-mathjax t))
|
|
(org-html-latex-fragment frag contents info)))
|
|
(plain-list . org-re-reveal-plain-list)
|
|
(quote-block . org-re-reveal-quote-block)
|
|
(section . org-re-reveal-section)
|
|
(src-block . org-re-reveal-src-block)
|
|
(special-block . org-re-reveal-special-block)
|
|
(template . org-re-reveal-template))
|
|
|
|
:filters-alist '((:filter-parse-tree . org-re-reveal-filter-parse-tree))))
|
|
|
|
(defun org-re-reveal-define-menu (symbol value)
|
|
"Define back-end with (new) key bindings.
|
|
SYMBOL must be `org-re-reveal-keys' and VALUE its new value."
|
|
(let ((standard (eval (car (get symbol 'standard-value)))))
|
|
(cl-assert
|
|
(eq symbol 'org-re-reveal-keys) nil
|
|
(format "Symbol in org-re-reveal-define-menu unexpected: %s" symbol))
|
|
(cl-assert
|
|
(= (length standard) (length value))
|
|
(format "Value for org-re-reveal-keys must have length %s (same as standard), not %s"
|
|
(length standard) (length value)))
|
|
(set-default symbol value)
|
|
(org-re-reveal-define-backend)))
|
|
|
|
(defgroup org-export-re-reveal nil
|
|
"Options for exporting Org files to reveal.js HTML pressentations."
|
|
:tag "Org Export Reveal"
|
|
:group 'org-export)
|
|
|
|
(defcustom org-re-reveal-keys '(?v ?v ?b ?s)
|
|
"Define keys for export with org-re-reveal.
|
|
This list must contain four characters: The first one triggers export
|
|
with org-re-reveal (after \\<org-mode-map> \\[org-export-dispatch]).
|
|
The remaining three charaters each invoke a different export variant.
|
|
One of those characters must be typed after the first one; the
|
|
variants are, in sequence: Export to file, export to file followed by
|
|
browsing that file, subtree export to file."
|
|
:group 'org-export-re-reveal
|
|
:type '(list (character :tag "Key to trigger export with org-re-reveal")
|
|
(character :tag "Key for export to file")
|
|
(character :tag "Key to browse file after export")
|
|
(character :tag "Key for subtree export to file"))
|
|
:set #'org-re-reveal-define-menu)
|
|
|
|
(defcustom org-re-reveal-root "./reveal.js"
|
|
"Specify root directory of reveal.js containing js/reveal.js."
|
|
:group 'org-export-re-reveal
|
|
:type '(radio (const :tag "Online at https://revealjs.com" "https://revealjs.com")
|
|
(string :tag "Other directory path")))
|
|
|
|
(defcustom org-re-reveal-script-files '("lib/js/head.min.js" "js/reveal.js")
|
|
"Specify files to initialize reveal.js.
|
|
Note that file names here are relative under `org-re-reveal-root'.
|
|
On 2018-10-04, head.min.js was removed on the dev branch of reveal.js.
|
|
If you are using a version including that removal, customize this variable
|
|
to remove the first file name."
|
|
:group 'org-export-re-reveal
|
|
:type '(repeat string))
|
|
|
|
(defcustom org-re-reveal-hlevel 1
|
|
"Specify minimum level of headings for grouping into vertical slides."
|
|
:group 'org-export-re-reveal
|
|
:type 'integer)
|
|
|
|
(defun org-re-reveal--get-hlevel (info)
|
|
"Get HLevel value safely for INFO.
|
|
If option \"REVEAL_HLEVEL\" is set, retrieve integer value from it,
|
|
else get value from custom variable `org-re-reveal-hlevel'."
|
|
(let ((hlevel-str (plist-get info :reveal-hlevel)))
|
|
(if hlevel-str (string-to-number hlevel-str)
|
|
org-re-reveal-hlevel)))
|
|
|
|
(defcustom org-re-reveal-title-slide 'auto
|
|
"If nil or empty string, do not insert a title slide.
|
|
Otherwise (`auto' or non-empty string), insert title slide.
|
|
When `auto', generate automatic title slide.
|
|
When set to a string, use this string as format string for the title
|
|
slide, where the following escaping elements are allowed:
|
|
|
|
%t for the title.
|
|
%s for the subtitle.
|
|
%a for the author's name.
|
|
%e for the author's email.
|
|
%d for the date.
|
|
%A for the author's academic title (set with #+REVEAL_ACADEMIC_TITLE).
|
|
%q for the name of a file to a QR code (set with #+REVEAL_TALK_QR_CODE).
|
|
%u for the URL of the presentation (set with #+REVEAL_TALK_URL).
|
|
%m for misc information (set with #+REVEAL_MISCINFO).
|
|
%% for a literal %.
|
|
|
|
Alternatively, the string can also be the name of a file with the title
|
|
slide's HTML code (containing the above escape sequences)."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const :tag "No title slide" nil)
|
|
(const :tag "Auto title slide" 'auto)
|
|
(string :tag "Custom title slide")))
|
|
|
|
(defcustom org-re-reveal-transition "convex"
|
|
"Reveal transistion style."
|
|
:group 'org-export-re-reveal
|
|
:type '(radio (const "none")
|
|
(const "fade")
|
|
(const "slide")
|
|
(const "convex")
|
|
(const "concave")
|
|
(const "zoom")
|
|
(string :tag "Other transition")))
|
|
|
|
(defcustom org-re-reveal-transition-speed "default"
|
|
"Reveal transistion speed."
|
|
:group 'org-export-re-reveal
|
|
:type '(radio (const "default")
|
|
(const "fast")
|
|
(const "slow")
|
|
(string :tag "Other transition speed")))
|
|
|
|
(defcustom org-re-reveal-theme "black"
|
|
"Reveal theme.
|
|
Note that most themes load fonts from remote servers, which (a)
|
|
obviously limits offline use of presentations and (b) is not privacy
|
|
friendly. See URL `https://github.com/hakimel/reveal.js/issues/2491'
|
|
and URL `https://github.com/google/fonts/issues/1495'."
|
|
:group 'org-export-re-reveal
|
|
:type '(radio (const "beige")
|
|
(const "black")
|
|
(const "blood")
|
|
(const "league")
|
|
(const "moon")
|
|
(const "night")
|
|
(const "serif")
|
|
(const "simple")
|
|
(const "sky")
|
|
(const "solarized")
|
|
(const "white")
|
|
(string :tag "Other theme"))
|
|
:package-version '(org-re-reveal . "2.8.1"))
|
|
|
|
(defcustom org-re-reveal-extra-js ""
|
|
"URL to extra JS file.
|
|
If you use this variable, please take the time to report your current
|
|
usage at URL `https://gitlab.com/oer/org-re-reveal/issues/31'."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-extra-scripts nil
|
|
"List of extra scripts.
|
|
Each list element can be the filename or URL of a JavaScript file or an
|
|
entire HTML script element.
|
|
If relative filenames are used, they must be relative to the presentation's
|
|
HTML file."
|
|
:group 'org-export-re-reveal
|
|
:type '(repeat string)
|
|
:package-version '(org-re-reveal . "2.10.0"))
|
|
(make-obsolete-variable 'org-re-reveal-extra-js
|
|
'org-re-reveal-extra-scripts "org-re-reveal 2.9.0")
|
|
|
|
(defcustom org-re-reveal-extra-attr nil
|
|
"Global Reveal Extra Attrs for all slides."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice
|
|
string
|
|
(const nil)))
|
|
|
|
(defcustom org-re-reveal-extra-css ""
|
|
"URL to extra css file."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-multiplex-id ""
|
|
"The ID to use for multiplexing.
|
|
E.g., per README of reveal.js 3.8.0, generate id and secrete by visiting
|
|
URL `https://reveal-js-multiplex-ccjbegmaii.now.sh/'.
|
|
To enable multiplex, see `org-re-reveal-plugins'."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-multiplex-secret ""
|
|
"The secret to use for the master presentation.
|
|
E.g., per README of reveal.js 3.8.0, generate id and secrete by visiting
|
|
URL `https://reveal-js-multiplex-ccjbegmaii.now.sh/'.
|
|
To enable multiplex, see `org-re-reveal-plugins'."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-multiplex-url
|
|
"https://reveal-js-multiplex-ccjbegmaii.now.sh"
|
|
"The url of the socketio server.
|
|
To enable multiplex, see `org-re-reveal-plugins'."
|
|
:group 'org-export-re-reveal
|
|
:type 'string
|
|
:package-version '(org-re-reveal . "2.1.0"))
|
|
|
|
(defcustom org-re-reveal-multiplex-socketio-url
|
|
"https://cdn.socket.io/socket.io-1.3.5.js"
|
|
"The url of the socketio.js library.
|
|
To enable multiplex, see `org-re-reveal-plugins'."
|
|
:group 'org-export-re-reveal
|
|
:type 'string
|
|
:package-version '(org-re-reveal . "2.1.0"))
|
|
|
|
(defcustom org-re-reveal-client-multiplex-filter nil
|
|
"If non-nil, a regular expression to filter multiplex client publication.
|
|
When using `org-re-reveal-publish-to-reveal-client', by default all Org
|
|
files are also published as multiplex client files (which roughly
|
|
doubles the amount of time necessary for publication). If you have got
|
|
a mix of Org files that use multiplexing and that do not, set to this
|
|
variable to a regular expression matching files for which a multiplex
|
|
client file should be generated."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice
|
|
regexp
|
|
(const nil))
|
|
:package-version '(org-re-reveal . "2.12.0"))
|
|
|
|
(defcustom org-re-reveal-control t
|
|
"Reveal control applet."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-progress t
|
|
"Reveal progress applet."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-history nil
|
|
"Reveal history applet."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-center t
|
|
"Reveal center applet."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-rolling-links nil
|
|
"Reveal use rolling links."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-slide-number "c"
|
|
"Reveal showing slide numbers."
|
|
:group 'org-export-re-reveal
|
|
:type '(radio (const :tag "horizontal . vertical slide number" "h.v")
|
|
(const :tag "horizontal / vertical slide number" "h/v")
|
|
(const :tag "flattened slide number" "c")
|
|
(const :tag "flattened slide number / total slides" "c/t")
|
|
(string :tag "Other slide number format")))
|
|
|
|
(defcustom org-re-reveal-keyboard t
|
|
"Reveal use keyboard navigation."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-mousewheel nil
|
|
"Reveal use mousewheel navigation."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-fragmentinurl nil
|
|
"Reveal use fragmentInURL setting."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-hashonebasedindex nil
|
|
"Reveal use hashOneBasedIndex setting."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-pdfseparatefragments t
|
|
"Reveal disable pdfSeparateFragments setting."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-defaulttiming nil
|
|
"If non-nil, use defaultTiming for speaker notes view.
|
|
For indivual timing of specific slides, use \"REVEAL_TITLE_SLIDE_TIMING\" for
|
|
the title slide, and assign data-timing attributes to other headlines/slides."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice integer (const nil)))
|
|
|
|
(defcustom org-re-reveal-overview t
|
|
"Reveal show overview."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-subtree-with-title-slide nil
|
|
"If t, export title slide also for subtree exports."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-width nil
|
|
"Slide width as positive integer (pixels) or string (percentage) or nil."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice integer string (const nil))
|
|
:package-version '(org-re-reveal . "1.1.4"))
|
|
|
|
(defcustom org-re-reveal-height nil
|
|
"Slide height as positive integer (pixels) or string (percentage) or nil."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice integer string (const nil))
|
|
:package-version '(org-re-reveal . "1.1.4"))
|
|
|
|
(defcustom org-re-reveal-margin "-1"
|
|
"Slide margin (in a string)."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-min-scale "-1"
|
|
"Minimum bound for scaling slide (in a string)."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-max-scale "-1"
|
|
"Maximum bound for scaling slide (in a string)."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-extra-options nil
|
|
"Extra options to be passed to Reveal.initialize().
|
|
Useful to specify options without keyword in org-re-reveal, e.g.,
|
|
\"controlsTutorial: false, controlsLayout: 'edges'\".
|
|
Individual options are separated by comma.
|
|
For the current list of reveal.js options, see URL
|
|
`https://github.com/hakimel/reveal.js/#configuration.'"
|
|
:group 'org-export-re-reveal
|
|
:type '(choice string (const nil)))
|
|
|
|
(defcustom org-re-reveal-mathjax-url
|
|
"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
|
|
"Default MathJax URL."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-preamble nil
|
|
"Preamble contents."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-head-preamble nil
|
|
"Preamble contents for head part."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-postamble nil
|
|
"Postamble contents."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-body-attrs nil
|
|
"Attribute string to assign to body element.
|
|
By default, no attributes are assigned."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-slide-header nil
|
|
"HTML content used as Reveal.js slide header."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-slide-header-html "<div class=\"slide-header\">%s</div>\n"
|
|
"HTML format string to construct slide footer."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-global-header nil
|
|
"If non nil, display slide header also on title and toc slide.
|
|
Header is defined by `org-re-reveal-slide-header'."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-global-footer nil
|
|
"If non nil, display slide footer also on title and toc slide.
|
|
Footer is defined by `org-re-reveal-slide-footer'."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-toc-footer nil
|
|
"If non nil, display slide footer also on toc slide.
|
|
Footer is defined by `org-re-reveal-slide-footer'."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-slide-footer nil
|
|
"Specify HTML content used as Reveal.js slide footer."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-slide-footer-html "<div class=\"slide-footer\">%s</div>\n"
|
|
"HTML format string to construct slide footer.
|
|
Must constain exactly one %-sequence \"%s\"."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-toc-slide-title "Table of Contents"
|
|
"String to display as title of toc slide."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-default-frag-style nil
|
|
"Default fragment style."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-plugins
|
|
'(markdown notes search zoom)
|
|
"Default builtin plugins.
|
|
|
|
By default, variables related to multiplex are hidden.
|
|
Include 'multiplex in this variable to enable it.
|
|
|
|
This variable, like any other variable, can be overridden
|
|
in the org buffer comments as follows:
|
|
#+REVEAL_PLUGINS: (markdown zoom notes multiplex)"
|
|
:group 'org-export-re-reveal
|
|
:type '(set
|
|
(const markdown)
|
|
(const highlight)
|
|
(const zoom)
|
|
(const notes)
|
|
(const search)
|
|
(const multiplex)
|
|
(const :tag "classList (absent from modern reveal.js)" classList)
|
|
(const :tag "remotes (absent from modern reveal.js)" remotes))
|
|
:package-version '(org-re-reveal . "1.1.11"))
|
|
|
|
(defcustom org-re-reveal-external-plugins nil
|
|
"Additional third-party plugins to load with reveal.js.
|
|
This is either an alist or a filename.
|
|
In case of an alist, each entry should contain a name and an expression
|
|
of the following form:
|
|
\"{src: '%srelative/path/from/reveal/root', async:true/false,
|
|
condition: jscallbackfunction(){}}\"
|
|
In case of a file, its lines must be expressions of the above form.
|
|
Note that some plugins have dependencies such as jquery; these must be
|
|
included here as well, BEFORE the plugins that depend on them."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice alist file))
|
|
|
|
(defcustom org-re-reveal-single-file nil
|
|
"Export presentation into one single HTML file.
|
|
That file embeds JS scripts and pictures."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-inter-presentation-links nil
|
|
"If non nil, try to convert links between presentations."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-init-script nil
|
|
"Custom script to be passed to Reveal.initialize."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-highlight-css "%r/lib/css/zenburn.css"
|
|
"Hightlight.js CSS file."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-highlight-url nil
|
|
"Location of Hightlight.js.
|
|
If nil (default), the local plugin file is used."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-note-key-char "n"
|
|
"If not nil, register key for Org structure completion for speaker notes.
|
|
When `<' followed by the key character are
|
|
typed and then the completion key is pressed, which is usually
|
|
`TAB', \"#+BEGIN_NOTES\" and \"#+END_NOTES\" is inserted (maybe in
|
|
lower-case). See \"Readme.org\" how to make this work with Org version
|
|
9.2 or later.
|
|
|
|
The default value is \"n\". Set the variable to nil to disable
|
|
registering the completion."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-no-htmlize-src nil
|
|
"For syntax highlighting with org-re-reveal, three options exist:
|
|
1. Use reveal.js plugin highlight for syntax highlighting with highlight.js.
|
|
This applies to all source code blocks.
|
|
2. If plugin highlight is not enabled, by default the library htmlize
|
|
is used.
|
|
3. Do not use highlight and customize this variable to t.
|
|
This disables syntax highlighting but you can activate htmlize for
|
|
individual source code blocks with attributes:
|
|
\"#+ATTR_REVEAL: :htmlize t\""
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-klipsify-src nil
|
|
"Set to non-nil to enable live code execution with klipse.
|
|
See test-cases/test-klipsify.org in the source repository for examples.
|
|
To export a source code block without klipse, use the following:
|
|
\"#+ATTR_REVEAL: :no-klipsify t\""
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean)
|
|
|
|
(defcustom org-re-reveal-klipse-css "https://storage.googleapis.com/app.klipse.tech/css/codemirror.css"
|
|
"Location of the codemirror css file for use with klipse."
|
|
:group 'org-export-re-reveal
|
|
:type 'string)
|
|
|
|
(defcustom org-re-reveal-klipse-extra-css "<style>
|
|
/* Position computations of klipse get confused by reveal.js's scaling.
|
|
Hence, scaling should be disabled with this code. Fix height of code area
|
|
with scrollbar (use overflow instead of overflow-y to restore CodeMirror
|
|
setting afterwards): */
|
|
.reveal section pre { max-height: 70vh; height: auto; overflow: auto; }
|
|
/* Reset some reveal.js and oer-reveal settings: */
|
|
.reveal section pre .CodeMirror pre { font-size: 2em; box-shadow: none; width: auto; padding: 0.4em; display: block; overflow: visible; }
|
|
/* Enlarge cursor: */
|
|
.CodeMirror-cursor { border-left: 3px solid black; }
|
|
</style>\n"
|
|
"CSS string to ensure compatibility between klipse and reveal.js."
|
|
:group 'org-export-re-reveal
|
|
:type 'string
|
|
:package-version '(org-re-reveal . "2.0.1"))
|
|
|
|
(defcustom org-re-reveal-klipse-codemirror nil
|
|
"If not nil, a string to pass as CodeMirror options to \"klipse_setting\"."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-klipse-js
|
|
"https://storage.googleapis.com/app.klipse.tech/plugin/js/klipse_plugin.js"
|
|
"Location of the klipse js source code.
|
|
The minified version may not work, see URL
|
|
`https://github.com/viebel/klipse/issues/334'."
|
|
:group 'org-export-re-reveal
|
|
:type 'string
|
|
:package-version '(org-re-reveal . "1.1.11"))
|
|
|
|
(defcustom org-re-reveal-klipse-setup
|
|
'(("clojure" "selector" "language-klipse")
|
|
("html" "selector_eval_html" "language-klipse-html")
|
|
("javascript" "selector_eval_js" "language-klipse-javascript")
|
|
("js" "selector_eval_js" "language-klipse-js")
|
|
("php" "selector_eval_php" "language-klipse-php")
|
|
("python" "selector_eval_python_client" "language-klipse-python")
|
|
("ruby" "selector_eval_ruby" "language-klipse-ruby")
|
|
("scheme" "selector_eval_scheme" "language-klipse-scheme")
|
|
("sql" "selector_sql" "language-klipse-sql"))
|
|
"Supported klipse languages with selectors.
|
|
This is a list of triples (language selectorname selectorvalue).
|
|
Each language needs to be the language of an Org source block.
|
|
For existing names of klipse selectors, see URL
|
|
`https://github.com/viebel/klipse/blob/master/README.md#page-level-configuration'.
|
|
If additional languages work for you, maybe you could report that in issue #23
|
|
at URL `https://gitlab.com/oer/org-re-reveal/issues/23'?"
|
|
:group 'org-export-re-reveal
|
|
:type '(repeat
|
|
(list
|
|
(string :tag "Language")
|
|
(string :tag "Selector name")
|
|
(string :tag "CSS class")))
|
|
:package-version '(org-re-reveal . "1.1.11"))
|
|
|
|
(defvar org-re-reveal-klipse-languages
|
|
(mapcar #'car org-re-reveal-klipse-setup)
|
|
"List of languages supported by org-re-reveal.")
|
|
|
|
(defcustom org-re-reveal-klipse-extra-config nil
|
|
"If not nil, extra JavaScript string to execute for klipse initialization.
|
|
E.g., window.klipse_settings.editor_type = \"html\"; for SQL."
|
|
:group 'org-export-re-reveal
|
|
:type '(choice (const nil) string))
|
|
|
|
(defcustom org-re-reveal-generate-custom-ids t
|
|
"If t, generate CUSTOM_IDs for headings that don't have one.
|
|
Set to nil to revert to old behavior, where HTML section elements have
|
|
content hashes as \"id\" attributes, which change when slide contents
|
|
change. With the default of t, generate CUSTOM_ID for headlines
|
|
missing such a property, by using the value of the headline's number.
|
|
This results in more stable URLs when working on presentations and
|
|
reloading slides. You may want to set \"#+OPTIONS: reveal_history:t\"
|
|
to see the section identifiers as URL fragments in the address bar,
|
|
and you should not disable section numbering (for unnumbered
|
|
headlines, hash IDs are used unless a CUSTOM_ID is present).
|
|
For CSS code to hide section numbers if necessary, see
|
|
URL `https://github.com/yjwen/org-reveal/pull/284'."
|
|
:group 'org-export-re-reveal
|
|
:type 'boolean
|
|
:package-version '(org-re-reveal . "1.1.3"))
|
|
|
|
(defvar org-re-reveal--slide-id-prefix "slide-"
|
|
"Prefix to use in ID attributes of slide elements.")
|
|
|
|
(defvar org-re-reveal--href-fragment-prefix
|
|
(concat "/" org-re-reveal--slide-id-prefix)
|
|
"Prefix to use when linking to specific slides.
|
|
The default uses a slash between hash sign and slide ID,
|
|
which leads to broken links that are not understood outside reveal.js.
|
|
See there: https://github.com/hakimel/reveal.js/issues/2276")
|
|
|
|
(defun org-re-reveal--if-format (fmt val)
|
|
"Apply `format' to FMT and VAL if VAL is a non-empty string.
|
|
Otherwise, return empty string."
|
|
(if (and (stringp val) (> (length val) 0)) (format fmt val) ""))
|
|
|
|
(defun org-re-reveal--frag-style (frag info)
|
|
"Return fragment string according to FRAG and the default fragment style.
|
|
FRAG is the fragment style set on element, INFO is a plist
|
|
holding contextual information."
|
|
(cond
|
|
((string= frag t)
|
|
(let ((default-frag-style (plist-get info :reveal-default-frag-style)))
|
|
(if default-frag-style (format "fragment %s" default-frag-style)
|
|
"fragment")))
|
|
(t (format "fragment %s" frag))))
|
|
|
|
(defun org-re-reveal--frag-class (frag info)
|
|
"Return proper HTML string description of fragment style.
|
|
FRAG is the fragment style set on element, INFO is a plist
|
|
holding contextual information."
|
|
(and frag
|
|
(format " class=\"%s\"" (org-re-reveal--frag-style frag info))))
|
|
|
|
(defun org-re-reveal--frag-index (index)
|
|
"Return attribute string for fragment INDEX if set."
|
|
(and index
|
|
(format " data-fragment-index=\"%s\"" index)))
|
|
|
|
(defun org-re-reveal-special-block (special-block contents info)
|
|
"Transcode a SPECIAL-BLOCK element from Org to Reveal.
|
|
CONTENTS holds the contents of the block. INFO is a plist
|
|
holding contextual information.
|
|
|
|
If the block type is 'NOTES' (case-insensitive), transcode the block
|
|
into a Reveal.js slide note. Otherwise, export the block as by the HTML
|
|
exporter."
|
|
(let ((block-type (org-element-property :type special-block)))
|
|
(if (string= (downcase block-type) "notes")
|
|
(format "<aside class=\"notes\">\n%s\n</aside>\n" contents)
|
|
(org-html-special-block special-block contents info))))
|
|
|
|
(defun org-re-reveal--add-class (elem value)
|
|
"Add VALUE as \"class\" attribute in HTML header element ELEM.
|
|
Do nothing if \"class\" attribute is already present."
|
|
(let ((match (string-match "\\`<h[1-9][^>]+>" elem)))
|
|
(unless match (error "Element no headline: %s" elem))
|
|
(let ((tag (match-string 0 elem)))
|
|
(if (string-match "class" tag)
|
|
elem
|
|
(replace-regexp-in-string "\\`\\(<h[1-9][^>]+\\)>"
|
|
(format "\\1 class=\"%s\">" value)
|
|
elem)))))
|
|
|
|
(defun org-re-reveal--fix-html-headline (headline contents info)
|
|
"Convert HEADLINE with CONTENTS and INFO to HTML.
|
|
Call `org-html-headline' to generate initial HTML, remove surrounding
|
|
\"div\" tags, and add class attribute to h-element if
|
|
\":HTML_HEADLINE_CLASS\" property is present.
|
|
|
|
Adding a class attribute in ox-reveal.el is a hack which is only
|
|
necessary until that functionality has arrived in ox-html.el:
|
|
https://lists.gnu.org/archive/html/emacs-orgmode/2018-12/msg00016.html
|
|
As that patch has been accepted, the property is called
|
|
\":HTML_HEADLINE_CLASS\". Otherwise, \":REVEAL_HEADLINE_CLASS\" would
|
|
have been appropriate..."
|
|
(let* ((class (org-element-property :HTML_HEADLINE_CLASS headline))
|
|
(html (org-html-headline headline contents info))
|
|
(nodiv
|
|
(if (string-prefix-p "<div" html)
|
|
;; Remove the first <div> and the last </div> tags from html
|
|
(concat "<"
|
|
(mapconcat 'identity
|
|
(butlast (cdr (split-string html "<" t)))
|
|
"<"))
|
|
;; Return the HTML content unchanged
|
|
html)))
|
|
(if class
|
|
(org-re-reveal--add-class nodiv class)
|
|
nodiv)))
|
|
|
|
(defun org-re-reveal--section-attrs (headline info)
|
|
"Compute attributes for section element of HEADLINE with INFO.
|
|
Return empty string or one starting with a space character."
|
|
(let* ((default-slide-background (plist-get info :reveal-default-slide-background))
|
|
(default-slide-background-size (plist-get info :reveal-default-slide-background-size))
|
|
(default-slide-background-position (plist-get info :reveal-default-slide-background-position))
|
|
(default-slide-background-repeat (plist-get info :reveal-default-slide-background-repeat))
|
|
(default-slide-background-transition (plist-get info :reveal-default-slide-background-transition))
|
|
(attrs (org-html--make-attribute-string
|
|
`(:data-transition ,(org-element-property :REVEAL_DATA_TRANSITION headline)
|
|
:data-state ,(org-element-property :REVEAL_DATA_STATE headline)
|
|
:data-background ,(or (org-element-property :REVEAL_BACKGROUND headline)
|
|
default-slide-background)
|
|
:data-background-size ,(or (org-element-property :REVEAL_BACKGROUND_SIZE headline)
|
|
default-slide-background-size)
|
|
:data-background-position ,(or (org-element-property :REVEAL_BACKGROUND_POSITION headline)
|
|
default-slide-background-position)
|
|
:data-background-repeat ,(or (org-element-property :REVEAL_BACKGROUND_REPEAT headline)
|
|
default-slide-background-repeat)
|
|
:data-background-transition ,(or (org-element-property :REVEAL_BACKGROUND_TRANS headline)
|
|
default-slide-background-transition)))))
|
|
(if (> (length attrs) 0) (format " %s" attrs) "")))
|
|
|
|
;; Copied from org-html-headline and modified to embed org-re-reveal
|
|
;; specific attributes.
|
|
(defun org-re-reveal-headline (headline contents info)
|
|
"Transcode a HEADLINE element from Org to HTML.
|
|
CONTENTS holds the contents of the headline. INFO is a plist
|
|
holding contextual information."
|
|
(unless (org-element-property :footnote-section-p headline)
|
|
(if (or (org-export-low-level-p headline info)
|
|
(org-element-property :NOSLIDE headline))
|
|
;; This is a deep sub-tree: export it as in ox-html.
|
|
(org-html-headline headline contents info)
|
|
;; Standard headline. Export it as a slide
|
|
(let* ((level (org-export-get-relative-level headline info))
|
|
(preferred-id (or (org-element-property :CUSTOM_ID headline)
|
|
(and (fboundp 'org-export-get-reference)
|
|
(org-export-get-reference headline info))
|
|
(org-element-property :ID headline)))
|
|
(hlevel (org-re-reveal--get-hlevel info))
|
|
(header (plist-get info :reveal-slide-header))
|
|
(header-div (if header (format org-re-reveal-slide-header-html header) ""))
|
|
(footer (plist-get info :reveal-slide-footer))
|
|
(footer-div (if footer (format org-re-reveal-slide-footer-html footer) ""))
|
|
(first-sibling (org-export-first-sibling-p headline info))
|
|
(attrs (org-re-reveal--section-attrs headline info))
|
|
(extra-attrs (or (org-element-property :REVEAL_EXTRA_ATTR headline)
|
|
(plist-get info :reveal-extra-attr)))
|
|
(slide-section-tag (format "<section id=\"%s\"%s%s>\n"
|
|
(format "%s%s" org-re-reveal--slide-id-prefix preferred-id)
|
|
attrs
|
|
(if extra-attrs (format " %s" extra-attrs) "")))
|
|
(ret (concat
|
|
(if (or (/= level 1) (not first-sibling))
|
|
;; Not the first heading. Close previous slide.
|
|
(concat
|
|
;; Slide footer if any.
|
|
footer-div
|
|
;; Close previous slide.
|
|
"</section>\n"
|
|
(if (<= level hlevel)
|
|
;; Close previous vertical slide group.
|
|
"</section>\n")))
|
|
(if (<= level hlevel)
|
|
;; Add an extra "<section>" to group following slides
|
|
;; into vertical slide group. Transition override
|
|
;; attributes are attached at this level, too.
|
|
(let ((attrs
|
|
(org-html--make-attribute-string
|
|
`(:data-transition ,(org-element-property :REVEAL_DATA_TRANSITION headline)))))
|
|
(if (string= attrs "")
|
|
"<section>\n"
|
|
(format "<section %s>\n" attrs))))
|
|
;; Start a new slide.
|
|
slide-section-tag
|
|
;; Slide header if any.
|
|
header-div
|
|
;; The HTML content of the headline
|
|
(org-re-reveal--fix-html-headline headline contents info)
|
|
(if (and (= level 1)
|
|
(org-export-last-sibling-p headline info))
|
|
;; Last head 1. Close all slides.
|
|
(concat
|
|
;; Slide footer if any
|
|
footer-div
|
|
"</section>\n</section>\n")))))
|
|
ret))))
|
|
|
|
(defun org-re-reveal--read-list (thing)
|
|
"Return THING if it is a list.
|
|
Otherwise, `read' THING and return value if it is a list.
|
|
Otherwise, raise an error."
|
|
(if (listp thing)
|
|
thing
|
|
(let ((lthing (read thing)))
|
|
(if (listp lthing)
|
|
lthing
|
|
(error "Expected a list, but got: %s" thing)))))
|
|
|
|
(defun org-re-reveal--parse-listoption (info option)
|
|
"Parse and return OPTION in INFO.
|
|
That value for OPTION may be a list or a string representing a list."
|
|
(org-re-reveal--read-list (plist-get info option)))
|
|
|
|
(defun org-re-reveal--read-file (file)
|
|
"Return the content of FILE."
|
|
(with-temp-buffer
|
|
(insert-file-contents-literally file)
|
|
(buffer-string)))
|
|
|
|
(defun org-re-reveal--file-url-to-path (url)
|
|
"Convert URL that points to local files to file path."
|
|
(replace-regexp-in-string
|
|
(if (string-equal system-type "windows-nt") "^file:///" "^file://")
|
|
"" url))
|
|
|
|
(defun org-re-reveal--css-label (in-single-file file-name style-id)
|
|
"Generate HTML code to include CSS file FILE-NAME.
|
|
If IN-SINGLE-FILE is t, the content of FILE-NAME is embedded;
|
|
otherwise, a `<link>' label is generated."
|
|
(when (and file-name (not (string= file-name "")))
|
|
(if in-single-file
|
|
;; Single-file
|
|
(let ((local-file-name (org-re-reveal--file-url-to-path file-name)))
|
|
(if (file-readable-p local-file-name)
|
|
(concat "<style type=\"text/css\">\n"
|
|
(org-re-reveal--read-file local-file-name)
|
|
"\n</style>\n")
|
|
;; But file is not readable.
|
|
(error "Cannot read %s" file-name)))
|
|
;; Not in-single-file
|
|
(concat "<link rel=\"stylesheet\" href=\"" file-name "\""
|
|
(if style-id (format " id=\"%s\"" style-id))
|
|
"/>\n"))))
|
|
|
|
(defun org-re-reveal--klipsify-header (info)
|
|
"Return code (CSS and JavaScript) to activate klipse when indicated by INFO."
|
|
(if (plist-get info :reveal-klipsify-src)
|
|
(concat (format "<link rel=\"stylesheet\" href=\"%s\"/>\n"
|
|
(plist-get info :reveal-klipse-css-url))
|
|
org-re-reveal-klipse-extra-css
|
|
(format "<script>
|
|
window.klipse_settings = {
|
|
%s%s
|
|
};\n"
|
|
(org-re-reveal--if-format
|
|
"%s,\n" (plist-get info :reveal-codemirror-config))
|
|
(mapconcat (lambda (elem)
|
|
(format " %s: '.%s'"
|
|
(nth 1 elem) (nth 2 elem)))
|
|
(org-re-reveal--parse-listoption
|
|
info :reveal-klipse-setup)
|
|
",\n"))
|
|
(org-re-reveal--if-format
|
|
" %s\n" (plist-get info :reveal-klipse-extra-config))
|
|
"</script>\n")
|
|
""))
|
|
|
|
(defun org-re-reveal--klipsify-script (info)
|
|
"Return script element for klipse when indicated by INFO."
|
|
(if (plist-get info :reveal-klipsify-src)
|
|
(format "<script src=\"%s\"></script>
|
|
<script>
|
|
/* Recompute layout upon changes by klipse. Code fragment from
|
|
asciidoctor-revealjs-klipse by Timothy Pratley under GPLv3:
|
|
https://github.com/timothypratley/asciidoctor-revealjs-klipse/blob/master/docs/docinfo-footer.html */
|
|
Reveal.addEventListener( 'slidechanged', function( event ) {
|
|
window.dispatchEvent( new Event('resize') );
|
|
} );
|
|
</script>\n" (plist-get info :reveal-klipse-js-url))
|
|
""))
|
|
|
|
(defun org-re-reveal-stylesheets (info)
|
|
"Return HTML code for reveal stylesheets using INFO and `org-re-reveal-root'."
|
|
(let* ((root-path (file-name-as-directory (plist-get info :reveal-root)))
|
|
(reveal-css (concat root-path "css/reveal.css"))
|
|
(theme (plist-get info :reveal-theme))
|
|
(theme-css (concat root-path "css/theme/" theme ".css"))
|
|
(extra-css (plist-get info :reveal-extra-css))
|
|
(in-single-file (plist-get info :reveal-single-file)))
|
|
(concat
|
|
;; Default embedded style sheets
|
|
"<style type=\"text/css\">
|
|
.underline { text-decoration: underline; }
|
|
</style>
|
|
"
|
|
;; stylesheets
|
|
(mapconcat (lambda (elem) (org-re-reveal--css-label
|
|
in-single-file (car elem) (cdr elem)))
|
|
(append (list (cons reveal-css nil)
|
|
(cons theme-css "theme"))
|
|
(mapcar (lambda (a) (cons a nil))
|
|
(cl-delete-duplicates
|
|
(split-string extra-css "\n" t)
|
|
:test #'equal)))
|
|
"\n")
|
|
|
|
;; Include CSS for highlight.js if necessary
|
|
(if (org-re-reveal--using-highlight.js info)
|
|
(format "<link rel=\"stylesheet\" href=\"%s\"/>\n"
|
|
(format-spec (plist-get info :reveal-highlight-css)
|
|
`((?r . ,(directory-file-name root-path)))))
|
|
"")
|
|
|
|
;; Include CSS for klipse if necessary
|
|
(org-re-reveal--klipsify-header info)
|
|
|
|
;; print-pdf
|
|
(if in-single-file ""
|
|
(format "\n<!-- If the query includes 'print-pdf', include the PDF print sheet -->
|
|
<script>
|
|
if( window.location.search.match( /print-pdf/gi ) ) {
|
|
var link = document.createElement( 'link' );
|
|
link.rel = 'stylesheet';
|
|
link.type = 'text/css';
|
|
link.href = '%scss/print/pdf.css';
|
|
document.getElementsByTagName( 'head' )[0].appendChild( link );
|
|
}
|
|
</script>
|
|
"
|
|
root-path)))))
|
|
|
|
(defun org-re-reveal-mathjax-scripts (info)
|
|
"Return HTML code for declaring MathJax scripts for INFO."
|
|
(if (plist-get info :reveal-mathjax)
|
|
;; MathJax enabled.
|
|
(format "<script type=\"text/javascript\" src=\"%s\"></script>\n"
|
|
(plist-get info :reveal-mathjax-url))))
|
|
|
|
(defun org-re-reveal--read-file-as-string (filename)
|
|
"If FILENAME exists as file, return its contents as string.
|
|
Otherwise, return nil."
|
|
(when (and (stringp filename)
|
|
(file-readable-p filename)
|
|
(not (file-directory-p filename)))
|
|
(with-temp-buffer
|
|
(insert-file-contents-literally filename)
|
|
(buffer-string))))
|
|
|
|
(defun org-re-reveal--external-plugins-maybe-from-file (info)
|
|
"Create list of plugin dependencies from INFO.
|
|
In INFO, `:reveal-external-plugins' can be a list or a filename.
|
|
If it is a filename, split lines to produce a list."
|
|
(let* ((external-plugins (plist-get info :reveal-external-plugins))
|
|
(file-contents (org-re-reveal--read-file-as-string external-plugins)))
|
|
(if file-contents
|
|
(mapcar (lambda (line) (cons 'dummy line))
|
|
(split-string (string-trim file-contents) "\n"))
|
|
(org-re-reveal--read-list external-plugins))))
|
|
|
|
(defun org-re-reveal--external-plugin-init (info root-path)
|
|
"Build initialization strings for plugins of INFO under ROOT-PATH.
|
|
Parameter INFO determines plugins and their initializations
|
|
based on `org-re-reveal-external-plugins'."
|
|
(let ((plugins (org-re-reveal--external-plugins-maybe-from-file info)))
|
|
(cl-loop for (nil . value) in plugins
|
|
collect (format value root-path))))
|
|
|
|
(defvar org-re-reveal-client-multiplex nil
|
|
"Used to cause generation of client html file for multiplex.")
|
|
|
|
(defun org-re-reveal-scripts--libraries (info)
|
|
"Internal function to generate script tags with INFO.
|
|
This includes reveal.js libraries in `org-re-reveal-script-files' under
|
|
`org-re-reveal-root', and libraries in `org-re-reveal-extra-scripts'."
|
|
(let* ((root-path (file-name-as-directory (plist-get info :reveal-root)))
|
|
(script-files (org-re-reveal--parse-listoption
|
|
info :reveal-script-files))
|
|
(root-libs (mapcar (lambda (file) (concat root-path file))
|
|
script-files))
|
|
(extra-scripts (org-re-reveal--parse-listoption
|
|
info :reveal-extra-scripts))
|
|
;; Treat extra scripts not starting with <script> as filenames.
|
|
(extra-script-files
|
|
(cl-remove-if (lambda (s) (string-prefix-p "<script>" s))
|
|
extra-scripts))
|
|
;; Treat extra scripts starting with <script> as elements.
|
|
(extra-script-elements
|
|
(cl-remove-if-not (lambda (s) (string-prefix-p "<script>" s))
|
|
extra-scripts))
|
|
(in-single-file (plist-get info :reveal-single-file)))
|
|
(concat
|
|
(if in-single-file
|
|
(let* ((local-root-path (org-re-reveal--file-url-to-path root-path))
|
|
(local-libs (append (mapcar (lambda (file)
|
|
(concat local-root-path file))
|
|
script-files)
|
|
extra-script-files))
|
|
(local-libs-exist-p (cl-every #'file-readable-p local-libs)))
|
|
(if local-libs-exist-p
|
|
;; Embed contents of files.
|
|
(mapconcat (lambda (file)
|
|
(format "<script>\n%s\n</script>\n"
|
|
(org-re-reveal--read-file file)))
|
|
local-libs "")
|
|
(error
|
|
(concat "Cannot read "
|
|
(mapconcat 'identity
|
|
(cl-remove-if #'file-readable-p local-libs)
|
|
", ")))))
|
|
;; Embed script files with src.
|
|
(mapconcat (lambda (file)
|
|
(concat "<script src=\"" file "\"></script>\n"))
|
|
(append root-libs extra-script-files) ""))
|
|
;; Embed script tags.
|
|
(mapconcat 'identity extra-script-elements "\n")
|
|
(if extra-script-elements "\n" ""))))
|
|
|
|
(defun org-re-reveal-scripts--reveal-options (info)
|
|
"Internal function for `org-re-reveal-scripts' with INFO."
|
|
(format "
|
|
controls: %s,
|
|
progress: %s,
|
|
history: %s,
|
|
center: %s,
|
|
slideNumber: %s,
|
|
rollingLinks: %s,
|
|
keyboard: %s,
|
|
mouseWheel: %s,
|
|
fragmentInURL: %s,
|
|
hashOneBasedIndex: %s,
|
|
pdfSeparateFragments: %s,
|
|
%s
|
|
overview: %s,
|
|
"
|
|
(if (plist-get info :reveal-control) "true" "false")
|
|
(if (plist-get info :reveal-progress) "true" "false")
|
|
(if (plist-get info :reveal-history) "true" "false")
|
|
(if (plist-get info :reveal-center) "true" "false")
|
|
(let ((slide-number (plist-get info :reveal-slide-number)))
|
|
(if slide-number (format "'%s'" slide-number)
|
|
"false"))
|
|
(if (plist-get info :reveal-rolling-links) "true" "false")
|
|
(if (plist-get info :reveal-keyboard) "true" "false")
|
|
(if (plist-get info :reveal-mousewheel) "true" "false")
|
|
(if (plist-get info :reveal-fragmentinurl) "true" "false")
|
|
(if (plist-get info :reveal-hashonebasedindex) "true" "false")
|
|
(if (plist-get info :reveal-pdfseparatefragments) "true" "false")
|
|
(let ((timing (plist-get info :reveal-defaulttiming)))
|
|
(if timing (format "defaultTiming: %s," timing)
|
|
""))
|
|
(if (plist-get info :reveal-overview) "true" "false")))
|
|
|
|
(defun org-re-reveal--to-string (option)
|
|
"Return OPTION as string.
|
|
If OPTION is an integer > 0, return as string.
|
|
If OPTION is a string, embed in quotation marks.
|
|
If OPTION is nil, return nil (not the empty string).
|
|
Otherwise, raise error."
|
|
(cond ((and (integerp option) (> option 0)) (format "%d" option))
|
|
((stringp option) (format "\"%s\"" option))
|
|
((eq option nil) nil)
|
|
(t (error "Option »%s« must be string, positive integer, or nil; not %s"
|
|
option (type-of option)))))
|
|
|
|
(defun org-re-reveal-scripts--main-configures (info)
|
|
"Internal function for `org-re-reveal-scripts' with INFO."
|
|
(concat
|
|
;; slide width
|
|
(let ((width (plist-get info :reveal-width)))
|
|
(org-re-reveal--if-format "width: %s,\n"
|
|
(org-re-reveal--to-string width)))
|
|
|
|
;; slide height
|
|
(let ((height (plist-get info :reveal-height)))
|
|
(org-re-reveal--if-format "height: %s,\n"
|
|
(org-re-reveal--to-string height)))
|
|
|
|
;; slide margin
|
|
(let ((margin (string-to-number (plist-get info :reveal-margin))))
|
|
(if (>= margin 0) (format "margin: %.2f,\n" margin) ""))
|
|
|
|
;; slide minimum scaling factor
|
|
(let ((min-scale (string-to-number (plist-get info :reveal-min-scale))))
|
|
(if (> min-scale 0) (format "minScale: %.2f,\n" min-scale) ""))
|
|
|
|
;; slide maximux scaling factor
|
|
(let ((max-scale (string-to-number (plist-get info :reveal-max-scale))))
|
|
(if (> max-scale 0) (format "maxScale: %.2f,\n" max-scale) ""))
|
|
|
|
;; thems and transitions
|
|
(format "
|
|
theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
|
|
transition: Reveal.getQueryHash().transition || '%s', // see README of reveal.js for options
|
|
transitionSpeed: '%s',\n"
|
|
(plist-get info :reveal-trans)
|
|
(plist-get info :reveal-speed))
|
|
|
|
(let ((options (plist-get info :reveal-extra-options)))
|
|
(org-re-reveal--if-format "%s,\n" options))))
|
|
|
|
(defun org-re-reveal-scripts--multiplex (info)
|
|
"Internal function for `org-re-reveal-scripts' with INFO."
|
|
(let ((enabled-builtin-plugins
|
|
(org-re-reveal--parse-listoption info :reveal-plugins)))
|
|
(when (memq 'multiplex enabled-builtin-plugins)
|
|
(format
|
|
"multiplex: {
|
|
secret: %s, // null if client
|
|
id: '%s', // id, obtained from socket.io server
|
|
url: '%s' // Location of socket.io server
|
|
},\n"
|
|
(if (eq org-re-reveal-client-multiplex nil)
|
|
(format "'%s'" (plist-get info :reveal-multiplex-secret))
|
|
(format "null"))
|
|
(plist-get info :reveal-multiplex-id)
|
|
(plist-get info :reveal-multiplex-url)))))
|
|
|
|
(defun org-re-reveal-scripts--dependencies (info)
|
|
"Internal function for `org-re-reveal-scripts' with INFO."
|
|
(let* ((root-path (file-name-as-directory (plist-get info :reveal-root)))
|
|
(in-single-file (plist-get info :reveal-single-file))
|
|
(enabled-builtin-plugins (org-re-reveal--parse-listoption
|
|
info :reveal-plugins)))
|
|
;; optional JS library heading
|
|
(if in-single-file ""
|
|
(concat
|
|
"
|
|
// Optional libraries used to extend reveal.js
|
|
dependencies: [
|
|
"
|
|
;; JS libraries
|
|
(let* ((highlight-url (plist-get info :reveal-highlight-url))
|
|
(builtins
|
|
`(classList ,(format " { src: '%slib/js/classList.js', condition: function() { return !document.body.classList; } }" root-path)
|
|
markdown ,(format " { src: '%splugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
|
|
{ src: '%splugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }" root-path root-path)
|
|
highlight ,(if highlight-url
|
|
(format " { src: '%s', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }" highlight-url)
|
|
(format " { src: '%splugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }" root-path))
|
|
zoom ,(format " { src: '%splugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } }" root-path)
|
|
notes ,(format " { src: '%splugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }" root-path)
|
|
search ,(format " { src: '%splugin/search/search.js', async: true, condition: function() { return !!document.body.classList; } }" root-path)
|
|
remotes ,(format " { src: '%splugin/remotes/remotes.js', async: true, condition: function() { return !!document.body.classList; } }" root-path)
|
|
multiplex ,(format " { src: '%s', async: true },\n%s"
|
|
(plist-get info :reveal-multiplex-socketio-url)
|
|
;; following ensures that either client.js or master.js is included depending on defvar org-re-reveal-client-multiplex value state
|
|
(if (not org-re-reveal-client-multiplex)
|
|
(progn
|
|
(if (not (string= "" (plist-get info :reveal-multiplex-secret)))
|
|
(setq org-re-reveal-client-multiplex t))
|
|
(format " { src: '%splugin/multiplex/master.js', async: true }" root-path))
|
|
(format " { src: '%splugin/multiplex/client.js', async: true }" root-path)))))
|
|
(builtin-codes
|
|
(mapcar (lambda (p) (plist-get builtins p)) enabled-builtin-plugins))
|
|
(external-plugins
|
|
(org-re-reveal--external-plugin-init info root-path))
|
|
(all-plugins (if external-plugins (append external-plugins builtin-codes) builtin-codes))
|
|
(extra-codes (plist-get info :reveal-extra-js))
|
|
(total-codes
|
|
(if (string= "" extra-codes)
|
|
all-plugins
|
|
(append (list extra-codes) all-plugins))))
|
|
(mapconcat 'identity total-codes ",\n"))
|
|
"]\n\n"))))
|
|
|
|
(defun org-re-reveal-scripts--init-script (info)
|
|
"Internal function for `org-re-reveal-scripts' with INFO."
|
|
(let ((init-script (plist-get info :reveal-init-script))
|
|
(in-single-file (plist-get info :reveal-single-file)))
|
|
(if (and (stringp init-script) (> (length init-script) 0))
|
|
(concat (if in-single-file "" ",") init-script)
|
|
"")))
|
|
|
|
(defun org-re-reveal-scripts (info)
|
|
"Return necessary scripts to initialize reveal.js.
|
|
Use INFO and custom variable `org-re-reveal-root'."
|
|
(concat
|
|
;; Libraries in script tags, including reveal.js itself.
|
|
(org-re-reveal-scripts--libraries info)
|
|
|
|
;; Create <script> tag for Reveal.initialize(...).
|
|
"<script>
|
|
// Full list of configuration options available here:
|
|
// https://github.com/hakimel/reveal.js#configuration
|
|
Reveal.initialize({
|
|
"
|
|
;; plugin configures/frags
|
|
(org-re-reveal-scripts--reveal-options info)
|
|
|
|
;; reveal.js main configures
|
|
(org-re-reveal-scripts--main-configures info)
|
|
|
|
;; multiplexing - depends on defvar 'org-re-reveal-client-multiplex'
|
|
(org-re-reveal-scripts--multiplex info)
|
|
|
|
;; load dependency js
|
|
(org-re-reveal-scripts--dependencies info)
|
|
|
|
;; init-script
|
|
(org-re-reveal-scripts--init-script info)
|
|
|
|
;; end of <script> tag
|
|
"});\n</script>\n"))
|
|
|
|
(defun org-re-reveal-toc (depth info)
|
|
"Build a slide of table of contents with DEPTH and INFO."
|
|
(let ((toc (org-html-toc depth info)))
|
|
(org-re-reveal-toc-1 toc info)))
|
|
|
|
(defun org-re-reveal-toc-1 (toc info)
|
|
"Build table of contents with TOC and INFO."
|
|
(when toc
|
|
(let* ((toc-slide-with-header (plist-get info :reveal-slide-global-header))
|
|
(toc-slide-with-footer (or
|
|
(plist-get info :reveal-slide-global-footer)
|
|
(plist-get info :reveal-slide-toc-footer)))
|
|
(toc-slide-state (plist-get info :reveal-toc-slide-state))
|
|
(toc-slide-class (plist-get info :reveal-toc-slide-class))
|
|
(toc-slide-title (plist-get info :reveal-toc-slide-title))
|
|
(toc (replace-regexp-in-string
|
|
"<a href=\"#"
|
|
(concat "<a href=\"#" org-re-reveal--href-fragment-prefix) toc))
|
|
(toc (replace-regexp-in-string
|
|
(org-html--translate "Table of Contents" info)
|
|
toc-slide-title toc)))
|
|
(concat "<section id=\"table-of-contents-section\""
|
|
(when toc-slide-state
|
|
(format " data-state=\"%s\"" toc-slide-state))
|
|
">\n"
|
|
(when toc-slide-with-header
|
|
(let ((header (plist-get info :reveal-slide-header)))
|
|
(when header (format org-re-reveal-slide-header-html header))))
|
|
(if toc-slide-class
|
|
(replace-regexp-in-string
|
|
"<h\\([1-3]\\)>"
|
|
(format "<h\\1 class=\"%s\">" toc-slide-class)
|
|
toc)
|
|
toc)
|
|
(when toc-slide-with-footer
|
|
(let ((footer (plist-get info :reveal-slide-footer)))
|
|
(when footer (format org-re-reveal-slide-footer-html footer))))
|
|
"</section>\n"))))
|
|
|
|
(defun org-re-reveal-inner-template (contents info)
|
|
"Return body of document string after HTML conversion.
|
|
CONTENTS is the transcoded contents string. INFO is a plist
|
|
holding export options."
|
|
(concat
|
|
;; Table of contents.
|
|
(let ((depth (plist-get info :with-toc)))
|
|
(when (and depth
|
|
(not (plist-get info :reveal-subtree)))
|
|
(org-re-reveal-toc depth info)))
|
|
;; Document contents.
|
|
contents))
|
|
|
|
(defun org-re-reveal-parse-keyword-value (value footer keyword info)
|
|
"According to VALUE of KEYWORD and INFO, return HTML tags to split slides.
|
|
Currently, only the keyword \"split\" is implemented, and VALUE must
|
|
start with \"split\". Any following text is inserted literally into
|
|
the section tag.
|
|
The possibly empty FOOTER is inserted at the end of the slide."
|
|
(cl-assert (string-prefix-p "split" value) nil
|
|
(format "Unknown REVEAL keyword. Expected \"split\", got: %s"
|
|
value))
|
|
(let* ((headline (org-export-get-parent-headline keyword))
|
|
(split-attrs (substring value 5)) ; Everything after "split"
|
|
(real-attrs (if (< 0 (length split-attrs))
|
|
split-attrs
|
|
(org-re-reveal--section-attrs headline info))))
|
|
(format "%s</section>\n<section%s>"
|
|
footer real-attrs)))
|
|
|
|
;; Copied from org-html-format-list-item. Overwrite HTML class
|
|
;; attribute when there is attr_html attributes.
|
|
(defun org-re-reveal-format-list-item (contents type checkbox attributes info
|
|
&optional term-counter-id
|
|
headline)
|
|
"Format a list item into HTML based on INFO.
|
|
Item has CONTENTS, TYPE, may be a CHECKBOX, have ATTRIBUTES, and may have
|
|
TERM-COUNTER-ID and HEADLINE."
|
|
(let ((attr-html (cond (attributes (format " %s" (org-html--make-attribute-string attributes)))
|
|
(checkbox (format " class=\"%s\"" (symbol-name checkbox)))
|
|
(t "")))
|
|
(checkbox (concat (org-html-checkbox checkbox info)
|
|
(and checkbox " ")))
|
|
(br (org-html-close-tag "br" nil info)))
|
|
(concat
|
|
(cl-case type
|
|
(ordered
|
|
(let* ((counter term-counter-id)
|
|
(extra (if counter (format " value=\"%s\"" counter) "")))
|
|
(concat
|
|
(format "<li%s%s>" attr-html extra)
|
|
(when headline (concat headline br)))))
|
|
(unordered
|
|
(let* ((id term-counter-id)
|
|
(extra (if id (format " id=\"%s\"" id) "")))
|
|
(concat
|
|
(format "<li%s%s>" attr-html extra)
|
|
(when headline (concat headline br)))))
|
|
(descriptive
|
|
(let* ((term term-counter-id))
|
|
(setq term (or term "(no term)"))
|
|
;; Check-boxes in descriptive lists are associated to tag.
|
|
(concat (format "<dt%s>%s</dt>"
|
|
attr-html (concat checkbox term))
|
|
(format "<dd%s>" attr-html)))))
|
|
(unless (eq type 'descriptive) checkbox)
|
|
(and contents (org-trim contents))
|
|
(cl-case type
|
|
(ordered "</li>")
|
|
(unordered "</li>")
|
|
(descriptive "</dd>")))))
|
|
|
|
;; Copied from org-html-item, changed to call
|
|
;; org-re-reveal-format-list-item.
|
|
(defun org-re-reveal-item (item contents info)
|
|
"Transcode an ITEM element from Org to Reveal.
|
|
CONTENTS holds the contents of the item. INFO is a plist holding
|
|
contextual information."
|
|
(let* ((plain-list (org-export-get-parent item))
|
|
(type (org-element-property :type plain-list))
|
|
(counter (org-element-property :counter item))
|
|
(attributes (org-export-read-attribute :attr_html item))
|
|
(checkbox (org-element-property :checkbox item))
|
|
(tag (let ((tag (org-element-property :tag item)))
|
|
(and tag (org-export-data tag info)))))
|
|
(org-re-reveal-format-list-item
|
|
contents type checkbox attributes info (or tag counter))))
|
|
|
|
(defun org-re-reveal-keyword (keyword contents info)
|
|
"Transcode a KEYWORD element from Org to Reveal.
|
|
May change custom variables as SIDE EFFECT.
|
|
CONTENTS is nil. INFO is a plist holding contextual information."
|
|
(let* ((key (org-element-property :key keyword))
|
|
(value (org-element-property :value keyword))
|
|
(footer (plist-get info :reveal-slide-footer))
|
|
(footer-div (if footer
|
|
(format org-re-reveal-slide-footer-html footer) "")))
|
|
(cl-case (intern key)
|
|
(REVEAL (org-re-reveal-parse-keyword-value value footer-div keyword info))
|
|
(REVEAL_HTML value)
|
|
(HTML value)
|
|
;; Handling of TOC at arbitrary position is a hack.
|
|
;; We end the previous section by inserting a closing section tag,
|
|
;; which will *break* the presentation if other tags are still open.
|
|
;; To avoid unbalanced tags, remove the TOC's closing tag.
|
|
;; If slide footers are used, insert it before closing the section.
|
|
;; In any case, if footers are used, the one of the closed section
|
|
;; is sufficient, and the one contained in the TOC needs to be removed.
|
|
(TOC (message "Please use #+REVEAL_TOC instead of #+TOC. See Readme.")
|
|
(sit-for 2)
|
|
(concat footer-div
|
|
"</section>\n"
|
|
(replace-regexp-in-string
|
|
(format "</section>\\|%s"
|
|
(format org-re-reveal-slide-footer-html ".*"))
|
|
""
|
|
(org-re-reveal-toc-1
|
|
(org-html-keyword keyword contents info) info))))
|
|
(REVEAL_TOC
|
|
;; Following code stiched together with snippets from
|
|
;; org-html-keyword and org-html-toc.
|
|
(when (string-match "\\<headlines\\>" value)
|
|
(let* ((depth (and (string-match "\\<[0-9]+\\>" value)
|
|
(string-to-number (match-string 0 value))))
|
|
(toc-entries
|
|
(mapcar (lambda (headline)
|
|
(cons (org-html--format-toc-headline headline info)
|
|
(org-export-get-relative-level headline info)))
|
|
(org-export-collect-headlines info depth))))
|
|
(when toc-entries
|
|
(let ((toc (concat "<div id=\"text-table-of-contents\">"
|
|
(org-html--toc-text toc-entries)
|
|
"</div>\n")))
|
|
;; Use link format of reveal.js.
|
|
(replace-regexp-in-string
|
|
"<a href=\"#"
|
|
(concat "<a href=\"#" org-re-reveal--href-fragment-prefix)
|
|
toc)))))))))
|
|
|
|
(defun org-re-reveal-embedded-svg (path)
|
|
"Embed the SVG content at PATH into Reveal HTML."
|
|
(with-temp-buffer
|
|
(insert-file-contents-literally path)
|
|
(let ((start (re-search-forward "<[ \t\n]*svg[ \t\n]"))
|
|
(end (re-search-forward "<[ \t\n]*/svg[ \t\n]*>")))
|
|
(concat "<svg " (buffer-substring-no-properties start end)))))
|
|
|
|
(defun org-re-reveal--format-image-data-uri (link path info)
|
|
"Generate the data URI for the image referenced by LINK at PATH with INFO."
|
|
(let* ((ext (downcase (file-name-extension path))))
|
|
(if (string= ext "svg")
|
|
(org-re-reveal-embedded-svg path)
|
|
(org-html-close-tag
|
|
"img"
|
|
(org-html--make-attribute-string
|
|
(org-combine-plists
|
|
(list :src
|
|
(concat
|
|
"data:image/"
|
|
;; Image type
|
|
ext
|
|
";base64,"
|
|
;; Base64 content
|
|
(with-temp-buffer
|
|
(insert-file-contents-literally path)
|
|
(base64-encode-region 1 (point-max))
|
|
(buffer-string))))
|
|
;; Get attribute list from parent element
|
|
;; Copied from ox-html.el
|
|
(let* ((parent (org-export-get-parent-element link))
|
|
(link (let ((container (org-export-get-parent link)))
|
|
(if (and (eq (org-element-type container) 'link)
|
|
(org-html-inline-image-p link info))
|
|
container
|
|
link))))
|
|
(and (eq (org-element-map parent 'link 'identity info t) link)
|
|
(org-export-read-attribute :attr_html parent)))))
|
|
info))))
|
|
|
|
(defun org-re-reveal--maybe-replace-in-link (link allow-inter-link)
|
|
"Replace hash sign in LINK, affected by ALLOW-INTER-LINK.
|
|
|
|
If ALLOW-INTER-LINK is nil, only replace hash signs if URL in LINK starts
|
|
with it. Otherwise, also replace if the URL does not contain a hostname;
|
|
such links are assumed to point into other presentations."
|
|
(if (and allow-inter-link
|
|
(string-match "<a href=\"\\([^\"]*\\)\"" link))
|
|
(let* ((url (match-string 1 link))
|
|
(obj (url-generic-parse-url url))
|
|
(host (url-host obj)))
|
|
(if host
|
|
link
|
|
(replace-regexp-in-string
|
|
"<a href=\"\\([^#]*\\)#"
|
|
(concat "<a href=\"\\1#" org-re-reveal--href-fragment-prefix)
|
|
link)))
|
|
(replace-regexp-in-string
|
|
"<a href=\"#"
|
|
(concat "<a href=\"#" org-re-reveal--href-fragment-prefix)
|
|
link)))
|
|
|
|
(defun org-re-reveal--internal-link-class (link info)
|
|
"Check if LINK is internal, given INFO, and maybe assign class.
|
|
The direction of the link is assigned as class attribute to the link
|
|
and to its parent via \"attr_html\":
|
|
If link points backward (to previous content), class \"backwardlink\"
|
|
is assigned, else \"forwardlink\".
|
|
Assigning the class to \"attr_html\" of parent is based on a hack in
|
|
`org-html-link', while use of \"attr_html\" of the link itself
|
|
requires a version of org-mode as of 2018-12-08 or newer."
|
|
(let ((target (or (ignore-errors (org-export-resolve-id-link link info))
|
|
(ignore-errors (org-export-resolve-fuzzy-link link info)))))
|
|
(when target
|
|
(let* ((lbegin (org-element-property :begin link))
|
|
(tbegin (org-element-property :begin target))
|
|
(direction (if (< tbegin lbegin)
|
|
"backwardlink"
|
|
"forwardlink"))
|
|
(parent (org-export-get-parent-element link))
|
|
(attrs (org-combine-plists
|
|
(org-export-read-attribute :attr_html parent)
|
|
(org-export-read-attribute :attr_html link)))
|
|
(class (plist-get attrs :class))
|
|
(newclass (if class (concat direction " " class) direction))
|
|
(newattrs (mapconcat (lambda (elem) (format "%s" elem))
|
|
(plist-put attrs :class newclass)
|
|
" ")))
|
|
(org-element-put-property parent :attr_html (list newattrs))
|
|
(org-element-put-property link :attr_html (list newattrs))))))
|
|
|
|
(defun org-re-reveal-link (link desc info)
|
|
"Transcode a LINK object with DESC and INFO from Org to Reveal.
|
|
The result is identical to ox-html expect for image links.
|
|
When `org-re-reveal-single-file' is t,
|
|
the result is the Data URI of the referenced image."
|
|
(let* ((want-embed-image (and (plist-get info :reveal-single-file)
|
|
(plist-get info :html-inline-images)
|
|
(string= "file" (org-element-property :type link))
|
|
(org-export-inline-image-p
|
|
link (plist-get info :html-inline-image-rules))))
|
|
(allow-inter-link (plist-get info :reveal-inter-presentation-links))
|
|
(raw-path (org-element-property :path link))
|
|
(clean-path (org-re-reveal--file-url-to-path raw-path))
|
|
(can-embed-image (and want-embed-image
|
|
(file-readable-p clean-path))))
|
|
(if can-embed-image
|
|
(org-re-reveal--format-image-data-uri link clean-path info)
|
|
(if want-embed-image
|
|
(error "Cannot embed image %s" raw-path)
|
|
(org-re-reveal--internal-link-class link info)
|
|
(org-re-reveal--maybe-replace-in-link (org-html-link link desc info)
|
|
allow-inter-link)))))
|
|
|
|
(defun org-re-reveal-latex-environment (latex-env contents info)
|
|
"Transcode a LaTeX environment from Org to Reveal.
|
|
LATEX-ENV is the Org element. CONTENTS is the contents of the environment.
|
|
INFO is a plist holding contextual information."
|
|
(setq info (plist-put info :reveal-mathjax t))
|
|
(let ((attrs (org-export-read-attribute :attr_html latex-env)))
|
|
(format "<div%s>\n%s\n</div>\n"
|
|
(if attrs (concat " " (org-html--make-attribute-string attrs)) "")
|
|
(org-html-latex-environment latex-env contents info))))
|
|
|
|
(defun org-re-reveal-plain-list (plain-list contents info)
|
|
"Transcode a PLAIN-LIST element from Org to Reveal.
|
|
CONTENTS is the contents of the list. INFO is a plist holding
|
|
contextual information.
|
|
Extract and set `attr_html' to plain-list tag attributes."
|
|
(ignore info) ; Silence byte compiler
|
|
(let ((tag (cl-case (org-element-property :type plain-list)
|
|
(ordered "ol")
|
|
(unordered "ul")
|
|
(descriptive "dl")))
|
|
(attrs (org-export-read-attribute :attr_html plain-list)))
|
|
(format "%s<%s%s>\n%s\n</%s>%s"
|
|
(if (string= org-html-checkbox-type 'html) "<form>" "")
|
|
tag
|
|
(if attrs (concat " " (org-html--make-attribute-string attrs)) "")
|
|
contents
|
|
tag
|
|
(if (string= org-html-checkbox-type 'html) "</form>" ""))))
|
|
|
|
(defun org-re-reveal-format-spec (info)
|
|
"Return format specification with INFO.
|
|
Formatting extends `org-html-format-spec' as follows:
|
|
misc information and academic title."
|
|
(append (org-html-format-spec info)
|
|
`((?A . ,(org-export-data
|
|
(plist-get info :reveal-academic-title) info))
|
|
(?m . ,(org-export-data
|
|
(plist-get info :reveal-miscinfo) info))
|
|
(?q . ,(url-encode-url
|
|
(org-export-data
|
|
(plist-get info :reveal-talk-qr-code) info)))
|
|
(?u . ,(url-encode-url
|
|
(org-export-data
|
|
(plist-get info :reveal-talk-url) info))))))
|
|
|
|
(defun org-re-reveal--build-pre-postamble (type info)
|
|
"Depending on TYPE, return preamble or postamble for INFO as string, or nil."
|
|
(let ((section (plist-get info (intern (format ":reveal-%s" type))))
|
|
(spec (org-re-reveal-format-spec info)))
|
|
(when section
|
|
(let ((section-contents
|
|
(if (functionp (intern section)) (funcall (intern section) info)
|
|
;; else section is a string.
|
|
(format-spec section spec))))
|
|
(when (org-string-nw-p section-contents)
|
|
(org-element-normalize-string section-contents))))))
|
|
|
|
|
|
(defun org-re-reveal-section (section contents info)
|
|
"Transcode a SECTION element from Org to Reveal.
|
|
CONTENTS holds the contents of the section. INFO is a plist
|
|
holding contextual information."
|
|
;; Just return the contents. No "<div>" tags.
|
|
(ignore section info) ; Silence byte compiler
|
|
contents)
|
|
|
|
(defun org-re-reveal--using-highlight.js (info)
|
|
"Check with INFO whether highlight.js plugin is enabled."
|
|
(let ((reveal-plugins (condition-case nil
|
|
(car (read-from-string (plist-get info :reveal-plugins)))
|
|
(end-of-file nil)
|
|
(wrong-type-argument nil))))
|
|
(memq 'highlight (or (and reveal-plugins (listp reveal-plugins) reveal-plugins)
|
|
org-re-reveal-plugins))))
|
|
|
|
(defun org-re-reveal--buffer-substring-html-escape (start end)
|
|
"Convert buffer substring characters from plain text to HTML equivalent.
|
|
START and END are character positions as used by `buffer-substring'.
|
|
Conversion is done by escaping special HTML chars."
|
|
(org-html-encode-plain-text (buffer-substring start end)))
|
|
|
|
(defun org-re-reveal-src-block (src-block contents info)
|
|
"Transcode a SRC-BLOCK element from Org to Reveal.
|
|
INFO is a plist holding contextual information. CONTENTS is unused."
|
|
(ignore contents) ; Silence byte compiler
|
|
(if (org-export-read-attribute :attr_html src-block :textarea)
|
|
(org-html--textarea-block src-block)
|
|
(let* ((use-highlight (org-re-reveal--using-highlight.js info))
|
|
(use-htmlize (or (not org-re-reveal-no-htmlize-src)
|
|
(org-export-read-attribute
|
|
:attr_reveal src-block :htmlize)))
|
|
(lang (org-element-property :language src-block))
|
|
(caption (org-export-get-caption src-block))
|
|
(code (if (and (not use-highlight) use-htmlize)
|
|
(org-html-format-code src-block info)
|
|
(cl-letf (((symbol-function
|
|
'org-html-htmlize-region-for-paste)
|
|
#'org-re-reveal--buffer-substring-html-escape))
|
|
(org-html-format-code src-block info))))
|
|
(frag (org-export-read-attribute :attr_reveal src-block :frag))
|
|
(findex (org-export-read-attribute :attr_reveal src-block :frag_idx))
|
|
(code-attribs (or (org-export-read-attribute
|
|
:attr_reveal src-block :code_attribs) ""))
|
|
(label (let ((lbl (org-element-property :name src-block)))
|
|
(if (not lbl) ""
|
|
(format " id=\"%s\"" lbl))))
|
|
(klipse-setup (org-re-reveal--parse-listoption
|
|
info :reveal-klipse-setup))
|
|
(klipsify (and (member lang (mapcar #'car klipse-setup))
|
|
(plist-get info :reveal-klipsify-src)
|
|
(not (org-export-read-attribute
|
|
:attr_reveal src-block :no-klipsify)))))
|
|
(if (not lang)
|
|
(format "<pre %s%s>\n%s</pre>"
|
|
(or (org-re-reveal--frag-class frag info) " class=\"example\"")
|
|
label
|
|
code)
|
|
(if klipsify
|
|
(let* ((triple (assoc lang klipse-setup))
|
|
(selectorclass (nth 2 triple)))
|
|
(concat
|
|
"<pre><code class=\"" selectorclass "\" " code-attribs ">\n"
|
|
(if (string= lang "html")
|
|
(replace-regexp-in-string
|
|
"'" "'"
|
|
(replace-regexp-in-string
|
|
"<" "<"
|
|
(replace-regexp-in-string
|
|
">" ">"
|
|
(replace-regexp-in-string
|
|
"&" "&"
|
|
(cl-letf (((symbol-function
|
|
'org-html-htmlize-region-for-paste)
|
|
#'buffer-substring))
|
|
(org-html-format-code src-block info))))))
|
|
(replace-regexp-in-string "'" "'" code))
|
|
"</code></pre>\n"))
|
|
(format
|
|
"<div class=\"org-src-container\">\n%s%s\n</div>"
|
|
(if (not caption) ""
|
|
(format "<label class=\"org-src-name\">%s</label>"
|
|
(org-export-data caption info)))
|
|
(if use-highlight
|
|
(format "\n<pre%s%s><code class=\"%s %s\" %s>%s</code></pre>"
|
|
(or (org-re-reveal--frag-class frag info) "")
|
|
(or (org-re-reveal--frag-index findex) "")
|
|
label lang code-attribs code)
|
|
(format "\n<pre %s%s%s>%s</pre>"
|
|
(or (org-re-reveal--frag-class frag info)
|
|
(format " class=\"src src-%s\"" lang))
|
|
(or (org-re-reveal--frag-index findex) "")
|
|
label code))))))))
|
|
|
|
(defun org-re-reveal-quote-block (quote-block contents info)
|
|
"Transcode a QUOTE-BLOCK element from Org to Reveal.
|
|
CONTENTS holds the contents of the block INFO is a plist holding
|
|
contextual information."
|
|
(format "<blockquote%s>\n%s</blockquote>"
|
|
(let ((frag (org-re-reveal--frag-class
|
|
(org-export-read-attribute
|
|
:attr_reveal quote-block :frag) info)))
|
|
(if frag
|
|
(concat " " frag)
|
|
""))
|
|
contents))
|
|
|
|
|
|
(defun org-re-reveal--auto-title-slide-template (info)
|
|
"Generate the automatic title slide template with INFO."
|
|
(let* ((spec (org-re-reveal-format-spec info))
|
|
(title (org-export-data (plist-get info :title) info))
|
|
(author (cdr (assq ?a spec)))
|
|
(email (cdr (assq ?e spec)))
|
|
(date (cdr (assq ?d spec))))
|
|
(concat
|
|
(when (and (plist-get info :with-title)
|
|
(org-string-nw-p title))
|
|
(concat "<h1 class=\"title\">" title "</h1>"))
|
|
(when (and (plist-get info :with-author)
|
|
(org-string-nw-p author))
|
|
(concat "<h2 class=\"author\">" author "</h2>"))
|
|
(when (and (plist-get info :with-email)
|
|
(org-string-nw-p email))
|
|
(concat "<h2 class=\"email\">" email "</h2>"))
|
|
(when (and (plist-get info :with-date)
|
|
(org-string-nw-p date))
|
|
(concat "<h2 class=\"date\">" date "</h2>"))
|
|
(when (plist-get info :time-stamp-file)
|
|
(concat "<p class=\"date\">"
|
|
(org-html--translate "Created" info)
|
|
": "
|
|
(format-time-string
|
|
(plist-get info :html-metadata-timestamp-format))
|
|
"</p>")))))
|
|
|
|
(defun org-re-reveal-template (contents info)
|
|
"Return complete document string after HTML conversion.
|
|
CONTENTS is the transcoded contents string.
|
|
INFO is a plist holding export options."
|
|
(concat
|
|
(format "<!DOCTYPE html>\n<html%s>\n<head>\n"
|
|
(org-re-reveal--if-format " lang=\"%s\"" (plist-get info :language)))
|
|
"<meta charset=\"utf-8\"/>\n"
|
|
(org-re-reveal--if-format "<title>%s</title>\n"
|
|
(org-export-data (plist-get info :title) info))
|
|
(org-re-reveal--if-format "<meta name=\"author\" content=\"%s\"/>\n"
|
|
(org-element-interpret-data (plist-get info :author)))
|
|
(org-re-reveal--if-format "<meta name=\"description\" content=\"%s\"/>\n"
|
|
(plist-get info :description))
|
|
(org-re-reveal--if-format "<meta name=\"keywords\" content=\"%s\"/>\n"
|
|
(plist-get info :keywords))
|
|
(org-re-reveal-stylesheets info)
|
|
(org-re-reveal-mathjax-scripts info)
|
|
(org-re-reveal--build-pre-postamble 'head-preamble info)
|
|
(org-element-normalize-string (plist-get info :html-head))
|
|
(org-element-normalize-string (plist-get info :html-head-extra))
|
|
"</head>\n<body"
|
|
(org-re-reveal--if-format " %s" org-re-reveal-body-attrs)
|
|
">\n"
|
|
(org-re-reveal--build-pre-postamble 'preamble info)
|
|
"<div class=\"reveal\">
|
|
<div class=\"slides\">\n"
|
|
;; Title slides
|
|
(let ((title-slide (plist-get info :reveal-title-slide)))
|
|
(when (and (or (eq 'auto title-slide)
|
|
(and (stringp title-slide) (< 0 (length title-slide))))
|
|
(or (not (plist-get info :reveal-subtree))
|
|
(plist-get info :reveal-subtree-with-title-slide)))
|
|
(let ((title-slide-background (plist-get info :reveal-title-slide-background))
|
|
(title-slide-background-size (plist-get info :reveal-title-slide-background-size))
|
|
(title-slide-background-position (plist-get info :reveal-title-slide-background-position))
|
|
(title-slide-background-repeat (plist-get info :reveal-title-slide-background-repeat))
|
|
(title-slide-background-transition (plist-get info :reveal-title-slide-background-transition))
|
|
(title-slide-state (plist-get info :reveal-title-slide-state))
|
|
(title-slide-timing (plist-get info :reveal-title-slide-timing))
|
|
(title-slide-with-header (plist-get info :reveal-slide-global-header))
|
|
(title-slide-with-footer (plist-get info :reveal-slide-global-footer)))
|
|
(concat "<section id=\"sec-title-slide\""
|
|
(when title-slide-background
|
|
(concat " data-background=\"" title-slide-background "\""))
|
|
(when title-slide-background-size
|
|
(concat " data-background-size=\"" title-slide-background-size "\""))
|
|
(when title-slide-background-position
|
|
(concat " data-background-position=\"" title-slide-background-position "\""))
|
|
(when title-slide-background-repeat
|
|
(concat " data-background-repeat=\"" title-slide-background-repeat "\""))
|
|
(when title-slide-background-transition
|
|
(concat " data-background-transition=\"" title-slide-background-transition "\""))
|
|
(when title-slide-state
|
|
(concat " data-state=\"" title-slide-state "\""))
|
|
(when title-slide-timing
|
|
(concat " data-timing=\"" title-slide-timing "\""))
|
|
">\n"
|
|
(when title-slide-with-header
|
|
(let ((header (plist-get info :reveal-slide-header)))
|
|
(when header (format org-re-reveal-slide-header-html header))))
|
|
(cond ((eq title-slide nil) nil)
|
|
((stringp title-slide)
|
|
(let* ((file-contents
|
|
(org-re-reveal--read-file-as-string title-slide))
|
|
(title-string (or file-contents title-slide)))
|
|
(format-spec title-string
|
|
(org-re-reveal-format-spec info))))
|
|
((eq title-slide 'auto) (org-re-reveal--auto-title-slide-template info)))
|
|
"\n"
|
|
(when title-slide-with-footer
|
|
(let ((footer (plist-get info :reveal-slide-footer)))
|
|
(when footer (format org-re-reveal-slide-footer-html footer))))
|
|
"</section>\n"))))
|
|
contents
|
|
"</div>
|
|
</div>\n"
|
|
(org-re-reveal--build-pre-postamble 'postamble info)
|
|
(org-re-reveal-scripts info)
|
|
(org-re-reveal--klipsify-script info)
|
|
"</body>
|
|
</html>\n"))
|
|
|
|
(defun org-re-reveal-filter-parse-tree (tree backend info)
|
|
"Do filtering before parsing TREE.
|
|
TREE is the parse tree being exported. BACKEND is the export
|
|
back-end used. INFO is a plist-used as a communication channel.
|
|
BACKEND must be (or be derived from) `re-reveal'.
|
|
Modify the TREE in two ways:
|
|
First, map each `attr_reveal' attribute to corresponding
|
|
`attr_html' attributes.
|
|
Second, if `org-re-reveal-generate-custom-ids' is t (or option
|
|
\"reveal_generate_ids\" is t), generate \"CUSTOM_ID\" values for
|
|
section headings that do not have one already."
|
|
(cl-assert (org-export-derived-backend-p backend 're-reveal) nil
|
|
(format "Function org-re-reveal-filter-parse-tree called on unexpected backend: %s" backend))
|
|
(let ((default-frag-style (plist-get info :reveal-default-frag-style)))
|
|
(org-element-map tree (remq 'item org-element-all-elements)
|
|
(lambda (elem) (org-re-reveal-append-frag elem default-frag-style))))
|
|
(when (plist-get info :reveal-generate-ids)
|
|
(let ((numbering (org-export--collect-headline-numbering tree info)))
|
|
(dolist (pair numbering nil)
|
|
(let ((headline (car pair))
|
|
(number (cdr pair)))
|
|
(when (org-export-numbered-headline-p headline info)
|
|
(let ((section-number (mapconcat #'number-to-string number "-")))
|
|
(when (and (> (length section-number) 0)
|
|
(not (org-element-property :CUSTOM_ID headline)))
|
|
(org-element-put-property headline :CUSTOM_ID section-number))))))))
|
|
;; Return the updated tree.
|
|
tree)
|
|
|
|
(defun org-re-reveal--update-attr-html (elem frag default-style
|
|
&optional frag-index frag-audio)
|
|
"Update ELEM's attr_html attribute with reveal's fragment attributes.
|
|
FRAG is the fragment style, a DEFAULT-STYLE may be used;
|
|
optional FRAG-INDEX and FRAG-AUDIO may indicate fragment positions
|
|
and audio files."
|
|
(let ((attr-html (org-element-property :attr_html elem)))
|
|
(when (and frag (not (string= frag "none")))
|
|
(push (if (string= frag t)
|
|
(if default-style (format ":class fragment %s" default-style)
|
|
":class fragment")
|
|
(format ":class fragment %s" frag))
|
|
attr-html)
|
|
(when frag-index
|
|
;; Index positions should be numbers or the minus sign.
|
|
(cl-assert (or (integerp frag-index)
|
|
(eq frag-index '-)
|
|
(and (not (listp frag-index))
|
|
(not (char-equal
|
|
(string-to-char frag-index) ?\())))
|
|
nil "Index cannot be a list: %s" frag-index)
|
|
(push (format ":data-fragment-index %s" frag-index) attr-html))
|
|
(when (and frag-audio (not (string= frag-audio "none")))
|
|
(push (format ":data-audio-src %s" frag-audio) attr-html)))
|
|
(org-element-put-property elem :attr_html attr-html)))
|
|
|
|
(defun org-re-reveal-append-frag (elem default-style)
|
|
"Append transformed fragment from ELEM with DEFAULT-STYLE.
|
|
Read fragment from ELEM and append transformed fragment attribute to ELEM's
|
|
attr_html plist."
|
|
(let ((frag (org-export-read-attribute :attr_reveal elem :frag))
|
|
(frag-index (org-export-read-attribute :attr_reveal elem :frag_idx))
|
|
(frag-audio (org-export-read-attribute :attr_reveal elem :audio)))
|
|
(when frag
|
|
(if (and (string= (org-element-type elem) 'plain-list)
|
|
(char-equal (string-to-char frag) ?\())
|
|
(let* ((items (org-element-contents elem))
|
|
(frag-list (car (read-from-string frag)))
|
|
(frag-list (if default-style
|
|
(mapcar (lambda (s)
|
|
"Replace t with default-style"
|
|
(if (string= s t) default-style
|
|
s))
|
|
frag-list)
|
|
frag-list))
|
|
(itemno (length items))
|
|
(style-list (make-list itemno default-style))
|
|
;; Make sure that we have enough fragments. Duplicate the
|
|
;; last element of frag-list so that frag-list and items
|
|
;; have the same length.
|
|
(last-frag (car (last frag-list)))
|
|
(tail-list (make-list
|
|
(- itemno (length frag-list)) last-frag))
|
|
(frag-list (append frag-list tail-list))
|
|
;; Concerning index positions and audio files, check later
|
|
;; that their number is OK.
|
|
(frag-index (if frag-index
|
|
(car (read-from-string frag-index))
|
|
(make-list itemno nil)))
|
|
(frag-audio (when frag-audio
|
|
(car (read-from-string frag-audio)))))
|
|
;; As we are looking at fragments in lists, we make sure
|
|
;; that other specs are lists of proper length.
|
|
(cl-assert (listp frag-index) t
|
|
"Must use list for index positions, not: %s")
|
|
(when frag-index
|
|
(cl-assert (= (length frag-index) itemno) nil
|
|
"Use one index per item! %s has %d, need %d"
|
|
frag-index (length frag-index) (length items)))
|
|
(cl-assert (listp frag-audio) t
|
|
"Must use list for audio files! %s")
|
|
(when frag-audio
|
|
(cl-assert (= (length frag-audio) itemno) nil
|
|
"Use one audio file per item! %s has %d, need %d"
|
|
frag-audio (length frag-audio) itemno))
|
|
(if frag-audio
|
|
(cl-mapcar 'org-re-reveal--update-attr-html
|
|
items frag-list style-list frag-index frag-audio)
|
|
(cl-mapcar 'org-re-reveal--update-attr-html
|
|
items frag-list style-list frag-index)))
|
|
(org-re-reveal--update-attr-html
|
|
elem frag default-style frag-index frag-audio))
|
|
elem)))
|
|
|
|
(defun org-re-reveal-export-to-html
|
|
(&optional async subtreep visible-only body-only ext-plist backend)
|
|
"Export current buffer to a reveal.js HTML file.
|
|
Optional ASYNC, SUBTREEP, VISIBLE-ONLY, BODY-ONLY, EXT-PLIST are passed
|
|
to `org-export-to-file'.
|
|
Optional BACKEND must be `re-reveal' or a backend derived from it."
|
|
(interactive)
|
|
(let* ((backend (or backend 're-reveal))
|
|
(extension (concat "." org-html-extension))
|
|
(file (org-export-output-file-name extension subtreep))
|
|
(clientfile (org-export-output-file-name (concat "_client" extension) subtreep))
|
|
(org-html-container-element "div"))
|
|
|
|
(setq org-re-reveal-client-multiplex nil)
|
|
(org-export-to-file backend file
|
|
async subtreep visible-only body-only ext-plist)
|
|
|
|
;; Export the client HTML file if org-re-reveal-client-multiplex is set true
|
|
;; by previous call to org-export-to-file
|
|
(if org-re-reveal-client-multiplex
|
|
(org-export-to-file backend clientfile
|
|
async subtreep visible-only body-only ext-plist))
|
|
file))
|
|
|
|
(defun org-re-reveal-export-to-html-and-browse
|
|
(&optional async subtreep visible-only body-only ext-plist)
|
|
"Export current buffer to a reveal.js and browse HTML file.
|
|
Optional ASYNC, SUBTREEP, VISIBLE-ONLY, BODY-ONLY, EXT-PLIST are passed
|
|
to `org-re-reveal-export-to-html'."
|
|
(interactive)
|
|
(browse-url-of-file
|
|
(expand-file-name
|
|
(org-re-reveal-export-to-html
|
|
async subtreep visible-only body-only ext-plist))))
|
|
|
|
(defun org-re-reveal-export-current-subtree
|
|
(&optional async subtreep visible-only body-only ext-plist)
|
|
"Export current subtree to a Reveal.js HTML file.
|
|
Optional ASYNC, SUBTREEP, VISIBLE-ONLY, BODY-ONLY, EXT-PLIST are passed
|
|
to `org-re-reveal-export-to-html'."
|
|
(interactive)
|
|
(org-narrow-to-subtree)
|
|
(let ((ret (org-re-reveal-export-to-html
|
|
async subtreep visible-only body-only
|
|
(plist-put ext-plist :reveal-subtree t))))
|
|
(widen)
|
|
ret))
|
|
|
|
;;;###autoload
|
|
(defun org-re-reveal-publish-to-reveal
|
|
(plist filename pub-dir &optional backend)
|
|
"Publish an Org file to HTML.
|
|
FILENAME is the filename of the Org file to be published. PLIST
|
|
is the property list for the given project. PUB-DIR is the
|
|
publishing directory. Optional BACKEND may specify a derived export
|
|
backend.
|
|
Return output file name."
|
|
(let ((org-re-reveal-client-multiplex nil))
|
|
(org-publish-org-to
|
|
(or backend 're-reveal) filename ".html" plist pub-dir)))
|
|
|
|
;;;###autoload
|
|
(defun org-re-reveal-publish-to-reveal-client
|
|
(plist filename pub-dir &optional backend)
|
|
"Publish an Org file to HTML as multiplex client.
|
|
FILENAME is the filename of the Org file to be published. PLIST
|
|
is the property list for the given project. PUB-DIR is the
|
|
publishing directory. Optional BACKEND may specify a derived export
|
|
backend.
|
|
If `org-re-reveal-client-multiplex-filter' is non-nil, use it as regular
|
|
expression to only publish FILENAME if it matches this regular expression.
|
|
Return output file name."
|
|
(if (or (not org-re-reveal-client-multiplex-filter)
|
|
(string-match org-re-reveal-client-multiplex-filter filename))
|
|
(let ((org-re-reveal-client-multiplex t))
|
|
(org-publish-org-to
|
|
(or backend 're-reveal) filename "_client.html" plist pub-dir))
|
|
(message "File '%s' not published (not matched by '%s')."
|
|
filename org-re-reveal-client-multiplex-filter)
|
|
nil)
|
|
:package-version '(org-re-reveal . "2.12.0"))
|
|
|
|
;; Register auto-completion for speaker notes.
|
|
(when org-re-reveal-note-key-char
|
|
(add-to-list 'org-structure-template-alist
|
|
(if (version< org-version "9.2")
|
|
(list org-re-reveal-note-key-char "#+BEGIN_NOTES\n\?\n#+END_NOTES")
|
|
(cons org-re-reveal-note-key-char "notes"))))
|
|
|
|
;;; Extract version string.
|
|
;;;###autoload
|
|
(defun org-re-reveal-version ()
|
|
"Display version string for org-re-reveal from Lisp file."
|
|
(interactive)
|
|
(let ((lisp-file
|
|
(concat (file-name-sans-extension (locate-library "org-re-reveal"))
|
|
".el")))
|
|
(with-temp-buffer
|
|
(insert-file-contents lisp-file)
|
|
(goto-char (point-min))
|
|
(re-search-forward "^;; Version: \\([0-9.]+\\)$")
|
|
(message "org-re-reveal version %s" (match-string 1)))))
|
|
|
|
(provide 'org-re-reveal)
|
|
;;; org-re-reveal.el ends here
|