@tblaisot/prez-as-adoc 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.github/workflows/release.yml +18 -0
  2. package/README.adoc +30 -0
  3. package/asciidoctor/extensions/slides_treeprocessor.js +96 -0
  4. package/asciidoctor/extensions/speaker_notes_treeprocessor.js +40 -0
  5. package/asciidoctor/templates/admonition.js +10 -0
  6. package/asciidoctor/templates/document.js +86 -0
  7. package/asciidoctor/templates/package.json +3 -0
  8. package/asciidoctor/templates/preamble.js +11 -0
  9. package/asciidoctor/templates/section.js +29 -0
  10. package/asciidoctor/templates/slide.js +54 -0
  11. package/asciidoctor/templates/speaker_note.js +12 -0
  12. package/asciidoctor/templates/title.js +24 -0
  13. package/bespoke-plugins/bespoke-classes.js +44 -0
  14. package/bespoke-plugins/bespoke-debug.js +30 -0
  15. package/bespoke-plugins/bespoke-editor.js +96 -0
  16. package/bespoke-plugins/bespoke-hash.js +89 -0
  17. package/bespoke-plugins/bespoke-nav.js +46 -0
  18. package/bespoke-plugins/bespoke-overview.js +21 -0
  19. package/bespoke-plugins/bespoke-progress.js +18 -0
  20. package/bespoke-plugins/bespoke-scale.js +45 -0
  21. package/bespoke-plugins/bespoke-speaker.js +112 -0
  22. package/bespoke-plugins/bespoke-view-mode.js +51 -0
  23. package/bin/prez-as-adoc.js +52 -0
  24. package/package.json +30 -0
  25. package/statics/assets/bespoke-speaker.css +193 -0
  26. package/statics/assets/bespoke-speaker.html +45 -0
  27. package/statics/assets/bespoke-speaker.js +100 -0
  28. package/statics/styles/blocks/progress.css +56 -0
  29. package/statics/styles/debug.css +9 -0
  30. package/statics/styles/deck/deck-full.css +19 -0
  31. package/statics/styles/deck/deck-grid.css +13 -0
  32. package/statics/styles/deck/deck-list.css +58 -0
  33. package/statics/styles/deck/deck-pointless.css +5 -0
  34. package/statics/styles/deck/deck-print.css +11 -0
  35. package/statics/styles/deck/deck.css +31 -0
  36. package/statics/styles/main.css +6 -0
  37. package/statics/styles/normalize.css +226 -0
  38. package/statics/styles/slide/slide-full.css +16 -0
  39. package/statics/styles/slide/slide-list.css +31 -0
  40. package/statics/styles/slide/slide.css +28 -0
  41. package/vitejs/plugins/prez-as-adoc-plugin.js +114 -0
@@ -0,0 +1,18 @@
1
+ name: Publish Package to npmjs
2
+ on:
3
+ release:
4
+ types: [published]
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v3
10
+ # Setup .npmrc file to publish to npm
11
+ - uses: actions/setup-node@v3
12
+ with:
13
+ node-version: '16.x'
14
+ registry-url: 'https://registry.npmjs.org'
15
+ - run: npm ci
16
+ - run: npm publish --access public
17
+ env:
18
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.adoc ADDED
@@ -0,0 +1,30 @@
1
+ = prez-as-adoc
2
+
3
+ This is a project to generate Bespoke slide deck.
4
+
5
+ It allow to use slide templates (layout).
6
+
7
+ It can be used as a CLI or as a Vite plugin (prefered method).
8
+
9
+ == Usage as CLI
10
+
11
+ [source,bash]
12
+ ----
13
+ prez-as-adoc --base_dir=./src --to_dir=./dist --slides-templates=./slide-templates ./src/index.adoc
14
+ ----
15
+
16
+ == Usage as Vite Plugin
17
+
18
+ .vite.config.js
19
+ [source,bash]
20
+ ----
21
+ // vite.config.js
22
+ import { prezAsAdocPlugin } from '@tblaisot/prez-as-adoc/vitejs/plugins/prez-as-adoc-plugin.js'
23
+ import { defineConfig } from 'vite'
24
+
25
+ export default defineConfig({
26
+ plugins: [
27
+ prezAsAdocPlugin({slidesTemplates: ['./slide-templates']})
28
+ ]
29
+ })
30
+ ----
@@ -0,0 +1,96 @@
1
+ import {HELPERS} from "@tblaisot/asciidoctor-js-templates";
2
+ const {sectionTitle, slice_text, $h, $div} = HELPERS;
3
+
4
+ function debugAST(node) {
5
+ return {
6
+ context: node.getContext(),
7
+ blocks: node.getBlocks().map(n => debugAST(n)),
8
+ }
9
+ }
10
+
11
+ export function register(registry) {
12
+ registry.treeProcessor(function () {
13
+ const self = this
14
+ self.process(function (document) {
15
+
16
+ // document.findBy({context: 'page_break'}).forEach((node) => {
17
+ // const parentSection = node.getParent();
18
+ // const breakIndex = parentSection.getBlocks().indexOf(node)
19
+ // const blockAfterBreak = parentSection.getBlocks().slice(breakIndex)
20
+ // const grandParentSection = parentSection.getParent();
21
+ // const slide = self.createBlock(document, 'slide', '', {...parentSection.getAttributes(), level: parentSection.getLevel()});
22
+ // blockAfterBreak.forEach((block) => {
23
+ // slide.getBlocks().push(block);
24
+ // })
25
+ // grandParentSection.getBlocks().splice(grandParentSection.getBlocks().indexOf(parentSection), 0, slide);
26
+ //
27
+ // // remove block after
28
+ // parentSection.getBlocks().splice(breakIndex, parentSection.getBlocks().length - parentSection.getBlocks() - 1)
29
+ // })
30
+
31
+ function recurse(node) {
32
+ const sections = node.getSections()
33
+ if (sections.length === 0) return;
34
+ sections.forEach((section) => {
35
+ const slide = self.createBlock(document, 'slide', '', {
36
+ ...section.getAttributes(),
37
+ level: section.getLevel()
38
+ });
39
+ const title = self.createBlock(slide, 'title', sectionTitle(section), {
40
+ level: section.getLevel(),
41
+ slot: 'title'
42
+ });
43
+ slide.getBlocks().push(title)
44
+ section.getBlocks().forEach((block) => {
45
+ slide.getBlocks().push(block);
46
+ })
47
+ node.getBlocks().splice(node.getBlocks().indexOf(section), 1); // remove node from parent
48
+ document.getBlocks().push(slide); // push slide to first level of the document
49
+ recurse(slide)
50
+ })
51
+ }
52
+
53
+ recurse(document)
54
+ // console.log(JSON.stringify(debugAST(document), null, 2))
55
+
56
+ // create title slide
57
+ const attrName = document.getAttribute('slide-template-attr', 'slide-template', 'slide-template-attr');
58
+
59
+ const title_slide = self.createBlock(document, 'slide', '', {
60
+ [attrName]: 'title-slide', ...document.getAttributes(),
61
+ level: 0
62
+ });
63
+
64
+ const _title_obj = document.getDoctitle({partition: true, use_fallback: true});
65
+ if (_title_obj.subtitle) {
66
+ const _slice = document.getHeader().isOption('slice');
67
+ const title1 = self.createBlock(title_slide, 'title', slice_text(_title_obj.main, _slice), {
68
+ level: 1,
69
+ slot: 'title'
70
+ });
71
+ const title2 = self.createBlock(title_slide, 'title', slice_text(_title_obj.subtitle, _slice), {
72
+ level: 2,
73
+ slot: 'subtitle'
74
+ });
75
+ title_slide.getBlocks().push(title1)
76
+ title_slide.getBlocks().push(title2)
77
+ } else {
78
+ const title = self.createBlock(title_slide, 'title', document.getHeader().getTitle(), {
79
+ level: 1,
80
+ slot: 'title'
81
+ });
82
+ title_slide.getBlocks().push(title)
83
+ }
84
+
85
+ const preambles = document.findBy({context: 'preamble'});
86
+ title_slide.getBlocks().push(...preambles);
87
+
88
+ document.getBlocks().splice(0, 0, title_slide);
89
+
90
+ // remove preamble block from document
91
+ document.getBlocks().splice(document.getBlocks().findIndex(b => b === preambles[0]), 1);
92
+
93
+ return document;
94
+ })
95
+ })
96
+ }
@@ -0,0 +1,40 @@
1
+ export function register(registry) {
2
+ registry.treeProcessor(function () {
3
+ const self = this
4
+ self.process(function (document) {
5
+ function recurse(node) {
6
+ const sections = node.getSections()
7
+ if(sections.length === 0) return;
8
+ sections.forEach((section) => {
9
+ section.findBy()
10
+ recurse(slide)
11
+ })
12
+ }
13
+
14
+ recurse(document)
15
+ document.findBy({context: 'open'}).forEach((node) => {
16
+ if (node.hasRole('aside') || node.hasRole('speaker') || node.hasRole('notes')) {
17
+ const note = self.createBlock(document, 'speaker_note', '', {...node.getAttributes()});
18
+ const blocks = node.getParent().getBlocks()
19
+ const node_idx = blocks.indexOf(node)
20
+ node.getBlocks().forEach((block) => {
21
+ note.getBlocks().push(block);
22
+ })
23
+ blocks[node_idx] = note;
24
+ }
25
+ })
26
+ document.findBy({context: 'admonition'}).forEach((node) => {
27
+ if (node.hasRole('aside') || node.hasRole('speaker') || node.hasRole('notes')) {
28
+ const note = self.createBlock(document, 'speaker_note', '', {...node.getAttributes()});
29
+ const blocks = node.getParent().getBlocks()
30
+ const node_idx = blocks.indexOf(node)
31
+ node.getBlocks().forEach((block) => {
32
+ note.getBlocks().push(block);
33
+ })
34
+ blocks[node_idx] = note;
35
+ }
36
+ })
37
+ return document;
38
+ })
39
+ })
40
+ }
@@ -0,0 +1,10 @@
1
+ const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
2
+ const {admonition: admonition_template} = TEMPLATES;
3
+ const {$aside} = HELPERS;
4
+
5
+ module.exports = function ({node}) {
6
+ if (node.hasRole('speaker')) {
7
+ return $aside({role: 'notes', class: 'speaker-notes'}, node.getContent())
8
+ }
9
+ return admonition_template({node})
10
+ }
@@ -0,0 +1,86 @@
1
+ const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
2
+ const {$, $metaIf, toAttribute, toAttributes,isEmptyString} = HELPERS;
3
+
4
+ function getFavicon(node) {
5
+ let favicon = ''
6
+ if (node.document.hasAttribute('favicon')) {
7
+ let icon_href = node.document.getAttribute('favicon');
8
+ if (isEmptyString(icon_href)) {
9
+ icon_href = 'favicon.ico';
10
+ }
11
+ const icon_ext = icon_href.split('.').pop();
12
+ const icon_type = icon_ext === 'ico' ? 'image/x-icon' : `image/${icon_ext}`;
13
+ favicon = $('link', {rel: "icon", type: icon_type, href: icon_href});
14
+ }
15
+ return favicon
16
+ }
17
+
18
+ // false needs to be verbatim everything else is a string.
19
+ // Calling side isn't responsible for quoting so we are doing it here
20
+ function toValidSlideNumber(val) {
21
+ // corner case: empty is empty attribute which is true
22
+ if (val === "") {
23
+ return true;
24
+ }
25
+ // using toString here handles both the 'false' string and the false boolean
26
+ return val.toString() === 'false' ? false : `'${val}'`
27
+ }
28
+
29
+ /**
30
+ * Returns formatted style/link and script tags for header.
31
+ */
32
+ module.exports = function ({node}) {
33
+ const document_content = node.getContent();
34
+ let docinfo_content_header = node.getDocinfo('header', '.html');
35
+ let docinfo_content_head = node.getDocinfo('head', '.html');
36
+ let docinfo_content_footer = node.getDocinfo('footer', '.html');
37
+
38
+
39
+ if (node.getNoheader() || isEmptyString(docinfo_content_header)) {
40
+ docinfo_content_header = '';
41
+ }
42
+ if (isEmptyString(docinfo_content_footer)) {
43
+ docinfo_content_footer = '';
44
+ }
45
+
46
+ const scripts=node.getAttribute('scripts', '').split(',').map(script => `<script type="module" src="${script}"></script>`)
47
+ const stylesheets=node.getAttribute('stylesheets', '').split(',').map(style => `<link rel="stylesheet" type="text/css" href="${style}">`)
48
+
49
+ return `
50
+ <!DOCTYPE html>
51
+ <html ${toAttribute('lang', node.hasAttribute('nolang') ? '' : node.getAttribute('lang', 'en'))}>
52
+ <head>
53
+ <meta charset="utf-8">
54
+ ${$('title', {}, node.getDoctitle() || node.getAttribute('untitled-label'))}
55
+ ${getFavicon(node)}
56
+ ${$metaIf('application-name', node.getAttribute('app-name'))}
57
+ ${$metaIf('author', node.getAttribute('authors'))}
58
+ ${$metaIf('copyright', node.getAttribute('copyright'))}
59
+ ${$metaIf('description', node.getAttribute('description'))}
60
+ ${$metaIf('keywords', node.getAttribute('keywords'))}
61
+ ${$('meta', {name: 'generator', content: `Asciidoctor ${node.getAttribute('asciidoctor-version')}`})}
62
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
63
+ ${stylesheets}
64
+ ${docinfo_content_head}
65
+ </head>
66
+ <body ${toAttributes({
67
+ id: node.getId(),
68
+ class: [
69
+ node.getAttribute('doctype'),
70
+ node.getAttribute('docrole') || node.getAttribute('role'),
71
+ ]
72
+ })}>
73
+ ${docinfo_content_header}
74
+ <div class="slides">
75
+ <!-- START CONTENT -->
76
+ ${document_content}
77
+ <!-- END CONTENT -->
78
+ </div>
79
+ ${docinfo_content_footer}
80
+ ${scripts}
81
+ </body>
82
+ </html>
83
+ `
84
+ }
85
+
86
+
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,11 @@
1
+ const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
2
+ const {$section} = HELPERS;
3
+
4
+ module.exports = function ({node}) {
5
+ return $section({
6
+ id: 'preamble',
7
+ 'aria-label': 'Preamble'
8
+ },
9
+ node.getContent()
10
+ );
11
+ }
@@ -0,0 +1,29 @@
1
+ const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
2
+ const {$h, $a, $section, sectionTitle,isDefined} = HELPERS;
3
+
4
+ module.exports = function ({node}) {
5
+ let content = '';
6
+ if (isDefined(node.getId())) {
7
+ if (node.document.hasAttribute('sectanchors')) {
8
+ content += $a({class: "anchor", href: `#${node.getId()}`, 'aria-hidden': "true"})
9
+ }
10
+ if (node.document.hasAttribute('sectlinks')) {
11
+ content += $a({class: "link", href: `#${node.getId()}`}, sectionTitle(node))
12
+ } else {
13
+ content += sectionTitle(node)
14
+ }
15
+ } else {
16
+ content += sectionTitle(node)
17
+ }
18
+ return $section({
19
+ class: ['doc-section', `level-${node.getLevel()}`, node.getRole()],
20
+ },
21
+ $h({
22
+ level: node.getLevel() + 1,
23
+ id: node.getId()
24
+ },
25
+ content
26
+ ),
27
+ node.getContent()
28
+ )
29
+ }
@@ -0,0 +1,54 @@
1
+ const {resolve} = require("path");
2
+ const {readFileSync, existsSync} = require("fs");
3
+ const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
4
+ const {$, isEmptyString} = HELPERS;
5
+
6
+ function resolveTemplate(paths, templateName) {
7
+ // find in folders
8
+ for(let path of paths){
9
+ const templatePath = resolve(path,`${templateName}-slide.html`)
10
+ if(existsSync(templatePath)){
11
+ return readFileSync(templatePath, {encoding: 'utf-8'});
12
+ }
13
+ }
14
+ throw new Error(`No Match found for template "${templateName}" in folders ${JSON.stringify(this._paths)}`)
15
+ }
16
+
17
+ module.exports = function ({node}) {
18
+ const templateAttrName = node.getAttribute('slide-template-attr', 'template', 'slide-template-attr');
19
+ const defaultTemplate = node.getAttribute('slide-default-template', '', 'slide-default-template');
20
+ const template = node.getAttribute(templateAttrName, defaultTemplate);
21
+
22
+ let slideContent = '';
23
+
24
+ if (isEmptyString(template)) {
25
+ slideContent = node.getBlocks().map(n => n.convert()).join('\n')
26
+ } else {
27
+ slideContent = resolveTemplate(node.document.getAttribute('slide-template-dirs'), template);
28
+ const blockBySlot = node.getBlocks().reduce(
29
+ (acc, n) => {
30
+ const slot = n.getAttribute('slot') || 'default'
31
+ if (!acc[slot]) {
32
+ acc[slot] = [];
33
+ }
34
+ acc[slot].push(n);
35
+ return acc;
36
+ },
37
+ {});
38
+ // Special slot
39
+ blockBySlot['all'] = node.getBlocks();
40
+ Object.entries(blockBySlot).forEach(([slotname, blocks]) => {
41
+ const content = $(blocks.map(n => n.convert()));
42
+ slideContent = slideContent.replace(`<!-- slot=${slotname} -->`, content);
43
+ })
44
+ }
45
+ return $('section', {
46
+ class: [
47
+ 'slide',
48
+ template,
49
+ node.getRole()
50
+ ]
51
+ },
52
+ slideContent
53
+ );
54
+ }
@@ -0,0 +1,12 @@
1
+ const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
2
+ const {$} = HELPERS;
3
+
4
+ module.exports = function ({node}) {
5
+ return $('aside',
6
+ {
7
+ id: node.getId(),
8
+ class: ['speaker-notes'],
9
+ },
10
+ node.getBlocks().map(block => block.convert()).join('\n')
11
+ )
12
+ }
@@ -0,0 +1,24 @@
1
+ const {HELPERS, TEMPLATES} = require("@tblaisot/asciidoctor-js-templates");
2
+ const {$, $h, $a, isDefined, sectionTitle} = HELPERS;
3
+
4
+ module.exports = function ({node}) {
5
+ let content = '';
6
+ if (isDefined(node.getId())) {
7
+ if (node.document.hasAttribute('sectanchors')) {
8
+ content += $a({class: "anchor", href: `#${node.getId()}`, 'aria-hidden': "true"})
9
+ }
10
+ if (node.document.hasAttribute('sectlinks')) {
11
+ content += $a({class: "link", href: `#${node.getId()}`}, node.getContent())
12
+ } else {
13
+ content += node.getContent()
14
+ }
15
+ } else {
16
+ content += node.getContent()
17
+ }
18
+ return $h({
19
+ level: node.getAttribute('level') + 1,
20
+ id: node.getId()
21
+ },
22
+ content
23
+ );
24
+ }
@@ -0,0 +1,44 @@
1
+ export default function () {
2
+ return function (deck) {
3
+ function addClass(el, cls) {
4
+ el.classList.add(cls);
5
+ }
6
+
7
+ function removeClass(el, cls) {
8
+ el.className = el.className
9
+ .replace(new RegExp('(\\s|^)' +cls + '(\\s|$)', 'g'), ' ')
10
+ .trim();
11
+ }
12
+
13
+ function deactivate(el, index) {
14
+ const activeSlide = deck.slides[deck.slide()];
15
+ const offset = index - deck.slide();
16
+ const offsetClass = offset > 0 ? 'after' : 'before';
17
+
18
+ // removeClass(el, 'before(-\\d+)?');
19
+ // removeClass(el, 'after(-\\d+)?');
20
+ removeClass(el, 'active');
21
+ removeClass(el, 'inactive');
22
+ removeClass(el, 'before');
23
+ removeClass(el, 'after');
24
+
25
+ if (el !== activeSlide) {
26
+ addClass(el, 'inactive');
27
+ addClass(el, offsetClass);
28
+ // addClass(el, 'slide-' + offsetClass);
29
+ // addClass(el, 'slide-' + offsetClass + '-' + Math.abs(offset));
30
+ }
31
+ }
32
+
33
+ addClass(deck.parent, 'parent');
34
+ // deck.slides.map(function (el) {
35
+ // addClass(el, 'slide');
36
+ // });
37
+
38
+ deck.on('activate', function (e) {
39
+ deck.slides.map(deactivate);
40
+ addClass(e.slide, 'active');
41
+ removeClass(e.slide, 'inactive');
42
+ });
43
+ };
44
+ };
@@ -0,0 +1,30 @@
1
+
2
+ const KEY_D = "d";
3
+ const DEBUG_CLASS='debug';
4
+
5
+ export default function () {
6
+ return function (deck) {
7
+
8
+ function debugOverflow(){
9
+ if(deck.parent.classList.contains(DEBUG_CLASS)) {
10
+ const currentSlide = deck.slides[deck.slide()];
11
+ Array.from(currentSlide.children).forEach(el => {
12
+ if (el.scrollHeight > currentSlide.clientHeight) {
13
+ deck.parent.classList.add("overflowing");
14
+ } else {
15
+ deck.parent.classList.remove("overflowing");
16
+ }
17
+ });
18
+ }
19
+ }
20
+ deck.addKeyHandler(KEY_D, () => {
21
+ deck.parent.classList.toggle(DEBUG_CLASS);
22
+ debugOverflow();
23
+ });
24
+
25
+ deck.on('activate', function (e) {
26
+ debugOverflow()
27
+ });
28
+
29
+ };
30
+ };
@@ -0,0 +1,96 @@
1
+ const KEY_E = "e";
2
+ const EDITOR_CLASS = 'editor';
3
+
4
+ export default function () {
5
+ return function (deck) {
6
+ let preview;
7
+ let previewContainer;
8
+
9
+ function scrollIntoView() {
10
+ const currentSlide = deck.slides[deck.slide()];
11
+ currentSlide.scrollIntoView({block: 'center', inline: 'center'});
12
+ }
13
+
14
+ function updateScaleList() {
15
+ const firstSlide = deck.slides[0];
16
+ const innerWidth = deck.parent.offsetWidth;
17
+ const innerHeight = deck.parent.offsetHeight;
18
+ const { offsetWidth, offsetHeight } = firstSlide;
19
+
20
+ const listScale = 1 / Math.max(offsetWidth / innerWidth, offsetHeight / innerHeight);
21
+
22
+ deck.parent.style.setProperty('--deck-list-scale', listScale);
23
+ }
24
+
25
+ function updateScalePreview() {
26
+ const innerWidth = preview.offsetWidth;
27
+ const innerHeight = preview.offsetHeight;
28
+ const {offsetWidth, offsetHeight} = previewContainer.children[0];
29
+
30
+ const fullScale = 1 / Math.max(offsetWidth / innerWidth, offsetHeight / innerHeight);
31
+
32
+ preview.style.setProperty('--deck-full-scale', fullScale);
33
+ }
34
+
35
+ const eventsHandlers = [];
36
+
37
+ function bindSlideClick() {
38
+ deck.slides.forEach((slide, index) => {
39
+ eventsHandlers.push(slide.addEventListener('click', () => {
40
+ deck.slide(index)
41
+ }));
42
+ });
43
+ }
44
+
45
+ function unbindSlideClick() {
46
+ deck.slides.forEach((slide, index) => {
47
+ slide.removeEventListener('click', eventsHandlers[index]);
48
+ });
49
+ }
50
+
51
+ function mountEditor() {
52
+ deck.parent.classList.add('list')
53
+ preview = document.createElement('div');
54
+ preview.classList.add('preview');
55
+ previewContainer = document.createElement('div');
56
+ previewContainer.classList.add('slides', 'full');
57
+ preview.appendChild(previewContainer);
58
+ document.body.appendChild(preview);
59
+ updatePreview();
60
+ bindSlideClick();
61
+ }
62
+
63
+ function unmountEditor() {
64
+ deck.parent.classList.remove('list')
65
+ preview.removeChild(previewContainer);
66
+ previewContainer = null;
67
+ document.body.removeChild(preview);
68
+ preview = null;
69
+ unbindSlideClick();
70
+ }
71
+
72
+ function updatePreview() {
73
+ if (previewContainer) {
74
+ previewContainer.innerHTML = deck.slides[deck.slide()]?.outerHTML;
75
+ updateScalePreview();
76
+ updateScaleList();
77
+ scrollIntoView();
78
+ }
79
+ }
80
+
81
+ deck.addKeyHandler(KEY_E, () => {
82
+ deck.toogleMode(EDITOR_CLASS);
83
+ });
84
+ deck.on('viewmode', function (e) {
85
+ if (e.current === EDITOR_CLASS) {
86
+ mountEditor();
87
+ } else if (preview) {
88
+ unmountEditor();
89
+ }
90
+ });
91
+ deck.on('activate', function (e) {
92
+ updatePreview()
93
+ });
94
+
95
+ };
96
+ };