├── .gitignore ├── .gitmodules ├── README.md ├── example-image.svg ├── example.html ├── example.org ├── production ├── common.css ├── org-html-slideshow.js ├── presenter.css ├── projection.css └── screen.css ├── project.clj └── src ├── cljs └── org_html_slideshow │ └── main.cljs └── css ├── common.css ├── presenter.css ├── projection.css └── screen.css /.gitignore: -------------------------------------------------------------------------------- 1 | /lib/jars 2 | /lib/closure 3 | /out/development 4 | *~ 5 | #* 6 | /.lein* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/one"] 2 | path = lib/one 3 | url = https://github.com/brentonashworth/one.git 4 | [submodule "lib/domina"] 5 | path = lib/domina 6 | url = https://github.com/levand/domina.git 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Org-HTML-Slideshow 2 | 3 | You have an outline written in Emacs Org-Mode. Export it to HTML. Add 4 | Org-HTML-Slideshow, and you have an interactive slide presentation 5 | that runs in a web browser! 6 | 7 | Supports anything Org-Mode can export: bulleted lists, code blocks, 8 | images, etc. 9 | 10 | Should work in most modern web browsers; tested only in Google Chrome 11 | 29.0.1547.76. 12 | 13 | Org-HTML-Slideshow is written in 14 | [ClojureScript](https://github.com/clojure/clojurescript). 15 | 16 | 17 | 18 | ## Recommended Emacs Platform 19 | 20 | * [GNU Emacs](http://www.gnu.org/software/emacs/) version 24+ 21 | * Check version with `M-x emacs-version` 22 | * [Org-Mode](http://orgmode.org/) version 8+ 23 | * Check version by opening an .org file and `M-x org-version` 24 | * [Htmlize](http://www.emacswiki.org/emacs/Htmlize) version 1.37+ 25 | 26 | For Emacs 23 and Org-mode 7, use the older version of 27 | org-html-slideshow on the Git branch [emacs23-org7](https://github.com/relevance/org-html-slideshow/tree/emacs23-org7) 28 | 29 | 30 | ## Using in Your Org-mode Files 31 | 32 | **Step 1.** Copy the following files from the `production` directory 33 | to the directory containing your .org file: 34 | 35 | org-html-slideshow.js 36 | common.css 37 | presenter.css 38 | projection.css 39 | screen.css 40 | 41 | **Step 2.** Add the following lines to the **bottom** of your .org file: 42 | 43 | #+OPTIONS: num:nil tags:t 44 | 45 | #+TAGS: slide(s) 46 | 47 | #+HTML_HEAD_EXTRA: 48 | #+HTML_HEAD_EXTRA: 49 | #+HTML_HEAD_EXTRA: 50 | #+HTML_HEAD_EXTRA: 51 | 52 | #+BEGIN_HTML 53 | 54 | #+END_HTML 55 | 56 | # Local Variables: 57 | # org-html-head-include-default-style: nil 58 | # org-html-head-include-scripts: nil 59 | # End: 60 | 61 | **Step 3.** Close and re-open your .org file. Type `y` to accept the 62 | buffer-local variables. 63 | 64 | 65 | ### Adding Tags to Your Org-Mode File 66 | 67 | For each org-mode headline that you want to make into a slide, add the 68 | `:slide:` tag by typing `C-c C-c s RET` with the cursor on the 69 | headline. 70 | 71 | Additional tags will be added as CSS classes on the slides. 72 | 73 | Read more about [tags](http://orgmode.org/manual/Tags.html) 74 | in the Org-Mode manual. 75 | 76 | See the files `example.org` and `example.html` for more examples of 77 | things you can do with Org-Mode. 78 | 79 | 80 | ### Exporting to HTML 81 | 82 | Type `C-c C-e h h` in your .org file to export as HTML. Repeat whenever 83 | you modify the .org file. 84 | 85 | Read more about [HTML export](http://orgmode.org/manual/HTML-export.html) 86 | in the Org-Mode manual. 87 | 88 | 89 | ### Playing the Slide Show 90 | 91 | Open the generated HTML file in your browser and type `t` to begin the 92 | slide show. 93 | 94 | The Space, Enter, Page Down, and `n` keys advance to the next slide. 95 | 96 | The Page Up and `p` keys go back to the previous slide. 97 | 98 | The `t` key toggles between slide-show and normal views. 99 | 100 | Move the mouse to the lower right-hand corner of the screen to show a 101 | control panel with links to navigate the slide show by mouse. 102 | 103 | 104 | ### Presenter Preview 105 | 106 | While playing the slide show, click on the control panel's "Open 107 | presenter preview" link. This will open a new window showing the 108 | currently visible slide, upcoming slide, wall clock time, and elapsed 109 | time since the presentation began. 110 | 111 | 112 | ### Presenter Notes 113 | 114 | Add a sub-heading with the tag `:notes:` beneath a `:slide:` 115 | heading. The content under the notes heading will be displayed in the 116 | Presenter Preview window with the slide. 117 | 118 | 119 | ### Changing Styles 120 | 121 | You can modify the appearance of your slides by editing the stylesheets: 122 | 123 | * `projection.css` affects only the slide-show view 124 | * `screen.css` affects only the normal view 125 | * `common.css` affects both 126 | * `presenter.css` affects only the presenter preview 127 | 128 | 129 | 130 | ## Development 131 | 132 | To develop and build org-html-slideshow, you will need the following 133 | programs already installed: 134 | 135 | * [Git][git] 136 | * [Leiningen][lein] 2.0.0 or later 137 | * [Java Development Kit][jdk] (JDK) 1.6 or later 138 | 139 | [git]: http://git-scm.com/ 140 | [lein]: https://github.com/technomancy/leiningen 141 | [jdk]: http://www.oracle.com/technetwork/java/javase/downloads/index.html 142 | 143 | 144 | In the top-level directory of this project, run the following commands 145 | to download additional dependencies: 146 | 147 | git submodule init 148 | git submodule update 149 | 150 | 151 | ### Rebuilding Development Examples 152 | 153 | Build the development version (one file, unoptimized, readable 154 | JavaScript source) with: 155 | 156 | lein cljsbuild once development 157 | 158 | The JavaScript file will be written to `out/development/org-html-slideshow.js`. 159 | 160 | You will need [Emacs](http://www.gnu.org/software/emacs/) (version 24+) and 161 | [org-mode](http://orgmode.org/) (version 8+) to generate the HTML. 162 | 163 | Open `example.org` in Emacs and type `C-e h o`. Emacs will generate 164 | an HTML file and open it in your default browser. Type `t` to begin 165 | the slide show. 166 | 167 | 168 | ### Rebuilding Production Files 169 | 170 | Build the production version (one file, optimized, not human-readable) 171 | with: 172 | 173 | lein cljsbuild once production 174 | 175 | The JavaScript file will be written to `production/org-html-slideshow.js`. 176 | 177 | 178 | ## Change Log 179 | 180 | * **27-Sept-2013:** Switch to Emacs 24 and Org-mode 8 181 | 182 | Org-mode 8 introduced breaking changes in the way it exports HTML, 183 | necessitating breaking changes in org-html-slideshow. 184 | 185 | For Emacs 23 and Org-mode 7, use the older version of 186 | org-html-slideshow on the Git branch [emacs23-org7](https://github.com/relevance/org-html-slideshow/tree/emacs23-org7) 187 | 188 | * **11-Dec-2011:** Initial release 189 | 190 | 191 | ## Copyright & Contributions 192 | 193 | There is no copyright. I dedicate this work to the public domain. 194 | 195 | I am not actively developing new features for this project. 196 | 197 | 198 | ### Contributors 199 | 200 | * Stuart Sierra (primary author) 201 | * Craig Andera 202 | * Alex Redington 203 | -------------------------------------------------------------------------------- /example-image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 39 | 46 | 53 | 54 | 74 | 79 | 81 | 86 | 91 | 96 | 100 | 105 | 110 | 115 | 120 | 124 | 128 | 133 | 138 | 139 | 142 | 147 | 152 | 157 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /example.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Example Presentation 7 | 8 | 9 | 10 | 88 | 89 | 90 | 91 | 92 | 138 | 139 | 140 |
141 |

Example Presentation

142 |

Type T to begin the slide show.

143 | 144 |
145 |

Org-HTML-Slideshow   slide

146 |
147 |

148 | Make slides from Emacs Org-Mode! 149 |

150 |
151 | 152 |
153 |

Making Slides   slide

154 |
155 |

156 | Org-Mode headlines with the :slide: tag will become slides. 157 |

158 |
159 |
160 |
161 |

Headlines Don't Have to be Slides

162 |
163 |

164 | This section doesn't have a :slide: tag, so it will not become a slide, although it is still part of the exported HTML document. 165 |

166 |
167 |
168 |
169 |

Use Lists For Bullets   slide

170 |
171 |
    172 |
  • Use Org-Mode lists for bullet points 173 |
  • 174 |
  • You can make nested bullet lists 175 |
      176 |
    • With sub-lists 177 |
    • 178 |
    • Like this 179 |
    • 180 |
    181 |
  • 182 |
183 |
184 |
185 |
186 |

Or Low-Level Headings   slide

187 |
188 |
195 |
196 |
197 |

Slides Can Be Nested   slide

198 |
199 |

200 | You can use the structure of the Org-Mode document to group your slides. 201 |

202 | 203 |

204 | For example, this slide is a level-2 Org-Mode heading. 205 |

206 |
207 | 208 |
209 |

Slide Headings Can Be Nested   slide

210 |
211 |

212 | This slide is a level-3 Org-Mode heading, inside the previous one. 213 |

214 |
215 |
216 |
217 |
218 |
219 |

Presenter Notes   slide

220 |
221 |
    222 |
  • Slides can have presenter notes 223 |
  • 224 |
  • Add a sub-heading with the :notes: tag 225 |
  • 226 |
227 |
228 | 229 |
230 |

A Slide with Notes   slide

231 |
232 |
    233 |
  • This slide has notes 234 |
  • 235 |
  • Notes are only visible to presenter 236 |
  • 237 |
238 |
239 | 240 |
241 |

Notes   notes

242 |
243 |
    244 |
  • Presenter notes for this slide 245 |
  • 246 |
  • Not displayed as part of the slide 247 |
  • 248 |
  • Displayed in Presenter Preview window 249 |
  • 250 |
  • Only one :notes: section per slide allowed 251 |
  • 252 |
253 |
254 |
255 |
256 |
257 |
258 |

Source Code   slide

259 |
260 |

261 | Use begin_src/end_src blocks to include source code. 262 |

263 | 264 |
265 | 266 |
(defn example []
267 |   (println "This is sample source code."))
268 | 
269 |
270 |
271 | 272 |
273 |

Syntax Highlighting   slide

274 |
275 |
    276 |
  • Org-Mode HTML export uses htmlize.el 277 |
  • 278 |
  • Code in exported HTML will match your current Emacs theme 279 |
      280 |
    • Choose a theme that looks good on a projector! 281 |
    • 282 |
    283 |
  • 284 |
285 |
286 |
287 |
288 |

Syntax Highlighting with CSS Classes   slide

289 |
290 |
    291 |
  • Set the Emacs variable 292 |
      293 |
    • org-export-htmlize-output-type 294 |
    • 295 |
    • to the symbol css 296 |
    • 297 |
    • (Does not work as a buffer-local variable) 298 |
    • 299 |
    300 |
  • 301 |
  • Htmlize.el will add SPAN tags with CSS classes 302 |
      303 |
    • Named for each font face, e.g. org-comment 304 |
    • 305 |
    306 |
  • 307 |
  • Examine HTML output to see class names 308 |
  • 309 |
  • Add CSS styles to set colors 310 |
  • 311 |
312 |
313 |
314 |
315 |
316 |

Images   slide

317 |
318 |
    319 |
  • Slides can contain images 320 |
      321 |
    • Any file type a browser can display 322 |
    • 323 |
    324 |
  • 325 |
  • See also these Emacs variables: 326 |
      327 |
    • org-export-html-inline-images 328 |
    • 329 |
    • org-export-html-inline-image-extensions 330 |
        331 |
      • Controls which file types get exported 332 |
      • 333 |
      334 |
    • 335 |
    336 |
  • 337 |
  • See Images in HTML Export in the Org-Mode manual. 338 |
  • 339 |
340 |
341 | 342 |
343 |

Slide with Image   slide

344 |
345 |

346 | Make a file: link with the path to the image and no link text. 347 |

348 | 349 | 350 |
351 |

example-image.svg

352 |
353 | 354 |

355 | This example image is public-domain clip art by Josiah / yoderj. 356 |

357 |
358 |
359 |
360 |
361 |

Styling   slide

362 |
363 |
    364 |
  • Use CSS styles to control appearance of slides 365 |
  • 366 |
  • Extra tags on a slide become extra CSS classes on its HTML 367 |
  • 368 |
369 |
370 | 371 |
372 |

Org-Mode Tag as CSS Class   slide blue_background

373 |
374 |
    375 |
  • This slide has the :blue_background: tag 376 |
      377 |
    • Which is a class defined in projection.css 378 |
    • 379 |
    380 |
  • 381 |
  • Make up your own tags 382 |
      383 |
    • Add them to the CSS file 384 |
    • 385 |
    386 |
  • 387 |
388 |
389 |
390 |
391 |
392 |

Placing Stylesheets/JavaScript   slide

393 |
394 |

395 | Include the stylesheets and JavaScript at the bottom of your Org-Mode file. 396 |

397 | 398 |

399 | They must go at the bottom because the Google Closure Library does not support an on-DOM-ready event. See the Closure mailing list discussion for an explanation. 400 |

401 |
402 | 403 |
404 |

Warning About Hidden Headlines   slide

405 |
406 |

407 | Stylesheets and JavaScript will not be loaded if the last headline in your Org-Mode file is hidden by any of: 408 |

409 | 410 |
    411 |
  • COMMENT at the start of the heading 412 |
  • 413 |
  • #+COMMENT at the start of the line 414 |
  • 415 |
  • :noexport: tag, or missing :export: tag 416 |
  • 417 |
418 | 419 |

420 | See Comment lines and Selective export in the Org-Mode manual for details. 421 |

422 |
423 |
424 |
425 |

The End   slide

426 |
427 |

428 | Sometimes it's safest to add an "empty" heading at the end of your document to make sure the stylesheets and JavaScript are included. 429 |

430 | 431 | 432 |
433 |
434 |
435 |
436 |
437 |

Author: Stuart Sierra

438 |

Emacs 24.3.1 (Org mode N/A)

439 |

Validate

440 |
441 | 442 | 443 | -------------------------------------------------------------------------------- /example.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Example Presentation 2 | #+AUTHOR: Stuart Sierra 3 | 4 | #+BEGIN_HTML 5 |

Type T to begin the slide show.

6 | #+END_HTML 7 | 8 | * Org-HTML-Slideshow :slide: 9 | 10 | Make slides from Emacs Org-Mode! 11 | 12 | ** Making Slides :slide: 13 | 14 | Org-Mode headlines with the =:slide:= tag will become slides. 15 | 16 | ** Headlines Don't Have to be Slides 17 | 18 | This section doesn't have a =:slide:= tag, so it will *not* become a slide, although it is still part of the exported HTML document. 19 | 20 | ** Use Lists For Bullets :slide: 21 | 22 | - Use Org-Mode lists for bullet points 23 | - You can make nested bullet lists 24 | - With sub-lists 25 | - Like this 26 | 27 | ** Or Low-Level Headings :slide: 28 | 29 | **** By default 30 | ***** Org-Mode headings below level 3 31 | ****** Become bullets 32 | ****** Meaning they *cannot* be slides 33 | **** This is configurable 34 | ***** See [[http://orgmode.org/manual/Export-options.html][Export Options in the Org-Mode manual]] 35 | 36 | ** Slides Can Be Nested :slide: 37 | 38 | You can use the structure of the Org-Mode document to group your slides. 39 | 40 | For example, this slide is a *level-2* Org-Mode heading. 41 | 42 | *** Slide Headings Can Be Nested :slide: 43 | 44 | This slide is a *level-3* Org-Mode heading, inside the previous one. 45 | 46 | * Presenter Notes :slide: 47 | 48 | - Slides can have presenter notes 49 | - Add a sub-heading with the =:notes:= tag 50 | 51 | ** A Slide with Notes :slide: 52 | 53 | - This slide has notes 54 | - Notes are only visible to presenter 55 | 56 | *** Notes :notes: 57 | 58 | - Presenter notes for this slide 59 | - Not displayed as part of the slide 60 | - Displayed in Presenter Preview window 61 | - Only one =:notes:= section per slide allowed 62 | 63 | * Source Code :slide: 64 | 65 | Use =begin_src/end_src= blocks to include source code. 66 | 67 | #+begin_src clojure 68 | (defn example [] 69 | (println "This is sample source code.")) 70 | #+end_src 71 | 72 | ** Syntax Highlighting :slide: 73 | 74 | - Org-Mode HTML export uses [[http://www.emacswiki.org/emacs/Htmlize][htmlize.el]] 75 | - Code in exported HTML will match your current Emacs theme 76 | - Choose a theme that looks good on a projector! 77 | 78 | ** Syntax Highlighting with CSS Classes :slide: 79 | 80 | - Set the Emacs variable 81 | - =org-export-htmlize-output-type= 82 | - to the symbol =css= 83 | - (Does not work as a buffer-local variable) 84 | - Htmlize.el will add SPAN tags with CSS classes 85 | - Named for each font face, e.g. =org-comment= 86 | - Examine HTML output to see class names 87 | - Add CSS styles to set colors 88 | 89 | * Images :slide: 90 | 91 | - Slides can contain images 92 | - Any file type a browser can display 93 | - See also these Emacs variables: 94 | - =org-export-html-inline-images= 95 | - =org-export-html-inline-image-extensions= 96 | - Controls which file types get exported 97 | - See [[http://orgmode.org/manual/Images-in-HTML-export.html][Images in HTML Export in the Org-Mode manual]]. 98 | 99 | ** Slide with Image :slide: 100 | 101 | Make a =file:= link with the path to the image and no link text. 102 | 103 | [[file:example-image.svg]] 104 | 105 | This example image is public-domain [[http://openclipart.org/detail/165554/geodesic_dome-by-yoderj][clip art by Josiah / yoderj]]. 106 | 107 | * Styling :slide: 108 | 109 | - Use CSS styles to control appearance of slides 110 | - Extra tags on a slide become extra CSS classes on its HTML 111 | 112 | ** Org-Mode Tag as CSS Class :slide:blue_background: 113 | 114 | - This slide has the =:blue_background:= tag 115 | - Which is a class defined in =projection.css= 116 | - Make up your own tags 117 | - Add them to the CSS file 118 | 119 | * Placing Stylesheets/JavaScript :slide: 120 | 121 | Include the stylesheets and JavaScript at the *bottom* of your Org-Mode file. 122 | 123 | They must go at the bottom because the Google Closure Library does not support an on-DOM-ready event. See the [[http://groups.google.com/group/closure-library-discuss/browse_thread/thread/1beecbb5d6afcb41/075c536259653946][Closure mailing list discussion]] for an explanation. 124 | 125 | ** Warning About Hidden Headlines :slide: 126 | 127 | Stylesheets and JavaScript will *not* be loaded if the *last* headline in your Org-Mode file is hidden by any of: 128 | 129 | - =COMMENT= at the start of the heading 130 | - =#+COMMENT= at the start of the line 131 | - =:noexport:= tag, or missing =:export:= tag 132 | 133 | See [[http://orgmode.org/manual/Comment-lines.html][Comment lines]] and [[http://orgmode.org/manual/Selective-export.html][Selective export]] in the Org-Mode manual for details. 134 | 135 | ** The End :slide: 136 | 137 | Sometimes it's safest to add an "empty" heading at the end of your document to make sure the stylesheets and JavaScript are included. 138 | 139 | #+OPTIONS: num:nil toc:nil tags:t 140 | 141 | #+TAGS: slide(s) 142 | 143 | #+HTML_HEAD_EXTRA: 144 | #+HTML_HEAD_EXTRA: 145 | #+HTML_HEAD_EXTRA: 146 | #+HTML_HEAD_EXTRA: 147 | 148 | #+BEGIN_HTML 149 | 150 | #+END_HTML 151 | 152 | # Local Variables: 153 | # org-html-head-include-default-style: nil 154 | # org-html-head-include-scripts: nil 155 | # buffer-file-coding-system: utf-8-unix 156 | # End: 157 | -------------------------------------------------------------------------------- /production/common.css: -------------------------------------------------------------------------------- 1 | /* Org-HTML-Slideshow common styles. 2 | * 3 | * These styles will apply to all views. 4 | */ 5 | 6 | body { 7 | font-family: Helvetica, Arial, sans-serif; 8 | } 9 | 10 | span.tag { 11 | display: none; 12 | } 13 | 14 | pre { 15 | font-family: Monaco, "Courier New", monospace; 16 | } 17 | 18 | #c-panel { 19 | background: lightgray; 20 | bottom: 0px; 21 | border: 1px solid black; 22 | font-size: 12pt; 23 | position: fixed; 24 | right: 0px; 25 | } 26 | 27 | #c-panel a { 28 | display: block; 29 | } 30 | 31 | #c-panel .key { 32 | display: none; 33 | } 34 | 35 | #c-panel .key { 36 | display: none; 37 | } 38 | -------------------------------------------------------------------------------- /production/org-html-slideshow.js: -------------------------------------------------------------------------------- 1 | function aa(){return function(a){return a}}function g(a){return function(){return this[a]}}function ba(a){return function(){return a}}var m,q=this;function ca(a){a=a.split(".");for(var b=q,c;c=a.shift();)if(null!=b[c])b=b[c];else return null;return b} 2 | function s(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null"; 3 | else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function da(a){var b=s(a);return"array"==b||"object"==b&&"number"==typeof a.length}function t(a){return"string"==typeof a}function ea(a){return"function"==s(a)}function fa(a){var b=typeof a;return"object"==b&&null!=a||"function"==b}function ga(a){return a[ha]||(a[ha]=++ia)}var ha="closure_uid_"+(1E9*Math.random()>>>0),ia=0;function ja(a,b,c){return a.call.apply(a.bind,arguments)} 4 | function ka(a,b,c){if(!a)throw Error();if(2/g,za=/\"/g,va=/[&<>\"]/;function Aa(a){for(var b=0,c=0;cc?Math.max(0,a.length+c):c;if(t(a))return t(b)&&1==b.length?a.indexOf(b,c):-1;for(;c=arguments.length?Ga.slice.call(a,b):Ga.slice.call(a,b,c)};function Oa(a){a=a.className;return t(a)&&a.match(/\S+/g)||[]}function Pa(a,b){for(var c=Oa(a),d=Na(arguments,1),e=c.length+d.length,f=c,h=0;hparseFloat(ib)){hb=String(mb);break a}}hb=ib}var nb={}; 10 | function ob(a){var b;if(!(b=nb[a])){b=0;for(var c=String(hb).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),d=String(a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),e=Math.max(c.length,d.length),f=0;0==b&&f(0==r[1].length?0:parseInt(r[1],10))?1:0)||((0==p[2].length)<(0==r[2].length)?-1:(0==p[2].length)>(0==r[2].length)?1:0)||(p[2]r[2]?1:0)}while(0==b)}b=nb[a]=0<=b}return b}var pb=q.document,qb=pb&&u?gb()||("CSS1Compat"==pb.compatMode?parseInt(hb,10):5):void 0;var rb=!u||u&&9<=qb,sb=u&&!ob("9");!db||ob("528");cb&&ob("1.9b")||u&&ob("8")||bb&&ob("9.5")||db&&ob("528");cb&&!ob("8")||u&&ob("9");function tb(a,b){this.type=a;this.currentTarget=this.target=b}m=tb.prototype;m.Ha=!1;m.defaultPrevented=!1;m.qb=!0;m.stopPropagation=function(){this.Ha=!0};m.preventDefault=function(){this.defaultPrevented=!0;this.qb=!1};function ub(a){ub[" "](a);return a}ub[" "]=function(){};function vb(a,b){a&&this.eb(a,b)}pa(vb,tb);m=vb.prototype;m.target=null;m.relatedTarget=null;m.offsetX=0;m.offsetY=0;m.clientX=0;m.clientY=0;m.screenX=0;m.screenY=0;m.button=0;m.keyCode=0;m.charCode=0;m.ctrlKey=!1;m.altKey=!1;m.shiftKey=!1;m.metaKey=!1;m.Oc=!1;m.Ra=null; 12 | m.eb=function(a,b){var c=this.type=a.type;tb.call(this,c);this.target=a.target||a.srcElement;this.currentTarget=b;var d=a.relatedTarget;if(d){if(cb){var e;a:{try{ub(d.nodeName);e=!0;break a}catch(f){}e=!1}e||(d=null)}}else"mouseover"==c?d=a.fromElement:"mouseout"==c&&(d=a.toElement);this.relatedTarget=d;this.offsetX=db||void 0!==a.offsetX?a.offsetX:a.layerX;this.offsetY=db||void 0!==a.offsetY?a.offsetY:a.layerY;this.clientX=void 0!==a.clientX?a.clientX:a.pageX;this.clientY=void 0!==a.clientY?a.clientY: 13 | a.pageY;this.screenX=a.screenX||0;this.screenY=a.screenY||0;this.button=a.button;this.keyCode=a.keyCode||0;this.charCode=a.charCode||("keypress"==c?a.keyCode:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.Oc=fb?a.metaKey:a.ctrlKey;this.state=a.state;this.Ra=a;a.defaultPrevented&&this.preventDefault();delete this.Ha}; 14 | m.stopPropagation=function(){vb.wc.stopPropagation.call(this);this.Ra.stopPropagation?this.Ra.stopPropagation():this.Ra.cancelBubble=!0};m.preventDefault=function(){vb.wc.preventDefault.call(this);var a=this.Ra;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,sb)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};var wb=0;function xb(){}m=xb.prototype;m.key=0;m.Ja=!1;m.hb=!1;m.eb=function(a,b,c,d,e,f){if(ea(a))this.lc=!0;else if(a&&a.handleEvent&&ea(a.handleEvent))this.lc=!1;else throw Error("Invalid listener argument");this.Ba=a;this.rc=b;this.src=c;this.type=d;this.capture=!!e;this.Tb=f;this.hb=!1;this.key=++wb;this.Ja=!1};m.handleEvent=function(a){return this.lc?this.Ba.call(this.Tb||this.src,a):this.Ba.handleEvent.call(this.Ba,a)};function yb(a,b){for(var c in a)b.call(void 0,a[c],c,a)}function zb(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b}function Ab(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b}var Bb="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" ");function Cb(a,b){for(var c,d,e=1;ee.keyCode||void 0!=e.returnValue)return!0;a:{var l=!1;if(0==e.keyCode)try{e.keyCode=-1;break a}catch(n){l=!0}if(l||void 0==e.returnValue)e.returnValue=!0}}l=new vb;l.eb(e,this);e=!0;try{if(h){for(var p=[],r=l.currentTarget;r;r=r.parentNode)p.push(r);f=d[!0];f.aa=f.v;for(var v=p.length-1;!l.Ha&&0<=v&&f.aa;v--)l.currentTarget=p[v],e&=Nb(f,p[v],c, 22 | !0,l);if(k)for(f=d[!1],f.aa=f.v,v=0;!l.Ha&&vb?1:ah?1:y?c.o(a,b,f,0):null}var c=null,c=function(c,e,f,h){switch(arguments.length){case 2:return b.call(this,c,e);case 4:return a.call(this,c,e,f,h)}throw Error("Invalid arity: "+arguments.length);};c.a=b;c.o=a;return c}(),Ad=function(){function a(a,b,c){for(c=L(c);;)if(c)b=a.a?a.a(b,M(c)):a.call(null,b,M(c)),c=P(c);else return b}function b(a, 68 | b){var c=L(b);return c?zd.e?zd.e(a,M(c),P(c)):zd.call(null,a,M(c),P(c)):a.W?a.W():a.call(null)}var c=null,c=function(c,e,f){switch(arguments.length){case 2:return b.call(this,c,e);case 3:return a.call(this,c,e,f)}throw Error("Invalid arity: "+arguments.length);};c.a=b;c.e=a;return c}(),zd=function(){function a(a,b,c){var h;h=c?((h=c.h&524288)?h:c.Ec)?!0:!1:!1;return h?c.T(c,a,b):c instanceof Array?Uc.e(c,a,b):"string"===typeof c?Uc.e(c,a,b):x(rc,c)?sc.e(c,a,b):y?Ad.e(a,b,c):null}function b(a,b){var c; 69 | c=b?((c=b.h&524288)?c:b.Ec)?!0:!1:!1;return c?b.S(b,a):b instanceof Array?Uc.a(b,a):"string"===typeof b?Uc.a(b,a):x(rc,b)?sc.a(b,a):y?Ad.a(a,b):null}var c=null,c=function(c,e,f){switch(arguments.length){case 2:return b.call(this,c,e);case 3:return a.call(this,c,e,f)}throw Error("Invalid arity: "+arguments.length);};c.a=b;c.e=a;return c}();function Bd(a){return 0<=a?Math.floor.c?Math.floor.c(a):Math.floor.call(null,a):Math.ceil.c?Math.ceil.c(a):Math.ceil.call(null,a)} 70 | function Cd(a){a-=a>>1&1431655765;a=(a&858993459)+(a>>2&858993459);return 16843009*(a+(a>>4)&252645135)>>24} 71 | var A=function(){function a(a){return null==a?"":a.toString()}var b=null,c=function(){function a(b,d){var k=null;1>2)}function Xc(a){return zd.e(function(a,c){return Rc(a,K.a(c,!1))},K.a(M(a),!1),P(a))} 73 | function Dd(a){var b=0;for(a=L(a);;)if(a){var c=M(a),b=(b+(K.c(Ed.c?Ed.c(c):Ed.call(null,c))^K.c(Fd.c?Fd.c(c):Fd.call(null,c))))%4503599627370496;a=P(a)}else return b}function Gd(a,b,c,d,e){this.j=a;this.bb=b;this.wa=c;this.count=d;this.l=e;this.t=0;this.h=65937646}m=Gd.prototype;m.G=function(a){var b=this.l;return null!=b?b:this.l=a=Xc(a)};m.$=function(){return 1===this.count?null:this.wa};m.I=function(a,b){return new Gd(this.j,b,a,this.count+1,null)};m.toString=function(){return Jc(this)}; 74 | m.S=function(a,b){return Ad.a(b,a)};m.T=function(a,b,c){return Ad.e(b,c,a)};m.A=aa();m.C=g("count");m.Q=g("bb");m.Y=function(){return 1===this.count?O:this.wa};m.D=function(a,b){return $c(a,b)};m.N=function(a,b){return new Gd(b,this.bb,this.wa,this.count,this.l)};m.M=g("j");m.P=function(){return O};function Hd(a){this.j=a;this.t=0;this.h=65937614}m=Hd.prototype;m.G=ba(0);m.$=ba(null);m.I=function(a,b){return new Gd(this.j,b,null,1,null)};m.toString=function(){return Jc(this)}; 75 | m.S=function(a,b){return Ad.a(b,a)};m.T=function(a,b,c){return Ad.e(b,c,a)};m.A=ba(null);m.C=ba(0);m.Q=ba(null);m.Y=function(){return O};m.D=function(a,b){return $c(a,b)};m.N=function(a,b){return new Hd(b)};m.M=g("j");m.P=aa(); 76 | var O=new Hd(null),Yc=function(){function a(a){var d=null;0a?0:a-1>>>5<<5} 104 | function ge(a,b,c){for(;;){if(0===b)return c;var d=new ee(a,Array(32));d.b[0]=c;c=d;b-=5}}var ie=function he(b,c,d,e){var f=new ee(d.q,d.b.slice()),h=b.g-1>>>c&31;5===c?f.b[h]=e:(d=d.b[h],b=null!=d?he(b,c-5,d,e):ge(null,c-5,e),f.b[h]=b);return f};function je(a,b){throw Error([A("No item "),A(a),A(" in vector of length "),A(b)].join(""));} 105 | function ke(a,b){var c=0<=b;if(c?b=fe(a))return a.V;for(var c=a.root,d=a.shift;;)if(0>>d&31],d=e;else return c.b}else return je(b,a.g)}var me=function le(b,c,d,e,f){var h=new ee(d.q,d.b.slice());if(0===c)h.b[e&31]=f;else{var k=e>>>c&31;b=le(b,c-5,d.b[k],e,f);h.b[k]=b}return h};function ne(a,b,c,d,e,f){this.j=a;this.g=b;this.shift=c;this.root=d;this.V=e;this.l=f;this.t=4;this.h=167668511}m=ne.prototype; 106 | m.Va=function(){return new oe(this.g,this.shift,pe.c?pe.c(this.root):pe.call(null,this.root),qe.c?qe.c(this.V):qe.call(null,this.V))};m.G=function(a){var b=this.l;return null!=b?b:this.l=a=Xc(a)};m.X=function(a,b){return a.L(a,b,null)};m.J=function(a,b,c){return a.L(a,b,c)}; 107 | m.qa=function(a,b,c){var d=0<=b;if(d?bthis.g-fe(a)){var c=this.V.slice();c.push(b);return new ne(this.j,this.g+1,this.shift,this.root,c,null)}var d=this.g>>>5>1<this.g?Q.c(this.V):y?re.e?re.e(a,0,0):re.call(null,a,0,0):null};m.C=g("g");m.Ob=function(a,b,c){return a.qa(a,b,c)};m.D=function(a,b){return $c(a,b)};m.N=function(a,b){return new ne(b,this.g,this.shift,this.root,this.V,this.l)};m.M=g("j");m.p=function(a,b){return ke(a,b)[b&31]};m.L=function(a,b,c){var d=0<=b;return(d?bb)return new ne(null,b,5,te,a,null);for(var c=a.slice(0,32),d=32,e=Dc(new ne(null,32,5,te,c,null));;)if(db?a:b}(),null):ze.call(null,d.j,gd.e(d.oa,e,c),d.start,function(){var a=d.end,b=e+1;return a>b?a:b}(),null)}; 117 | m.call=function(){var a=null;return a=function(a,c,d){switch(arguments.length){case 2:return this.p(this,c);case 3:return this.L(this,c,d)}throw Error("Invalid arity: "+arguments.length);}}();m.apply=function(a,b){a=this;return a.call.apply(a,[a].concat(b.slice()))};m.I=function(a,b){return ze.R?ze.R(this.j,mc(this.oa,this.end,b),this.start,this.end+1,null):ze.call(null,this.j,mc(this.oa,this.end,b),this.start,this.end+1,null)};m.toString=function(){return Jc(this)}; 118 | m.S=function(a,b){return Tc.a(a,b)};m.T=function(a,b,c){return Tc.e(a,b,c)};m.A=function(){var a=this;return function c(d){return d===a.end?null:T(B.a(a.oa,d),new Kd(null,!1,function(){return c(d+1)},null))}(a.start)};m.C=function(){return this.end-this.start};m.Ob=function(a,b,c){return a.qa(a,b,c)};m.D=function(a,b){return $c(a,b)};m.N=function(a,b){return ze.R?ze.R(b,this.oa,this.start,this.end,this.l):ze.call(null,b,this.oa,this.start,this.end,this.l)};m.M=g("j"); 119 | m.p=function(a,b){var c=0>b;return(c?c:this.end<=this.start+b)?je(b,this.end-this.start):B.a(this.oa,this.start+b)};m.L=function(a,b,c){return((a=0>b)?a:this.end<=this.start+b)?c:B.e(this.oa,this.start+b,c)};m.P=function(){return ld(se,this.j)};function ze(a,b,c,d,e){for(;;)if(b instanceof ye){var f=b.start+c,h=b.start+d;b=b.oa;c=f;d=h}else{var k=U(b);if(function(){var a=0>c;return a||(a=0>d)?a:(a=c>k)?a:d>k}())throw Error("Index out of bounds");return new ye(a,b,c,d,e)}} 120 | var xe=function(){function a(a,b,c){return ze(null,a,b,c,null)}function b(a,b){return c.e(a,b,U(a))}var c=null,c=function(c,e,f){switch(arguments.length){case 2:return b.call(this,c,e);case 3:return a.call(this,c,e,f)}throw Error("Invalid arity: "+arguments.length);};c.a=b;c.e=a;return c}();function pe(a){return new ee({},a.b.slice())}function qe(a){var b=Array(32);td(a,0,b,0,a.length);return b} 121 | var Be=function Ae(b,c,d,e){d=b.root.q===d.q?d:new ee(b.root.q,d.b.slice());var f=b.g-1>>>c&31;if(5===c)b=e;else{var h=d.b[f];b=null!=h?Ae(b,c-5,h,e):ge(b.root.q,c-5,e)}d.b[f]=b;return d};function oe(a,b,c,d){this.g=a;this.shift=b;this.root=c;this.V=d;this.h=275;this.t=88}m=oe.prototype;m.call=function(){var a=null;return a=function(a,c,d){switch(arguments.length){case 2:return this.X(this,c);case 3:return this.J(this,c,d)}throw Error("Invalid arity: "+arguments.length);}}(); 122 | m.apply=function(a,b){a=this;return a.call.apply(a,[a].concat(b.slice()))};m.X=function(a,b){return a.L(a,b,null)};m.J=function(a,b,c){return a.L(a,b,c)};m.p=function(a,b){if(this.root.q)return ke(a,b)[b&31];throw Error("nth after persistent!");};m.L=function(a,b,c){var d=0<=b;return(d?b>>b&31,r=h(b-5,n.b[p]);n.b[p]=r}return n}.call(null,a.shift,a.root);a.root=e}return b}if(c===a.g)return b.xa(b,d);if(y)throw Error([A("Index "),A(c),A(" out of bounds for TransientVector of length"),A(a.g)].join(""));return null}throw Error("assoc! after persistent!");} 124 | m.Oa=function(a,b,c){return Ce(a,a,b,c)};m.xa=function(a,b){if(this.root.q){if(32>this.g-fe(a))this.V[this.g&31]=b;else{var c=new ee(this.root.q,this.V),d=Array(32);d[0]=b;this.V=d;if(this.g>>>5>1<=c)return new Ie(this.j,this.g-1,d,null);if(S.a(b,this.b[e]))e+=2;else if(y)d[f]=this.b[e],d[f+1]=this.b[e+1],f+=2,e+=2;else return null}}else return a};var Me=new Ie(null,0,[],null),Ke=8;function Kc(a,b){var c=b?a:a.slice();return new Ie(null,c.length/2,c,null)} 133 | function Je(a,b,c){this.Pa=a;this.ua=b;this.b=c;this.t=56;this.h=258}m=Je.prototype;m.Oa=function(a,b,c){if(w(this.Pa)){var d=Ge(a,b);if(-1===d){if(this.ua+2<=2*Ke)return this.ua+=2,this.b.push(b),this.b.push(c),a;a=Ne.a?Ne.a(this.ua,this.b):Ne.call(null,this.ua,this.b);return Gc(a,b,c)}c!==this.b[d+1]&&(this.b[d+1]=c);return a}throw Error("assoc! after persistent!");}; 134 | m.xa=function(a,b){if(w(this.Pa)){var c;c=b?((c=b.h&2048)?c:b.Cc)?!0:b.h?!1:x(hc,b):x(hc,b);if(c)return a.Oa(a,Ed.c?Ed.c(b):Ed.call(null,b),Fd.c?Fd.c(b):Fd.call(null,b));c=L(b);for(var d=a;;){var e=M(c);if(w(e))c=P(c),d=d.Oa(d,Ed.c?Ed.c(e):Ed.call(null,e),Fd.c?Fd.c(e):Fd.call(null,e));else return d}}else throw Error("conj! after persistent!");};m.Da=function(){if(w(this.Pa))return this.Pa=!1,new Ie(null,Bd((this.ua-this.ua%2)/2),this.b,null);throw Error("persistent! called twice");}; 135 | m.X=function(a,b){return a.J(a,b,null)};m.J=function(a,b,c){if(w(this.Pa))return a=Ge(a,b),-1===a?c:this.b[a+1];throw Error("lookup after persistent!");};m.C=function(){if(w(this.Pa))return Bd((this.ua-this.ua%2)/2);throw Error("count after persistent!");};function Ne(a,b){for(var c=Dc(Le),d=0;;)if(d>>b&31),k=Cd(this.w&h-1);if(0===(this.w&h)){var l=Cd(this.w);if(2*l>>b&31]=Ue.ia(a,b+5,c,d,e,f);for(e=d=0;;)if(32>d)0!==(this.w>>>d&1)&&(k[d]=null!=this.b[e]?Ue.ia(a,b+5,K.c(this.b[e]),this.b[e],this.b[e+1],f):this.b[e+1],e+=2),d+=1;else break;return new Ve(a,l+1,k)}return y? 139 | (b=Array(2*(l+4)),td(this.b,0,b,0,2*k),b[2*k]=d,b[2*k+1]=e,td(this.b,2*k,b,2*(k+1),2*(l-k)),f.pa=!0,a=this.Qa(a),a.b=b,a.w|=h,a):null}l=this.b[2*k];h=this.b[2*k+1];return null==l?(l=h.ia(a,b+5,c,d,e,f),l===h?this:Se.o(this,a,2*k+1,l)):Pe(d,l)?e===h?this:Se.o(this,a,2*k+1,e):y?(f.pa=!0,Se.ra(this,a,2*k,null,2*k+1,We.Na?We.Na(a,b+5,l,h,c,d,e):We.call(null,a,b+5,l,h,c,d,e))):null};m.fb=function(){return Xe.c?Xe.c(this.b):Xe.call(null,this.b)}; 140 | m.Qa=function(a){if(a===this.q)return this;var b=Cd(this.w),c=Array(0>b?4:2*(b+1));td(this.b,0,c,0,2*b);return new Te(a,this.w,c)};m.gb=function(a,b,c){var d=1<<(b>>>a&31);if(0===(this.w&d))return this;var e=Cd(this.w&d-1),f=this.b[2*e],h=this.b[2*e+1];return null==f?(a=h.gb(a+5,b,c),a===h?this:null!=a?new Te(null,this.w,Qe.e(this.b,2*e+1,a)):this.w===d?null:y?new Te(null,this.w^d,Re(this.b,e)):null):Pe(c,f)?new Te(null,this.w^d,Re(this.b,e)):y?this:null}; 141 | m.ha=function(a,b,c,d,e){var f=1<<(b>>>a&31),h=Cd(this.w&f-1);if(0===(this.w&f)){var k=Cd(this.w);if(16<=k){h=Array(32);h[b>>>a&31]=Ue.ha(a+5,b,c,d,e);for(d=c=0;;)if(32>c)0!==(this.w>>>c&1)&&(h[c]=null!=this.b[d]?Ue.ha(a+5,K.c(this.b[d]),this.b[d],this.b[d+1],e):this.b[d+1],d+=2),c+=1;else break;return new Ve(null,k+1,h)}a=Array(2*(k+1));td(this.b,0,a,0,2*h);a[2*h]=c;a[2*h+1]=d;td(this.b,2*h,a,2*(h+1),2*(k-h));e.pa=!0;return new Te(null,this.w|f,a)}k=this.b[2*h];f=this.b[2*h+1];return null==k?(k= 142 | f.ha(a+5,b,c,d,e),k===f?this:new Te(null,this.w,Qe.e(this.b,2*h+1,k))):Pe(c,k)?d===f?this:new Te(null,this.w,Qe.e(this.b,2*h+1,d)):y?(e.pa=!0,new Te(null,this.w,Qe.R(this.b,2*h,null,2*h+1,We.ra?We.ra(a+5,k,f,b,c,d):We.call(null,a+5,k,f,b,c,d)))):null};m.za=function(a,b,c,d){var e=1<<(b>>>a&31);if(0===(this.w&e))return d;var f=Cd(this.w&e-1),e=this.b[2*f],f=this.b[2*f+1];return null==e?f.za(a+5,b,c,d):Pe(c,e)?f:y?d:null};var Ue=new Te(null,0,[]);function Ve(a,b,c){this.q=a;this.g=b;this.b=c}m=Ve.prototype; 143 | m.ia=function(a,b,c,d,e,f){var h=c>>>b&31,k=this.b[h];if(null==k)return a=Se.o(this,a,h,Ue.ia(a,b+5,c,d,e,f)),a.g+=1,a;b=k.ia(a,b+5,c,d,e,f);return b===k?this:Se.o(this,a,h,b)};m.fb=function(){return Ye.c?Ye.c(this.b):Ye.call(null,this.b)};m.Qa=function(a){return a===this.q?this:new Ve(a,this.g,this.b.slice())}; 144 | m.gb=function(a,b,c){var d=b>>>a&31,e=this.b[d];if(null!=e){a=e.gb(a+5,b,c);if(a===e)d=this;else if(null==a)if(8>=this.g)a:{e=this.b;a=2*(this.g-1);b=Array(a);c=0;for(var f=1,h=0;;)if(c>>a&31,h=this.b[f];if(null==h)return new Ve(null,this.g+1,Qe.e(this.b,f,Ue.ha(a+5,b,c,d,e)));a=h.ha(a+5,b,c,d,e);return a===h?this:new Ve(null,this.g,Qe.e(this.b,f,a))};m.za=function(a,b,c,d){var e=this.b[b>>>a&31];return null!=e?e.za(a+5,b,c,d):d};function Ze(a,b,c){b*=2;for(var d=0;;)if(d2*this.g)return a=Se.ra(this,a,2*this.g,d,2*this.g+1,e),f.pa=!0,a.g+=1,a;c=this.b.length;b=Array(c+2);td(this.b,0,b,0,c);b[c]=d;b[c+1]=e;f.pa=!0;f=this.g+1;a===this.q?(this.b=b,this.g=f,a=this):a=new af(this.q,this.sa,f,b);return a}return this.b[b+1]===e?this:Se.o(this,a,b+1,e)}return(new Te(a,1<<(this.sa>>>b&31),[null,this,null,null])).ia(a,b,c,d,e,f)}; 147 | m.fb=function(){return Xe.c?Xe.c(this.b):Xe.call(null,this.b)};m.Qa=function(a){if(a===this.q)return this;var b=Array(2*(this.g+1));td(this.b,0,b,0,2*this.g);return new af(a,this.sa,this.g,b)};m.gb=function(a,b,c){a=Ze(this.b,this.g,c);return-1===a?this:1===this.g?null:y?new af(null,this.sa,this.g-1,Re(this.b,Bd((a-a%2)/2))):null}; 148 | m.ha=function(a,b,c,d,e){return b===this.sa?(a=Ze(this.b,this.g,c),-1===a?(a=this.b.length,b=Array(a+2),td(this.b,0,b,0,a),b[a]=c,b[a+1]=d,e.pa=!0,new af(null,this.sa,this.g+1,b)):S.a(this.b[a],d)?this:new af(null,this.sa,this.g,Qe.e(this.b,a+1,d))):(new Te(null,1<<(this.sa>>>a&31),[null,this])).ha(a,b,c,d,e)};m.za=function(a,b,c,d){a=Ze(this.b,this.g,c);return 0>a?d:Pe(c,this.b[a])?this.b[a+1]:y?d:null}; 149 | var We=function(){function a(a,b,c,h,k,l,n){var p=K.c(c);if(p===k)return new af(null,p,2,[c,h,l,n]);var r=new Oe;return Ue.ia(a,b,p,c,h,r).ia(a,b,k,l,n,r)}function b(a,b,c,h,k,l){var n=K.c(b);if(n===h)return new af(null,n,2,[b,c,k,l]);var p=new Oe;return Ue.ha(a,n,b,c,p).ha(a,h,k,l,p)}var c=null,c=function(c,e,f,h,k,l,n){switch(arguments.length){case 6:return b.call(this,c,e,f,h,k,l);case 7:return a.call(this,c,e,f,h,k,l,n)}throw Error("Invalid arity: "+arguments.length);};c.ra=b;c.Na=a;return c}(); 150 | function bf(a,b,c,d,e){this.j=a;this.ka=b;this.m=c;this.la=d;this.l=e;this.t=0;this.h=32374860}m=bf.prototype;m.G=function(a){var b=this.l;return null!=b?b:this.l=a=Xc(a)};m.I=function(a,b){return T(b,a)};m.toString=function(){return Jc(this)};m.S=function(a,b){return Ad.a(b,a)};m.T=function(a,b,c){return Ad.e(b,c,a)};m.A=aa();m.Q=function(){return null==this.la?ue([this.ka[this.m],this.ka[this.m+1]]):M(this.la)}; 151 | m.Y=function(){return null==this.la?Xe.e?Xe.e(this.ka,this.m+2,null):Xe.call(null,this.ka,this.m+2,null):Xe.e?Xe.e(this.ka,this.m,P(this.la)):Xe.call(null,this.ka,this.m,P(this.la))};m.D=function(a,b){return $c(a,b)};m.N=function(a,b){return new bf(b,this.ka,this.m,this.la,this.l)};m.M=g("j");m.P=function(){return ld(O,this.j)}; 152 | var Xe=function(){function a(a,b,c){if(null==c)for(c=a.length;;)if(bthis.end?new qf(this.j,this.start+this.step,this.end,this.step,null):null};m.I=function(a,b){return T(b,a)};m.toString=function(){return Jc(this)};m.S=function(a,b){return Tc.a(a,b)};m.T=function(a,b,c){return Tc.e(a,b,c)};m.A=function(a){return 0this.end?a:null}; 173 | m.C=function(a){return Sb(a.A(a))?0:Math.ceil((this.end-this.start)/this.step)};m.Q=g("start");m.Y=function(a){return null!=a.A(a)?new qf(this.j,this.start+this.step,this.end,this.step,null):O};m.D=function(a,b){return $c(a,b)};m.N=function(a,b){return new qf(b,this.start,this.end,this.step,this.l)};m.M=g("j");m.p=function(a,b){if(bthis.end;if(c?0===this.step:c)return this.start;throw Error("Index out of bounds");}; 174 | m.L=function(a,b,c){c=bthis.end)?0===this.step:a)?this.start:c;return c};m.P=function(){return ld(O,this.j)}; 175 | var rf=function(){function a(a,b,c){return new qf(null,a,b,c,null)}function b(a,b){return e.e(a,b,1)}function c(a){return e.e(0,a,1)}function d(){return e.e(0,Number.MAX_VALUE,1)}var e=null,e=function(e,h,k){switch(arguments.length){case 0:return d.call(this);case 1:return c.call(this,e);case 2:return b.call(this,e,h);case 3:return a.call(this,e,h,k)}throw Error("Invalid arity: "+arguments.length);};e.W=d;e.c=c;e.a=b;e.e=a;return e}(); 176 | function sf(a,b,c,d,e,f,h){H(a,c);L(h)&&(b.e?b.e(M(h),a,f):b.call(null,M(h),a,f));c=L(P(h));h=null;for(var k=0,l=0;;)if(l2*this.v&&Gf(this),!0):!1};function Gf(a){if(a.v!=a.Z.length){for(var b=0,c=0;bb.length){c.push(Kf(a)+"(");for(var d=a.arguments,e=0;e=Vf(this).value)for(a=this.Ic(a,b,c),b="log:"+a.oc,q.console&&(q.console.timeStamp?q.console.timeStamp(b):q.console.markTimeline&&q.console.markTimeline(b)),q.msWriteProfilerMark&&q.msWriteProfilerMark(b),b=this;b;){c=b;var d=a;if(c.cb)for(var e=0,f=void 0;f=c.cb[e];e++)f(d);b=b.getParent()}}; 198 | m.Ic=function(a,b,c){var d=new Mf(a,String(b),this.Nc);if(c){d.Rb=c;var e;var f=arguments.callee.caller;try{var h;var k=ca("window.location.href");if(t(c))h={message:c,name:"Unknown error",lineNumber:"Not available",fileName:k,stack:"Not available"};else{var l,n,p=!1;try{l=c.lineNumber||c.kd||"Not available"}catch(r){l="Not available",p=!0}try{n=c.fileName||c.filename||c.sourceURL||q.$googDebugFname||k}catch(v){n="Not available",p=!0}h=!p&&c.lineNumber&&c.fileName&&c.stack?c:{message:c.message,name:c.name, 199 | lineNumber:l,fileName:n,stack:c.stack||"Not available"}}e="Message: "+ua(h.message)+'\nUrl: \x3ca href\x3d"view-source:'+h.fileName+'" target\x3d"_new"\x3e'+h.fileName+"\x3c/a\x3e\nLine: "+h.lineNumber+"\n\nBrowser stack:\n"+ua(h.stack+"-\x3e ")+"[end]\n\nJS stack traversal:\n"+ua(If(f)+"-\x3e ")}catch(D){e="Exception trying to expose exception! You win, we lose. "+D}d.Qb=e}return d};m.info=function(a,b){this.log(Tf,a,b)};var Wf={},Xf=null;function Yf(){Xf||(Xf=new Of(""),Wf[""]=Xf,Xf.tc(Uf))} 200 | function Zf(a){Yf();var b;if(!(b=Wf[a])){b=new Of(a);var c=a.lastIndexOf("."),d=a.substr(c+1),c=Zf(a.substr(0,c));c.ub||(c.ub={});c.ub[d]=b;b.nb=c;Wf[a]=b}return b};var $f=!u||u&&9<=qb;!cb&&!u||u&&u&&9<=qb||cb&&ob("1.9.1");u&&ob("9");function ag(a){return t(a)?document.getElementById(a):a} 201 | function bg(a,b,c){var d=document;c=c||d;a=a&&"*"!=a?a.toUpperCase():"";if(c.querySelectorAll&&c.querySelector&&(a||b))return c.querySelectorAll(a+(b?"."+b:""));if(b&&c.getElementsByClassName){c=c.getElementsByClassName(b);if(a){for(var d={},e=0,f=0,h;h=c[f];f++)a==h.nodeName&&(d[e++]=h);d.length=e;return d}return c}c=c.getElementsByTagName(a||"*");if(b){d={};for(f=e=0;h=c[f];f++)a=h.className,"function"==typeof a.split&&Ka(a.split(/\s+/),b)&&(d[e++]=h);d.length=e;return d}return c} 202 | function cg(a,b){yb(b,function(b,d){"style"==d?a.style.cssText=b:"class"==d?a.className=b:"for"==d?a.htmlFor=b:d in dg?a.setAttribute(dg[d],b):0==d.lastIndexOf("aria-",0)||0==d.lastIndexOf("data-",0)?a.setAttribute(d,b):a[d]=b})}var dg={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",frameborder:"frameBorder",height:"height",maxlength:"maxLength",role:"role",rowspan:"rowSpan",type:"type",usemap:"useMap",valign:"vAlign",width:"width"}; 203 | function eg(a,b,c){var d=arguments,e=document,f=d[0],h=d[1];if(!$f&&h&&(h.name||h.type)){f=["\x3c",f];h.name&&f.push(' name\x3d"',ua(h.name),'"');if(h.type){f.push(' type\x3d"',ua(h.type),'"');var k={};Cb(k,h);delete k.type;h=k}f.push("\x3e");f=f.join("")}f=e.createElement(f);h&&(t(h)?f.className=h:"array"==s(h)?Pa.apply(null,[f].concat(h)):cg(f,h));2=a||96<=a&&106>=a||65<=a&&90>=a||db&&0==a)return!0;switch(a){case 32:case 63:case 107:case 109:case 110:case 111:case 186:case 59:case 189:case 187:case 61:case 188:case 190:case 191:case 192:case 222:case 219:case 220:case 221:return!0;default:return!1}}function lg(a){switch(a){case 61:return 187;case 59:return 186;case 224:return 91;case 0:return 224;default:return a}};function mg(a,b){var c=Array.prototype.slice.call(arguments),d=c.shift();if("undefined"==typeof d)throw Error("[goog.string.format] Template required");return d.replace(/%([0\-\ \+]*)(\d+)?(\.(\d+))?([%sfdiu])/g,function(a,b,d,k,l,n,p,r){if("%"==n)return"%";var v=c.shift();if("undefined"==typeof v)throw Error("[goog.string.format] Not enough arguments");arguments[0]=v;return ng[n].apply(null,arguments)})} 207 | var ng={s:function(a,b,c){return isNaN(c)||""==c||a.length>=c?a:a=-1a?"-":0<=b.indexOf("+")?"+":0<=b.indexOf(" ")?" ":"";0<=a&&(d=f+d);if(isNaN(c)||d.length>=c)return d;d=isNaN(e)?Math.abs(a).toString():Math.abs(a).toFixed(e);a=c-d.length-f.length;return d=0<=b.indexOf("-",0)?f+d+Array(a+1).join(" "):f+Array(a+1).join(0<=b.indexOf("0", 208 | 0)?"0":" ")+d},d:function(a,b,c,d,e,f,h,k){return ng.f(parseInt(a,10),b,c,d,0,f,h,k)}};ng.i=ng.d;ng.u=ng.d;function og(a){var b=ag("c-panel");t("opacity")?pg(b,a,"opacity"):yb("opacity",na(pg,b))}function pg(a,b,c){var d;a:if(d=Ba(c),void 0===a.style[d]&&(c=(db?"Webkit":cb?"Moz":u?"ms":bb?"O":null)+Ca(c),void 0!==a.style[c])){d=c;break a}d&&(a.style[d]=b)}function qg(a,b){a.style.display=b?"":"none"};var Pc=new Y(null,"dup","dup"),rg=new Y(null,"html","html"),sg=new Y(null,"target","target"),tg=new Y(null,"toolbar","toolbar"),ug=new Y(null,"head-elem","head-elem"),vg=new Y(null,"show-control-panel","show-control-panel"),wg=new Y(null,"statusbar","statusbar"),xg=new Y(null,"show-last-slide","show-last-slide"),yg=new Y(null,"notes-html","notes-html"),Mc=new Y(null,"flush-on-newline","flush-on-newline"),zg=new Y(null,"location","location"),Ag=new Y(null,"go-to-top","go-to-top"),Bg=new Y(null,"max-count", 209 | "max-count"),Cg=new Y(null,"reset-elapsed-time","reset-elapsed-time"),Dg=new Y(null,"show-prev-slide","show-prev-slide"),Eg=new Y(null,"body-elem","body-elem"),Fg=new Y(null,"menubar","menubar"),y=new Y(null,"else","else"),Nc=new Y(null,"readably","readably"),Gg=new Y(null,"show-first-slide","show-first-slide"),Hg=new Y(null,"show-presenter-window","show-presenter-window"),zf=new Y(null,"validator","validator"),Oc=new Y(null,"meta","meta"),Ig=new Y(null,"change-mode","change-mode"),Jg=new Y(null, 210 | "event-pred","event-pred"),Kg=new Y(null,"hide-control-panel","hide-control-panel"),Lg=new Y(null,"reactor","reactor"),Mg=new Y(null,"id","id"),Ng=new Y(null,"toggle-mode","toggle-mode"),Og=new Y(null,"show-next-slide","show-next-slide");function Pg(a){if(a?a.Pb:a)return a.Pb(a);var b;b=Pg[s(null==a?null:a)];if(!b&&(b=Pg._,!b))throw z("DomContent.single-node",a);return b.call(null,a)}function Qg(a){return ag(nf(a))} 211 | var Rg=function(){function a(a,b){return ba?"0"+a:String(a)}function Wg(a,b){var c=(a.xc-b)/1E3,d=c.toFixed(3),e=0;if(1>c)e=2;else for(;100>c;)e++,c*=10;for(;0b)throw Error("Bad port number "+b);a.pb=b}else a.pb=null}function ih(a,b,c){gh(a);b instanceof jh?(a.Ia=b,a.Ia.Xb(a.ea)):(c||(b=kh(b,ph)),a.Ia=new jh(b,0,a.ea))}function gh(a){if(a.Lc)throw Error("Tried to modify a read-only Uri");}m.Xb=function(a){this.ea=a;this.Ia&&this.Ia.Xb(a);return this}; 222 | function qh(){var a=window.location;return a instanceof eh?a.Ya():new eh(a,void 0)}function kh(a,b){return t(a)?encodeURI(a).replace(b,rh):null}function rh(a){a=a.charCodeAt(0);return"%"+(a>>4&15).toString(16)+(a&15).toString(16)}var lh=/[#\/\?@]/g,nh=/[\#\?:]/g,mh=/[\#\?]/g,ph=/[\#\?@]/g,oh=/#/g;function jh(a,b,c){this.da=a||null;this.ea=!!c} 223 | function sh(a){if(!a.H&&(a.H=new Ff,a.v=0,a.da))for(var b=a.da.split("\x26"),c=0;cb.charCode&&kg(c)?b.charCode:0):bb?(c=this.Aa,d=kg(c)?b.keyCode:0):(c=b.keyCode||this.Aa,d=b.charCode||0,yh&&(e=this.sb),fb&&(63==d&&224==c)&&(c=191));var f=c,h=b.keyIdentifier;c?63232<=c&&c in vh?f=vh[c]:25==c&&a.shiftKey&&(f=9):h&&h in wh&&(f=wh[h]);a=f==this.ba;this.ba=f;b=new zh(f,d,a,b);b.altKey=e;this.dispatchEvent(b)}; 230 | uh.prototype.detach=function(){this.kb&&(Lb(this.kb),Lb(this.Ub),Lb(this.lb),this.lb=this.Ub=this.kb=null);this.ab=null;this.Aa=this.ba=-1};function zh(a,b,c,d){d&&this.eb(d,void 0);this.type="key";this.keyCode=a;this.charCode=b;this.repeat=c}pa(zh,vb);var Ah={},Bh=Af.c(Me),be=Af.c(null),Ch=Af.c(!1),Dh=Af.c(null),Eh=Af.c(null),Fh=function(){function a(a){var d=null;0show/hide") 130 | 131 | (defn toggle-visibility [head body] 132 | (if (style/isElementShown body) 133 | (do (style/showElement body false) 134 | (classes/remove head "unfolded") 135 | (classes/add head "folded")) 136 | (do (style/showElement body true) 137 | (classes/remove head "folded") 138 | (classes/add head "unfolded")))) 139 | 140 | (defn handle-show-hide [event] 141 | (. event (preventDefault)) 142 | (let [head-elem (. event -currentTarget) 143 | body-elem (first (dom-tags "div" nil (nearest-containing-div head-elem)))] 144 | (toggle-visibility head-elem body-elem))) 145 | 146 | (defn install-folds [] 147 | (doseq [{:keys [head-elem body-elem]} (get-folds)] 148 | (toggle-visibility head-elem body-elem) 149 | (let [a (dom/htmlToDocumentFragment show-hide-html)] 150 | (. head-elem (appendChild a)) 151 | (let [a (dom-tags "a" "show-hide" head-elem)] 152 | (events/listen head-elem goog.events.EventType.CLICK 153 | handle-show-hide))))) 154 | 155 | ;;; CONTROL PANEL 156 | 157 | (def control-html 158 | "") 183 | 184 | (defn show-control-panel [] 185 | (style/setStyle (dom/getElement "c-panel") "opacity" 0.75)) 186 | 187 | (defn hide-control-panel [] 188 | (style/setStyle (dom/getElement "c-panel") "opacity" 0.0)) 189 | 190 | (defn install-control-panel [] 191 | (. (body-elem) (appendChild (dom/htmlToDocumentFragment control-html))) 192 | (let [panel (dom/getElement "c-panel")] 193 | (dispatch/fire :show-control-panel) 194 | (Timer/callOnce (fire-handler :hide-control-panel) 3000) 195 | (events/listen panel goog.events.EventType.MOUSEOVER 196 | (fire-handler :show-control-panel)) 197 | (events/listen panel goog.events.EventType.MOUSEOUT 198 | (fire-handler :hide-control-panel)) 199 | (events/listen (dom/getElement "c-toggle") 200 | goog.events.EventType.CLICK 201 | (fire-handler :toggle-mode)) 202 | (events/listen (dom/getElement "c-first") 203 | goog.events.EventType.CLICK 204 | (fire-handler :show-first-slide)) 205 | (events/listen (dom/getElement "c-prev") 206 | goog.events.EventType.CLICK 207 | (fire-handler :show-prev-slide)) 208 | (events/listen (dom/getElement "c-next") 209 | goog.events.EventType.CLICK 210 | (fire-handler :show-next-slide)) 211 | (events/listen (dom/getElement "c-last") 212 | goog.events.EventType.CLICK 213 | (fire-handler :show-last-slide)) 214 | (events/listen (dom/getElement "c-presenter-window") 215 | goog.events.EventType.CLICK 216 | (fire-handler :show-presenter-window)))) 217 | 218 | 219 | ;;; SLIDES 220 | 221 | (def current-slide-div-html 222 | "
") 223 | 224 | (defn nearest-containing-div [elem] 225 | (if (= "DIV" (. elem -nodeName)) 226 | elem 227 | (recur (. elem -parentNode)))) 228 | 229 | (def heading-tag-names (set (map #(str "H" %) (range 1 9)))) 230 | 231 | (defn copy-heading-tags-to-div-classes [] 232 | (doseq [tags (dom-tags "span" "tag")] 233 | (let [div (nearest-containing-div tags)] 234 | (when-not (= "text-table-of-contents" (.-id div)) 235 | (doseq [tag (dom-tags "span" nil tags)] 236 | (classes/add div (classes/get tag))))))) 237 | 238 | (defn remove-nested-sections [slide-div-elem] 239 | (let [div (. slide-div-elem (cloneNode true))] 240 | (doseq [elem (dom-tags "div" nil div)] 241 | (when (and (not ) 242 | (some #(classes/has elem (str "outline-" %)) (range 1 9))) 243 | (remove-elem elem))) 244 | div)) 245 | 246 | (defn slide-notes-html [slide-div-elem] 247 | (if-let [div (first (filter (fn [elem] 248 | (and (= "DIV" (.-nodeName elem)) 249 | (classes/has elem "notes"))) 250 | (.-children slide-div-elem)))] 251 | (dom/getOuterHtml div) 252 | "")) 253 | 254 | (defn get-slides [] 255 | (vec (map (fn [elem] 256 | {:id (. elem -id) 257 | :html (dom/getOuterHtml (remove-nested-sections elem)) 258 | :notes-html (slide-notes-html elem)}) 259 | (dom-tags "div" "slide")))) 260 | 261 | (defn slide-from-id [id] 262 | (some (fn [slide] (when (= id (:id slide)) slide)) @slides)) 263 | 264 | (defn find-slide-after [id] 265 | (second (drop-while #(pos? (string/numerateCompare id (:id %))) 266 | @slides))) 267 | 268 | (defn current-slide [] 269 | (let [fragment-id (location-fragment) 270 | target-id (if (string/startsWith fragment-id "outline-container-") 271 | fragment-id 272 | (str "outline-container-" fragment-id))] 273 | (or (slide-from-id target-id) 274 | (and (seq fragment-id) (find-slide-after target-id)) 275 | (first @slides)))) 276 | 277 | (defn next-slide [] 278 | (find-slide-after (:id (current-slide)))) 279 | 280 | (defn show-slide [{:keys [id html]}] 281 | (set-location-fragment id) 282 | (set! (. (dom/getElement "current-slide") -innerHTML) html) 283 | (show-presenter-slides)) 284 | 285 | 286 | ;;; GUI EVENTS 287 | 288 | (defn enter-slideshow-mode [] 289 | (info '(enter-slideshow-mode)) 290 | (hide! (d/by-id "preamble")) 291 | (hide! (d/by-id "content")) 292 | (hide! (d/by-id "postamble")) 293 | (remove-stylesheets (get @stylesheet-urls "screen")) 294 | (add-stylesheets (get @stylesheet-urls "projection")) 295 | (show! (d/by-id "current-slide")) 296 | (show-slide (current-slide))) 297 | 298 | (defn leave-slideshow-mode [] 299 | (info '(leave-slideshow-mode)) 300 | (hide! (d/by-id "current-slide")) 301 | (remove-stylesheets (get @stylesheet-urls "projection")) 302 | (add-stylesheets (get @stylesheet-urls "screen")) 303 | (show! (d/by-id "preamble")) 304 | (show! (d/by-id "content")) 305 | (show! (d/by-id "postamble")) 306 | (. (dom/getElement (location-fragment)) (scrollIntoView))) 307 | 308 | (defn change-mode [] 309 | (if @slideshow-mode? 310 | (enter-slideshow-mode) 311 | (leave-slideshow-mode))) 312 | 313 | (defn toggle-mode [] 314 | (info '(toggle-mode)) 315 | (swap! slideshow-mode? not)) 316 | 317 | (add-watch slideshow-mode? :change-mode 318 | (fn [k r o n] 319 | (dispatch/fire :change-mode))) 320 | 321 | (defn show-next-slide [] 322 | (let [current (current-slide) 323 | next (second (drop-while #(not= current %) @slides))] 324 | (when next (show-slide next)) 325 | (swap! presenter-start-time (fn [t] 326 | (if (nil? t) 327 | (.getTime (js/Date.)) 328 | t))))) 329 | 330 | (defn show-prev-slide [] 331 | (let [current (current-slide) 332 | prev (last (take-while #(not= current %) @slides))] 333 | (when prev (show-slide prev)))) 334 | 335 | (defn show-first-slide [] 336 | (show-slide (first @slides))) 337 | 338 | (defn show-last-slide [] 339 | (show-slide (last @slides))) 340 | 341 | (defn go-to-top [] 342 | (set-location-fragment "top") 343 | (. window (scrollTo 0 0))) 344 | 345 | 346 | ;;; KEYBOARD 347 | 348 | (def normal-keymap 349 | {goog.events.KeyCodes.T :toggle-mode 350 | goog.events.KeyCodes.HOME :go-to-top}) 351 | 352 | (def slideshow-keymap 353 | {goog.events.KeyCodes.T :toggle-mode 354 | 355 | goog.events.KeyCodes.HOME :show-first-slide 356 | goog.events.KeyCodes.END :show-last-slide 357 | 358 | goog.events.KeyCodes.SPACE :show-next-slide 359 | goog.events.KeyCodes.ENTER :show-next-slide 360 | goog.events.KeyCodes.MAC_ENTER :show-next-slide 361 | goog.events.KeyCodes.RIGHT :show-next-slide 362 | goog.events.KeyCodes.DOWN :show-next-slide 363 | goog.events.KeyCodes.PAGE_DOWN :show-next-slide 364 | goog.events.KeyCodes.N :show-next-slide 365 | 366 | goog.events.KeyCodes.LEFT :show-prev-slide 367 | goog.events.KeyCodes.UP :show-prev-slide 368 | goog.events.KeyCodes.PAGE_UP :show-prev-slide 369 | goog.events.KeyCodes.P :show-prev-slide}) 370 | 371 | (defn handle-key [event] 372 | (let [code (. event -keyCode) 373 | keymap (if @slideshow-mode? slideshow-keymap normal-keymap) 374 | event-id (get keymap code)] 375 | (when event-id 376 | (dispatch/fire event-id) 377 | (. event (preventDefault)) 378 | (. event (stopPropagation))))) 379 | 380 | (defn install-keyhandler [document] 381 | (events/listen (goog.events.KeyHandler. document) 382 | goog.events.KeyHandler.EventType.KEY 383 | handle-key)) 384 | 385 | 386 | ;;; PRESENTER WINDOW 387 | 388 | (def presenter-display-html 389 | " 390 | 391 | 392 | 393 | 394 |
395 |
396 | Current Slide 397 |
398 |
399 |
400 |
401 | Next Slide 402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 | 0:00:00 410 | 411 | reset 412 | 413 |
414 |
415 |
416 | 417 | 418 | ") 419 | 420 | (defn get-presenter-window [] 421 | (when @presenter-window 422 | (if (. @presenter-window -closed) 423 | (reset! presenter-window nil) 424 | @presenter-window))) 425 | 426 | (defn update-presenter-clock-time [win] 427 | (let [elem (.. win -document 428 | (getElementById "presenter-clock-time")) 429 | now (js/Date.) 430 | hours (. now (getHours)) 431 | display-hours (if (< 12 hours) (- hours 12) hours)] 432 | (set! (. elem -innerHTML) 433 | (goog.string.format 434 | "%d:%02d:%02d %s" 435 | display-hours 436 | (. now (getMinutes)) 437 | (.. now (getSeconds)) 438 | (if (<= 12 hours) 439 | "pm" "am"))))) 440 | 441 | (defn elapsed-time-string [] 442 | (let [elapsed (- (.getTime (js/Date.)) @presenter-start-time) 443 | secs (mod (/ elapsed 1000) 60) 444 | mins (mod (/ elapsed (* 60 1000)) 60) 445 | hours (/ elapsed (* 60 60 1000))] 446 | (goog.string.format 447 | "%d:%02d:%02d" 448 | hours mins secs))) 449 | 450 | (defn update-presenter-elapsed-time [win] 451 | (let [elem (.. win -document 452 | (getElementById "presenter-elapsed-time"))] 453 | (set! (. elem -innerHTML) 454 | (if @presenter-start-time 455 | (elapsed-time-string) 456 | "0:00:00"))) ) 457 | 458 | (defn update-presenter-clock [] 459 | (when-let [win (get-presenter-window)] 460 | (update-presenter-clock-time win) 461 | (update-presenter-elapsed-time win) 462 | (. js/window (setTimeout update-presenter-clock 1000)))) 463 | 464 | (defn reset-elapsed-time [] 465 | (reset! presenter-start-time nil) 466 | (when-let [win (get-presenter-window)] 467 | (update-presenter-elapsed-time win))) 468 | 469 | (defn show-presenter-slides [] 470 | (when-let [win (get-presenter-window)] 471 | (let [{:keys [html notes-html]} (current-slide)] 472 | (let [div (.. win -document 473 | (getElementById "presenter-current-slide"))] 474 | (set! (. div -innerHTML) html)) 475 | (let [div (.. win -document 476 | (getElementById "presenter-notes-container"))] 477 | (set! (. div -innerHTML) notes-html))) 478 | (let [div (.. win -document 479 | (getElementById "presenter-next-slide"))] 480 | (set! (. div -innerHTML) (:html (next-slide)))))) 481 | 482 | (defn show-presenter-window [] 483 | (if-let [win (get-presenter-window)] 484 | (. win (focus)) 485 | (do (reset! presenter-window 486 | (window/open "" (. {:target "PRESENTERDISPLAY" 487 | :toolbar false 488 | :location false 489 | :statusbar false 490 | :menubar false} 491 | -strobj))) 492 | (let [doc (. @presenter-window -document)] 493 | (. doc (write presenter-display-html)) 494 | (add-stylesheets (get @stylesheet-urls "common") doc) 495 | (add-stylesheets (get @stylesheet-urls "projection") doc) 496 | (add-stylesheets (get @stylesheet-urls "presenter") doc) 497 | (install-keyhandler doc) 498 | (events/listen (.getElementById doc "presenter-elapsed-time-reset") 499 | goog.events.EventType.CLICK 500 | (fire-handler :reset-elapsed-time))) 501 | (show-presenter-slides) 502 | (update-presenter-clock)))) 503 | 504 | 505 | ;;; EVENTS 506 | 507 | (defn install-event-handlers [] 508 | (dispatch/react-to #{:show-next-slide} (fn [id _] (show-next-slide))) 509 | (dispatch/react-to #{:show-prev-slide} (fn [id _] (show-prev-slide))) 510 | (dispatch/react-to #{:show-first-slide} (fn [id _] (show-first-slide))) 511 | (dispatch/react-to #{:show-last-slide} (fn [id _] (show-last-slide))) 512 | (dispatch/react-to #{:toggle-mode} (fn [id _] (toggle-mode))) 513 | (dispatch/react-to #{:go-to-top} (fn [id _] (go-to-top))) 514 | (dispatch/react-to #{:show-control-panel} (fn [id _] (show-control-panel))) 515 | (dispatch/react-to #{:hide-control-panel} (fn [id _] (hide-control-panel))) 516 | (dispatch/react-to #{:change-mode} (fn [id _] (change-mode))) 517 | (dispatch/react-to #{:show-presenter-window} (fn [id _] (show-presenter-window))) 518 | (dispatch/react-to #{:reset-elapsed-time} (fn [id _] (reset-elapsed-time)))) 519 | 520 | ;;; INITIAL SETUP 521 | 522 | (defn init-stylesheets [] 523 | (swap! stylesheet-urls assoc 524 | "projection" (stylesheets "projection") 525 | "screen" (stylesheets "screen") 526 | "common" (stylesheets nil) 527 | "presenter" (stylesheets "presenter"))) 528 | 529 | (defn add-image-classes [] 530 | (doseq [img (dom-tags "img")] 531 | (let [p (. img -parentNode)] 532 | (when (= "P" (. p -nodeName)) 533 | (classes/add p "image"))))) 534 | 535 | (defn add-outline-text-class [] 536 | (doseq [i (range 1 9)] 537 | (doseq [elem (dom-tags "div" (str "outline-text-" i))] 538 | (classes/add elem "outline-text")))) 539 | 540 | (defn remove-nbsp [elem] 541 | (set! (.-innerHTML elem) 542 | (.replace (.-innerHTML elem) 543 | (js/RegExp. " " "g") ""))) 544 | 545 | (defn remove-heading-spaces 546 | "Remove extraneous   from org-mode headlines" 547 | [] 548 | (doseq [n (range 1 9) 549 | elem (dom-tags (str "h" n))] 550 | (remove-nbsp elem)) 551 | (doseq [elem (dom-tags "a" nil (dom/getElement "table-of-contents"))] 552 | (remove-nbsp elem))) 553 | 554 | 555 | ;;; MAIN 556 | 557 | (defn main [] 558 | (.setCapturing (goog.debug.Console.) true) 559 | (info "Application started") 560 | (info "Preparing document") 561 | (init-stylesheets) 562 | (remove-stylesheets (get @stylesheet-urls "projection")) 563 | (remove-stylesheets (get @stylesheet-urls "presenter")) 564 | (add-image-classes) 565 | (copy-heading-tags-to-div-classes) 566 | (add-outline-text-class) 567 | (remove-heading-spaces) 568 | (install-folds) 569 | (. (body-elem) 570 | (appendChild (dom/htmlToDocumentFragment current-slide-div-html))) 571 | (hide! (d/by-id "current-slide")) 572 | (reset! slides (get-slides)) 573 | (info '(count slides) (count @slides)) 574 | (info "Installing key handler") 575 | (install-event-handlers) 576 | (install-control-panel) 577 | (install-keyhandler (dom/getDocument))) 578 | 579 | (main) 580 | -------------------------------------------------------------------------------- /src/css/common.css: -------------------------------------------------------------------------------- 1 | /* Org-HTML-Slideshow common styles. 2 | * 3 | * These styles will apply to all views. 4 | */ 5 | 6 | body { 7 | font-family: Helvetica, Arial, sans-serif; 8 | } 9 | 10 | span.tag { 11 | display: none; 12 | } 13 | 14 | pre { 15 | font-family: Monaco, "Courier New", monospace; 16 | } 17 | 18 | #c-panel { 19 | background: lightgray; 20 | bottom: 0px; 21 | border: 1px solid black; 22 | font-size: 12pt; 23 | position: fixed; 24 | right: 0px; 25 | } 26 | 27 | #c-panel a { 28 | display: block; 29 | } 30 | 31 | #c-panel .key { 32 | display: none; 33 | } 34 | 35 | #c-panel .key { 36 | display: none; 37 | } 38 | -------------------------------------------------------------------------------- /src/css/presenter.css: -------------------------------------------------------------------------------- 1 | /* Org-HTML-Slideshow presenter styles. 2 | * 3 | * These styles will apply only to the presenter preview. 4 | */ 5 | 6 | body.presenter-display { 7 | background-color: black; 8 | } 9 | 10 | .presenter-label { 11 | color: white; 12 | font-family: Helvetica, Arial, sans-serif; 13 | } 14 | 15 | #presenter-current-slide-container { 16 | bottom: 200px; 17 | height: 40%; 18 | left: 1%; 19 | overflow: hidden; 20 | position: absolute; 21 | top: 0; 22 | vertical-align: top; 23 | width: 50%; 24 | zoom: 60%; 25 | } 26 | 27 | #presenter-next-slide-container { 28 | height: 30%; 29 | overflow: hidden; 30 | position: absolute; 31 | right: 1%; 32 | top: 1%; 33 | vertical-align: top; 34 | width: 40%; 35 | zoom: 50%; 36 | } 37 | 38 | #presenter-current-slide { 39 | background: white; 40 | height: 100%; 41 | padding: 12pt; 42 | } 43 | 44 | #presenter-next-slide { 45 | background: white; 46 | height: 100%; 47 | padding: 12pt; 48 | } 49 | 50 | #presenter-times { 51 | bottom: 1%; 52 | font-size: 2.5em; 53 | position: absolute; 54 | text-align: center; 55 | height: 12%; 56 | width: 98%; 57 | } 58 | 59 | #presenter-elapsed-time-container { 60 | position: absolute; 61 | left: 1%; 62 | width: 45%; 63 | } 64 | 65 | #presenter-clock-time { 66 | position: absolute; 67 | right: 1%; 68 | width: 45%; 69 | } 70 | 71 | #presenter-clock-time-ampm { 72 | font-size: 0.5em; 73 | } 74 | 75 | #presenter-elapsed-time-reset-container { 76 | font-size: 12pt; 77 | } 78 | 79 | a#presenter-elapsed-time-reset { 80 | color: cyan; 81 | } 82 | 83 | #presenter-notes-container { 84 | position: absolute; 85 | overflow: auto; 86 | top: 40%; 87 | left: 10px; 88 | height: 45%; 89 | width: 98%; 90 | font-size: 18pt; 91 | color: white; 92 | } 93 | 94 | #presenter-notes-container h1,#presenter-notes-container h2,#presenter-notes-container h3,#presenter-notes-container h4,#presenter-notes-container h5,#presenter-notes-container h6,#presenter-notes-container h7,#presenter-notes-container h8 { 95 | font-size: 12pt; 96 | text-align: left; 97 | } -------------------------------------------------------------------------------- /src/css/projection.css: -------------------------------------------------------------------------------- 1 | /* Org-HTML-Slideshow projection styles. 2 | * 3 | * These styles will apply only to the slide-show view. 4 | */ 5 | 6 | body { 7 | margin: 18pt; 8 | font-size: 24pt; 9 | } 10 | 11 | /* Use all headings as slide titles, regardless of level. */ 12 | h1,h2,h3,h4,h5,h6,h7,h8 { 13 | font-size: 48pt; 14 | margin: 18pt; 15 | text-align: center; 16 | } 17 | 18 | li { 19 | margin: 12pt; 20 | } 21 | 22 | /* Center embedded images. */ 23 | p.image { 24 | text-align: center; 25 | } 26 | 27 | /* Hide Org-Mode tags in slide-show view. */ 28 | span.tag { 29 | display: none; 30 | } 31 | 32 | /* Hide Org-Mode section numbers in slide-show view. */ 33 | span.section-number-1,span.section-number-2,span.section-number-3,span.section-number-4,span.section-number-5,span.section-number-6,span.section-number-7,span.section-number-8 { 34 | display: none; 35 | } 36 | 37 | .blue_background { 38 | background: blue; 39 | color: white; 40 | } 41 | -------------------------------------------------------------------------------- /src/css/screen.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/relevance/org-html-slideshow/4ba9c2cc965a026f75f0bae2d0e77b65fe94bc4d/src/css/screen.css --------------------------------------------------------------------------------