├── example ├── eg0.png ├── eg0.org └── eg0.html ├── README.org └── ox-twbs.el /example/eg0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsmining/ox-twbs/master/example/eg0.png -------------------------------------------------------------------------------- /example/eg0.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Example 2 | 3 | * Basics 4 | 5 | You can make words *bold*, /italic/, _underlined_, =code= and 6 | ~verbatim~, and, if you must, +strike-through+. Text in the code and 7 | verbatim string is not processed for Org mode specific syntax, it is 8 | exported verbatim. 9 | 10 | Some Greek like \alpha, \beta and \gamma. 11 | 12 | And here is an example link to [[http://orgmode.org/][org-mode]] homepage. 13 | 14 | * Headlines 15 | 16 | text 17 | 18 | ** Alpha 19 | 20 | text 21 | 22 | *** Bravo 23 | 24 | text 25 | 26 | * Lists 27 | 28 | - List Item 0 29 | - List Item 1 30 | - List Item 2 31 | - List Item 3 32 | 33 | * Blocks 34 | :PROPERTIES: 35 | :CUSTOM_ID: blocks 36 | :END: 37 | 38 | *** Normal blocks 39 | 40 | : Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do 41 | : eiusmod tempor incididunt ut labore et dolore magna aliqua. 42 | 43 | *** Quote blocks 44 | 45 | #+BEGIN_QUOTE 46 | Programs must be written for people to read, and only incidentally 47 | for machines to execute. 48 | 49 | /Abelson & Sussman, SICP, preface to the first edition/ 50 | #+END_QUOTE 51 | 52 | *** Source code blocks 53 | 54 | #+BEGIN_SRC elisp 55 | (defun yell (n) 56 | (if (= n 0) "hiya" 57 | (concat (yell (- n 1)) "!"))) 58 | 59 | (yell 5) ;; "hiya!!!!" 60 | #+END_SRC 61 | 62 | * Tables 63 | 64 | | Name | Price | Freshwater | Family | 65 | |-----------+-------+------------+---------------| 66 | | Stingray | 49.99 | no | Myliobatoidei | 67 | | Salmon | 23.99 | both | Salmonidae | 68 | | Barracuda | 12.99 | no | Sphyraena | 69 | 70 | * Sections 71 | 72 | ** Lord of the Rings 73 | 74 | My favorite scenes are (in this order) 75 | 76 | 1. The attack of the Rohirrim 77 | 2. Eowyn's fight with the witch king 78 | + this was already my favorite scene in the book 79 | + I really like Miranda Otto. 80 | 3. Peter Jackson being shot by Legolas 81 | - on DVD only 82 | He makes a really funny face when it happens. 83 | 84 | But in the end, no individual scenes matter but the film as a whole. 85 | 86 | Important actors in this film are: 87 | 88 | - Elijah Wood :: He plays Frodo 89 | - Sean Austin :: He plays Sam, Frodo's friend. I still remember 90 | him very well from his role as Mikey Walsh in The Goonies. 91 | 92 | * HTML 93 | 94 | Here is some markup: not bold text 95 | 96 | And a source block: 97 | 98 | #+BEGIN_SRC html 99 | pow! 100 | #+END_SRC 101 | 102 | #+BEGIN_HTML 103 | pow! 104 | 109 | #+END_HTML 110 | 111 | #+HTML: italics 112 | 113 | Finally inline: @@html:@@bold text@@html:@@ 114 | 115 | See org-mode manual [[http://orgmode.org/manual/Quoting-HTML-tags.html#Quoting-HTML-tags][Quoting HTML tags]]. 116 | 117 | * Footnote 118 | 119 | Here lies exact instructions [fn:a] for random [fn:b] noise. 120 | 121 | * Latex 122 | 123 | /Trace execution using example:/ 124 | 125 | Assume $\alpha=9$, $n=16$ and $x=0$. 126 | 127 | Stack grows until base case $2^{x}=n$, thenunwinds. 128 | 129 | * Custom ID 130 | 131 | [[#blocks][Link to custom id]] 132 | 133 | [fn:a] Except for USA, Mexico and Canada 134 | 135 | [fn:b] Further tournament types will be added 136 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * ox-twbs 2 | 3 | ** Summary 4 | 5 | Export [[http://orgmode.org/][org-mode]] docs as HTML compatible with [[http://getbootstrap.com/][Twitter Bootstrap]]. 6 | 7 | ** Example 8 | 9 | The following [[https://raw.githubusercontent.com/marsmining/ox-twbs/master/example/eg0.org][org source]] exports to [[http://clubctrl.com/org/prog/ox-twbs.html][this html]]. 10 | 11 | ** Description 12 | 13 | Output your org-mode docs with a simple, clean and modern look. 14 | 15 | This library implements a new HTML back-end for exporting org-mode 16 | docs as HTML compatible with Twitter Bootstrap. By default, HTML is 17 | exported with jQuery and Bootstrap resources included via [[http://osscdn.com][osscdn]]. 18 | 19 | Derived from the built-in HTML back-end of [[http://www.gnu.org/software/emacs/][GNU Emacs]], =ox-html.el=, 20 | which was written by Carsten Dominik and Jambunathan K. 21 | 22 | ** Install 23 | 24 | *** via package.el 25 | 26 | Latest builds available on [[http://melpa.org/#/][MELPA]] and for a bit more stability, use 27 | [[http://stable.melpa.org/#/][MELPA Stable]]. You can install ~ox-twbs~ using the following command: 28 | 29 | =M-x package-install [RET] ox-twbs [RET]= 30 | 31 | If the installation doesn't work try refreshing the package list: 32 | 33 | =M-x package-refresh-contents [RET]= 34 | 35 | *** Manual 36 | 37 | Put ~ox-twbs.el~ in your load path and require it. Alternatively, open 38 | =ox-twbs.el= in your buffer and run =package-install-file=, which will 39 | compile and install the package in your package folder. 40 | 41 | ** Usage 42 | 43 | Open or create an org file and run ~org-twbs-export-to-html~. This 44 | will create an HTML file in the same dir as your org file. 45 | 46 | You will more likely want more control and automation of the export 47 | process. You can read [[http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html][the org-mode docs]] on setting up your project. An 48 | example configuration might look like: 49 | 50 | #+BEGIN_SRC elisp 51 | (setq org-publish-project-alist 52 | '(("org-notes" 53 | :base-directory "~/org/" 54 | :publishing-directory "~/public_html/" 55 | :publishing-function org-twbs-publish-to-html 56 | :with-sub-superscript nil 57 | ))) 58 | #+END_SRC 59 | 60 | Using the above config, you can run: =org-publish-all= 61 | 62 | And you might create a function which publishes the current buffers 63 | file and opens it in your system's default browser. Here is what I 64 | use in my emacs config: 65 | 66 | #+BEGIN_SRC elisp 67 | (defun my-org-publish-buffer () 68 | (interactive) 69 | (save-buffer) 70 | (save-excursion (org-publish-current-file)) 71 | (let* ((proj (org-publish-get-project-from-filename buffer-file-name)) 72 | (proj-plist (cdr proj)) 73 | (rel (file-relative-name buffer-file-name 74 | (plist-get proj-plist :base-directory))) 75 | (dest (plist-get proj-plist :publishing-directory))) 76 | (browse-url (concat "file://" 77 | (file-name-as-directory (expand-file-name dest)) 78 | (file-name-sans-extension rel) 79 | ".html")))) 80 | #+END_SRC 81 | 82 | And bind the above command. I'm on OSX and happen to use ~CMD-\~. 83 | 84 | #+BEGIN_SRC elisp 85 | (add-hook 'org-mode-hook 86 | (lambda () 87 | (local-set-key (kbd "s-\\") 'my-org-publish-buffer))) 88 | #+END_SRC 89 | 90 | ** General Org Tips 91 | 92 | To specify a title of your org doc, other than the default: 93 | 94 | : #+TITLE: My Doc 95 | 96 | To quickly add blocks, check this [[http://orgmode.org/manual/Easy-Templates.html#Easy-Templates][easy template]] section of org manual. 97 | 98 | Be sure to understand how to [[http://orgmode.org/manual/Editing-source-code.html#Editing-source-code][edit source code blocks]]. 99 | 100 | Controlling depth of section numbers, table of contents and headings 101 | can be controlled per document via a declaration like the following: 102 | 103 | : #+OPTIONS: num:5 whn:2 toc:4 H:6 104 | 105 | And to set these via your publish configuration using the 106 | =org-publish-project-alist=, the options would be =:section-numbers=, 107 | =:headline-levels= and =:with-toc=. 108 | 109 | The above options are described in the [[http://orgmode.org/manual/Export-settings.html][export settings]] section of the 110 | orgmode manual. This component introduces a new setting =whn= for per 111 | document, and =:with-headline-numbers= for publish config, which 112 | controls the display of section numbers. To disable, set to =nil=, to 113 | enable, set to =t=, and to control depth of display, use a whole 114 | number. 115 | 116 | ** Note re: latest Org 8.3.x 117 | 118 | Traditionally preventing section numbers from display was 119 | accomplished via the =:section-numbers= option, however, in 8.3.x, 120 | setting it to =nil= now also eliminates the numbering from the parsed 121 | document, which then breaks toc and linking. Therefore, this module 122 | introduces a new option =:with-headline-numbers= which can be used for 123 | toggling display of section numbers. 124 | 125 | ** Customize 126 | 127 | The first place to look is in the definition of [[https://github.com/marsmining/ox-twbs/blob/d5ae9c3fb224d081d59d3686d619edf152523f09/ox-twbs.el#L987-L1002][org-twbs-head]]. You can 128 | set this on a per-file basis using ~#+HTML_HEAD:~, or for publication 129 | projects using the ~:html-head~ property. 130 | 131 | ** Todo 132 | 133 | Contributions are welcome! A list of potential fixes and enhancements 134 | follows: 135 | 136 | - Allow users to more easily add a Twitter Bootstrap theme 137 | - Document areas where this package deviates from org-mode manual on 138 | [[http://orgmode.org/manual/HTML-export.html#HTML-export][HTML export]] 139 | - Improve Affix.js plugin scroll-spying/following 140 | - Ensure this package works well with org's sitemap function 141 | -------------------------------------------------------------------------------- /example/eg0.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 172 | 184 | 185 | 186 | 187 |
188 |

Example

189 | 190 |
191 |

1 Basics

192 |
193 |

194 | You can make words bold, italic, underlined, code and 195 | verbatim, and, if you must, strike-through. Text in the code and 196 | verbatim string is not processed for Org mode specific syntax, it is 197 | exported verbatim. 198 |

199 | 200 |

201 | Some Greek like α, β and γ. 202 |

203 | 204 |

205 | And here is an example link to org-mode homepage. 206 |

207 |
208 |
209 | 210 |
211 |

2 Headlines

212 |
213 |

214 | text 215 |

216 |
217 | 218 |
219 |

2.1 Alpha

220 |
221 |

222 | text 223 |

224 |
225 | 226 |
227 |

2.1.1 Bravo

228 |
229 |

230 | text 231 |

232 |
233 |
234 |
235 |
236 | 237 |
238 |

3 Lists

239 |
240 |
    241 |
  • List Item 0 242 |
  • 243 |
  • List Item 1 244 |
  • 245 |
  • List Item 2 246 |
  • 247 |
  • List Item 3 248 |
  • 249 |
250 |
251 |
252 | 253 |
254 |

4 Blocks

255 |
256 |
257 | 258 |
259 |

4.0.1 Normal blocks

260 |
261 |
262 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
263 | eiusmod tempor incididunt ut labore et dolore magna aliqua.
264 | 
265 |
266 |
267 | 268 |
269 |

4.0.2 Quote blocks

270 |
271 |
272 |

273 | Programs must be written for people to read, and only incidentally 274 | for machines to execute. 275 |

276 | 277 |

278 | Abelson & Sussman, SICP, preface to the first edition 279 |

280 |
281 |
282 |
283 | 284 |
285 |

4.0.3 Source code blocks

286 |
287 |
288 | 289 |
(defun yell (n)
290 |   (if (= n 0) "hiya"
291 |     (concat (yell (- n 1)) "!")))
292 | 
293 | (yell 5) ;; "hiya!!!!"
294 | 
295 |
296 |
297 |
298 |
299 | 300 |
301 |

5 Tables

302 |
303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 |
NamePriceFreshwaterFamily
Stingray49.99noMyliobatoidei
Salmon23.99bothSalmonidae
Barracuda12.99noSphyraena
346 |
347 |
348 | 349 |
350 |

6 Sections

351 |
352 |
353 |

6.1 Lord of the Rings

354 |
355 |

356 | My favorite scenes are (in this order) 357 |

358 | 359 |
    360 |
  1. The attack of the Rohirrim 361 |
  2. 362 |
  3. Eowyn's fight with the witch king 363 |
      364 |
    • this was already my favorite scene in the book 365 |
    • 366 |
    • I really like Miranda Otto. 367 |
    • 368 |
    369 |
  4. 370 |
  5. Peter Jackson being shot by Legolas 371 |
      372 |
    • on DVD only 373 |
    • 374 |
    375 |

    376 | He makes a really funny face when it happens. 377 |

    378 |
  6. 379 |
380 | 381 |

382 | But in the end, no individual scenes matter but the film as a whole. 383 |

384 | 385 |

386 | Important actors in this film are: 387 |

388 | 389 |
390 |
Elijah Wood
He plays Frodo 391 |
392 |
Sean Austin
He plays Sam, Frodo's friend. I still remember 393 | him very well from his role as Mikey Walsh in The Goonies. 394 |
395 |
396 |
397 |
398 |
399 | 400 |
401 |

7 HTML

402 |
403 |

404 | Here is some markup: <b>not bold text</b> 405 |

406 | 407 |

408 | And a source block: 409 |

410 | 411 |
412 | 413 |
<b>pow!</b>
414 | 
415 |
416 | 417 | pow! 418 |
    419 |
  • bing 420 |
  • bam 421 |
  • boom 422 |
423 | 424 | italics 425 | 426 |

427 | Finally inline: bold text 428 |

429 | 430 |

431 | See org-mode manual Quoting HTML tags. 432 |

433 |
434 |
435 | 436 |
437 |

8 Footnote

438 |
439 |

440 | Here lies exact instructions 1 for random 2 noise. 441 |

442 |
443 |
444 | 445 |
446 |

9 Latex

447 |
448 |

449 | Trace execution using example: 450 |

451 | 452 |

453 | Assume \(\alpha=9\), \(n=16\) and \(x=0\). 454 |

455 | 456 |

457 | Stack grows until base case \(2^{x}=n\), thenunwinds. 458 |

459 |
460 |
461 | 462 |
463 |

10 Custom ID

464 |
465 |

466 | Link to custom id 467 |

468 |
469 |
470 |
471 |

Footnotes:

472 |
473 | 474 |
1

475 | Except for USA, Mexico and Canada 476 |

477 | 478 |
2

479 | Further tournament types will be added 480 |

481 | 482 | 483 |
484 |
508 |
509 | 515 | 516 | 517 | -------------------------------------------------------------------------------- /ox-twbs.el: -------------------------------------------------------------------------------- 1 | ;;; ox-twbs.el --- Bootstrap compatible HTML Back-End for Org 2 | 3 | ;; Copyright (C) 2011-2014 Free Software Foundation, Inc. 4 | ;; Copyright (C) 2016 Brandon van Beekum 5 | 6 | ;; Author: Carsten Dominik 7 | ;; Jambunathan K 8 | ;; Brandon van Beekum 9 | ;; URL: https://github.com/marsmining/ox-twbs 10 | ;; Keywords: org, html, publish, twitter, bootstrap 11 | ;; Version: 1.1.4 12 | 13 | ;; This file is not part of GNU Emacs. 14 | 15 | ;;; Commentary: 16 | 17 | ;; This library implements an HTML back-end for exporting org-mode 18 | ;; docs as HTML compatible with Twitter Bootstrap. Use the function 19 | ;; `org-twbs-export-to-html` to export an org file. For publishing 20 | ;; use the function `org-twbs-publish-to-html`. 21 | 22 | ;;; License: 23 | 24 | ;; This program is free software; you can redistribute it and/or 25 | ;; modify it under the terms of the GNU General Public License 26 | ;; as published by the Free Software Foundation; either version 3 27 | ;; of the License, or (at your option) any later version. 28 | ;; 29 | ;; This program is distributed in the hope that it will be useful, 30 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | ;; GNU General Public License for more details. 33 | ;; 34 | ;; You should have received a copy of the GNU General Public License 35 | ;; along with GNU Emacs; see the file COPYING. If not, write to the 36 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 37 | ;; Boston, MA 02110-1301, USA. 38 | 39 | ;;; Code: 40 | 41 | ;;; Dependencies 42 | 43 | (require 'ox-publish) 44 | (require 'format-spec) 45 | (eval-when-compile (require 'cl) (require 'table nil 'noerror)) 46 | 47 | 48 | ;;; Function Declarations 49 | 50 | (declare-function org-id-find-id-file "org-id" (id)) 51 | (declare-function htmlize-region "ext:htmlize" (beg end)) 52 | (declare-function org-pop-to-buffer-same-window 53 | "org-compat" (&optional buffer-or-name norecord label)) 54 | (declare-function mm-url-decode-entities "mm-url" ()) 55 | 56 | ;;; Define Back-End 57 | 58 | (org-export-define-backend 'twbs 59 | '((bold . org-twbs-bold) 60 | (center-block . org-twbs-center-block) 61 | (clock . org-twbs-clock) 62 | (code . org-twbs-code) 63 | (drawer . org-twbs-drawer) 64 | (dynamic-block . org-twbs-dynamic-block) 65 | (entity . org-twbs-entity) 66 | (example-block . org-twbs-example-block) 67 | (export-block . org-twbs-export-block) 68 | (export-snippet . org-twbs-export-snippet) 69 | (fixed-width . org-twbs-fixed-width) 70 | (footnote-definition . org-twbs-footnote-definition) 71 | (footnote-reference . org-twbs-footnote-reference) 72 | (headline . org-twbs-headline) 73 | (horizontal-rule . org-twbs-horizontal-rule) 74 | (inline-src-block . org-twbs-inline-src-block) 75 | (inlinetask . org-twbs-inlinetask) 76 | (inner-template . org-twbs-inner-template) 77 | (italic . org-twbs-italic) 78 | (item . org-twbs-item) 79 | (keyword . org-twbs-keyword) 80 | (latex-environment . org-twbs-latex-environment) 81 | (latex-fragment . org-twbs-latex-fragment) 82 | (line-break . org-twbs-line-break) 83 | (link . org-twbs-link) 84 | (paragraph . org-twbs-paragraph) 85 | (plain-list . org-twbs-plain-list) 86 | (plain-text . org-twbs-plain-text) 87 | (planning . org-twbs-planning) 88 | (property-drawer . org-twbs-property-drawer) 89 | (quote-block . org-twbs-quote-block) 90 | (quote-section . org-twbs-quote-section) 91 | (radio-target . org-twbs-radio-target) 92 | (section . org-twbs-section) 93 | (special-block . org-twbs-special-block) 94 | (src-block . org-twbs-src-block) 95 | (statistics-cookie . org-twbs-statistics-cookie) 96 | (strike-through . org-twbs-strike-through) 97 | (subscript . org-twbs-subscript) 98 | (superscript . org-twbs-superscript) 99 | (table . org-twbs-table) 100 | (table-cell . org-twbs-table-cell) 101 | (table-row . org-twbs-table-row) 102 | (target . org-twbs-target) 103 | (template . org-twbs-template) 104 | (timestamp . org-twbs-timestamp) 105 | (underline . org-twbs-underline) 106 | (verbatim . org-twbs-verbatim) 107 | (verse-block . org-twbs-verse-block)) 108 | :filters-alist '((:filter-final-output . org-twbs-final-function)) 109 | :menu-entry 110 | '(?w "Export to TWBS HTML" 111 | ((?H "As HTML buffer" org-twbs-export-as-html) 112 | (?h "As HTML file" org-twbs-export-to-html) 113 | (?o "As HTML file and open" 114 | (lambda (a s v b) 115 | (if a (org-twbs-export-to-html t s v b) 116 | (org-open-file (org-twbs-export-to-html nil s v b))))))) 117 | :options-alist 118 | '((:html-extension nil nil org-twbs-extension) 119 | (:html-link-org-files-as-html nil nil org-twbs-link-org-files-as-html) 120 | (:html-container "HTML_CONTAINER" nil org-twbs-container-element) 121 | (:html-link-use-abs-url nil "html-link-use-abs-url" org-twbs-link-use-abs-url) 122 | (:html-link-home "HTML_LINK_HOME" nil org-twbs-link-home) 123 | (:html-link-up "HTML_LINK_UP" nil org-twbs-link-up) 124 | (:html-mathjax "HTML_MATHJAX" nil "" space) 125 | (:html-mathjax-options nil nil org-twbs-mathjax-options) 126 | (:html-mathjax-template nil nil org-twbs-mathjax-template) 127 | (:html-postamble nil "html-postamble" org-twbs-postamble) 128 | (:html-preamble nil "html-preamble" org-twbs-preamble) 129 | (:html-head "HTML_HEAD" nil org-twbs-head newline) 130 | (:html-head-extra "HTML_HEAD_EXTRA" nil org-twbs-head-extra newline) 131 | (:html-head-include-default-style nil "html-style" org-twbs-head-include-default-style) 132 | (:html-head-include-scripts nil "html-scripts" org-twbs-head-include-scripts) 133 | (:html-table-attributes nil nil org-twbs-table-default-attributes) 134 | (:html-table-row-tags nil nil org-twbs-table-row-tags) 135 | (:html-inline-images nil nil org-twbs-inline-images) 136 | (:html-inline-image-rules nil nil org-twbs-inline-image-rules) 137 | ;; Redefine regular options. 138 | (:creator "CREATOR" nil org-twbs-creator-string) 139 | (:with-latex nil "tex" org-twbs-with-latex) 140 | (:with-toc nil nil 2) 141 | (:with-creator nil nil t) 142 | (:section-numbers nil nil t) 143 | ;; Extra Options 144 | (:gid nil "gid" nil) 145 | (:with-headline-numbers nil "whn" t) 146 | (:with-toc-todo-keywords nil "toc-todo" nil) 147 | (:with-toc-tags nil "toc-tag" nil) 148 | ;; Retrieve LaTeX header for fragments. 149 | (:latex-header "LATEX_HEADER" nil nil newline))) 150 | 151 | 152 | ;;; Internal Variables 153 | 154 | (defvar org-twbs-format-table-no-css) 155 | (defvar htmlize-buffer-places) ; from htmlize.el 156 | 157 | (defvar org-twbs--pre/postamble-class "" 158 | "CSS class used for pre/postamble") 159 | 160 | (defconst org-twbs-special-string-regexps 161 | '(("\\\\-" . "­") ; shy 162 | ("---\\([^-]\\)" . "—\\1") ; mdash 163 | ("--\\([^-]\\)" . "–\\1") ; ndash 164 | ("\\.\\.\\." . "…")) ; hellip 165 | "Regular expressions for special string conversion.") 166 | 167 | (defconst org-twbs-scripts 168 | "" 179 | "Basic JavaScript that is needed by HTML files produced by Org mode.") 180 | 181 | (defconst org-twbs-style-default 182 | "" 349 | "The default style specification for exported HTML files. 350 | You can use `org-twbs-head' and `org-twbs-head-extra' to add to 351 | this style. If you don't want to include this default style, 352 | customize `org-twbs-head-include-default-style'.") 353 | 354 | 355 | ;;; User Configuration Variables 356 | 357 | (defgroup org-export-twbs nil 358 | "Options for exporting Org mode files to HTML compatible with Twitter's Bootstrap." 359 | :tag "Org Export TWBS" 360 | :group 'org-export) 361 | 362 | ;;;; Bold, etc. 363 | 364 | (defcustom org-twbs-text-markup-alist 365 | '((bold . "%s") 366 | (code . "%s") 367 | (italic . "%s") 368 | (strike-through . "%s") 369 | (underline . "%s") 370 | (verbatim . "%s")) 371 | "Alist of HTML expressions to convert text markup. 372 | 373 | The key must be a symbol among `bold', `code', `italic', 374 | `strike-through', `underline' and `verbatim'. The value is 375 | a formatting string to wrap fontified text with. 376 | 377 | If no association can be found for a given markup, text will be 378 | returned as-is." 379 | :group 'org-export-twbs 380 | :version "24.4" 381 | :package-version '(Org . "8.0") 382 | :type '(alist :key-type (symbol :tag "Markup type") 383 | :value-type (string :tag "Format string")) 384 | :options '(bold code italic strike-through underline verbatim)) 385 | 386 | (defcustom org-twbs-indent nil 387 | "Non-nil means to indent the generated HTML. 388 | Warning: non-nil may break indentation of source code blocks." 389 | :group 'org-export-twbs 390 | :version "24.4" 391 | :package-version '(Org . "8.0") 392 | :type 'boolean) 393 | 394 | (defcustom org-twbs-use-unicode-chars nil 395 | "Non-nil means to use unicode characters instead of HTML entities." 396 | :group 'org-export-twbs 397 | :version "24.4" 398 | :package-version '(Org . "8.0") 399 | :type 'boolean) 400 | 401 | ;;;; Drawers 402 | 403 | (defcustom org-twbs-format-drawer-function 404 | (lambda (name contents) contents) 405 | "Function called to format a drawer in HTML code. 406 | 407 | The function must accept two parameters: 408 | NAME the drawer name, like \"LOGBOOK\" 409 | CONTENTS the contents of the drawer. 410 | 411 | The function should return the string to be exported. 412 | 413 | For example, the variable could be set to the following function 414 | in order to mimic default behaviour: 415 | 416 | The default value simply returns the value of CONTENTS." 417 | :group 'org-export-twbs 418 | :version "24.4" 419 | :package-version '(Org . "8.0") 420 | :type 'function) 421 | 422 | ;;;; Footnotes 423 | 424 | (defcustom org-twbs-footnotes-section "
425 |

%s:

426 |
427 | %s 428 |
429 |
" 430 | "Format for the footnotes section. 431 | Should contain a two instances of %s. The first will be replaced with the 432 | language-specific word for \"Footnotes\", the second one will be replaced 433 | by the footnotes themselves." 434 | :group 'org-export-twbs 435 | :type 'string) 436 | 437 | (defcustom org-twbs-footnote-format "%s" 438 | "The format for the footnote reference. 439 | %s will be replaced by the footnote reference itself." 440 | :group 'org-export-twbs 441 | :type 'string) 442 | 443 | (defcustom org-twbs-footnote-separator ", " 444 | "Text used to separate footnotes." 445 | :group 'org-export-twbs 446 | :type 'string) 447 | 448 | ;;;; Headline 449 | 450 | (defcustom org-twbs-toplevel-hlevel 2 451 | "The level for level 1 headings in HTML export. 452 | This is also important for the classes that will be wrapped around headlines 453 | and outline structure. If this variable is 1, the top-level headlines will 454 | be

, and the corresponding classes will be outline-1, section-number-1, 455 | and outline-text-1. If this is 2, all of these will get a 2 instead. 456 | The default for this variable is 2, because we use

for formatting the 457 | document title." 458 | :group 'org-export-twbs 459 | :type 'integer) 460 | 461 | (defcustom org-twbs-format-headline-function 'ignore 462 | "Function to format headline text. 463 | 464 | This function will be called with 5 arguments: 465 | TODO the todo keyword (string or nil). 466 | TODO-TYPE the type of todo (symbol: `todo', `done', nil) 467 | PRIORITY the priority of the headline (integer or nil) 468 | TEXT the main headline text (string). 469 | TAGS the tags (string or nil). 470 | 471 | The function result will be used in the section format string." 472 | :group 'org-export-twbs 473 | :version "24.4" 474 | :package-version '(Org . "8.0") 475 | :type 'function) 476 | 477 | ;;;; HTML-specific 478 | 479 | (defcustom org-twbs-allow-name-attribute-in-anchors t 480 | "When nil, do not set \"name\" attribute in anchors. 481 | By default, anchors are formatted with both \"id\" and \"name\" 482 | attributes, when appropriate." 483 | :group 'org-export-twbs 484 | :version "24.4" 485 | :package-version '(Org . "8.0") 486 | :type 'boolean) 487 | 488 | ;;;; Inlinetasks 489 | 490 | (defcustom org-twbs-format-inlinetask-function 'ignore 491 | "Function called to format an inlinetask in HTML code. 492 | 493 | The function must accept six parameters: 494 | TODO the todo keyword, as a string 495 | TODO-TYPE the todo type, a symbol among `todo', `done' and nil. 496 | PRIORITY the inlinetask priority, as a string 497 | NAME the inlinetask name, as a string. 498 | TAGS the inlinetask tags, as a list of strings. 499 | CONTENTS the contents of the inlinetask, as a string. 500 | 501 | The function should return the string to be exported." 502 | :group 'org-export-twbs 503 | :version "24.4" 504 | :package-version '(Org . "8.0") 505 | :type 'function) 506 | 507 | ;;;; LaTeX 508 | 509 | (defcustom org-twbs-with-latex org-export-with-latex 510 | "Non-nil means process LaTeX math snippets. 511 | 512 | When set, the exporter will process LaTeX environments and 513 | fragments. 514 | 515 | This option can also be set with the +OPTIONS line, 516 | e.g. \"tex:mathjax\". Allowed values are: 517 | 518 | nil Ignore math snippets. 519 | `verbatim' Keep everything in verbatim 520 | `dvipng' Process the LaTeX fragments to images. This will also 521 | include processing of non-math environments. 522 | `imagemagick' Convert the LaTeX fragments to pdf files and use 523 | imagemagick to convert pdf files to png files. 524 | `mathjax' Do MathJax preprocessing and arrange for MathJax.js to 525 | be loaded. 526 | t Synonym for `mathjax'." 527 | :group 'org-export-twbs 528 | :version "24.4" 529 | :package-version '(Org . "8.0") 530 | :type '(choice 531 | (const :tag "Do not process math in any way" nil) 532 | (const :tag "Use dvipng to make images" dvipng) 533 | (const :tag "Use imagemagick to make images" imagemagick) 534 | (const :tag "Use MathJax to display math" mathjax) 535 | (const :tag "Leave math verbatim" verbatim))) 536 | 537 | ;;;; Links :: Generic 538 | 539 | (defcustom org-twbs-link-org-files-as-html t 540 | "Non-nil means make file links to `file.org' point to `file.html'. 541 | When `org-mode' is exporting an `org-mode' file to HTML, links to 542 | non-html files are directly put into a href tag in HTML. 543 | However, links to other Org-mode files (recognized by the 544 | extension `.org.) should become links to the corresponding html 545 | file, assuming that the linked `org-mode' file will also be 546 | converted to HTML. 547 | When nil, the links still point to the plain `.org' file." 548 | :group 'org-export-twbs 549 | :type 'boolean) 550 | 551 | ;;;; Links :: Inline images 552 | 553 | (defcustom org-twbs-inline-images t 554 | "Non-nil means inline images into exported HTML pages. 555 | This is done using an tag. When nil, an anchor with href is used to 556 | link to the image." 557 | :group 'org-export-twbs 558 | :version "24.4" 559 | :package-version '(Org . "8.1") 560 | :type 'boolean) 561 | 562 | (defcustom org-twbs-inline-image-rules 563 | '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'") 564 | ("http" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'") 565 | ("https" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")) 566 | "Rules characterizing image files that can be inlined into HTML. 567 | A rule consists in an association whose key is the type of link 568 | to consider, and value is a regexp that will be matched against 569 | link's path." 570 | :group 'org-export-twbs 571 | :version "24.4" 572 | :package-version '(Org . "8.0") 573 | :type '(alist :key-type (string :tag "Type") 574 | :value-type (regexp :tag "Path"))) 575 | 576 | ;;;; Plain Text 577 | 578 | (defcustom org-twbs-protect-char-alist 579 | '(("&" . "&") 580 | ("<" . "<") 581 | (">" . ">")) 582 | "Alist of characters to be converted by `org-twbs-protect'." 583 | :group 'org-export-twbs 584 | :type '(repeat (cons (string :tag "Character") 585 | (string :tag "HTML equivalent")))) 586 | 587 | ;;;; Src Block 588 | 589 | (defcustom org-twbs-htmlize-output-type 'inline-css 590 | "Output type to be used by htmlize when formatting code snippets. 591 | Choices are `css', to export the CSS selectors only, or `inline-css', to 592 | export the CSS attribute values inline in the HTML. We use as default 593 | `inline-css', in order to make the resulting HTML self-containing. 594 | 595 | However, this will fail when using Emacs in batch mode for export, because 596 | then no rich font definitions are in place. It will also not be good if 597 | people with different Emacs setup contribute HTML files to a website, 598 | because the fonts will represent the individual setups. In these cases, 599 | it is much better to let Org/Htmlize assign classes only, and to use 600 | a style file to define the look of these classes. 601 | To get a start for your css file, start Emacs session and make sure that 602 | all the faces you are interested in are defined, for example by loading files 603 | in all modes you want. Then, use the command 604 | \\[org-twbs-htmlize-generate-css] to extract class definitions." 605 | :group 'org-export-twbs 606 | :type '(choice (const css) (const inline-css))) 607 | 608 | (defcustom org-twbs-htmlize-font-prefix "org-" 609 | "The prefix for CSS class names for htmlize font specifications." 610 | :group 'org-export-twbs 611 | :type 'string) 612 | 613 | ;;;; Table 614 | 615 | (defcustom org-twbs-table-default-attributes 616 | '(:class "table table-striped table-bordered table-hover table-condensed") 617 | "Default attributes and values which will be used in table tags. 618 | This is a plist where attributes are symbols, starting with 619 | colons, and values are strings." 620 | :group 'org-export-twbs 621 | :version "24.4" 622 | :package-version '(Org . "8.0") 623 | :type '(plist :key-type (symbol :tag "Property") 624 | :value-type (string :tag "Value"))) 625 | 626 | (defcustom org-twbs-table-header-tags '("" . "") 627 | "The opening tag for table header fields. 628 | This is customizable so that alignment options can be specified. 629 | The first %s will be filled with the scope of the field, either row or col. 630 | The second %s will be replaced by a style entry to align the field. 631 | See also the variable `org-twbs-table-use-header-tags-for-first-column'. 632 | See also the variable `org-twbs-table-align-individual-fields'." 633 | :group 'org-export-twbs 634 | :type '(cons (string :tag "Opening tag") (string :tag "Closing tag"))) 635 | 636 | (defcustom org-twbs-table-data-tags '("" . "") 637 | "The opening tag for table data fields. 638 | This is customizable so that alignment options can be specified. 639 | The first %s will be filled with the scope of the field, either row or col. 640 | The second %s will be replaced by a style entry to align the field. 641 | See also the variable `org-twbs-table-align-individual-fields'." 642 | :group 'org-export-twbs 643 | :type '(cons (string :tag "Opening tag") (string :tag "Closing tag"))) 644 | 645 | (defcustom org-twbs-table-row-tags '("" . "") 646 | "The opening and ending tags for table rows. 647 | This is customizable so that alignment options can be specified. 648 | Instead of strings, these can be Lisp forms that will be 649 | evaluated for each row in order to construct the table row tags. 650 | 651 | During evaluation, these variables will be dynamically bound so that 652 | you can reuse them: 653 | 654 | `row-number': row number (0 is the first row) 655 | `rowgroup-number': group number of current row 656 | `start-rowgroup-p': non-nil means the row starts a group 657 | `end-rowgroup-p': non-nil means the row ends a group 658 | `top-row-p': non-nil means this is the top row 659 | `bottom-row-p': non-nil means this is the bottom row 660 | 661 | For example: 662 | 663 | \(setq org-twbs-table-row-tags 664 | (cons '(cond (top-row-p \"\") 665 | (bottom-row-p \"\") 666 | (t (if (= (mod row-number 2) 1) 667 | \"\" 668 | \"\"))) 669 | \"\")) 670 | 671 | will use the \"tr-top\" and \"tr-bottom\" classes for the top row 672 | and the bottom row, and otherwise alternate between \"tr-odd\" and 673 | \"tr-even\" for odd and even rows." 674 | :group 'org-export-twbs 675 | :type '(cons 676 | (choice :tag "Opening tag" 677 | (string :tag "Specify") 678 | (sexp)) 679 | (choice :tag "Closing tag" 680 | (string :tag "Specify") 681 | (sexp)))) 682 | 683 | (defcustom org-twbs-table-align-individual-fields t 684 | "Non-nil means attach style attributes for alignment to each table field. 685 | When nil, alignment will only be specified in the column tags, but this 686 | is ignored by some browsers (like Firefox, Safari). Opera does it right 687 | though." 688 | :group 'org-export-twbs 689 | :type 'boolean) 690 | 691 | (defcustom org-twbs-table-use-header-tags-for-first-column nil 692 | "Non-nil means format column one in tables with header tags. 693 | When nil, also column one will use data tags." 694 | :group 'org-export-twbs 695 | :type 'boolean) 696 | 697 | (defcustom org-twbs-table-caption-above t 698 | "When non-nil, place caption string at the beginning of the table. 699 | Otherwise, place it near the end." 700 | :group 'org-export-twbs 701 | :type 'boolean) 702 | 703 | ;;;; Tags 704 | 705 | (defcustom org-twbs-tag-class "badge" 706 | "Class name for tags." 707 | :group 'org-export-twbs 708 | :type 'string) 709 | 710 | (defcustom org-twbs-tag-class-prefix "" 711 | "Prefix to class names for TODO keywords. 712 | Each tag gets a class given by the tag itself, with this prefix. 713 | The default prefix is empty because it is nice to just use the keyword 714 | as a class name. But if you get into conflicts with other, existing 715 | CSS classes, then this prefix can be very useful." 716 | :group 'org-export-twbs 717 | :type 'string) 718 | 719 | ;;;; Template :: Generic 720 | 721 | (defcustom org-twbs-extension "html" 722 | "The extension for exported HTML files." 723 | :group 'org-export-twbs 724 | :type 'string) 725 | 726 | (defcustom org-twbs-coding-system 'utf-8 727 | "Coding system for HTML export. 728 | Use utf-8 as the default value." 729 | :group 'org-export-html 730 | :version "24.4" 731 | :package-version '(Org . "8.0") 732 | :type 'coding-system) 733 | 734 | (defcustom org-twbs-container-element "div" 735 | "HTML element to use for wrapping top level sections. 736 | Can be set with the in-buffer HTML_CONTAINER property or for 737 | publishing, with :html-container." 738 | :group 'org-export-twbs 739 | :version "24.4" 740 | :package-version '(Org . "8.0") 741 | :type 'string) 742 | 743 | (defcustom org-twbs-divs 744 | '((preamble "div" "preamble") 745 | (content "div" "content" "container") 746 | (postamble "footer" "postamble")) 747 | "Alist of the three section elements for HTML export. 748 | The car of each entry is one of 'preamble, 'content or 'postamble. 749 | The cdrs of each entry are the ELEMENT_TYPE and ID for each 750 | section of the exported document. 751 | 752 | Note that changing the default will prevent you from using 753 | org-info.js for your website." 754 | :group 'org-export-twbs 755 | :version "24.4" 756 | :package-version '(Org . "8.0") 757 | :type '(list :greedy t 758 | (list :tag "Preamble" 759 | (const :format "" preamble) 760 | (string :tag "element") (string :tag " id")) 761 | (list :tag "Content" 762 | (const :format "" content) 763 | (string :tag "element") (string :tag " id")) 764 | (list :tag "Postamble" (const :format "" postamble) 765 | (string :tag " id") (string :tag "element")))) 766 | 767 | (defcustom org-twbs-metadata-timestamp-format "%Y-%m-%d %a %H:%M" 768 | "Format used for timestamps in preamble, postamble and metadata. 769 | See `format-time-string' for more information on its components." 770 | :group 'org-export-twbs 771 | :version "24.4" 772 | :package-version '(Org . "8.0") 773 | :type 'string) 774 | 775 | ;;;; Template :: Mathjax 776 | 777 | (defcustom org-twbs-mathjax-options 778 | '((path "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_SVG") 779 | (scale "100") 780 | (dscale "100") 781 | (align "center") 782 | (indent "2em") 783 | (messages "none")) 784 | "Options for MathJax setup. 785 | 786 | path The path where to find MathJax 787 | scale Scaling for the HTML-CSS backend, omit percentage symbol 788 | dscale Scaling for displayed math, omit percentage symbol 789 | align How to align display math: left, center, or right 790 | indent If align is not center, how far from the left/right side? 791 | messages Should display messages in corner? 792 | 793 | You can also customize this for each buffer, using something like 794 | 795 | #+HTML_MATHJAX: scale:110 dscale:190 align:left messages:none" 796 | :group 'org-export-twbs 797 | :type '(list :greedy t 798 | (list :tag "path (the path from where to load MathJax.js)" 799 | (const :format " " path) (string)) 800 | (list :tag "scale (scaling for math)" 801 | (const :format " " scale) (string)) 802 | (list :tag "dscale (scaling for the displayed math)" 803 | (const :format " " scale) (string)) 804 | (list :tag "align (alignment of displayed equations)" 805 | (const :format " " align) (string)) 806 | (list :tag "indent (indentation with left or right alignment)" 807 | (const :format " " indent) (string)) 808 | (list :tag "messages (show pocessing messages in corner)" 809 | (const :format " " messages) 810 | (choice (const "none") 811 | (const "simple"))))) 812 | 813 | (defcustom org-twbs-mathjax-template 814 | " 815 | 839 | " 840 | "The MathJax setup for HTML files." 841 | :group 'org-export-twbs 842 | :type 'string) 843 | 844 | ;;;; Template :: Postamble 845 | 846 | (defcustom org-twbs-postamble 'auto 847 | "Non-nil means insert a postamble in HTML export. 848 | 849 | When set to 'auto, check against the 850 | `org-export-with-author/email/creator/date' variables to set the 851 | content of the postamble. When set to a string, use this string 852 | as the postamble. When t, insert a string as defined by the 853 | formatting string in `org-twbs-postamble-format'. 854 | 855 | When set to a function, apply this function and insert the 856 | returned string. The function takes the property list of export 857 | options as its only argument. 858 | 859 | Setting :html-postamble in publishing projects will take 860 | precedence over this variable." 861 | :group 'org-export-twbs 862 | :type '(choice (const :tag "No postamble" nil) 863 | (const :tag "Auto postamble" auto) 864 | (const :tag "Default formatting string" t) 865 | (string :tag "Custom formatting string") 866 | (function :tag "Function (must return a string)"))) 867 | 868 | (defcustom org-twbs-postamble-format 869 | '(("en" "

Author: %a (%e)

870 |

Date: %d

871 |

%c

")) 872 | "Alist of languages and format strings for the HTML postamble. 873 | 874 | The first element of each list is the language code, as used for 875 | the LANGUAGE keyword. See `org-export-default-language'. 876 | 877 | The second element of each list is a format string to format the 878 | postamble itself. This format string can contain these elements: 879 | 880 | %t stands for the title. 881 | %a stands for the author's name. 882 | %e stands for the author's email. 883 | %d stands for the date. 884 | %c will be replaced by `org-twbs-creator-string'. 885 | %v will be replaced by `org-twbs-validation-link'. 886 | %T will be replaced by the export time. 887 | %C will be replaced by the last modification time. 888 | 889 | If you need to use a \"%\" character, you need to escape it 890 | like that: \"%%\"." 891 | :group 'org-export-twbs 892 | :type '(repeat 893 | (list (string :tag "Language") 894 | (string :tag "Format string")))) 895 | 896 | (defcustom org-twbs-validation-link 897 | "Validate" 898 | "Link to HTML validation service." 899 | :group 'org-export-twbs 900 | :type 'string) 901 | 902 | (defcustom org-twbs-creator-string 903 | (format "Emacs %s (Org-mode %s)" 904 | emacs-version 905 | (if (fboundp 'org-version) (org-version) "unknown version")) 906 | "Information about the creator of the HTML document. 907 | This option can also be set on with the CREATOR keyword." 908 | :group 'org-export-twbs 909 | :version "24.4" 910 | :package-version '(Org . "8.0") 911 | :type '(string :tag "Creator string")) 912 | 913 | ;;;; Template :: Preamble 914 | 915 | (defcustom org-twbs-preamble t 916 | "Non-nil means insert a preamble in HTML export. 917 | 918 | When t, insert a string as defined by the formatting string in 919 | `org-twbs-preamble-format'. When set to a string, use this 920 | formatting string instead (see `org-twbs-postamble-format' for an 921 | example of such a formatting string). 922 | 923 | When set to a function, apply this function and insert the 924 | returned string. The function takes the property list of export 925 | options as its only argument. 926 | 927 | Setting :html-preamble in publishing projects will take 928 | precedence over this variable." 929 | :group 'org-export-twbs 930 | :type '(choice (const :tag "No preamble" nil) 931 | (const :tag "Default preamble" t) 932 | (string :tag "Custom formatting string") 933 | (function :tag "Function (must return a string)"))) 934 | 935 | (defcustom org-twbs-preamble-format '(("en" "")) 936 | "Alist of languages and format strings for the HTML preamble. 937 | 938 | The first element of each list is the language code, as used for 939 | the LANGUAGE keyword. See `org-export-default-language'. 940 | 941 | The second element of each list is a format string to format the 942 | preamble itself. This format string can contain these elements: 943 | 944 | %t stands for the title. 945 | %a stands for the author's name. 946 | %e stands for the author's email. 947 | %d stands for the date. 948 | %c will be replaced by `org-twbs-creator-string'. 949 | %v will be replaced by `org-twbs-validation-link'. 950 | %T will be replaced by the export time. 951 | %C will be replaced by the last modification time. 952 | 953 | If you need to use a \"%\" character, you need to escape it 954 | like that: \"%%\". 955 | 956 | See the default value of `org-twbs-postamble-format' for an 957 | example." 958 | :group 'org-export-twbs 959 | :type '(repeat 960 | (list (string :tag "Language") 961 | (string :tag "Format string")))) 962 | 963 | (defcustom org-twbs-link-up "" 964 | "Where should the \"UP\" link of exported HTML pages lead?" 965 | :group 'org-export-twbs 966 | :type '(string :tag "File or URL")) 967 | 968 | (defcustom org-twbs-link-home "" 969 | "Where should the \"HOME\" link of exported HTML pages lead?" 970 | :group 'org-export-twbs 971 | :type '(string :tag "File or URL")) 972 | 973 | (defcustom org-twbs-link-use-abs-url nil 974 | "Should we prepend relative links with HTML_LINK_HOME?" 975 | :group 'org-export-twbs 976 | :version "24.4" 977 | :package-version '(Org . "8.1") 978 | :type 'boolean) 979 | 980 | (defcustom org-twbs-home/up-format 981 | "
982 | UP 983 | | 984 | HOME 985 |
" 986 | "Snippet used to insert the HOME and UP links. 987 | This is a format string, the first %s will receive the UP link, 988 | the second the HOME link. If both `org-twbs-link-up' and 989 | `org-twbs-link-home' are empty, the entire snippet will be 990 | ignored." 991 | :group 'org-export-twbs 992 | :type 'string) 993 | 994 | ;;;; Template :: Scripts 995 | 996 | (define-obsolete-variable-alias 997 | 'org-twbs-style-include-scripts 'org-twbs-head-include-scripts "24.4") 998 | (defcustom org-twbs-head-include-scripts t 999 | "Non-nil means include the JavaScript snippets in exported HTML files. 1000 | The actual script is defined in `org-twbs-scripts' and should 1001 | not be modified." 1002 | :group 'org-export-twbs 1003 | :version "24.4" 1004 | :package-version '(Org . "8.0") 1005 | :type 'boolean) 1006 | 1007 | ;;;; Template :: Styles 1008 | 1009 | (define-obsolete-variable-alias 1010 | 'org-twbs-style-include-default 'org-twbs-head-include-default-style "24.4") 1011 | (defcustom org-twbs-head-include-default-style t 1012 | "Non-nil means include the default style in exported HTML files. 1013 | The actual style is defined in `org-twbs-style-default' and 1014 | should not be modified. Use `org-twbs-head' to use your own 1015 | style information." 1016 | :group 'org-export-twbs 1017 | :version "24.4" 1018 | :package-version '(Org . "8.0") 1019 | :type 'boolean) 1020 | ;;;###autoload 1021 | (put 'org-twbs-head-include-default-style 'safe-local-variable 'booleanp) 1022 | 1023 | (define-obsolete-variable-alias 'org-twbs-style 'org-twbs-head "24.4") 1024 | (defcustom org-twbs-head " 1025 | 1026 | 1027 | " 1028 | "Org-wide head definitions for exported HTML files. 1029 | 1030 | As the value of this option simply gets inserted into the HTML 1031 | header, you can use it to add any arbitrary text to the 1032 | header. 1033 | 1034 | You can set this on a per-file basis using #+HTML_HEAD:, 1035 | or for publication projects using the :html-head property." 1036 | :group 'org-export-twbs 1037 | :version "24.4" 1038 | :package-version '(Org . "8.0") 1039 | :type 'string) 1040 | ;;;###autoload 1041 | (put 'org-twbs-head 'safe-local-variable 'stringp) 1042 | 1043 | (defcustom org-twbs-head-extra "" 1044 | "More head information to add in the HTML output. 1045 | 1046 | You can set this on a per-file basis using #+HTML_HEAD_EXTRA:, 1047 | or for publication projects using the :html-head-extra property." 1048 | :group 'org-export-twbs 1049 | :version "24.4" 1050 | :package-version '(Org . "8.0") 1051 | :type 'string) 1052 | ;;;###autoload 1053 | (put 'org-twbs-head-extra 'safe-local-variable 'stringp) 1054 | 1055 | ;;;; Todos 1056 | 1057 | (defcustom org-twbs-todo-kwd-class-prefix "" 1058 | "Prefix to class names for TODO keywords. 1059 | Each TODO keyword gets a class given by the keyword itself, with this prefix. 1060 | The default prefix is empty because it is nice to just use the keyword 1061 | as a class name. But if you get into conflicts with other, existing 1062 | CSS classes, then this prefix can be very useful." 1063 | :group 'org-export-twbs 1064 | :type 'string) 1065 | 1066 | (defcustom org-twbs-todo-kwd-class-undone "label-primary" 1067 | "Class name for TODO keywords which are not done. 1068 | Traditionally this was not configurable, and was the value 'todo'." 1069 | :group 'org-export-twbs 1070 | :type 'string) 1071 | 1072 | (defcustom org-twbs-todo-kwd-class-done "label-default" 1073 | "Class name for TODO keywords which are done. 1074 | Traditionally this was not configurable, and was the value 'done'." 1075 | :group 'org-export-twbs 1076 | :type 'string) 1077 | 1078 | ;;;; Google Analytics 1079 | 1080 | (defcustom org-twbs-google-analytics " 1081 | \n" 1091 | "Snippet used to insert the Google Analytics tracking code. 1092 | This is a format string, the %s will be replaced with the value 1093 | set using the :gid keyword." 1094 | :group 'org-export-twbs 1095 | :type 'string) 1096 | 1097 | 1098 | ;;; Internal Functions 1099 | 1100 | (defun org-twbs-close-tag (tag attr info) 1101 | (concat "<" tag " " attr ">")) 1102 | 1103 | (defun org-twbs--make-attribute-string (attributes) 1104 | "Return a list of attributes, as a string. 1105 | ATTRIBUTES is a plist where values are either strings or nil. An 1106 | attributes with a nil value will be omitted from the result." 1107 | (let (output) 1108 | (dolist (item attributes (mapconcat 'identity (nreverse output) " ")) 1109 | (cond ((null item) (pop output)) 1110 | ((symbolp item) (push (substring (symbol-name item) 1) output)) 1111 | (t (let ((key (car output)) 1112 | (value (replace-regexp-in-string 1113 | "\"" """ (org-twbs-encode-plain-text item)))) 1114 | (setcar output (format "%s=\"%s\"" key value)))))))) 1115 | 1116 | (defun org-twbs--wrap-image (contents info &optional caption label) 1117 | "Wrap CONTENTS string within an appropriate environment for images. 1118 | INFO is a plist used as a communication channel. When optional 1119 | arguments CAPTION and LABEL are given, use them for caption and 1120 | \"id\" attribute." 1121 | (format "\n%s%s\n" 1122 | ;; ID. 1123 | (if (not (org-string-nw-p label)) "" 1124 | (format " id=\"%s\"" label)) 1125 | ;; Contents. 1126 | (format "\n

%s

" contents) 1127 | ;; Caption. 1128 | (if (not (org-string-nw-p caption)) "" 1129 | (format "\n
%s
" caption)))) 1130 | 1131 | (defun org-twbs--format-image (source attributes info) 1132 | "Return \"img\" tag with given SOURCE and ATTRIBUTES. 1133 | SOURCE is a string specifying the location of the image. 1134 | ATTRIBUTES is a plist, as returned by 1135 | `org-export-read-attribute'. INFO is a plist used as 1136 | a communication channel." 1137 | (org-twbs-close-tag 1138 | "img" 1139 | (org-twbs--make-attribute-string 1140 | (org-combine-plists 1141 | (list :src source 1142 | :class "img-responsive" 1143 | :alt (if (string-match-p "^ltxpng/" source) 1144 | (org-twbs-encode-plain-text 1145 | (org-find-text-property-in-string 'org-latex-src source)) 1146 | (file-name-nondirectory source))) 1147 | attributes)) 1148 | info)) 1149 | 1150 | (defun org-twbs--textarea-block (element) 1151 | "Transcode ELEMENT into a textarea block. 1152 | ELEMENT is either a src block or an example block." 1153 | (let* ((code (car (org-export-unravel-code element))) 1154 | (attr (org-export-read-attribute :attr_html element))) 1155 | (format "

\n\n

" 1156 | (or (plist-get attr :width) 80) 1157 | (or (plist-get attr :height) (org-count-lines code)) 1158 | code))) 1159 | 1160 | (defun org-twbs--has-caption-p (element &optional info) 1161 | "Non-nil when ELEMENT has a caption affiliated keyword. 1162 | INFO is a plist used as a communication channel. This function 1163 | is meant to be used as a predicate for `org-export-get-ordinal' or 1164 | a value to `org-twbs-standalone-image-predicate'." 1165 | (org-element-property :caption element)) 1166 | 1167 | ;;;; Table 1168 | 1169 | (defun org-twbs-htmlize-region-for-paste (beg end) 1170 | "Convert the region between BEG and END to HTML, using htmlize.el. 1171 | This is much like `htmlize-region-for-paste', only that it uses 1172 | the settings define in the org-... variables." 1173 | (let* ((htmlize-output-type org-twbs-htmlize-output-type) 1174 | (htmlize-css-name-prefix org-twbs-htmlize-font-prefix) 1175 | (htmlbuf (htmlize-region beg end))) 1176 | (unwind-protect 1177 | (with-current-buffer htmlbuf 1178 | (buffer-substring (plist-get htmlize-buffer-places 'content-start) 1179 | (plist-get htmlize-buffer-places 'content-end))) 1180 | (kill-buffer htmlbuf)))) 1181 | 1182 | ;;;###autoload 1183 | (defun org-twbs-htmlize-generate-css () 1184 | "Create the CSS for all font definitions in the current Emacs session. 1185 | Use this to create face definitions in your CSS style file that can then 1186 | be used by code snippets transformed by htmlize. 1187 | This command just produces a buffer that contains class definitions for all 1188 | faces used in the current Emacs session. You can copy and paste the ones you 1189 | need into your CSS file. 1190 | 1191 | If you then set `org-twbs-htmlize-output-type' to `css', calls 1192 | to the function `org-twbs-htmlize-region-for-paste' will 1193 | produce code that uses these same face definitions." 1194 | (interactive) 1195 | (require 'htmlize) 1196 | (and (get-buffer "*html*") (kill-buffer "*html*")) 1197 | (with-temp-buffer 1198 | (let ((fl (face-list)) 1199 | (htmlize-css-name-prefix "org-") 1200 | (htmlize-output-type 'css) 1201 | f i) 1202 | (while (setq f (pop fl) 1203 | i (and f (face-attribute f :inherit))) 1204 | (when (and (symbolp f) (or (not i) (not (listp i)))) 1205 | (insert (org-add-props (copy-sequence "1") nil 'face f)))) 1206 | (htmlize-region (point-min) (point-max)))) 1207 | (org-pop-to-buffer-same-window "*html*") 1208 | (goto-char (point-min)) 1209 | (if (re-search-forward "" nil t) 1212 | (delete-region (1+ (match-end 0)) (point-max))) 1213 | (beginning-of-line 1) 1214 | (if (looking-at " +") (replace-match "")) 1215 | (goto-char (point-min))) 1216 | 1217 | (defun org-twbs--make-string (n string) 1218 | "Build a string by concatenating N times STRING." 1219 | (let (out) (dotimes (i n out) (setq out (concat string out))))) 1220 | 1221 | (defun org-twbs-fix-class-name (kwd) ; audit callers of this function 1222 | "Turn todo keyword KWD into a valid class name. 1223 | Replaces invalid characters with \"_\"." 1224 | (save-match-data 1225 | (while (string-match "[^a-zA-Z0-9_]" kwd) 1226 | (setq kwd (replace-match "_" t t kwd)))) 1227 | kwd) 1228 | 1229 | (defun org-twbs-format-footnote-reference (n def refcnt) 1230 | "Format footnote reference N with definition DEF into HTML." 1231 | (let ((extra (if (= refcnt 1) "" (format ".%d" refcnt)))) 1232 | (format org-twbs-footnote-format 1233 | (let* ((id (format "fnr.%s%s" n extra)) 1234 | (href (format " href=\"#fn.%s\"" n)) 1235 | (attributes (concat " class=\"footref\"" href))) 1236 | (org-twbs--anchor id n attributes))))) 1237 | 1238 | (defun org-twbs-format-footnotes-section (section-name definitions) 1239 | "Format footnotes section SECTION-NAME." 1240 | (if (not definitions) "" 1241 | (format org-twbs-footnotes-section section-name definitions))) 1242 | 1243 | (defun org-twbs-format-footnote-definition (fn) 1244 | "Format the footnote definition FN." 1245 | (let ((n (car fn)) (def (cdr fn))) 1246 | (format 1247 | "
%s %s
\n" 1248 | (format org-twbs-footnote-format 1249 | (let* ((id (format "fn.%s" n)) 1250 | (href (format " href=\"#fnr.%s\"" n)) 1251 | (attributes (concat " class=\"footnum\"" href))) 1252 | (org-twbs--anchor id n attributes))) 1253 | def))) 1254 | 1255 | (defun org-twbs-collect-footnote-definitions (info) 1256 | "Signature change underneath us, released maybe with 8.3 commit URL at: 1257 | http://orgmode.org/w/?p=org-mode.git;a=commit;h=014de0a532cbc60987d09d6040ed46195cffdf12 1258 | Try the old 2-arity and if fails, try the new single-arity." 1259 | (with-no-warnings 1260 | (condition-case nil 1261 | (org-export-collect-footnote-definitions 1262 | (plist-get info :parse-tree) info) 1263 | (error (org-export-collect-footnote-definitions info))))) 1264 | 1265 | (defun org-twbs-footnote-section (info) 1266 | "Format the footnote section. 1267 | INFO is a plist used as a communication channel." 1268 | (let* ((fn-alist (org-twbs-collect-footnote-definitions info)) 1269 | (fn-alist 1270 | (loop for (n type raw) in fn-alist collect 1271 | (cons n (if (eq (org-element-type raw) 'org-data) 1272 | (org-trim (org-export-data raw info)) 1273 | (org-trim (org-export-data raw info))))))) 1274 | (when fn-alist 1275 | (org-twbs-format-footnotes-section 1276 | (org-twbs--translate "Footnotes" info) 1277 | (format 1278 | "\n%s\n" 1279 | (mapconcat 'org-twbs-format-footnote-definition fn-alist "\n")))))) 1280 | 1281 | 1282 | ;;; Template 1283 | 1284 | (defun org-twbs--build-meta-info (info) 1285 | "Return meta tags for exported document. 1286 | INFO is a plist used as a communication channel." 1287 | (let ((protect-string 1288 | (lambda (str) 1289 | (replace-regexp-in-string 1290 | "\"" """ (org-twbs-encode-plain-text str)))) 1291 | (title (org-export-data (plist-get info :title) info)) 1292 | (author (and (plist-get info :with-author) 1293 | (let ((auth (plist-get info :author))) 1294 | (and auth 1295 | ;; Return raw Org syntax, skipping non 1296 | ;; exportable objects. 1297 | (org-element-interpret-data 1298 | (org-element-map auth 1299 | (cons 'plain-text org-element-all-objects) 1300 | 'identity info)))))) 1301 | (description (plist-get info :description)) 1302 | (keywords (plist-get info :keywords)) 1303 | (charset (or (and org-twbs-coding-system 1304 | (fboundp 'coding-system-get) 1305 | (coding-system-get org-twbs-coding-system 1306 | 'mime-charset)) 1307 | "iso-8859-1"))) 1308 | (concat 1309 | (format "%s\n" title) 1310 | (when (plist-get info :time-stamp-file) 1311 | (format-time-string 1312 | (concat "\n"))) 1313 | (format 1314 | (org-twbs-close-tag "meta" "charset=\"%s\"" info) 1315 | charset) "\n" 1316 | "" 1317 | "\n" 1318 | (org-twbs-close-tag "meta" "name=\"generator\" content=\"Org-mode\"" info) 1319 | "\n" 1320 | (and (org-string-nw-p author) 1321 | (concat 1322 | (org-twbs-close-tag "meta" 1323 | (format "name=\"author\" content=\"%s\"" 1324 | (funcall protect-string author)) 1325 | info) 1326 | "\n")) 1327 | (and (org-string-nw-p description) 1328 | (concat 1329 | (org-twbs-close-tag "meta" 1330 | (format "name=\"description\" content=\"%s\"\n" 1331 | (funcall protect-string description)) 1332 | info) 1333 | "\n")) 1334 | (and (org-string-nw-p keywords) 1335 | (concat 1336 | (org-twbs-close-tag "meta" 1337 | (format "name=\"keywords\" content=\"%s\"" 1338 | (funcall protect-string keywords)) 1339 | info) 1340 | "\n"))))) 1341 | 1342 | (defun org-twbs--build-head (info) 1343 | "Return information for the .. of the HTML output. 1344 | INFO is a plist used as a communication channel." 1345 | (org-element-normalize-string 1346 | (concat 1347 | (org-element-normalize-string (plist-get info :html-head)) 1348 | (when (and (plist-get info :html-htmlized-css-url) 1349 | (eq org-twbs-htmlize-output-type 'css)) 1350 | (org-twbs-close-tag "link" 1351 | (format " rel=\"stylesheet\" href=\"%s\" type=\"text/css\"" 1352 | (plist-get info :html-htmlized-css-url)) 1353 | info)) 1354 | (when (plist-get info :html-head-include-default-style) 1355 | (org-element-normalize-string org-twbs-style-default)) 1356 | (when (not (plist-get info :html-postamble)) 1357 | "") 1358 | (when (plist-get info :html-head-include-scripts) org-twbs-scripts) 1359 | (org-element-normalize-string (plist-get info :html-head-extra))))) 1360 | 1361 | (defun org-twbs--build-mathjax-config (info) 1362 | "Insert the user setup into the mathjax template. 1363 | INFO is a plist used as a communication channel." 1364 | (when (and (memq (plist-get info :with-latex) '(mathjax t)) 1365 | (org-element-map (plist-get info :parse-tree) 1366 | '(latex-fragment latex-environment) 'identity info t)) 1367 | (let ((template (plist-get info :html-mathjax-template)) 1368 | (options (plist-get info :html-mathjax-options)) 1369 | (in-buffer (or (plist-get info :html-mathjax) ""))) 1370 | (dolist (e options (org-element-normalize-string template)) 1371 | (let ((name (car e)) 1372 | (val (nth 1 e))) 1373 | (when (string-match (concat "\\<" (symbol-name name) ":") in-buffer) 1374 | (setq val 1375 | (car (read-from-string (substring in-buffer (match-end 0)))))) 1376 | (unless (stringp val) (setq val (format "%s" val))) 1377 | (while (string-match (concat "%" (upcase (symbol-name name))) 1378 | template) 1379 | (setq template (replace-match val t t template)))))))) 1380 | 1381 | (defun org-twbs-format-spec (info) 1382 | "Return format specification for elements that can be 1383 | used in the preamble or postamble." 1384 | `((?t . ,(org-export-data (plist-get info :title) info)) 1385 | (?d . ,(org-export-data (org-export-get-date info) info)) 1386 | (?T . ,(format-time-string org-twbs-metadata-timestamp-format)) 1387 | (?a . ,(org-export-data (plist-get info :author) info)) 1388 | (?e . ,(mapconcat 1389 | (lambda (e) 1390 | (format "%s" e e)) 1391 | (split-string (plist-get info :email) ",+ *") 1392 | ", ")) 1393 | (?c . ,(plist-get info :creator)) 1394 | (?C . ,(let ((file (plist-get info :input-file))) 1395 | (format-time-string org-twbs-metadata-timestamp-format 1396 | (if file (nth 5 (file-attributes file)) 1397 | (current-time))))) 1398 | (?v . ,(or org-twbs-validation-link "")))) 1399 | 1400 | (defun org-twbs--build-pre/postamble (type info) 1401 | "Return document preamble or postamble as a string, or nil. 1402 | TYPE is either 'preamble or 'postamble, INFO is a plist used as a 1403 | communication channel." 1404 | (let ((section (plist-get info (intern (format ":html-%s" type)))) 1405 | (spec (org-twbs-format-spec info))) 1406 | (when section 1407 | (let ((section-contents 1408 | (if (functionp section) (funcall section info) 1409 | (cond 1410 | ((stringp section) (format-spec section spec)) 1411 | ((eq section 'auto) 1412 | (let ((date (cdr (assq ?d spec))) 1413 | (author (cdr (assq ?a spec))) 1414 | (email (cdr (assq ?e spec))) 1415 | (creator (cdr (assq ?c spec))) 1416 | (timestamp (cdr (assq ?T spec))) 1417 | (validation-link (cdr (assq ?v spec)))) 1418 | (concat 1419 | "
" 1420 | (when (and (plist-get info :with-date) 1421 | (org-string-nw-p date)) 1422 | (format "

%s: %s

\n" 1423 | (org-twbs--translate "Date" info) 1424 | date)) 1425 | (when (and (plist-get info :with-author) 1426 | (org-string-nw-p author)) 1427 | (format "

%s: %s

\n" 1428 | (org-twbs--translate "Author" info) 1429 | author)) 1430 | (when (and (plist-get info :with-email) 1431 | (org-string-nw-p email)) 1432 | (format "

%s: %s

\n" 1433 | (org-twbs--translate "Email" info) 1434 | email)) 1435 | (when (plist-get info :time-stamp-file) 1436 | (format 1437 | "

%s: %s

\n" 1438 | (org-twbs--translate "Created" info) 1439 | (format-time-string org-twbs-metadata-timestamp-format))) 1440 | (when (plist-get info :with-creator) 1441 | (format "

%s

\n" creator)) 1442 | "
"))) 1443 | (t (format-spec 1444 | (or (cadr (assoc 1445 | (plist-get info :language) 1446 | (eval (intern 1447 | (format "org-twbs-%s-format" type))))) 1448 | (cadr 1449 | (assoc 1450 | "en" 1451 | (eval 1452 | (intern (format "org-twbs-%s-format" type)))))) 1453 | spec)))))) 1454 | (when (org-string-nw-p section-contents) 1455 | (concat 1456 | (format "<%s id=\"%s\" class=\"%s\">\n" 1457 | (nth 1 (assq type org-twbs-divs)) 1458 | (nth 2 (assq type org-twbs-divs)) 1459 | org-twbs--pre/postamble-class) 1460 | (org-element-normalize-string section-contents) 1461 | (format "\n" (nth 1 (assq type org-twbs-divs))))))))) 1462 | 1463 | (defun org-twbs-inner-template (contents info) 1464 | "Return body of document string after HTML conversion. 1465 | CONTENTS is the transcoded contents string. INFO is a plist 1466 | holding export options." 1467 | (concat 1468 | ;; Document contents. 1469 | contents 1470 | ;; Footnotes section. 1471 | (org-twbs-footnote-section info))) 1472 | 1473 | (defun org-twbs-template (contents info) 1474 | "Return complete document string after HTML conversion. 1475 | CONTENTS is the transcoded contents string. INFO is a plist 1476 | holding export options." 1477 | (concat 1478 | "\n" 1479 | (format "\n" (plist-get info :language)) 1480 | "\n" 1481 | (org-twbs--build-meta-info info) 1482 | (org-twbs--build-head info) 1483 | (org-twbs--build-mathjax-config info) 1484 | "\n" 1485 | "\n" 1486 | (let ((link-up (org-trim (plist-get info :html-link-up))) 1487 | (link-home (org-trim (plist-get info :html-link-home)))) 1488 | (unless (and (string= link-up "") (string= link-home "")) 1489 | (format org-twbs-home/up-format 1490 | (or link-up link-home) 1491 | (or link-home link-up)))) 1492 | ;; Preamble. 1493 | (org-twbs--build-pre/postamble 'preamble info) 1494 | ;; Document contents. 1495 | (format "<%s id=\"%s\" class=\"%s\">\n" 1496 | (nth 1 (assq 'content org-twbs-divs)) 1497 | (nth 2 (assq 'content org-twbs-divs)) 1498 | (nth 3 (assq 'content org-twbs-divs))) 1499 | ;; Main doc body twbs row 1500 | "
" 1501 | ;; Table of contents. 1502 | (let ((depth (plist-get info :with-toc))) 1503 | (when depth 1504 | (concat 1505 | "
" 1506 | (org-twbs-toc depth info) 1507 | "
"))) 1508 | (if (plist-get info :with-toc) "
" 1509 | "
") 1510 | ;; Document title. 1511 | (let ((title (plist-get info :title))) 1512 | (format "

%s

\n" (org-export-data (or title "") info))) 1513 | contents 1514 | "
" 1515 | "
" 1516 | (format "\n" 1517 | (nth 1 (assq 'content org-twbs-divs))) 1518 | ;; Postamble. 1519 | (org-twbs--build-pre/postamble 'postamble info) 1520 | ;; Google Analytics 1521 | (let ((gid (plist-get info :gid))) 1522 | (when gid 1523 | (format org-twbs-google-analytics gid))) 1524 | ;; Closing document. 1525 | "\n")) 1526 | 1527 | (defun org-twbs--translate (s info) 1528 | "Translate string S according to specified language. 1529 | INFO is a plist used as a communication channel." 1530 | (org-export-translate s :html info)) 1531 | 1532 | ;;;; Anchor 1533 | 1534 | (defun org-twbs--anchor (&optional id desc attributes) 1535 | "Format a HTML anchor." 1536 | (let* ((name (and org-twbs-allow-name-attribute-in-anchors id)) 1537 | (attributes (concat (and id (format " id=\"%s\"" id)) 1538 | (and name (format " name=\"%s\"" name)) 1539 | attributes))) 1540 | (format "%s" attributes (or desc "")))) 1541 | 1542 | ;;;; Todo 1543 | 1544 | (defun org-twbs--todo (todo) 1545 | "Format TODO keywords into HTML." 1546 | (when todo 1547 | (let* ((is-done (member todo org-done-keywords)) 1548 | (class (if is-done org-twbs-todo-kwd-class-done 1549 | org-twbs-todo-kwd-class-undone)) 1550 | (is-label (string-prefix-p "label-" class))) 1551 | (format "%s" 1552 | (if is-label "label " "") 1553 | class 1554 | org-twbs-todo-kwd-class-prefix (org-twbs-fix-class-name todo) 1555 | todo)))) 1556 | 1557 | ;;;; Tags 1558 | 1559 | (defun org-twbs--tags (tags) 1560 | "Format TAGS into HTML." 1561 | (when tags 1562 | (format "%s" 1563 | (mapconcat 1564 | (lambda (tag) 1565 | (format "%s" 1566 | org-twbs-tag-class 1567 | (concat org-twbs-tag-class-prefix 1568 | (org-twbs-fix-class-name tag)) 1569 | tag)) 1570 | tags " ")))) 1571 | 1572 | ;;;; Headline 1573 | 1574 | (defun* org-twbs-format-headline 1575 | (todo todo-type priority text tags 1576 | &key level section-number headline-label &allow-other-keys) 1577 | "Format a headline in HTML." 1578 | (let ((section-number 1579 | (when section-number 1580 | (format "%s " 1581 | level section-number))) 1582 | (todo (org-twbs--todo todo)) 1583 | (tags (org-twbs--tags tags))) 1584 | (concat section-number todo (and todo " ") text 1585 | (and tags "   ") tags))) 1586 | 1587 | ;;;; Src Code 1588 | 1589 | (defun org-twbs-fontify-code (code lang) 1590 | "Color CODE with htmlize library. 1591 | CODE is a string representing the source code to colorize. LANG 1592 | is the language used for CODE, as a string, or nil." 1593 | (when code 1594 | (cond 1595 | ;; Case 1: No lang. Possibly an example block. 1596 | ((not lang) 1597 | ;; Simple transcoding. 1598 | (org-twbs-encode-plain-text code)) 1599 | ;; Case 2: No htmlize or an inferior version of htmlize 1600 | ((not (and (require 'htmlize nil t) (fboundp 'htmlize-region-for-paste))) 1601 | ;; Emit a warning. 1602 | (message "Cannot fontify src block (htmlize.el >= 1.34 required)") 1603 | ;; Simple transcoding. 1604 | (org-twbs-encode-plain-text code)) 1605 | (t 1606 | ;; Map language 1607 | (setq lang (or (assoc-default lang org-src-lang-modes) lang)) 1608 | (let* ((lang-mode (and lang (intern (format "%s-mode" lang))))) 1609 | (cond 1610 | ;; Case 1: Language is not associated with any Emacs mode 1611 | ((not (functionp lang-mode)) 1612 | ;; Simple transcoding. 1613 | (org-twbs-encode-plain-text code)) 1614 | ;; Case 2: Default. Fontify code. 1615 | (t 1616 | ;; htmlize 1617 | (setq code (with-temp-buffer 1618 | ;; Switch to language-specific mode. 1619 | (funcall lang-mode) 1620 | (insert code) 1621 | ;; Fontify buffer. 1622 | (font-lock-fontify-buffer) 1623 | ;; Remove formatting on newline characters. 1624 | (save-excursion 1625 | (let ((beg (point-min)) 1626 | (end (point-max))) 1627 | (goto-char beg) 1628 | (while (progn (end-of-line) (< (point) end)) 1629 | (put-text-property (point) (1+ (point)) 'face nil) 1630 | (forward-char 1)))) 1631 | (org-src-mode) 1632 | (set-buffer-modified-p nil) 1633 | ;; Htmlize region. 1634 | (org-twbs-htmlize-region-for-paste 1635 | (point-min) (point-max)))) 1636 | ;; Strip any enclosing
 tags.
1637 |           (let* ((beg (and (string-match "\\`]*>\n*" code) (match-end 0)))
1638 |                  (end (and beg (string-match "\\'" code))))
1639 |             (if (and beg end) (substring code beg end) code)))))))))
1640 | 
1641 | (defun org-twbs-do-format-code
1642 |     (code &optional lang refs retain-labels num-start)
1643 |   "Format CODE string as source code.
1644 | Optional arguments LANG, REFS, RETAIN-LABELS and NUM-START are,
1645 | respectively, the language of the source code, as a string, an
1646 | alist between line numbers and references (as returned by
1647 | `org-export-unravel-code'), a boolean specifying if labels should
1648 | appear in the source code, and the number associated to the first
1649 | line of code."
1650 |   (let* ((code-lines (org-split-string code "\n"))
1651 |          (code-length (length code-lines))
1652 |          (num-fmt
1653 |           (and num-start
1654 |                (format "%%%ds: "
1655 |                        (length (number-to-string (+ code-length num-start))))))
1656 |          (code (org-twbs-fontify-code code lang)))
1657 |     (org-export-format-code
1658 |      code
1659 |      (lambda (loc line-num ref)
1660 |        (setq loc
1661 |              (concat
1662 |               ;; Add line number, if needed.
1663 |               (when num-start
1664 |                 (format "%s"
1665 |                         (format num-fmt line-num)))
1666 |               ;; Transcoded src line.
1667 |               loc
1668 |               ;; Add label, if needed.
1669 |               (when (and ref retain-labels) (format " (%s)" ref))))
1670 |        ;; Mark transcoded line as an anchor, if needed.
1671 |        (if (not ref) loc
1672 |          (format "%s"
1673 |                  ref loc)))
1674 |      num-start refs)))
1675 | 
1676 | (defun org-twbs-format-code (element info)
1677 |   "Format contents of ELEMENT as source code.
1678 | ELEMENT is either an example block or a src block.  INFO is
1679 | a plist used as a communication channel."
1680 |   (let* ((lang (org-element-property :language element))
1681 |          ;; Extract code and references.
1682 |          (code-info (org-export-unravel-code element))
1683 |          (code (car code-info))
1684 |          (refs (cdr code-info))
1685 |          ;; Does the src block contain labels?
1686 |          (retain-labels (org-element-property :retain-labels element))
1687 |          ;; Does it have line numbers?
1688 |          (num-start (case (org-element-property :number-lines element)
1689 |                       (continued (org-export-get-loc element info))
1690 |                       (new 0))))
1691 |     (org-twbs-do-format-code code lang refs retain-labels num-start)))
1692 | 
1693 | 
1694 | ;;; Tables of Contents
1695 | 
1696 | (defun org-twbs-display-headline-number-p (headline-number info)
1697 |   "Predicate deciding if headline number should be displayed."
1698 |   (let ((whn (plist-get info :with-headline-numbers)))
1699 |     (or (eq whn t) (and (wholenump whn) (<= (length headline-number) whn)))))
1700 | 
1701 | (defun org-twbs-collect-headlines (info depth &optional scope)
1702 |   "Another arity change in org:
1703 | http://orgmode.org/w/?p=org-mode.git;a=commit;h=b07e2f6ff1feddde83506b7fdb370bfe8e0a5337
1704 | Try new 3-arity first, then old 2-arity."
1705 |   (with-no-warnings
1706 |     (condition-case nil
1707 |         (org-export-collect-headlines info depth scope)
1708 |       (error (org-export-collect-headlines info depth)))))
1709 | 
1710 | (defun org-twbs-toc (depth info &optional scope)
1711 |   "Build a table of contents.
1712 | DEPTH is an integer specifying the depth of the table.  INFO is a
1713 | plist used as a communication channel.  Return the table of
1714 | contents as a string, or nil if it is empty."
1715 |   (let ((toc-entries
1716 |          (mapcar (lambda (headline)
1717 |                    (cons (org-twbs--format-toc-headline headline info)
1718 |                          (org-export-get-relative-level headline info)))
1719 |                  (org-twbs-collect-headlines info depth scope)))
1720 |         (outer-tag "nav"))
1721 |     (when toc-entries
1722 |       (concat (format "<%s id=\"table-of-contents\">\n" outer-tag)
1723 |               "
" 1724 | (org-twbs--toc-text toc-entries) 1725 | "
\n" 1726 | (format "\n" outer-tag))))) 1727 | 1728 | (defun org-twbs--toc-text (toc-entries) 1729 | "Return innards of a table of contents, as a string. 1730 | TOC-ENTRIES is an alist where key is an entry title, as a string, 1731 | and value is its relative level, as an integer." 1732 | (let* ((prev-level (1- (cdar toc-entries))) 1733 | (start-level prev-level)) 1734 | (concat 1735 | (mapconcat 1736 | (lambda (entry) 1737 | (let ((headline (car entry)) 1738 | (level (cdr entry))) 1739 | (concat 1740 | (let* ((cnt (- level prev-level)) 1741 | (times (if (> cnt 0) (1- cnt) (- cnt))) 1742 | rtn) 1743 | (setq prev-level level) 1744 | (concat 1745 | (org-twbs--make-string 1746 | times (cond ((> cnt 0) "\n
    \n
  • ") 1747 | ((< cnt 0) "
  • \n
\n"))) 1748 | (if (> cnt 0) "\n
    \n
  • " "
  • \n
  • "))) 1749 | headline))) 1750 | toc-entries "") 1751 | (org-twbs--make-string (- prev-level start-level) "
  • \n
\n")))) 1752 | 1753 | (defun org-twbs--format-toc-headline (headline info) 1754 | "Return an appropriate table of contents entry for HEADLINE. 1755 | INFO is a plist used as a communication channel." 1756 | (let* ((headline-number (org-export-get-headline-number headline info)) 1757 | (todo (and (plist-get info :with-todo-keywords) 1758 | (plist-get info :with-toc-todo-keywords) 1759 | (let ((todo (org-element-property :todo-keyword headline))) 1760 | (and todo (org-export-data todo info))))) 1761 | (todo-type (and todo (org-element-property :todo-type headline))) 1762 | (priority (and (plist-get info :with-priority) 1763 | (org-element-property :priority headline))) 1764 | (text (org-export-data-with-backend 1765 | (org-export-get-alt-title headline info) 1766 | ;; Create an anonymous back-end that will ignore any 1767 | ;; footnote-reference, link, radio-target and target 1768 | ;; in table of contents. 1769 | (org-export-create-backend 1770 | :parent 'twbs 1771 | :transcoders '((footnote-reference . ignore) 1772 | (link . (lambda (object c i) c)) 1773 | (radio-target . (lambda (object c i) c)) 1774 | (target . ignore))) 1775 | info)) 1776 | (tags (and (plist-get info :with-tags) 1777 | (plist-get info :with-toc-tags) 1778 | (org-export-get-tags headline info)))) 1779 | (format "%s" 1780 | ;; Label. 1781 | (or (org-element-property :CUSTOM_ID headline) 1782 | (concat "sec-" 1783 | (mapconcat #'number-to-string headline-number "-"))) 1784 | ;; Body. 1785 | (concat 1786 | (and (not (org-export-low-level-p headline info)) 1787 | (org-export-numbered-headline-p headline info) 1788 | (org-twbs-display-headline-number-p headline-number info) 1789 | (concat (mapconcat #'number-to-string headline-number ".") 1790 | ". ")) 1791 | (apply (if (not (eq org-twbs-format-headline-function 'ignore)) 1792 | (lambda (todo todo-type priority text tags &rest ignore) 1793 | (funcall org-twbs-format-headline-function 1794 | todo todo-type priority text tags)) 1795 | #'org-twbs-format-headline) 1796 | todo todo-type priority text tags :section-number nil))))) 1797 | 1798 | (defun org-twbs-list-of-listings (info) 1799 | "Build a list of listings. 1800 | INFO is a plist used as a communication channel. Return the list 1801 | of listings as a string, or nil if it is empty." 1802 | (let ((lol-entries (org-export-collect-listings info))) 1803 | (when lol-entries 1804 | (concat "
\n" 1805 | (format "%s\n" 1806 | org-twbs-toplevel-hlevel 1807 | (org-twbs--translate "List of Listings" info) 1808 | org-twbs-toplevel-hlevel) 1809 | "
\n
    \n" 1810 | (let ((count 0) 1811 | (initial-fmt (format "%s" 1812 | (org-twbs--translate "Listing %d:" info)))) 1813 | (mapconcat 1814 | (lambda (entry) 1815 | (let ((label (org-element-property :name entry)) 1816 | (title (org-trim 1817 | (org-export-data 1818 | (or (org-export-get-caption entry t) 1819 | (org-export-get-caption entry)) 1820 | info)))) 1821 | (concat 1822 | "
  • " 1823 | (if (not label) 1824 | (concat (format initial-fmt (incf count)) " " title) 1825 | (format "%s %s" 1826 | label 1827 | (format initial-fmt (incf count)) 1828 | title)) 1829 | "
  • "))) 1830 | lol-entries "\n")) 1831 | "\n
\n
\n
")))) 1832 | 1833 | (defun org-twbs-list-of-tables (info) 1834 | "Build a list of tables. 1835 | INFO is a plist used as a communication channel. Return the list 1836 | of tables as a string, or nil if it is empty." 1837 | (let ((lol-entries (org-export-collect-tables info))) 1838 | (when lol-entries 1839 | (concat "
\n" 1840 | (format "%s\n" 1841 | org-twbs-toplevel-hlevel 1842 | (org-twbs--translate "List of Tables" info) 1843 | org-twbs-toplevel-hlevel) 1844 | "
\n
    \n" 1845 | (let ((count 0) 1846 | (initial-fmt (format "%s" 1847 | (org-twbs--translate "Table %d:" info)))) 1848 | (mapconcat 1849 | (lambda (entry) 1850 | (let ((label (org-element-property :name entry)) 1851 | (title (org-trim 1852 | (org-export-data 1853 | (or (org-export-get-caption entry t) 1854 | (org-export-get-caption entry)) 1855 | info)))) 1856 | (concat 1857 | "
  • " 1858 | (if (not label) 1859 | (concat (format initial-fmt (incf count)) " " title) 1860 | (format "%s %s" 1861 | label 1862 | (format initial-fmt (incf count)) 1863 | title)) 1864 | "
  • "))) 1865 | lol-entries "\n")) 1866 | "\n
\n
\n
")))) 1867 | 1868 | 1869 | ;;; Transcode Functions 1870 | 1871 | ;;;; Bold 1872 | 1873 | (defun org-twbs-bold (bold contents info) 1874 | "Transcode BOLD from Org to HTML. 1875 | CONTENTS is the text with bold markup. INFO is a plist holding 1876 | contextual information." 1877 | (format (or (cdr (assq 'bold org-twbs-text-markup-alist)) "%s") 1878 | contents)) 1879 | 1880 | ;;;; Center Block 1881 | 1882 | (defun org-twbs-center-block (center-block contents info) 1883 | "Transcode a CENTER-BLOCK element from Org to HTML. 1884 | CONTENTS holds the contents of the block. INFO is a plist 1885 | holding contextual information." 1886 | (format "
\n%s
" contents)) 1887 | 1888 | ;;;; Clock 1889 | 1890 | (defun org-twbs-clock (clock contents info) 1891 | "Transcode a CLOCK element from Org to HTML. 1892 | CONTENTS is nil. INFO is a plist used as a communication 1893 | channel." 1894 | (format "

1895 | 1896 | %s %s%s 1897 | 1898 |

" 1899 | org-clock-string 1900 | (org-timestamp-translate (org-element-property :value clock)) 1901 | (let ((time (org-element-property :duration clock))) 1902 | (and time (format " (%s)" time))))) 1903 | 1904 | ;;;; Code 1905 | 1906 | (defun org-twbs-code (code contents info) 1907 | "Transcode CODE from Org to HTML. 1908 | CONTENTS is nil. INFO is a plist holding contextual 1909 | information." 1910 | (format (or (cdr (assq 'code org-twbs-text-markup-alist)) "%s") 1911 | (org-twbs-encode-plain-text (org-element-property :value code)))) 1912 | 1913 | ;;;; Drawer 1914 | 1915 | (defun org-twbs-drawer (drawer contents info) 1916 | "Transcode a DRAWER element from Org to HTML. 1917 | CONTENTS holds the contents of the block. INFO is a plist 1918 | holding contextual information." 1919 | (if (functionp org-twbs-format-drawer-function) 1920 | (funcall org-twbs-format-drawer-function 1921 | (org-element-property :drawer-name drawer) 1922 | contents) 1923 | ;; If there's no user defined function: simply 1924 | ;; display contents of the drawer. 1925 | contents)) 1926 | 1927 | ;;;; Dynamic Block 1928 | 1929 | (defun org-twbs-dynamic-block (dynamic-block contents info) 1930 | "Transcode a DYNAMIC-BLOCK element from Org to HTML. 1931 | CONTENTS holds the contents of the block. INFO is a plist 1932 | holding contextual information. See `org-export-data'." 1933 | contents) 1934 | 1935 | ;;;; Entity 1936 | 1937 | (defun org-twbs-entity (entity contents info) 1938 | "Transcode an ENTITY object from Org to HTML. 1939 | CONTENTS are the definition itself. INFO is a plist holding 1940 | contextual information." 1941 | (org-element-property :html entity)) 1942 | 1943 | ;;;; Example Block 1944 | 1945 | (defun org-twbs-example-block (example-block contents info) 1946 | "Transcode a EXAMPLE-BLOCK element from Org to HTML. 1947 | CONTENTS is nil. INFO is a plist holding contextual 1948 | information." 1949 | (if (org-export-read-attribute :attr_html example-block :textarea) 1950 | (org-twbs--textarea-block example-block) 1951 | (format "
\n%s
" 1952 | (org-twbs-format-code example-block info)))) 1953 | 1954 | ;;;; Export Snippet 1955 | 1956 | (defun org-twbs-export-snippet (export-snippet contents info) 1957 | "Transcode a EXPORT-SNIPPET object from Org to HTML. 1958 | CONTENTS is nil. INFO is a plist holding contextual 1959 | information." 1960 | (when (eq (org-export-snippet-backend export-snippet) 'html) 1961 | (org-element-property :value export-snippet))) 1962 | 1963 | ;;;; Export Block 1964 | 1965 | (defun org-twbs-export-block (export-block contents info) 1966 | "Transcode a EXPORT-BLOCK element from Org to HTML. 1967 | CONTENTS is nil. INFO is a plist holding contextual information." 1968 | (when (string= (org-element-property :type export-block) "HTML") 1969 | (org-remove-indentation (org-element-property :value export-block)))) 1970 | 1971 | ;;;; Fixed Width 1972 | 1973 | (defun org-twbs-fixed-width (fixed-width contents info) 1974 | "Transcode a FIXED-WIDTH element from Org to HTML. 1975 | CONTENTS is nil. INFO is a plist holding contextual information." 1976 | (format "
\n%s
" 1977 | (org-twbs-do-format-code 1978 | (org-remove-indentation 1979 | (org-trim 1980 | (org-element-property :value fixed-width)))))) 1981 | 1982 | ;;;; Footnote Reference 1983 | 1984 | (defun org-twbs-footnote-reference (footnote-reference contents info) 1985 | "Transcode a FOOTNOTE-REFERENCE element from Org to HTML. 1986 | CONTENTS is nil. INFO is a plist holding contextual information." 1987 | (concat 1988 | ;; Insert separator between two footnotes in a row. 1989 | (let ((prev (org-export-get-previous-element footnote-reference info))) 1990 | (when (eq (org-element-type prev) 'footnote-reference) 1991 | org-twbs-footnote-separator)) 1992 | (cond 1993 | ((not (org-export-footnote-first-reference-p footnote-reference info)) 1994 | (org-twbs-format-footnote-reference 1995 | (org-export-get-footnote-number footnote-reference info) 1996 | "IGNORED" 100)) 1997 | ;; Inline definitions are secondary strings. 1998 | ((eq (org-element-property :type footnote-reference) 'inline) 1999 | (org-twbs-format-footnote-reference 2000 | (org-export-get-footnote-number footnote-reference info) 2001 | "IGNORED" 1)) 2002 | ;; Non-inline footnotes definitions are full Org data. 2003 | (t (org-twbs-format-footnote-reference 2004 | (org-export-get-footnote-number footnote-reference info) 2005 | "IGNORED" 1))))) 2006 | 2007 | ;;;; Headline 2008 | 2009 | (defun org-twbs-format-headline--wrap 2010 | (headline info &optional format-function &rest extra-keys) 2011 | "Transcode a HEADLINE element from Org to HTML. 2012 | CONTENTS holds the contents of the headline. INFO is a plist 2013 | holding contextual information." 2014 | (let* ((level (+ (org-export-get-relative-level headline info) 2015 | (1- org-twbs-toplevel-hlevel))) 2016 | (headline-number (org-export-get-headline-number headline info)) 2017 | (section-number (and (not (org-export-low-level-p headline info)) 2018 | (org-export-numbered-headline-p headline info) 2019 | (org-twbs-display-headline-number-p headline-number info) 2020 | (mapconcat 'number-to-string 2021 | headline-number "."))) 2022 | (todo (and (plist-get info :with-todo-keywords) 2023 | (let ((todo (org-element-property :todo-keyword headline))) 2024 | (and todo (org-export-data todo info))))) 2025 | (todo-type (and todo (org-element-property :todo-type headline))) 2026 | (priority (and (plist-get info :with-priority) 2027 | (org-element-property :priority headline))) 2028 | (text (org-export-data (org-element-property :title headline) info)) 2029 | (tags (and (plist-get info :with-tags) 2030 | (org-export-get-tags headline info))) 2031 | (headline-label (or (org-element-property :CUSTOM_ID headline) 2032 | (concat "sec-" (mapconcat 'number-to-string 2033 | headline-number "-")))) 2034 | (format-function 2035 | (cond ((functionp format-function) format-function) 2036 | ((not (eq org-twbs-format-headline-function 'ignore)) 2037 | (lambda (todo todo-type priority text tags &rest ignore) 2038 | (funcall org-twbs-format-headline-function 2039 | todo todo-type priority text tags))) 2040 | (t 'org-twbs-format-headline)))) 2041 | (apply format-function 2042 | todo todo-type priority text tags 2043 | :headline-label headline-label :level level 2044 | :section-number section-number extra-keys))) 2045 | 2046 | (defun org-twbs-headline (headline contents info) 2047 | "Transcode a HEADLINE element from Org to HTML. 2048 | CONTENTS holds the contents of the headline. INFO is a plist 2049 | holding contextual information." 2050 | (unless (org-element-property :footnote-section-p headline) 2051 | (let* ((contents (or contents "")) 2052 | (numberedp (org-export-numbered-headline-p headline info)) 2053 | (level (org-export-get-relative-level headline info)) 2054 | (text (org-export-data (org-element-property :title headline) info)) 2055 | (todo (and (plist-get info :with-todo-keywords) 2056 | (let ((todo (org-element-property :todo-keyword headline))) 2057 | (and todo (org-export-data todo info))))) 2058 | (todo-type (and todo (org-element-property :todo-type headline))) 2059 | (tags (and (plist-get info :with-tags) 2060 | (org-export-get-tags headline info))) 2061 | (priority (and (plist-get info :with-priority) 2062 | (org-element-property :priority headline))) 2063 | (section-number (mapconcat #'number-to-string 2064 | (org-export-get-headline-number 2065 | headline info) "-")) 2066 | (ids (delq 'nil 2067 | (list (org-element-property :CUSTOM_ID headline) 2068 | (concat "sec-" section-number) 2069 | (org-element-property :ID headline)))) 2070 | (preferred-id (car ids)) 2071 | (extra-ids (mapconcat 2072 | (lambda (id) 2073 | (org-twbs--anchor 2074 | (if (org-uuidgen-p id) (concat "ID-" id) id))) 2075 | (cdr ids) "")) 2076 | ;; Create the headline text. 2077 | (full-text (org-twbs-format-headline--wrap headline info))) 2078 | (if (org-export-low-level-p headline info) 2079 | ;; This is a deep sub-tree: export it as a list item. 2080 | (let* ((type (if numberedp 'ordered 'unordered)) 2081 | (itemized-body 2082 | (org-twbs-format-list-item 2083 | contents type nil info nil 2084 | (concat (org-twbs--anchor preferred-id) extra-ids 2085 | full-text)))) 2086 | (concat 2087 | (and (org-export-first-sibling-p headline info) 2088 | (org-twbs-begin-plain-list type)) 2089 | itemized-body 2090 | (and (org-export-last-sibling-p headline info) 2091 | (org-twbs-end-plain-list type)))) 2092 | ;; Standard headline. Export it as a section. 2093 | (let ((extra-class (org-element-property :HTML_CONTAINER_CLASS headline)) 2094 | (level1 (+ level (1- org-twbs-toplevel-hlevel))) 2095 | (first-content (car (org-element-contents headline)))) 2096 | (format "<%s id=\"%s\" class=\"%s\">%s%s\n" 2097 | (org-twbs--container headline info) 2098 | (format "outline-container-%s" 2099 | (or (org-element-property :CUSTOM_ID headline) 2100 | (concat "sec-" section-number))) 2101 | (concat (format "outline-%d" level1) (and extra-class " ") 2102 | extra-class) 2103 | (format "\n%s%s\n" 2104 | level1 preferred-id extra-ids full-text level1) 2105 | ;; When there is no section, pretend there is an 2106 | ;; empty one to get the correct
\n" class extra) text "
\n"))) 2143 | 2144 | (defun org-twbs-inlinetask (inlinetask contents info) 2145 | "Transcode an INLINETASK element from Org to HTML. 2146 | CONTENTS holds the contents of the block. INFO is a plist 2147 | holding contextual information." 2148 | (cond 2149 | ;; If `org-twbs-format-inlinetask-function' is not 'ignore, call it 2150 | ;; with appropriate arguments. 2151 | ((not (eq org-twbs-format-inlinetask-function 'ignore)) 2152 | (let ((format-function 2153 | (function* 2154 | (lambda (todo todo-type priority text tags 2155 | &key contents &allow-other-keys) 2156 | (funcall org-twbs-format-inlinetask-function 2157 | todo todo-type priority text tags contents))))) 2158 | (org-twbs-format-headline--wrap 2159 | inlinetask info format-function :contents contents))) 2160 | ;; Otherwise, use a default template. 2161 | (t (format "
\n%s%s\n%s
" 2162 | (org-twbs-format-headline--wrap inlinetask info) 2163 | (org-twbs-close-tag "br" nil info) 2164 | contents)))) 2165 | 2166 | ;;;; Italic 2167 | 2168 | (defun org-twbs-italic (italic contents info) 2169 | "Transcode ITALIC from Org to HTML. 2170 | CONTENTS is the text with italic markup. INFO is a plist holding 2171 | contextual information." 2172 | (format (or (cdr (assq 'italic org-twbs-text-markup-alist)) "%s") contents)) 2173 | 2174 | ;;;; Item 2175 | 2176 | (defun org-twbs-checkbox (checkbox) 2177 | "Format CHECKBOX into HTML." 2178 | (case checkbox (on "[X]") 2179 | (off "[ ]") 2180 | (trans "[-]") 2181 | (t ""))) 2182 | 2183 | (defun org-twbs-format-list-item (contents type checkbox info 2184 | &optional term-counter-id 2185 | headline) 2186 | "Format a list item into HTML." 2187 | (let ((checkbox (concat (org-twbs-checkbox checkbox) (and checkbox " "))) 2188 | (br (org-twbs-close-tag "br" nil info))) 2189 | (concat 2190 | (case type 2191 | (ordered 2192 | (let* ((counter term-counter-id) 2193 | (extra (if counter (format " value=\"%s\"" counter) ""))) 2194 | (concat 2195 | (format "" extra) 2196 | (when headline (concat headline br))))) 2197 | (unordered 2198 | (let* ((id term-counter-id) 2199 | (extra (if id (format " id=\"%s\"" id) ""))) 2200 | (concat 2201 | (format "" extra) 2202 | (when headline (concat headline br))))) 2203 | (descriptive 2204 | (let* ((term term-counter-id)) 2205 | (setq term (or term "(no term)")) 2206 | ;; Check-boxes in descriptive lists are associated to tag. 2207 | (concat (format "
%s
" 2208 | (concat checkbox term)) 2209 | "
")))) 2210 | (unless (eq type 'descriptive) checkbox) 2211 | contents 2212 | (case type 2213 | (ordered "") 2214 | (unordered "") 2215 | (descriptive "
"))))) 2216 | 2217 | (defun org-twbs-item (item contents info) 2218 | "Transcode an ITEM element from Org to HTML. 2219 | CONTENTS holds the contents of the item. INFO is a plist holding 2220 | contextual information." 2221 | (let* ((plain-list (org-export-get-parent item)) 2222 | (type (org-element-property :type plain-list)) 2223 | (counter (org-element-property :counter item)) 2224 | (checkbox (org-element-property :checkbox item)) 2225 | (tag (let ((tag (org-element-property :tag item))) 2226 | (and tag (org-export-data tag info))))) 2227 | (org-twbs-format-list-item 2228 | contents type checkbox info (or tag counter)))) 2229 | 2230 | ;;;; Keyword 2231 | 2232 | (defun org-twbs-keyword (keyword contents info) 2233 | "Transcode a KEYWORD element from Org to HTML. 2234 | CONTENTS is nil. INFO is a plist holding contextual information." 2235 | (let ((key (org-element-property :key keyword)) 2236 | (value (org-element-property :value keyword))) 2237 | (cond 2238 | ((string= key "HTML") value) 2239 | ((string= key "TOC") 2240 | (let ((value (downcase value))) 2241 | (cond 2242 | ((string-match "\\" value) 2243 | (let ((depth (or (and (string-match "[0-9]+" value) 2244 | (string-to-number (match-string 0 value))) 2245 | (plist-get info :with-toc)))) 2246 | (org-twbs-toc depth info))) 2247 | ((string= "listings" value) (org-twbs-list-of-listings info)) 2248 | ((string= "tables" value) (org-twbs-list-of-tables info)))))))) 2249 | 2250 | ;;;; Latex Environment 2251 | 2252 | (defun org-twbs-format-latex-arity (prefix &optional dir overlays msg 2253 | at forbuffer processing-type) 2254 | "Arity fix for org-format-latex signature change here: 2255 | http://orgmode.org/w/?p=org-mode.git;a=commit;h=8daf4a89f1a157c0ee2c91e5b990203679b31cf7 2256 | Call 7-arity first, then 6-arity if first fails." 2257 | (with-no-warnings 2258 | (condition-case nil 2259 | (org-format-latex prefix nil nil dir overlays msg forbuffer processing-type) 2260 | (error 2261 | (condition-case nil 2262 | (org-format-latex prefix dir overlays msg at forbuffer processing-type) 2263 | (error 2264 | (org-format-latex prefix dir overlays msg forbuffer processing-type))))))) 2265 | 2266 | (defun org-twbs-format-latex (latex-frag processing-type info) 2267 | "Format a LaTeX fragment LATEX-FRAG into HTML. 2268 | PROCESSING-TYPE designates the tool used for conversion. It is 2269 | a symbol among `mathjax', `dvipng', `imagemagick', `verbatim' nil 2270 | and t. See `org-twbs-with-latex' for more information. INFO is 2271 | a plist containing export properties." 2272 | (let ((cache-relpath "") (cache-dir "")) 2273 | (unless (eq processing-type 'mathjax) 2274 | (let ((bfn (or (buffer-file-name) 2275 | (make-temp-name 2276 | (expand-file-name "latex" temporary-file-directory)))) 2277 | (latex-header 2278 | (let ((header (plist-get info :latex-header))) 2279 | (and header 2280 | (concat (mapconcat 2281 | (lambda (line) (concat "#+LATEX_HEADER: " line)) 2282 | (org-split-string header "\n") 2283 | "\n") 2284 | "\n"))))) 2285 | (setq cache-relpath 2286 | (concat "ltxpng/" 2287 | (file-name-sans-extension 2288 | (file-name-nondirectory bfn))) 2289 | cache-dir (file-name-directory bfn)) 2290 | ;; Re-create LaTeX environment from original buffer in 2291 | ;; temporary buffer so that dvipng/imagemagick can properly 2292 | ;; turn the fragment into an image. 2293 | (setq latex-frag (concat latex-header latex-frag)))) 2294 | (with-temp-buffer 2295 | (insert latex-frag) 2296 | (org-twbs-format-latex-arity cache-relpath cache-dir nil 2297 | "Creating LaTeX Image..." 2298 | nil nil processing-type) 2299 | (buffer-string)))) 2300 | 2301 | (defun org-twbs-latex-environment (latex-environment contents info) 2302 | "Transcode a LATEX-ENVIRONMENT element from Org to HTML. 2303 | CONTENTS is nil. INFO is a plist holding contextual information." 2304 | (let ((processing-type (plist-get info :with-latex)) 2305 | (latex-frag (org-remove-indentation 2306 | (org-element-property :value latex-environment))) 2307 | (attributes (org-export-read-attribute :attr_html latex-environment))) 2308 | (case processing-type 2309 | ((t mathjax) 2310 | (org-twbs-format-latex latex-frag 'mathjax info)) 2311 | ((dvipng imagemagick) 2312 | (let ((formula-link 2313 | (org-twbs-format-latex latex-frag processing-type info))) 2314 | (when (and formula-link (string-match "file:\\([^]]*\\)" formula-link)) 2315 | ;; Do not provide a caption or a name to be consistent with 2316 | ;; `mathjax' handling. 2317 | (org-twbs--wrap-image 2318 | (org-twbs--format-image 2319 | (match-string 1 formula-link) attributes info) info)))) 2320 | (t latex-frag)))) 2321 | 2322 | ;;;; Latex Fragment 2323 | 2324 | (defun org-twbs-latex-fragment (latex-fragment contents info) 2325 | "Transcode a LATEX-FRAGMENT object from Org to HTML. 2326 | CONTENTS is nil. INFO is a plist holding contextual information." 2327 | (let ((latex-frag (org-element-property :value latex-fragment)) 2328 | (processing-type (plist-get info :with-latex))) 2329 | (case processing-type 2330 | ((t mathjax) 2331 | (org-twbs-format-latex latex-frag 'mathjax info)) 2332 | ((dvipng imagemagick) 2333 | (let ((formula-link 2334 | (org-twbs-format-latex latex-frag processing-type info))) 2335 | (when (and formula-link (string-match "file:\\([^]]*\\)" formula-link)) 2336 | (org-twbs--format-image (match-string 1 formula-link) nil info)))) 2337 | (t latex-frag)))) 2338 | 2339 | ;;;; Line Break 2340 | 2341 | (defun org-twbs-line-break (line-break contents info) 2342 | "Transcode a LINE-BREAK object from Org to HTML. 2343 | CONTENTS is nil. INFO is a plist holding contextual information." 2344 | (concat (org-twbs-close-tag "br" nil info) "\n")) 2345 | 2346 | ;;;; Link 2347 | 2348 | (defun org-twbs-inline-image-p (link info) 2349 | "Non-nil when LINK is meant to appear as an image. 2350 | INFO is a plist used as a communication channel. LINK is an 2351 | inline image when it has no description and targets an image 2352 | file (see `org-twbs-inline-image-rules' for more information), or 2353 | if its description is a single link targeting an image file." 2354 | (if (not (org-element-contents link)) 2355 | (org-export-inline-image-p link org-twbs-inline-image-rules) 2356 | (not 2357 | (let ((link-count 0)) 2358 | (org-element-map (org-element-contents link) 2359 | (cons 'plain-text org-element-all-objects) 2360 | (lambda (obj) 2361 | (case (org-element-type obj) 2362 | (plain-text (org-string-nw-p obj)) 2363 | (link (if (= link-count 1) t 2364 | (incf link-count) 2365 | (not (org-export-inline-image-p 2366 | obj org-twbs-inline-image-rules)))) 2367 | (otherwise t))) 2368 | info t))))) 2369 | 2370 | (defvar org-twbs-standalone-image-predicate) 2371 | (defun org-twbs-standalone-image-p (element info) 2372 | "Non-nil if ELEMENT is a standalone image. 2373 | 2374 | INFO is a plist holding contextual information. 2375 | 2376 | An element or object is a standalone image when 2377 | 2378 | - its type is `paragraph' and its sole content, save for white 2379 | spaces, is a link that qualifies as an inline image; 2380 | 2381 | - its type is `link' and its containing paragraph has no other 2382 | content save white spaces. 2383 | 2384 | Bind `org-twbs-standalone-image-predicate' to constrain paragraph 2385 | further. For example, to check for only captioned standalone 2386 | images, set it to: 2387 | 2388 | \(lambda (paragraph) (org-element-property :caption paragraph))" 2389 | (let ((paragraph (case (org-element-type element) 2390 | (paragraph element) 2391 | (link (org-export-get-parent element))))) 2392 | (and (eq (org-element-type paragraph) 'paragraph) 2393 | (or (not (fboundp 'org-twbs-standalone-image-predicate)) 2394 | (funcall org-twbs-standalone-image-predicate paragraph)) 2395 | (catch 'exit 2396 | (let ((link-count 0)) 2397 | (org-element-map (org-element-contents paragraph) 2398 | (cons 'plain-text org-element-all-objects) 2399 | #'(lambda (obj) 2400 | (when (case (org-element-type obj) 2401 | (plain-text (org-string-nw-p obj)) 2402 | (link (or (> (incf link-count) 1) 2403 | (not (org-twbs-inline-image-p obj info)))) 2404 | (otherwise t)) 2405 | (throw 'exit nil))) 2406 | info nil 'link) 2407 | (= link-count 1)))))) 2408 | 2409 | (defun org-twbs-export-file-uri (filename) 2410 | "Return file URI associated to FILENAME." 2411 | (cond ((org-string-match-p "\\`//" filename) (concat "file:" filename)) 2412 | ((not (file-name-absolute-p filename)) filename) 2413 | ((org-file-remote-p filename) (concat "file:/" filename)) 2414 | (t (concat "file://" (expand-file-name filename))))) 2415 | 2416 | (defun org-twbs-fuzzy (file search) 2417 | (cond ((fboundp 'org-publish-resolve-external-fuzzy-link) 2418 | (let ((numbers 2419 | (org-publish-resolve-external-fuzzy-link file search))) 2420 | (and numbers (concat "#sec-" 2421 | (mapconcat 'number-to-string 2422 | numbers "-"))))) 2423 | ((fboundp 'org-publish-resolve-external-link) 2424 | (let ((rez (org-publish-resolve-external-link search file))) 2425 | (concat "#" rez))) 2426 | (t ""))) 2427 | 2428 | (defun org-twbs-link (link desc info) 2429 | "Transcode a LINK object from Org to HTML. 2430 | DESC is the description part of the link, or the empty string. 2431 | INFO is a plist holding contextual information. See 2432 | `org-export-data'." 2433 | (let* ((home (when (plist-get info :html-link-home) 2434 | (org-trim (plist-get info :html-link-home)))) 2435 | (use-abs-url (plist-get info :html-link-use-abs-url)) 2436 | (link-org-files-as-html-maybe 2437 | (lambda (raw-path info) 2438 | ;; Treat links to `file.org' as links to `file.html', if 2439 | ;; needed. See `org-twbs-link-org-files-as-html'. 2440 | (cond 2441 | ((and (plist-get info :html-link-org-files-as-html) 2442 | (string= ".org" 2443 | (downcase (file-name-extension raw-path ".")))) 2444 | (concat (file-name-sans-extension raw-path) "." 2445 | (plist-get info :html-extension))) 2446 | (t raw-path)))) 2447 | (type (org-element-property :type link)) 2448 | (raw-path (org-element-property :path link)) 2449 | ;; Ensure DESC really exists, or set it to nil. 2450 | (desc (org-string-nw-p desc)) 2451 | (path 2452 | (cond 2453 | ((member type '("http" "https" "ftp" "mailto")) 2454 | (with-no-warnings 2455 | ;; handle changes in arity and naming between org 9.1 and 9.3 2456 | (condition-case nil 2457 | (org-link-encode 2458 | (org-link-decode 2459 | (concat type ":" raw-path)) '(32 91 93 37)) 2460 | (error 2461 | (org-link-escape 2462 | (org-link-unescape 2463 | (concat type ":" raw-path)) '(32 91 93 37)))))) 2464 | ((string= type "file") 2465 | ;; Treat links to ".org" files as ".html", if needed. 2466 | (setq raw-path 2467 | (funcall link-org-files-as-html-maybe raw-path info)) 2468 | ;; If file path is absolute, prepend it with protocol 2469 | ;; component - "file://". 2470 | (cond 2471 | ((file-name-absolute-p raw-path) 2472 | (setq raw-path (org-twbs-export-file-uri raw-path))) 2473 | ((and home use-abs-url) 2474 | (setq raw-path (concat (file-name-as-directory home) raw-path)))) 2475 | ;; Add search option, if any. A search option can be 2476 | ;; relative to a custom-id, a headline title a name, 2477 | ;; a target or a radio-target. 2478 | (let ((option (org-element-property :search-option link))) 2479 | (cond ((not option) raw-path) 2480 | ;; Since HTML back-end use custom-id value as-is, 2481 | ;; resolving is them is trivial. 2482 | ((eq (string-to-char option) ?#) (concat raw-path option)) 2483 | (t 2484 | (concat raw-path 2485 | (org-twbs-fuzzy 2486 | (org-element-property :path link) 2487 | option)))))) 2488 | (t raw-path))) 2489 | ;; Extract attributes from parent's paragraph. HACK: Only do 2490 | ;; this for the first link in parent (inner image link for 2491 | ;; inline images). This is needed as long as attributes 2492 | ;; cannot be set on a per link basis. 2493 | (attributes-plist 2494 | (let* ((parent (org-export-get-parent-element link)) 2495 | (link (let ((container (org-export-get-parent link))) 2496 | (if (and (eq (org-element-type container) 'link) 2497 | (org-twbs-inline-image-p link info)) 2498 | container 2499 | link)))) 2500 | (and (eq (org-element-map parent 'link 'identity info t) link) 2501 | (org-export-read-attribute :attr_html parent)))) 2502 | (attributes 2503 | (let ((attr (org-twbs--make-attribute-string attributes-plist))) 2504 | (if (org-string-nw-p attr) (concat " " attr) "")))) 2505 | (cond 2506 | ;; Image file. 2507 | ((and (plist-get info :html-inline-images) 2508 | (org-export-inline-image-p 2509 | link (plist-get info :html-inline-image-rules))) 2510 | (org-twbs--format-image path attributes-plist info)) 2511 | ;; Radio target: Transcode target's contents and use them as 2512 | ;; link's description. 2513 | ((string= type "radio") 2514 | (let ((destination (org-export-resolve-radio-link link info))) 2515 | (if (not destination) desc 2516 | (format "%s" 2517 | (org-element-property :value destination) 2518 | attributes desc)))) 2519 | ;; Links pointing to a headline: Find destination and build 2520 | ;; appropriate referencing command. 2521 | ((member type '("custom-id" "fuzzy" "id")) 2522 | (let ((destination (if (string= type "fuzzy") 2523 | (org-export-resolve-fuzzy-link link info) 2524 | (org-export-resolve-id-link link info)))) 2525 | (case (org-element-type destination) 2526 | ;; ID link points to an external file. 2527 | (plain-text 2528 | (let ((fragment (concat "ID-" path)) 2529 | ;; Treat links to ".org" files as ".html", if needed. 2530 | (path (funcall link-org-files-as-html-maybe 2531 | destination info))) 2532 | (format "%s" 2533 | path fragment attributes (or desc destination)))) 2534 | ;; Fuzzy link points nowhere. 2535 | ((nil) 2536 | (format "%s" 2537 | (or desc 2538 | (org-export-data 2539 | (org-element-property :raw-link link) info)))) 2540 | ;; Link points to a headline. 2541 | (headline 2542 | (let ((href 2543 | ;; What href to use? 2544 | (cond 2545 | ;; Case 1: Headline is linked via it's CUSTOM_ID 2546 | ;; property. Use CUSTOM_ID. 2547 | ((string= type "custom-id") 2548 | (org-element-property :CUSTOM_ID destination)) 2549 | ;; Case 2: Headline is linked via it's ID property 2550 | ;; or through other means. Use the default href. 2551 | ((member type '("id" "fuzzy")) 2552 | (format "sec-%s" 2553 | (mapconcat 'number-to-string 2554 | (org-export-get-headline-number 2555 | destination info) "-"))) 2556 | (t (error "Shouldn't reach here")))) 2557 | ;; What description to use? Previously, we'd look if 2558 | ;; section numbering was enabled, and use that 2559 | ;; number, however, rendering a link description as 2560 | ;; number seems less useful than destination title. 2561 | ;; And since Org 8.3 there has been a lot of 2562 | ;; dependencies on :section-number, so will do 2563 | ;; something simple here for now. 2564 | (desc 2565 | (or desc (org-export-data (org-element-property 2566 | :title destination) info)))) 2567 | (format "%s" 2568 | href attributes desc))) 2569 | ;; Fuzzy link points to a target or an element. 2570 | (t 2571 | (let* ((path path) 2572 | (org-twbs-standalone-image-predicate 'org-twbs--has-caption-p) 2573 | (number (cond 2574 | (desc nil) 2575 | ((org-twbs-standalone-image-p destination info) 2576 | (org-export-get-ordinal 2577 | (org-element-map destination 'link 2578 | 'identity info t) 2579 | info 'link 'org-twbs-standalone-image-p)) 2580 | (t (org-export-get-ordinal 2581 | destination info nil 'org-twbs--has-caption-p)))) 2582 | (desc (cond (desc) 2583 | ((not number) "No description for this link") 2584 | ((numberp number) (number-to-string number)) 2585 | (t (mapconcat 'number-to-string number "."))))) 2586 | (format "%s" path attributes desc)))))) 2587 | ;; Coderef: replace link with the reference name or the 2588 | ;; equivalent line number. 2589 | ((string= type "coderef") 2590 | (let ((fragment (concat "coderef-" (org-twbs-encode-plain-text path)))) 2591 | (format "%s" 2592 | fragment 2593 | (format "class=\"coderef\" onmouseover=\"CodeHighlightOn(this, \ 2594 | '%s');\" onmouseout=\"CodeHighlightOff(this, '%s');\"" 2595 | fragment fragment) 2596 | attributes 2597 | (format (org-export-get-coderef-format path desc) 2598 | (org-export-resolve-coderef path info))))) 2599 | ;; External link with a description part. 2600 | ((and path desc) (format "%s" 2601 | (org-twbs-encode-plain-text path) 2602 | attributes 2603 | desc)) 2604 | ;; External link without a description part. 2605 | (path (let ((path (org-twbs-encode-plain-text path))) 2606 | (format "%s" path attributes path))) 2607 | ;; No path, only description. Try to do something useful. 2608 | (t (format "%s" desc))))) 2609 | 2610 | ;;;; Paragraph 2611 | 2612 | (defun org-twbs-paragraph (paragraph contents info) 2613 | "Transcode a PARAGRAPH element from Org to HTML. 2614 | CONTENTS is the contents of the paragraph, as a string. INFO is 2615 | the plist used as a communication channel." 2616 | (let* ((parent (org-export-get-parent paragraph)) 2617 | (parent-type (org-element-type parent)) 2618 | (style '((footnote-definition " class=\"footpara\""))) 2619 | (extra (or (cadr (assoc parent-type style)) ""))) 2620 | (cond 2621 | ((and (eq (org-element-type parent) 'item) 2622 | (= (org-element-property :begin paragraph) 2623 | (org-element-property :contents-begin parent))) 2624 | ;; Leading paragraph in a list item have no tags. 2625 | contents) 2626 | ((org-twbs-standalone-image-p paragraph info) 2627 | ;; Standalone image. 2628 | (let ((caption 2629 | (let ((raw (org-export-data 2630 | (org-export-get-caption paragraph) info)) 2631 | (org-twbs-standalone-image-predicate 2632 | 'org-twbs--has-caption-p)) 2633 | (if (not (org-string-nw-p raw)) raw 2634 | (concat 2635 | "" 2636 | (format (org-twbs--translate "Figure %d:" info) 2637 | (org-export-get-ordinal 2638 | (org-element-map paragraph 'link 2639 | 'identity info t) 2640 | info nil 'org-twbs-standalone-image-p)) 2641 | " " raw)))) 2642 | (label (org-element-property :name paragraph))) 2643 | (org-twbs--wrap-image contents info caption label))) 2644 | ;; Regular paragraph. 2645 | (t (format "\n%s

" extra contents))))) 2646 | 2647 | ;;;; Plain List 2648 | 2649 | ;; FIXME Maybe arg1 is not needed because
  • already sets 2650 | ;; the correct value for the item counter 2651 | (defun org-twbs-begin-plain-list (type &optional arg1) 2652 | "Insert the beginning of the HTML list depending on TYPE. 2653 | When ARG1 is a string, use it as the start parameter for ordered 2654 | lists." 2655 | (case type 2656 | (ordered 2657 | (format "
      " 2658 | (if arg1 (format " start=\"%d\"" arg1) ""))) 2659 | (unordered "
        ") 2660 | (descriptive "
        "))) 2661 | 2662 | (defun org-twbs-end-plain-list (type) 2663 | "Insert the end of the HTML list depending on TYPE." 2664 | (case type 2665 | (ordered "
    ") 2666 | (unordered "") 2667 | (descriptive ""))) 2668 | 2669 | (defun org-twbs-plain-list (plain-list contents info) 2670 | "Transcode a PLAIN-LIST element from Org to HTML. 2671 | CONTENTS is the contents of the list. INFO is a plist holding 2672 | contextual information." 2673 | (let* (arg1 ;; (assoc :counter (org-element-map plain-list 'item 2674 | (type (org-element-property :type plain-list))) 2675 | (format "%s\n%s%s" 2676 | (org-twbs-begin-plain-list type) 2677 | contents (org-twbs-end-plain-list type)))) 2678 | 2679 | ;;;; Plain Text 2680 | 2681 | (defun org-twbs-convert-special-strings (string) 2682 | "Convert special characters in STRING to HTML." 2683 | (let ((all org-twbs-special-string-regexps) 2684 | e a re rpl start) 2685 | (while (setq a (pop all)) 2686 | (setq re (car a) rpl (cdr a) start 0) 2687 | (while (string-match re string start) 2688 | (setq string (replace-match rpl t nil string)))) 2689 | string)) 2690 | 2691 | (defun org-twbs-encode-plain-text (text) 2692 | "Convert plain text characters from TEXT to HTML equivalent. 2693 | Possible conversions are set in `org-twbs-protect-char-alist'." 2694 | (mapc 2695 | (lambda (pair) 2696 | (setq text (replace-regexp-in-string (car pair) (cdr pair) text t t))) 2697 | org-twbs-protect-char-alist) 2698 | text) 2699 | 2700 | (defun org-twbs-plain-text (text info) 2701 | "Transcode a TEXT string from Org to HTML. 2702 | TEXT is the string to transcode. INFO is a plist holding 2703 | contextual information." 2704 | (let ((output text)) 2705 | ;; Protect following characters: <, >, &. 2706 | (setq output (org-twbs-encode-plain-text output)) 2707 | ;; Handle smart quotes. Be sure to provide original string since 2708 | ;; OUTPUT may have been modified. 2709 | (when (plist-get info :with-smart-quotes) 2710 | (setq output (org-export-activate-smart-quotes output :html info text))) 2711 | ;; Handle special strings. 2712 | (when (plist-get info :with-special-strings) 2713 | (setq output (org-twbs-convert-special-strings output))) 2714 | ;; Handle break preservation if required. 2715 | (when (plist-get info :preserve-breaks) 2716 | (setq output 2717 | (replace-regexp-in-string 2718 | "\\(\\\\\\\\\\)?[ \t]*\n" 2719 | (concat (org-twbs-close-tag "br" nil info) "\n") output))) 2720 | ;; Return value. 2721 | output)) 2722 | 2723 | 2724 | ;; Planning 2725 | 2726 | (defun org-twbs-planning (planning contents info) 2727 | "Transcode a PLANNING element from Org to HTML. 2728 | CONTENTS is nil. INFO is a plist used as a communication 2729 | channel." 2730 | (let ((span-fmt "%s %s")) 2731 | (format 2732 | "

    %s

    " 2733 | (mapconcat 2734 | 'identity 2735 | (delq nil 2736 | (list 2737 | (let ((closed (org-element-property :closed planning))) 2738 | (when closed 2739 | (format span-fmt org-closed-string 2740 | (org-timestamp-translate closed)))) 2741 | (let ((deadline (org-element-property :deadline planning))) 2742 | (when deadline 2743 | (format span-fmt org-deadline-string 2744 | (org-timestamp-translate deadline)))) 2745 | (let ((scheduled (org-element-property :scheduled planning))) 2746 | (when scheduled 2747 | (format span-fmt org-scheduled-string 2748 | (org-timestamp-translate scheduled)))))) 2749 | " ")))) 2750 | 2751 | ;;;; Property Drawer 2752 | 2753 | (defun org-twbs-property-drawer (property-drawer contents info) 2754 | "Transcode a PROPERTY-DRAWER element from Org to HTML. 2755 | CONTENTS is nil. INFO is a plist holding contextual 2756 | information." 2757 | ;; The property drawer isn't exported but we want separating blank 2758 | ;; lines nonetheless. 2759 | "") 2760 | 2761 | ;;;; Quote Block 2762 | 2763 | (defun org-twbs-quote-block (quote-block contents info) 2764 | "Transcode a QUOTE-BLOCK element from Org to HTML. 2765 | CONTENTS holds the contents of the block. INFO is a plist 2766 | holding contextual information." 2767 | (format "
    \n%s
    " contents)) 2768 | 2769 | ;;;; Quote Section 2770 | 2771 | (defun org-twbs-quote-section (quote-section contents info) 2772 | "Transcode a QUOTE-SECTION element from Org to HTML. 2773 | CONTENTS is nil. INFO is a plist holding contextual information." 2774 | (let ((value (org-remove-indentation 2775 | (org-element-property :value quote-section)))) 2776 | (when value (format "
    \n%s
    " value)))) 2777 | 2778 | ;;;; Section 2779 | 2780 | (defun org-twbs-section (section contents info) 2781 | "Transcode a SECTION element from Org to HTML. 2782 | CONTENTS holds the contents of the section. INFO is a plist 2783 | holding contextual information." 2784 | (let ((parent (org-export-get-parent-headline section))) 2785 | ;; Before first headline: no container, just return CONTENTS. 2786 | (if (not parent) contents 2787 | ;; Get div's class and id references. 2788 | (let* ((class-num (+ (org-export-get-relative-level parent info) 2789 | (1- org-twbs-toplevel-hlevel))) 2790 | (section-number 2791 | (mapconcat 2792 | 'number-to-string 2793 | (org-export-get-headline-number parent info) "-"))) 2794 | ;; Build return value. 2795 | (format "
    \n%s
    " 2796 | class-num 2797 | (or (org-element-property :CUSTOM_ID parent) section-number) 2798 | (or contents "")))))) 2799 | 2800 | ;;;; Radio Target 2801 | 2802 | (defun org-twbs-radio-target (radio-target text info) 2803 | "Transcode a RADIO-TARGET object from Org to HTML. 2804 | TEXT is the text of the target. INFO is a plist holding 2805 | contextual information." 2806 | (let ((id (org-element-property :value radio-target))) 2807 | (org-twbs--anchor id text))) 2808 | 2809 | ;;;; Special Block 2810 | 2811 | (defun org-twbs-special-block (special-block contents info) 2812 | "Transcode a SPECIAL-BLOCK element from Org to HTML. 2813 | CONTENTS holds the contents of the block. INFO is a plist 2814 | holding contextual information." 2815 | (let* ((block-type (downcase 2816 | (org-element-property :type special-block))) 2817 | (contents (or contents "")) 2818 | (is-html5-tag? (member block-type org-html-html5-elements)) 2819 | (attributes (org-export-read-attribute :attr_html special-block))) 2820 | (unless is-html5-tag? 2821 | (let ((class (plist-get attributes :class))) 2822 | (setq attributes (plist-put attributes :class 2823 | (if class (concat class " " block-type) 2824 | block-type))))) 2825 | (setq attributes (org-twbs--make-attribute-string attributes)) 2826 | (when (not (equal attributes "")) 2827 | (setq attributes (concat " " attributes))) 2828 | (if is-html5-tag? 2829 | (format "<%s%s>\n%s" block-type attributes contents block-type) 2830 | (format "\n%s\n
  • " attributes contents)))) 2831 | 2832 | ;;;; Src Block 2833 | 2834 | (defun org-twbs-src-block (src-block contents info) 2835 | "Transcode a SRC-BLOCK element from Org to HTML. 2836 | CONTENTS holds the contents of the item. INFO is a plist holding 2837 | contextual information." 2838 | (if (org-export-read-attribute :attr_html src-block :textarea) 2839 | (org-twbs--textarea-block src-block) 2840 | (let ((lang (org-element-property :language src-block)) 2841 | (caption (org-export-get-caption src-block)) 2842 | (code (org-twbs-format-code src-block info)) 2843 | (label (let ((lbl (org-element-property :name src-block))) 2844 | (if (not lbl) "" 2845 | (format " id=\"%s\"" 2846 | lbl))))) 2847 | (if (not lang) (format "
    \n%s
    " label code) 2848 | (format 2849 | "
    \n%s%s\n
    " 2850 | (if (not caption) "" 2851 | (format "" 2852 | (org-export-data caption info))) 2853 | (format "\n
    %s
    " lang label code)))))) 2854 | 2855 | ;;;; Statistics Cookie 2856 | 2857 | (defun org-twbs-statistics-cookie (statistics-cookie contents info) 2858 | "Transcode a STATISTICS-COOKIE object from Org to HTML. 2859 | CONTENTS is nil. INFO is a plist holding contextual information." 2860 | (let ((cookie-value (org-element-property :value statistics-cookie))) 2861 | (format "%s" cookie-value))) 2862 | 2863 | ;;;; Strike-Through 2864 | 2865 | (defun org-twbs-strike-through (strike-through contents info) 2866 | "Transcode STRIKE-THROUGH from Org to HTML. 2867 | CONTENTS is the text with strike-through markup. INFO is a plist 2868 | holding contextual information." 2869 | (format (or (cdr (assq 'strike-through org-twbs-text-markup-alist)) "%s") 2870 | contents)) 2871 | 2872 | ;;;; Subscript 2873 | 2874 | (defun org-twbs-subscript (subscript contents info) 2875 | "Transcode a SUBSCRIPT object from Org to HTML. 2876 | CONTENTS is the contents of the object. INFO is a plist holding 2877 | contextual information." 2878 | (format "%s" contents)) 2879 | 2880 | ;;;; Superscript 2881 | 2882 | (defun org-twbs-superscript (superscript contents info) 2883 | "Transcode a SUPERSCRIPT object from Org to HTML. 2884 | CONTENTS is the contents of the object. INFO is a plist holding 2885 | contextual information." 2886 | (format "%s" contents)) 2887 | 2888 | ;;;; Table Cell 2889 | 2890 | (defun org-twbs-table-cell (table-cell contents info) 2891 | "Transcode a TABLE-CELL element from Org to HTML. 2892 | CONTENTS is nil. INFO is a plist used as a communication 2893 | channel." 2894 | (let* ((table-row (org-export-get-parent table-cell)) 2895 | (table (org-export-get-parent-table table-cell)) 2896 | (cell-attrs 2897 | (if (not org-twbs-table-align-individual-fields) "" 2898 | (format (if (and (boundp 'org-twbs-format-table-no-css) 2899 | org-twbs-format-table-no-css) 2900 | " align=\"%s\"" " class=\"text-%s\"") 2901 | (org-export-table-cell-alignment table-cell info))))) 2902 | (when (or (not contents) (string= "" (org-trim contents))) 2903 | (setq contents " ")) 2904 | (cond 2905 | ((and (org-export-table-has-header-p table info) 2906 | (= 1 (org-export-table-row-group table-row info))) 2907 | (concat "\n" (format (car org-twbs-table-header-tags) "col" cell-attrs) 2908 | contents (cdr org-twbs-table-header-tags))) 2909 | ((and org-twbs-table-use-header-tags-for-first-column 2910 | (zerop (cdr (org-export-table-cell-address table-cell info)))) 2911 | (concat "\n" (format (car org-twbs-table-header-tags) "row" cell-attrs) 2912 | contents (cdr org-twbs-table-header-tags))) 2913 | (t (concat "\n" (format (car org-twbs-table-data-tags) cell-attrs) 2914 | contents (cdr org-twbs-table-data-tags)))))) 2915 | 2916 | ;;;; Table Row 2917 | 2918 | (defun org-twbs-table-row (table-row contents info) 2919 | "Transcode a TABLE-ROW element from Org to HTML. 2920 | CONTENTS is the contents of the row. INFO is a plist used as a 2921 | communication channel." 2922 | ;; Rules are ignored since table separators are deduced from 2923 | ;; borders of the current row. 2924 | (when (eq (org-element-property :type table-row) 'standard) 2925 | (let* ((rowgroup-number (org-export-table-row-group table-row info)) 2926 | (row-number (org-export-table-row-number table-row info)) 2927 | (start-rowgroup-p 2928 | (org-export-table-row-starts-rowgroup-p table-row info)) 2929 | (end-rowgroup-p 2930 | (org-export-table-row-ends-rowgroup-p table-row info)) 2931 | ;; `top-row-p' and `end-rowgroup-p' are not used directly 2932 | ;; but should be set so that `org-twbs-table-row-tags' can 2933 | ;; use them (see the docstring of this variable.) 2934 | (top-row-p (and (equal start-rowgroup-p '(top)) 2935 | (equal end-rowgroup-p '(below top)))) 2936 | (bottom-row-p (and (equal start-rowgroup-p '(above)) 2937 | (equal end-rowgroup-p '(bottom above)))) 2938 | (rowgroup-tags 2939 | (cond 2940 | ;; Case 1: Row belongs to second or subsequent rowgroups. 2941 | ((not (= 1 rowgroup-number)) 2942 | '("" . "\n")) 2943 | ;; Case 2: Row is from first rowgroup. Table has >=1 rowgroups. 2944 | ((org-export-table-has-header-p 2945 | (org-export-get-parent-table table-row) info) 2946 | '("" . "\n")) 2947 | ;; Case 2: Row is from first and only row group. 2948 | (t '("" . "\n"))))) 2949 | (concat 2950 | ;; Begin a rowgroup? 2951 | (when start-rowgroup-p (car rowgroup-tags)) 2952 | ;; Actual table row 2953 | (concat "\n" (eval (car org-twbs-table-row-tags)) 2954 | contents 2955 | "\n" 2956 | (eval (cdr org-twbs-table-row-tags))) 2957 | ;; End a rowgroup? 2958 | (when end-rowgroup-p (cdr rowgroup-tags)))))) 2959 | 2960 | ;;;; Table 2961 | 2962 | (defun org-twbs-table-first-row-data-cells (table info) 2963 | "Transcode the first row of TABLE. 2964 | INFO is a plist used as a communication channel." 2965 | (let ((table-row 2966 | (org-element-map table 'table-row 2967 | (lambda (row) 2968 | (unless (eq (org-element-property :type row) 'rule) row)) 2969 | info 'first-match)) 2970 | (special-column-p (org-export-table-has-special-column-p table))) 2971 | (if (not special-column-p) (org-element-contents table-row) 2972 | (cdr (org-element-contents table-row))))) 2973 | 2974 | (defun org-twbs-table--table.el-table (table info) 2975 | "Format table.el tables into HTML. 2976 | INFO is a plist used as a communication channel." 2977 | (when (eq (org-element-property :type table) 'table.el) 2978 | (require 'table) 2979 | (let ((outbuf (with-current-buffer 2980 | (get-buffer-create "*org-export-table*") 2981 | (erase-buffer) (current-buffer)))) 2982 | (with-temp-buffer 2983 | (insert (org-element-property :value table)) 2984 | (goto-char 1) 2985 | (re-search-forward "^[ \t]*|[^|]" nil t) 2986 | (table-generate-source 'html outbuf)) 2987 | (with-current-buffer outbuf 2988 | (prog1 (org-trim (buffer-string)) 2989 | (kill-buffer) ))))) 2990 | 2991 | (defun org-twbs-table (table contents info) 2992 | "Transcode a TABLE element from Org to HTML. 2993 | CONTENTS is the contents of the table. INFO is a plist holding 2994 | contextual information." 2995 | (case (org-element-property :type table) 2996 | ;; Case 1: table.el table. Convert it using appropriate tools. 2997 | (table.el (org-twbs-table--table.el-table table info)) 2998 | ;; Case 2: Standard table. 2999 | (t 3000 | (let* ((label (org-element-property :name table)) 3001 | (caption (org-export-get-caption table)) 3002 | (number (org-export-get-ordinal 3003 | table info nil 'org-twbs--has-caption-p)) 3004 | (attributes 3005 | (org-twbs--make-attribute-string 3006 | (org-combine-plists 3007 | (and label (list :id label)) 3008 | (plist-get info :html-table-attributes) 3009 | (org-export-read-attribute :attr_html table)))) 3010 | (alignspec 3011 | (if (and (boundp 'org-twbs-format-table-no-css) 3012 | org-twbs-format-table-no-css) 3013 | "align=\"%s\"" "class=\"%s\"")) 3014 | (table-column-specs 3015 | (function 3016 | (lambda (table info) 3017 | (mapconcat 3018 | (lambda (table-cell) 3019 | (let ((alignment (org-export-table-cell-alignment 3020 | table-cell info))) 3021 | (concat 3022 | ;; Begin a colgroup? 3023 | (when (org-export-table-cell-starts-colgroup-p 3024 | table-cell info) 3025 | "\n") 3026 | ;; Add a column. Also specify it's alignment. 3027 | (format "\n%s" 3028 | (org-twbs-close-tag 3029 | "col" (concat " " (format alignspec alignment)) info)) 3030 | ;; End a colgroup? 3031 | (when (org-export-table-cell-ends-colgroup-p 3032 | table-cell info) 3033 | "\n")))) 3034 | (org-twbs-table-first-row-data-cells table info) "\n"))))) 3035 | (format "\n%s\n%s\n%s" 3036 | (if (equal attributes "") "" (concat " " attributes)) 3037 | (if (not caption) "" 3038 | (format (if org-twbs-table-caption-above 3039 | "%s" 3040 | "%s") 3041 | (concat 3042 | "" 3043 | (format (org-twbs--translate "Table %d:" info) number) 3044 | " " (org-export-data caption info)))) 3045 | (funcall table-column-specs table info) 3046 | contents))))) 3047 | 3048 | ;;;; Target 3049 | 3050 | (defun org-twbs-target (target contents info) 3051 | "Transcode a TARGET object from Org to HTML. 3052 | CONTENTS is nil. INFO is a plist holding contextual 3053 | information." 3054 | (let ((id (org-element-property :value target))) 3055 | (org-twbs--anchor id))) 3056 | 3057 | ;;;; Timestamp 3058 | 3059 | (defun org-twbs-timestamp (timestamp contents info) 3060 | "Transcode a TIMESTAMP object from Org to HTML. 3061 | CONTENTS is nil. INFO is a plist holding contextual 3062 | information." 3063 | (let ((value (org-twbs-plain-text 3064 | (org-timestamp-translate timestamp) info))) 3065 | (format "%s" 3066 | (replace-regexp-in-string "--" "–" value)))) 3067 | 3068 | ;;;; Underline 3069 | 3070 | (defun org-twbs-underline (underline contents info) 3071 | "Transcode UNDERLINE from Org to HTML. 3072 | CONTENTS is the text with underline markup. INFO is a plist 3073 | holding contextual information." 3074 | (format (or (cdr (assq 'underline org-twbs-text-markup-alist)) "%s") 3075 | contents)) 3076 | 3077 | ;;;; Verbatim 3078 | 3079 | (defun org-twbs-verbatim (verbatim contents info) 3080 | "Transcode VERBATIM from Org to HTML. 3081 | CONTENTS is nil. INFO is a plist holding contextual 3082 | information." 3083 | (format (or (cdr (assq 'verbatim org-twbs-text-markup-alist)) "%s") 3084 | (org-twbs-encode-plain-text (org-element-property :value verbatim)))) 3085 | 3086 | ;;;; Verse Block 3087 | 3088 | (defun org-twbs-verse-block (verse-block contents info) 3089 | "Transcode a VERSE-BLOCK element from Org to HTML. 3090 | CONTENTS is verse block contents. INFO is a plist holding 3091 | contextual information." 3092 | ;; Replace each newline character with line break. Also replace 3093 | ;; each blank line with a line break. 3094 | (setq contents (replace-regexp-in-string 3095 | "^ *\\\\\\\\$" (format "%s\n" (org-twbs-close-tag "br" nil info)) 3096 | (replace-regexp-in-string 3097 | "\\(\\\\\\\\\\)?[ \t]*\n" 3098 | (format "%s\n" (org-twbs-close-tag "br" nil info)) contents))) 3099 | ;; Replace each white space at beginning of a line with a 3100 | ;; non-breaking space. 3101 | (while (string-match "^[ \t]+" contents) 3102 | (let* ((num-ws (length (match-string 0 contents))) 3103 | (ws (let (out) (dotimes (i num-ws out) 3104 | (setq out (concat out " ")))))) 3105 | (setq contents (replace-match ws nil t contents)))) 3106 | (format "

    \n%s

    " contents)) 3107 | 3108 | 3109 | ;;; Filter Functions 3110 | 3111 | (defun org-twbs-final-function (contents backend info) 3112 | "Filter to indent the HTML and convert HTML entities." 3113 | (with-temp-buffer 3114 | (insert contents) 3115 | (set-auto-mode t) 3116 | (if org-twbs-indent 3117 | (indent-region (point-min) (point-max))) 3118 | (when org-twbs-use-unicode-chars 3119 | (require 'mm-url) 3120 | (mm-url-decode-entities)) 3121 | (buffer-substring-no-properties (point-min) (point-max)))) 3122 | 3123 | 3124 | ;;; End-user functions 3125 | 3126 | ;;;###autoload 3127 | (defun org-twbs-export-as-html 3128 | (&optional async subtreep visible-only body-only ext-plist) 3129 | "Export current buffer to an HTML buffer. 3130 | 3131 | If narrowing is active in the current buffer, only export its 3132 | narrowed part. 3133 | 3134 | If a region is active, export that region. 3135 | 3136 | A non-nil optional argument ASYNC means the process should happen 3137 | asynchronously. The resulting buffer should be accessible 3138 | through the `org-export-stack' interface. 3139 | 3140 | When optional argument SUBTREEP is non-nil, export the sub-tree 3141 | at point, extracting information from the headline properties 3142 | first. 3143 | 3144 | When optional argument VISIBLE-ONLY is non-nil, don't export 3145 | contents of hidden elements. 3146 | 3147 | When optional argument BODY-ONLY is non-nil, only write code 3148 | between \"\" and \"\" tags. 3149 | 3150 | EXT-PLIST, when provided, is a property list with external 3151 | parameters overriding Org default settings, but still inferior to 3152 | file-local settings. 3153 | 3154 | Export is done in a buffer named \"*Org HTML Export*\", which 3155 | will be displayed when `org-export-show-temporary-export-buffer' 3156 | is non-nil." 3157 | (interactive) 3158 | (org-export-to-buffer 'twbs "*Org HTML Export*" 3159 | async subtreep visible-only body-only ext-plist 3160 | (lambda () (set-auto-mode t)))) 3161 | 3162 | ;;;###autoload 3163 | (defun org-twbs-convert-region-to-html () 3164 | "Assume the current region has org-mode syntax, and convert it to HTML. 3165 | This can be used in any buffer. For example, you can write an 3166 | itemized list in org-mode syntax in an HTML buffer and use this 3167 | command to convert it." 3168 | (interactive) 3169 | (org-export-replace-region-by 'twbs)) 3170 | 3171 | ;;;###autoload 3172 | (defun org-twbs-export-to-html 3173 | (&optional async subtreep visible-only body-only ext-plist) 3174 | "Export current buffer to a HTML file. 3175 | 3176 | If narrowing is active in the current buffer, only export its 3177 | narrowed part. 3178 | 3179 | If a region is active, export that region. 3180 | 3181 | A non-nil optional argument ASYNC means the process should happen 3182 | asynchronously. The resulting file should be accessible through 3183 | the `org-export-stack' interface. 3184 | 3185 | When optional argument SUBTREEP is non-nil, export the sub-tree 3186 | at point, extracting information from the headline properties 3187 | first. 3188 | 3189 | When optional argument VISIBLE-ONLY is non-nil, don't export 3190 | contents of hidden elements. 3191 | 3192 | When optional argument BODY-ONLY is non-nil, only write code 3193 | between \"\" and \"\" tags. 3194 | 3195 | EXT-PLIST, when provided, is a property list with external 3196 | parameters overriding Org default settings, but still inferior to 3197 | file-local settings. 3198 | 3199 | Return output file's name." 3200 | (interactive) 3201 | (let* ((extension (concat "." org-twbs-extension)) 3202 | (file (org-export-output-file-name extension subtreep)) 3203 | (org-export-coding-system org-twbs-coding-system)) 3204 | (org-export-to-file 'twbs file 3205 | async subtreep visible-only body-only ext-plist))) 3206 | 3207 | ;;;###autoload 3208 | (defun org-twbs-publish-to-html (plist filename pub-dir) 3209 | "Publish an org file to HTML. 3210 | 3211 | FILENAME is the filename of the Org file to be published. PLIST 3212 | is the property list for the given project. PUB-DIR is the 3213 | publishing directory. 3214 | 3215 | Return output file name." 3216 | (org-publish-org-to 'twbs filename 3217 | (concat "." (or (plist-get plist :html-extension) 3218 | org-twbs-extension "html")) 3219 | plist pub-dir)) 3220 | 3221 | 3222 | (provide 'ox-twbs) 3223 | 3224 | ;; Local variables: 3225 | ;; coding: utf-8 3226 | ;; End: 3227 | 3228 | ;;; ox-twbs.el ends here 3229 | --------------------------------------------------------------------------------