Fixed #448. Refined third-party plugin for reveal.js 4.

This commit is contained in:
Yujie Wen 2021-08-15 17:07:54 +08:00
parent 014561540b
commit 775b1386bb
2 changed files with 155 additions and 150 deletions

View File

@ -569,26 +569,16 @@ supported options. Check the head part of this document for an
example. example.
** Third-Party Plugins ** Third-Party Plugins
Reveal.js is also extensible through third-party plugins. Org-reveal Reveal.js is also extensible through third-party plugins. Org-reveal
now includes a mechanism to load these as well, either for all org buffers provides a customizable variable ~org-reveal-external-plugins~ for
by defining variable, or for local org buffer by setting option line. defining available third-party plugins. This variable is an
associative list. The first element of each Assoc cell is a symbol
*** By Defining Variable same as the name of the plugin and the second is a string specifying
Store the names and loading instructions for each plugin in the the location of the plugin script. The string can have ONE optional
customizable variable ~org-reveal-external-plugins~. This variable is ~%s~, which will be replaced by `reveal-root`. Code below is an
an associative list. The first element of each Assoc cell is a symbol example.
-- the name of the plugin -- and the second is the string of the code #+begin_src lisp
for enabling the plugin. The string can have ONE optional ~%s~, which (setq org-reveal-external-plugins '((menu . "path/to/reveal.js-menu/menu.js"))
will be replaced by `reveal-root`. #+end_src
So, this second element should have the form ~"{src:
\"%srelative/path/toplugin/from/reveal/root.js\"}~. If you need the
async or callback parameters, include those too. Ox-reveal will add
the plugin to the dependencies parameter when Reveal is initialized.
*** By Local Option Line
Specify the plugin by option line ~#+REVEAL_EXTERNAL_PLUGINS: string
of code~. Similar to the global plugin definition, the string of code
can have one optional ~%s~ to be replaced by ~reveal-root~.
** Highlight Source Code ** Highlight Source Code

View File

@ -270,11 +270,10 @@ embedded into Reveal.initialize()."
:type 'string) :type 'string)
(defcustom org-reveal-plugins (defcustom org-reveal-plugins
'(classList markdown zoom notes) '(markdown zoom notes)
"Default builtin plugins" "Default builtin plugins"
:group 'org-export-reveal :group 'org-export-reveal
:type '(set :type '(set
(const classList)
(const markdown) (const markdown)
(const highlight) (const highlight)
(const zoom) (const zoom)
@ -668,6 +667,53 @@ using custom variable `org-reveal-root'."
(or (and buffer-plugins (listp buffer-plugins) buffer-plugins) (or (and buffer-plugins (listp buffer-plugins) buffer-plugins)
org-reveal-plugins))) org-reveal-plugins)))
(defun org-reveal--legacy-dependency (root-path plugins info)
(concat
"
// Optional libraries used to extend on reveal.js
dependencies: [
"
;; JS libraries
(let* ((builtins
(list
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 (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 setup for reveal.js 3.x
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 defva client-multiplex value state
(if (not client-multiplex)
(progn
(if (plist-get info :reveal-multiplex-secret)
(setq 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)
(eval (plist-get builtins p)))
plugins))
(external-plugins
(append
;; Global setting
(cl-loop for (key . value) in org-reveal-external-plugins
collect (format value root-path ))
;; Local settings
(let ((local-plugins (plist-get info :reveal-external-plugins)))
(and local-plugins
(list (format local-plugins 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"))
(defun org-reveal-scripts (info) (defun org-reveal-scripts (info)
"Return the necessary scripts for initializing reveal.js using "Return the necessary scripts for initializing reveal.js using
custom variable `org-reveal-root'." custom variable `org-reveal-root'."
@ -677,8 +723,9 @@ custom variable `org-reveal-root'."
;; Local files ;; Local files
(local-root-path (org-reveal--file-url-to-path root-path)) (local-root-path (org-reveal--file-url-to-path root-path))
(local-reveal-js (org-reveal--choose-path local-root-path version "dist/reveal.js" "js/reveal.js")) (local-reveal-js (org-reveal--choose-path local-root-path version "dist/reveal.js" "js/reveal.js"))
(reveal-4-plugin (if (eq 4 (org-reveal--get-reveal-js-version info)) (plugins (org-reveal--get-plugins info))
(org-reveal-plugin-scripts-4 info) (reveal-4-plugin (if (eq 4 version)
(org-reveal-plugin-scripts-4 plugins info)
(cons nil nil))) (cons nil nil)))
(in-single-file (plist-get info :reveal-single-file))) (in-single-file (plist-get info :reveal-single-file)))
(concat (concat
@ -701,140 +748,108 @@ custom variable `org-reveal-root'."
"<script src=\"" reveal-js "\"></script>\n")) "<script src=\"" reveal-js "\"></script>\n"))
;; plugin headings ;; plugin headings
(if-format "%s\n" (car reveal-4-plugin)) (if-format "%s\n" (car reveal-4-plugin))
"
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
"
(if-format "%s,\n" (cdr reveal-4-plugin))
(let ((options (plist-get info :reveal-init-options)))
(and (string< "" options)
(format "%s,\n" options)))
;; multiplexing - depends on defvar 'client-multiplex' ;; Reveal.initialize
(when (plist-get info :reveal-multiplex-id) (let ((reveal-4-plugin-statement (cdr reveal-4-plugin))
(format (init-options (plist-get info :reveal-init-options))
"multiplex: { (multiplex-statement
;; multiplexing - depends on defvar 'client-multiplex'
(when (memq 'multiplex plugins)
(concat
(format "multiplex: {
secret: %s, // null if client secret: %s, // null if client
id: '%s', // id, obtained from socket.io server id: '%s', // id, obtained from socket.io server
url: '%s' // Location of socket.io server url: '%s' // Location of socket.io server
},\n" },\n"
(if (eq client-multiplex nil) (if (eq client-multiplex nil)
(format "'%s'" (plist-get info :reveal-multiplex-secret)) (format "'%s'" (plist-get info :reveal-multiplex-secret))
(format "null")) (format "null"))
(plist-get info :reveal-multiplex-id) (plist-get info :reveal-multiplex-id)
(plist-get info :reveal-multiplex-url))) (plist-get info :reveal-multiplex-url))
(let ((url (plist-get info :reveal-multiplex-url)))
(let ((extra-initial-js (plist-get info :reveal-extra-initial-js))) (format "dependencies: [ { src: '%s/socket.io/socket.io.js', async: true }, { src: '%s/%s', async: true } ]"
(unless (string= extra-initial-js "") url url
(format "%s,\n" extra-initial-js))) (if client-multiplex "client.js"
(progn
;; optional JS library heading (setq client-multiplex t)
(if in-single-file "" "master.js")))))
(concat ))
" (extra-initial-js-statement (plist-get info :reveal-extra-initial-js))
// Optional libraries used to extend on reveal.js (legacy-dependency-statement
dependencies: [ (unless (or in-single-file (eq version 4))
(org-reveal--legacy-dependency root-path plugins info)))
(init-script-statement (plist-get info :reveal-init-script)))
(format "
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
%s
});
%s
</script>
" "
;; JS libraries (mapconcat 'identity
(let* ((builtins (seq-filter (lambda (x) ;; Remove nil and ""
'(classList (format " { src: '%slib/js/classList.js', condition: function() { return !document.body.classList; } }" root-path) (and x (not (string= x ""))))
markdown (format " { src: '%splugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, (list reveal-4-plugin-statement
{ src: '%splugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }" root-path root-path) init-options
highlight (format " { src: '%splugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }" root-path) multiplex-statement
zoom (format " { src: '%splugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } }" root-path) extra-initial-js-statement
notes (format " { src: '%splugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }" root-path) legacy-dependency-statement))
search (format " { src: '%splugin/search/search.js', async: true, condition: function() { return !!document.body.classList; } }" root-path) ",\n")
remotes (format " { src: '%splugin/remotes/remotes.js', async: true, condition: function() { return !!document.body.classList; } }" root-path) ;; Extra initialization scripts
;; multiplex setup for reveal.js 3.x (or (plist-get info :reveal-extra-script) "")))
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 defva client-multiplex value state
(if (not client-multiplex)
(progn
(if (plist-get info :reveal-multiplex-secret)
(setq 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
(let ((plugins (org-reveal--get-plugins info)))
(if (eq version 4)
;; For reveal.js 4.x, skip the builtin plug-in
;; codes except multiplex as all other plug-ins
;; in 4.x are specified by separate <script>
;; blocks
(let ((url (plist-get info :reveal-multiplex-url)))
(if (memq 'multiplex plugins)
(list (format " { src: '%s/socket.io/socket.io.js', async: true }, { src: '%s/%s', async: true } "
url url
(if client-multiplex "client.js"
(progn
(setq client-multiplex t)
"master.js"))))
'()))
(mapcar (lambda (p)
(eval (plist-get builtins p)))
plugins))))
(external-plugins
(append
;; Global setting
(cl-loop for (key . value) in org-reveal-external-plugins
collect (format value root-path ))
;; Local settings
(let ((local-plugins (plist-get info :reveal-external-plugins)))
(and local-plugins
(list (format local-plugins root-path))))))
(all-plugins (if external-plugins (append external-plugins builtin-codes) builtin-codes)) (defun org-reveal-plugin-scripts-4 (plugins info)
(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"
))
(let ((init-script (plist-get info :reveal-init-script)))
(if init-script (concat (if in-single-file "" ",") init-script)))
"});\n"
(let ((extra-script (plist-get info :reveal-extra-script)))
(if extra-script extra-script))
"
\n</script>\n")))
(defun org-reveal-plugin-scripts-4 (info)
"Return scripts for initializing reveal.js 4.x builtin scripts" "Return scripts for initializing reveal.js 4.x builtin scripts"
(let ((plugins (org-reveal--get-plugins info))) (if (not (null plugins))
(if (not (null plugins)) ;; Generate plugin scripts
;; Generate plugin scripts (let* ((plugins (mapcar
(let* ((available-plugins (lambda (p)
'(highlight ("RevealHighlight" . "highlight/highlight.js") ;; Convert legacy
markdown ("RevealMarkdown" . "markdown/markdown.js") ;; plugin names into
search ("RevealSearch" . "search/search.js") ;; reveal.js 4.0 ones
notes ("RevealNotes" . "notes/notes.js") (cond
math ("RevealMath" . "math/math.js") ((eq p 'highlight) 'RevealHighlight)
zoom ("RevealZoom" . "zoom/zoom.js"))) ((eq p 'markdown) 'RevealMarkdown)
(plugin-info (seq-filter 'identity ((eq p 'search) 'RevealSearch)
(seq-map (lambda (p) ((eq p 'notes) 'RevealNotes)
(plist-get available-plugins p)) ((eq p 'math) 'RevealMath)
plugins)))) ((eq p 'zoom) 'RevealZoom)
(if (not (null plugin-info)) (t p)))
(cons plugins))
;; Plugin initialization script (available-plugins
(let ((root-path (file-name-as-directory (plist-get info :reveal-root)))) (append '((RevealHighlight . "%splugin/highlight/highlight.js")
(mapconcat (RevealMarkdown . "%splugin/markdown/markdown.js")
(lambda (p) (RevealSearch . "%splugin/search/search.js")
(format "<script src=\"%splugin/%s\"></script>\n" root-path (cdr p))) (RevealNotes . "%splugin/notes/notes.js")
plugin-info (RevealMath . "%splugin/math/math.js")
"")) (RevealZoom . "%splugin/zoom/zoom.js"))
;; Reveal initialization for plugins org-reveal-external-plugins))
(format "plugins: [%s]" (plugin-js (seq-filter 'identity ;; Filter out nil
(mapconcat #'car plugin-info ","))) (mapcar (lambda (p)
;; No available plugin info found. Perhaps wrong plugin (cdr (assoc p available-plugins)))
;; names are given plugins))))
(cons nil nil))) (if (not (null plugin-js))
;; No plugins, return empty string (cons
(cons nil nil)))) ;; Plugin initialization script
(let ((root-path (file-name-as-directory (plist-get info :reveal-root))))
(mapconcat
(lambda (p)
(format "<script src=\"%s\"></script>\n"
(format p root-path)))
plugin-js
""))
;; Reveal initialization for plugins
(format "plugins: [%s]"
(mapconcat 'symbol-name plugins ", ")))
;; No available plugin info found. Perhaps wrong plugin
;; names are given
(cons nil nil)))
;; No plugins, return empty string
(cons nil nil)))
(defun org-reveal-toc (depth info) (defun org-reveal-toc (depth info)
"Build a slide of table of contents." "Build a slide of table of contents."
(let ((toc (org-html-toc depth info))) (let ((toc (org-html-toc depth info)))