dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

ox-s5.el (15973B)


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