├── .gitignore
├── .npmignore
├── .vscode
└── settings.json
├── README.md
├── examples
└── tsnyc-jan-2020.md
├── img
├── config.png
├── slides-after.png
└── slides.png
├── package.json
├── rollup.config.js
├── scripts
├── getDTS.js
└── getRevealAssets.js
├── src
├── index.ts
├── slideshow
│ ├── ambient.d.ts
│ ├── markdown.js
│ ├── marked.js
│ ├── reveal.d.ts
│ ├── slideshow.css
│ └── slideshow.ts
└── vendor
│ ├── ds
│ └── createDesignSystem.d.ts
│ ├── playground.d.ts
│ ├── pluginUtils.d.ts
│ ├── sandbox.d.ts
│ ├── tsWorker.d.ts
│ ├── typescript-vfs.d.ts
│ └── utils.ts
├── tsconfig.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *-error.log
3 | dist
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | .gitignore
3 | rollup.config.jss
4 | !dist
5 | scripts
6 | .vscode
7 | yarn*
8 | tsconfig.json
9 | rollup*
10 | img
11 | examples
12 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib"
3 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## TypeScript Playground Present
2 |
3 | A way to present your TypeScript talk in style!
4 |
5 | This plugin adds a copy of [Reveal.js](https://github.com/hakimel/reveal.js) above the playground, slides are created
6 | using Markdown (via [marked](https://github.com/markedjs/marked)) and have the ability to set the text in the playground.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | With markdown looking like:
15 |
16 | ````md
17 |
18 |
19 | # TSNYC Jan 2020
20 |
21 | ---
22 |
23 | ## What is TypeScript?
24 |
25 | TypeScript extends JavaScript by adding types.
26 |
27 | TypeScript speeds up your development experience by catching errors and providing fixes before you even run your code.
28 |
29 | Any browser, any OS, anywhere JavaScript runs. Entirely Open Source.
30 |
31 | ---
32 |
33 | ## `import type`
34 |
35 | ### Why?
36 |
37 | > ### Guaranteed Side-effect free syntax
38 | >
39 | > Tools like Babel, which don’t type-check can be certain with 100% accuracy
whether to remove the import.
40 |
41 |
42 | // Look at the JS, this isn't included in the output
43 | import {DangerDSLType} from "danger"
44 |
45 | declare const myDSL: DangerDSLType
46 |
47 | myDSL.bitbucket_cloud
48 |
49 | // On the other hand, this one is...
50 | import {danger} from "danger"
51 | danger.git
52 |
53 | // But why?
54 |
55 | // TS keeps track of whether an import is a "JS" value
56 | // or a TypeScript type.
57 | import {DangerDSLJSONType, message} from "danger"
58 | message
59 |
60 | // Babel cannot do this!
61 |
62 | // So now Babel knows that it can always skip these
63 | // 'import type' statements
64 | import type {DangerUtilsDSL} from "danger"
65 |
66 | // Because they can't be used with "JS" values:
67 | import type {markdown} from "danger"
68 |
69 |
70 | ---
71 | ````
72 |
73 | This markdown would turn into 2 slides, where the showing the second would change the Playground's code.
74 |
75 | ## Examples
76 |
77 | - [TSNY Jan 2020](./examples/tsnyc-jan-2020.md) - [gist](https://gist.github.com/orta/d7dbd4cdb8d1f99c52871fb15db620bc)
78 |
_Note: the `` element is not visible, so [view the source](https://gist.githubusercontent.com/orta/d7dbd4cdb8d1f99c52871fb15db620bc/raw/33eff5573a2a592d7be4364a791d6f0e1d557b72/index.md) please._
79 |
80 | ## Useful info for making slides
81 |
82 | 1. Get started by making a gist: https://gist.github.com
83 | 2. Make an `index.md` and add some example markdown
84 | 3. Split your slides with `---`
85 | 4. Save your gist, then tell the playground to load that gist
86 |
87 | #### Playground support
88 |
89 | You can change the playground support by putting your code inside the `` HTML element in the slides. This lets you use
90 | markdown code blocks to show the code in the slides:
91 |
92 | ````md
93 | # Network Requests
94 |
95 | There are a few ways to get info from an API
96 |
97 | ---
98 |
99 | # What is `await`?
100 |
101 | ```ts
102 | const response = await fetch("mysite.com/api/dogs")
103 | ```
104 |
105 |
106 | import fetch from "node-fetch"
107 |
108 | const start = await () => {
109 | const response = await fetch("https://mysite.com/api/dogs)
110 | ...
111 | }
112 |
113 |
114 | ---
115 |
116 | # How do Promises work?
117 | ````
118 |
119 | #### Build In Slides
120 |
121 | Reveal.js supports building out sections in a slide [using fragments]([https://github.com/hakimel/reveal.js#element-attributes](https://revealjs.com/fragments/))
122 |
123 | ```md
124 | # Anyone can contribute
125 |
126 | It takes a village to make a big OSS project
127 | ---
128 | # Extra thanks to
129 |
130 | - Orta Therox
131 | - Danger McShane
132 |
133 | ---
134 | ```
135 |
136 | ## TODO
137 |
138 | - Make it pretty
139 | - Add a back to slides button
140 | - Add a down to code button when playground has changed
141 | - Are there more things we can hook into than just code?
142 |
143 | ## Contributing
144 |
145 | You can use `yarn start` to set up both a copy of rollup to generate the JS, and serve to host it
146 |
147 | ```sh
148 | yarn start
149 | ```
150 |
151 | Then set up the TypeScript playground to get a plugin from from `http://localhost:5000/index.js`.
152 |
--------------------------------------------------------------------------------
/examples/tsnyc-jan-2020.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # TSNYC Jan 2020
4 |
5 | ---
6 |
7 | ## What is TypeScript?
8 |
9 | TypeScript extends JavaScript by adding types.
10 |
11 | TypeScript speeds up your development experience by catching errors and providing fixes before you even run your code.
12 |
13 | Any browser, any OS, anywhere JavaScript runs. Entirely Open Source.
14 |
15 | ---
16 |
17 |
18 |
19 | ## Your organizers: Dan, Jason, Kirill and Orta'
20 |
21 | ---
22 |
23 | ### Meetup Format
24 |
25 | - Summary of TypeScript changes
26 | - Two or Three 10–20 minute talks: Beginner, Intermediate, Advanced
27 | - Q&As after each talk
28 |
29 | Please use #tsnyc on Twitter, Instagram, etc.
30 |
31 | We follow the JSConf Code of Conduct
32 |
33 | ---
34 |
35 | ## v3.8 Five main features
36 |
37 | - Import type
38 | - Private Fields
39 | - Top Level Await
40 | - JSDoc Improvements
41 | - Watch Options
42 |
43 | ---
44 |
45 | ## `import type`
46 |
47 | ### Why?
48 |
49 | > ### Guaranteed Side-effect free syntax
50 | >
51 | > Tools like Babel, which don’t type-check can be certain with 100% accuracy
whether to remove the import.
52 |
53 |
54 | // Look at the JS, this isn't included in the output
55 | import {DangerDSLType} from "danger"
56 |
57 | declare const myDSL: DangerDSLType
58 |
59 | myDSL.bitbucket_cloud
60 |
61 | // On the other hand, this one is...
62 | import {danger} from "danger"
63 | danger.git
64 |
65 | // But why?
66 |
67 | // TS keeps track of whether an import is a "JS" value
68 | // or a TypeScript type.
69 | import {DangerDSLJSONType, message} from "danger"
70 | message
71 |
72 | // Babel cannot do this!
73 |
74 | // So now Babel knows that it can always skip these
75 | // 'import type' statements
76 | import type {DangerUtilsDSL} from "danger"
77 |
78 | // Because they can't be used with "JS" values:
79 | import type {markdown} from "danger"
80 |
81 |
82 | ---
83 |
84 | ## `import type`
85 |
86 | > ### Guaranteed Side-effect-y imports
87 | >
88 | > There are folks who want to rely on importing side-effects, but also import a type from that import
89 |
90 | ---
91 |
92 | ```ts
93 | // This statement will get erased because of import elision.
94 | import { SomeTypeFoo, SomeOtherTypeBar } from "./module-with-side-effects";
95 |
96 | // This statement always sticks around.
97 | import "./module-with-side-effects";
98 | ```
99 |
--------------------------------------------------------------------------------
/img/config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/playground-slides/6916100ebe227ae3886b550eb20f369396414d6a/img/config.png
--------------------------------------------------------------------------------
/img/slides-after.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/playground-slides/6916100ebe227ae3886b550eb20f369396414d6a/img/slides-after.png
--------------------------------------------------------------------------------
/img/slides.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/playground-slides/6916100ebe227ae3886b550eb20f369396414d6a/img/slides.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typescript-playground-presentation-mode",
3 | "description": "Present your TypeScript talk directly in the playground, powered by GitHub gists!",
4 | "repository": {
5 | "url": "https://github.com/orta/playground-slides"
6 | },
7 | "version": "0.5.1",
8 | "main": "dist/index.js",
9 | "author": "Orta Therox",
10 | "license": "MIT",
11 | "keywords": [
12 | "playground-plugin"
13 | ],
14 | "scripts": {
15 | "build": "node scripts/getDTS.js; rollup -c rollup.config.js;",
16 | "start": "concurrently -p \"[{name}]\" -n \"ROLLUP,SITE\" -c \"bgBlue.bold,bgMagenta.bold\" \"yarn rollup -c rollup.config.js --watch\" \"yarn serve dist\"",
17 | "prepublish": "yarn build",
18 | "postinstall": "yarn build"
19 | },
20 | "devDependencies": {
21 | "@polvtypes/reveal.js": "^3.8.1",
22 | "@rollup/plugin-commonjs": "^11.0.2",
23 | "@rollup/plugin-json": "^4.0.2",
24 | "@rollup/plugin-node-resolve": "^7.1.0",
25 | "@rollup/plugin-typescript": "^3.0.0",
26 | "@types/commonmark": "^0.27.4",
27 | "concurrently": "^5.1.0",
28 | "monaco-editor": "^0.19.3",
29 | "node-fetch": "^2.6.0",
30 | "react": "^16.13.1",
31 | "rollup": "^1.31.0",
32 | "serve": "^11.3.0",
33 | "typescript": " 3.8.0-beta"
34 | },
35 | "dependencies": {
36 | "reveal.js": "^3.9.2",
37 | "tslib": "^1.10.0"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import typescript from "@rollup/plugin-typescript";
2 | import node from "@rollup/plugin-node-resolve";
3 | import commonjs from "@rollup/plugin-commonjs";
4 | import json from "@rollup/plugin-json";
5 | import {copyFileSync, existsSync, mkdirSync} from "fs"
6 |
7 | if (!existsSync('dist')) {
8 | mkdirSync('dist')
9 | }
10 |
11 | copyFileSync("src/slideshow/slideshow.css", "dist/slideshow.css")
12 |
13 | export default ["index.ts", "slideshow/slideshow.ts", "slideshow/markdown.js"].map(name => ({
14 | input: `src/${name}`,
15 | output: {
16 | name,
17 | dir: "dist",
18 | format: "amd"
19 | },
20 | plugins: [typescript({ tsconfig: "tsconfig.json" }), commonjs(), node(), json()]
21 | }));
22 |
--------------------------------------------------------------------------------
/scripts/getDTS.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | // Grab the DTS files from the TypeScript website
4 | // then do a bit of string manipulation in order to make it
5 | // compile without _all_ of the dependencies
6 |
7 | const nodeFetch = require("node-fetch").default
8 | const { writeFileSync, existsSync, mkdirSync } = require("fs")
9 | const { join } = require("path")
10 |
11 | const getFileAndStoreLocally = async (url, path, editFunc) => {
12 | const editingFunc = editFunc ? editFunc : text => text
13 | const packageJSON = await nodeFetch(url)
14 | const contents = await packageJSON.text()
15 | writeFileSync(join(__dirname, "..", path), editingFunc(contents), "utf8")
16 | }
17 |
18 | const go = async () => {
19 | const vendor = join("src", "vendor")
20 | const ds = join("src", "vendor", "ds")
21 |
22 | if (!existsSync(vendor)) mkdirSync(vendor)
23 | if (!existsSync(ds)) mkdirSync(ds)
24 |
25 | const host = "https://www.staging-typescript.org"
26 |
27 | // For playground-dev purposes
28 | // const host = "http://localhost:8000";
29 |
30 | // The API for the monaco typescript worker
31 | await getFileAndStoreLocally(host + "/js/sandbox/tsWorker.d.ts", join(vendor, "tsWorker.d.ts"))
32 |
33 | // The Design System DTS
34 | await getFileAndStoreLocally(
35 | host + "/js/playground/ds/createDesignSystem.d.ts",
36 | join(ds, "createDesignSystem.d.ts"),
37 | text => {
38 | const renameImport = text.replace("typescriptlang-org/static/js/sandbox", "../sandbox")
39 | return renameImport
40 | }
41 | )
42 |
43 | // Util funcs
44 | await getFileAndStoreLocally(host + "/js/playground/pluginUtils.d.ts", join(vendor, "pluginUtils.d.ts"), text => {
45 | const renameImport = text.replace('from "typescript-sandbox"', 'from "./sandbox"')
46 | return renameImport
47 | })
48 |
49 | // TS-VFS
50 | await getFileAndStoreLocally(
51 | host + "/js/sandbox/vendor/typescript-vfs.d.ts",
52 | join(vendor, "typescript-vfs.d.ts"),
53 | text => {
54 | const removeImports = text.replace('/// ', "")
55 | const removedLZ = removeImports.replace('import("lz-string").LZStringStatic', "any")
56 | return removedLZ
57 | }
58 | )
59 |
60 | // Sandbox
61 | await getFileAndStoreLocally(host + "/js/sandbox/index.d.ts", join(vendor, "sandbox.d.ts"), text => {
62 | const removeImports = text.replace(/^import/g, "// import").replace(/\nimport/g, "\n// import")
63 | const replaceTSVFS = removeImports.replace(
64 | '// import * as tsvfs from "./vendor/typescript-vfs"',
65 | "\nimport * as tsvfs from './typescript-vfs'"
66 | )
67 | const removedLZ = replaceTSVFS.replace("lzstring: typeof lzstring", "// lzstring: typeof lzstring")
68 | const addedTsWorkerImport = 'import { TypeScriptWorker } from "./tsWorker";' + removedLZ
69 | return addedTsWorkerImport
70 | })
71 |
72 | // Playground
73 | await getFileAndStoreLocally(host + "/js/playground/index.d.ts", join(vendor, "/playground.d.ts"), text => {
74 | const replaceSandbox = text.replace(/typescript-sandbox/g, "./sandbox")
75 | const replaceTSVFS = replaceSandbox.replace(
76 | /typescriptlang-org\/static\/js\/sandbox\/vendor\/typescript-vfs/g,
77 | "./typescript-vfs"
78 | )
79 | const removedLZ = replaceTSVFS.replace("lzstring: typeof", "// lzstring: typeof")
80 | const removedWorker = removedLZ.replace("getWorkerProcess", "// getWorkerProcess")
81 | const removedUI = removedWorker.replace("ui:", "// ui:")
82 | return removedUI
83 | })
84 | }
85 |
86 | go()
87 |
--------------------------------------------------------------------------------
/scripts/getRevealAssets.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | // Grab CSS
4 |
5 | const nodeFetch = require("node-fetch").default;
6 | const { writeFileSync } = require("fs");
7 | const { join } = require("path");
8 |
9 | const getFileAndStoreLocally = async (url, path, editFunc) => {
10 | const editingFunc = editFunc ? editFunc : text => text;
11 | const packageJSON = await nodeFetch(url);
12 | const contents = await packageJSON.text();
13 | writeFileSync(join(__dirname, "..", path), editingFunc(contents), "utf8");
14 | };
15 |
16 | const go = async () => {
17 | await getFileAndStoreLocally(
18 | "https://raw.githubusercontent.com/hakimel/reveal.js/master/css/reveal.css",
19 | "dist/reveal.css"
20 | );
21 | await getFileAndStoreLocally(
22 | "https://raw.githubusercontent.com/hakimel/reveal.js/master/css/theme/white.css",
23 | "dist/reveal-theme.css"
24 | );
25 | };
26 |
27 | go();
28 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { el } from './vendor/utils';
2 |
3 | declare const playground: ReturnType;
4 |
5 | const slidePlugin: import("./vendor/playground").PlaygroundPlugin = {
6 | id: "present",
7 | displayName: "Present",
8 | didMount: (_sandbox, container) =>{
9 | const p = (str: string) => el(str, "p", container)
10 | const h4 = (str: string) => el(str, "h4", container)
11 |
12 | h4("Create a Slideshow")
13 | p("Use Markdown powered by GitHub Gists")
14 | p("This plugin adds Reveal.js support to the TypeScript Playground, slides have the ability to change the code inside the playground.")
15 |
16 | h4("Get Started")
17 | p(`Create a gist with an index.md
using a set of ---
s to split between slides. You can find out more about the syntax here. If you want to demo the slides, click here to try an existing deck.`)
18 |
19 | const startButton = document.createElement("input")
20 |
21 | const gistForm = createGistInputForm(startButton)
22 | container.appendChild(gistForm)
23 |
24 | p(`Then when you're ready, hit start below. This will start the slides and scroll you to the top of the page. You can scroll (down with the mouse, or press escape) to get back to the code below it.`)
25 |
26 | startButton.type = "button"
27 | startButton.value = "Start slideshow"
28 | container.appendChild(startButton)
29 |
30 | const firstRunSetup = () => {
31 | const re = window.require as any
32 | const isDev = document.location.host.includes("localhost")
33 |
34 | // https://unpkg.com/browse/typescript-playground-presentation-mode@0.0.1/dist/x.js => unpkg/browse/typescript-playground-presentation-mode@0.0.1/dist/x
35 | const prefix = isDev ? "local" : "unpkg/typescript-playground-presentation-mode/dist"
36 |
37 | re([prefix + "/slideshow"], (slides: typeof import("./slideshow/slideshow")) => {
38 | // @ts-ignore sets the window.Reveal for the upcoming plugins
39 | window.Reveal = slides.revealJS
40 |
41 | re([prefix + "/markdown"], ( ) => {
42 | slides.startSlides(localStorage.getItem("playground-slides-gist-href"))
43 | // p.textContent = "In slideshow, scroll up to get back to your slides."
44 | startButton.disabled = true
45 | })
46 | })
47 | }
48 |
49 | startButton.onclick = () => {
50 | firstRunSetup()
51 | }
52 | }
53 | }
54 |
55 | const createGistInputForm = (startButton: HTMLInputElement) => {
56 | const form = document.createElement("form")
57 |
58 | const gistHref = document.createElement("input")
59 | gistHref.type = "url"
60 | gistHref.id = "gist-input"
61 | gistHref.placeholder = "https://gist.github.com/.../..."
62 | const storedGistHref = localStorage.getItem("playground-slides-gist-href")
63 | gistHref.value = storedGistHref
64 |
65 | const updateState = ({ enable }) => {
66 | if (enable) {
67 | gistHref.classList.add("good")
68 | startButton.disabled = false
69 |
70 | } else {
71 | gistHref.classList.remove("good")
72 | startButton.disabled = true
73 | }
74 | }
75 |
76 | const textUpdate = (e) => {
77 | const href = e.target.value.toLowerCase().trim()
78 | localStorage.setItem("playground-slides-gist-href", href)
79 | updateState({ enable: isGist(href) })
80 | }
81 |
82 | gistHref.onkeyup = textUpdate
83 | gistHref.onpaste = textUpdate
84 | gistHref.onchange = textUpdate
85 | gistHref.onblur = textUpdate
86 | gistHref.oninput = textUpdate
87 | form.appendChild(gistHref)
88 |
89 | updateState({ enable: isGist(storedGistHref) })
90 | return form
91 | }
92 |
93 | const isGist = (str: string) => {
94 | return str && str.startsWith("https://gist.github.com/") && str.split("/").length === 5
95 | }
96 |
97 | export default slidePlugin
98 |
99 |
--------------------------------------------------------------------------------
/src/slideshow/ambient.d.ts:
--------------------------------------------------------------------------------
1 | declare module "reveal.js"
2 |
--------------------------------------------------------------------------------
/src/slideshow/markdown.js:
--------------------------------------------------------------------------------
1 | // This is a modified version of https://github.com/hakimel/reveal.js/blob/master/plugin/markdown/markdown.js
2 | // which is MIT licensed
3 |
4 | // Modified to:
5 | // - Work well as an AMD module
6 | // - Work under strict mode JS
7 |
8 | import marked from "./marked"
9 |
10 | /**
11 | * The reveal.js markdown plugin. Handles parsing of
12 | * markdown inside of presentations as well as loading
13 | * of external markdown documents.
14 | */
15 |
16 |
17 | var DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$',
18 | DEFAULT_NOTES_SEPARATOR = 'notes?:',
19 | DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\\.element\\\s*?(.+?)$',
20 | DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\\.slide:\\\s*?(\\\S.+?)$';
21 |
22 | var SCRIPT_END_PLACEHOLDER = '__SCRIPT_END__';
23 |
24 |
25 | /**
26 | * Retrieves the markdown contents of a slide section
27 | * element. Normalizes leading tabs/whitespace.
28 | */
29 | function getMarkdownFromSlide( section ) {
30 |
31 | // look for a ' );
39 |
40 | var leadingWs = text.match( /^\n?(\s*)/ )[1].length,
41 | leadingTabs = text.match( /^\n?(\t*)/ )[1].length;
42 |
43 | if( leadingTabs > 0 ) {
44 | text = text.replace( new RegExp('\\n?\\t{' + leadingTabs + '}','g'), '\n' );
45 | }
46 | else if( leadingWs > 1 ) {
47 | text = text.replace( new RegExp('\\n? {' + leadingWs + '}', 'g'), '\n' );
48 | }
49 |
50 | return text;
51 |
52 | }
53 |
54 | /**
55 | * Given a markdown slide section element, this will
56 | * return all arguments that aren't related to markdown
57 | * parsing. Used to forward any other user-defined arguments
58 | * to the output markdown slide.
59 | */
60 | function getForwardedAttributes( section ) {
61 |
62 | var attributes = section.attributes;
63 | var result = [];
64 |
65 | for( var i = 0, len = attributes.length; i < len; i++ ) {
66 | var name = attributes[i].name,
67 | value = attributes[i].value;
68 |
69 | // disregard attributes that are used for markdown loading/parsing
70 | if( /data\-(markdown|separator|vertical|notes)/gi.test( name ) ) continue;
71 |
72 | if( value ) {
73 | result.push( name + '="' + value + '"' );
74 | }
75 | else {
76 | result.push( name );
77 | }
78 | }
79 |
80 | return result.join( ' ' );
81 |
82 | }
83 |
84 | /**
85 | * Inspects the given options and fills out default
86 | * values for what's not defined.
87 | */
88 | function getSlidifyOptions( options ) {
89 |
90 | options = options || {};
91 | options.separator = options.separator || DEFAULT_SLIDE_SEPARATOR;
92 | options.notesSeparator = options.notesSeparator || DEFAULT_NOTES_SEPARATOR;
93 | options.attributes = options.attributes || '';
94 |
95 | return options;
96 |
97 | }
98 |
99 | /**
100 | * Helper function for constructing a markdown slide.
101 | */
102 | function createMarkdownSlide( content, options ) {
103 |
104 | options = getSlidifyOptions( options );
105 |
106 | var notesMatch = content.split( new RegExp( options.notesSeparator, 'mgi' ) );
107 |
108 | if( notesMatch.length === 2 ) {
109 | content = notesMatch[0] + '';
110 | }
111 |
112 | // prevent script end tags in the content from interfering
113 | // with parsing
114 | content = content.replace( /<\/script>/g, SCRIPT_END_PLACEHOLDER );
115 |
116 | return '';
117 |
118 | }
119 |
120 | /**
121 | * Parses a data string into multiple slides based
122 | * on the passed in separator arguments.
123 | */
124 | function slidify( markdown, options ) {
125 |
126 | options = getSlidifyOptions( options );
127 |
128 | var separatorRegex = new RegExp( options.separator + ( options.verticalSeparator ? '|' + options.verticalSeparator : '' ), 'mg' ),
129 | horizontalSeparatorRegex = new RegExp( options.separator );
130 |
131 | var matches,
132 | lastIndex = 0,
133 | isHorizontal,
134 | wasHorizontal = true,
135 | content,
136 | sectionStack = [];
137 |
138 | // iterate until all blocks between separators are stacked up
139 | while( matches = separatorRegex.exec( markdown ) ) {
140 | let notes = null;
141 |
142 | // determine direction (horizontal by default)
143 | isHorizontal = horizontalSeparatorRegex.test( matches[0] );
144 |
145 | if( !isHorizontal && wasHorizontal ) {
146 | // create vertical stack
147 | sectionStack.push( [] );
148 | }
149 |
150 | // pluck slide content from markdown input
151 | content = markdown.substring( lastIndex, matches.index );
152 |
153 | if( isHorizontal && wasHorizontal ) {
154 | // add to horizontal stack
155 | sectionStack.push( content );
156 | }
157 | else {
158 | // add to vertical stack
159 | sectionStack[sectionStack.length-1].push( content );
160 | }
161 |
162 | lastIndex = separatorRegex.lastIndex;
163 | wasHorizontal = isHorizontal;
164 | }
165 |
166 | // add the remaining slide
167 | ( wasHorizontal ? sectionStack : sectionStack[sectionStack.length-1] ).push( markdown.substring( lastIndex ) );
168 |
169 | var markdownSections = '';
170 |
171 | // flatten the hierarchical stack, and insert tags
172 | for( var i = 0, len = sectionStack.length; i < len; i++ ) {
173 | // vertical
174 | if( sectionStack[i] instanceof Array ) {
175 | markdownSections += '';
176 |
177 | sectionStack[i].forEach( function( child ) {
178 | markdownSections += '' + createMarkdownSlide( child, options ) + '';
179 | } );
180 |
181 | markdownSections += '';
182 | }
183 | else {
184 | markdownSections += '' + createMarkdownSlide( sectionStack[i], options ) + '';
185 | }
186 | }
187 |
188 | return markdownSections;
189 |
190 | }
191 |
192 | /**
193 | * Parses any current data-markdown slides, splits
194 | * multi-slide markdown into separate sections and
195 | * handles loading of external markdown.
196 | */
197 | function processSlides() {
198 |
199 | return new Promise( function( resolve ) {
200 |
201 | var externalPromises = [];
202 |
203 | [].slice.call( document.querySelectorAll( '[data-markdown]') ).forEach( function( section, i ) {
204 |
205 | if( section.getAttribute( 'data-markdown' ).length ) {
206 |
207 | externalPromises.push( loadExternalMarkdown( section ).then(
208 |
209 | // Finished loading external file
210 | function( xhr, url ) {
211 | section.outerHTML = slidify( xhr.responseText, {
212 | separator: section.getAttribute( 'data-separator' ),
213 | verticalSeparator: section.getAttribute( 'data-separator-vertical' ),
214 | notesSeparator: section.getAttribute( 'data-separator-notes' ),
215 | attributes: getForwardedAttributes( section )
216 | });
217 | },
218 |
219 | // Failed to load markdown
220 | function( xhr, url ) {
221 | debugger
222 | section.outerHTML = '' +
223 | 'ERROR: The attempt to fetch ' + url + ' failed with HTTP status ' + xhr.status + '.' +
224 | 'Check your browser\'s JavaScript console for more details.' +
225 | 'Remember that you need to serve the presentation HTML from a HTTP server.
' +
226 | '';
227 | }
228 |
229 | ) );
230 |
231 | }
232 | else if( section.getAttribute( 'data-separator' ) || section.getAttribute( 'data-separator-vertical' ) || section.getAttribute( 'data-separator-notes' ) ) {
233 |
234 | section.outerHTML = slidify( getMarkdownFromSlide( section ), {
235 | separator: section.getAttribute( 'data-separator' ),
236 | verticalSeparator: section.getAttribute( 'data-separator-vertical' ),
237 | notesSeparator: section.getAttribute( 'data-separator-notes' ),
238 | attributes: getForwardedAttributes( section )
239 | });
240 |
241 | }
242 | else {
243 | section.innerHTML = createMarkdownSlide( getMarkdownFromSlide( section ) );
244 | }
245 |
246 | });
247 |
248 | Promise.all( externalPromises ).then( resolve );
249 |
250 | } );
251 |
252 | }
253 |
254 | function loadExternalMarkdown( section ) {
255 |
256 | return new Promise( function( resolve, reject ) {
257 |
258 | var xhr = new XMLHttpRequest(),
259 | url = section.getAttribute( 'data-markdown' );
260 |
261 | datacharset = section.getAttribute( 'data-charset' );
262 |
263 | // see https://developer.mozilla.org/en-US/docs/Web/API/element.getAttribute#Notes
264 | if( datacharset != null && datacharset != '' ) {
265 | xhr.overrideMimeType( 'text/html; charset=' + datacharset );
266 | }
267 |
268 | xhr.onreadystatechange = function( section, xhr ) {
269 | if( xhr.readyState === 4 ) {
270 | // file protocol yields status code 0 (useful for local debug, mobile applications etc.)
271 | if ( ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status === 0 ) {
272 |
273 | resolve( xhr, url );
274 |
275 | }
276 | else {
277 |
278 | reject( xhr, url );
279 |
280 | }
281 | }
282 | }.bind( this, section, xhr );
283 |
284 | xhr.open( 'GET', url, true );
285 |
286 | try {
287 | xhr.send();
288 | }
289 | catch ( e ) {
290 | alert( 'Failed to get the Markdown file ' + url + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + e );
291 | resolve( xhr, url );
292 | }
293 |
294 | } );
295 |
296 | }
297 |
298 | /**
299 | * Check if a node value has the attributes pattern.
300 | * If yes, extract it and add that value as one or several attributes
301 | * to the target element.
302 | *
303 | * You need Cache Killer on Chrome to see the effect on any FOM transformation
304 | * directly on refresh (F5)
305 | * http://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development/7000899#answer-11786277
306 | */
307 | function addAttributeInElement( node, elementTarget, separator ) {
308 |
309 | var mardownClassesInElementsRegex = new RegExp( separator, 'mg' );
310 | var mardownClassRegex = new RegExp( "([^\"= ]+?)=\"([^\"=]+?)\"", 'mg' );
311 | var nodeValue = node.nodeValue;
312 | if( matches = mardownClassesInElementsRegex.exec( nodeValue ) ) {
313 |
314 | var classes = matches[1];
315 | nodeValue = nodeValue.substring( 0, matches.index ) + nodeValue.substring( mardownClassesInElementsRegex.lastIndex );
316 | node.nodeValue = nodeValue;
317 | while( matchesClass = mardownClassRegex.exec( classes ) ) {
318 | elementTarget.setAttribute( matchesClass[1], matchesClass[2] );
319 | }
320 | return true;
321 | }
322 | return false;
323 | }
324 |
325 | /**
326 | * Add attributes to the parent element of a text node,
327 | * or the element of an attribute node.
328 | */
329 | function addAttributes( section, element, previousElement, separatorElementAttributes, separatorSectionAttributes ) {
330 |
331 | if ( element != null && element.childNodes != undefined && element.childNodes.length > 0 ) {
332 | var previousParentElement = element;
333 | for( var i = 0; i < element.childNodes.length; i++ ) {
334 | var childElement = element.childNodes[i];
335 | if ( i > 0 ) {
336 | var j = i - 1;
337 | while ( j >= 0 ) {
338 | var aPreviousChildElement = element.childNodes[j];
339 | if ( typeof aPreviousChildElement.setAttribute == 'function' && aPreviousChildElement.tagName != "BR" ) {
340 | previousParentElement = aPreviousChildElement;
341 | break;
342 | }
343 | j = j - 1;
344 | }
345 | }
346 | var parentSection = section;
347 | if( childElement.nodeName == "section" ) {
348 | parentSection = childElement ;
349 | previousParentElement = childElement ;
350 | }
351 | if ( typeof childElement.setAttribute == 'function' || childElement.nodeType == Node.COMMENT_NODE ) {
352 | addAttributes( parentSection, childElement, previousParentElement, separatorElementAttributes, separatorSectionAttributes );
353 | }
354 | }
355 | }
356 |
357 | if ( element.nodeType == Node.COMMENT_NODE ) {
358 | if ( addAttributeInElement( element, previousElement, separatorElementAttributes ) == false ) {
359 | addAttributeInElement( element, section, separatorSectionAttributes );
360 | }
361 | }
362 | }
363 |
364 | /**
365 | * Converts any current data-markdown slides in the
366 | * DOM to HTML.
367 | */
368 | function convertSlides() {
369 |
370 | var sections = document.querySelectorAll( '[data-markdown]:not([data-markdown-parsed])');
371 |
372 | [].slice.call( sections ).forEach( function( section ) {
373 |
374 | section.setAttribute( 'data-markdown-parsed', true )
375 |
376 | var notes = section.querySelector( 'aside.notes' );
377 | var markdown = getMarkdownFromSlide( section );
378 |
379 | section.innerHTML = marked( markdown );
380 | addAttributes( section, section, null, section.getAttribute( 'data-element-attributes' ) ||
381 | section.parentNode.getAttribute( 'data-element-attributes' ) ||
382 | DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR,
383 | section.getAttribute( 'data-attributes' ) ||
384 | section.parentNode.getAttribute( 'data-attributes' ) ||
385 | DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR);
386 |
387 | // If there were notes, we need to re-add them after
388 | // having overwritten the section's HTML
389 | if( notes ) {
390 | section.appendChild( notes );
391 | }
392 |
393 | } );
394 |
395 | return Promise.resolve();
396 |
397 | }
398 |
399 | // API
400 | var RevealMarkdown = {
401 |
402 | /**
403 | * Starts processing and converting Markdown within the
404 | * current reveal.js deck.
405 | *
406 | * @param {function} callback function to invoke once
407 | * we've finished loading and parsing Markdown
408 | */
409 | init: function( callback ) {
410 |
411 | if( typeof marked === 'undefined' ) {
412 | throw 'The reveal.js Markdown plugin requires marked to be loaded';
413 | }
414 |
415 | if( typeof hljs !== 'undefined' ) {
416 | marked.setOptions({
417 | highlight: function( code, lang ) {
418 | return hljs.highlightAuto( code, [lang] ).value;
419 | }
420 | });
421 | }
422 |
423 | // marked can be configured via reveal.js config options
424 | var options = Reveal.getConfig().markdown;
425 | if( options ) {
426 | marked.setOptions( options );
427 | }
428 |
429 | return processSlides().then( convertSlides );
430 |
431 | },
432 |
433 | // TODO: Do these belong in the API?
434 | processSlides: processSlides,
435 | convertSlides: convertSlides,
436 | slidify: slidify
437 |
438 | };
439 |
440 | // Register our plugin so that reveal.js will call our
441 | // plugin 'init' method as part of the initialization
442 | Reveal.registerPlugin( 'markdown', RevealMarkdown );
443 |
444 | export default RevealMarkdown;
445 |
--------------------------------------------------------------------------------
/src/slideshow/marked.js:
--------------------------------------------------------------------------------
1 | /**
2 | * marked - a markdown parser
3 | * Copyright (c) 2011-2018, Christopher Jeffrey. (MIT Licensed)
4 | * https://github.com/markedjs/marked
5 | */
6 | !function(e){"use strict";var k={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:f,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,nptable:f,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)|(?!script|pre|style)[a-z][\\w-]*\\s*>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:f,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,text:/^[^\n]+/};function a(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||m.defaults,this.rules=k.normal,this.options.pedantic?this.rules=k.pedantic:this.options.gfm&&(this.options.tables?this.rules=k.tables:this.rules=k.gfm)}k._label=/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,k._title=/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/,k.def=i(k.def).replace("label",k._label).replace("title",k._title).getRegex(),k.bullet=/(?:[*+-]|\d{1,9}\.)/,k.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,k.item=i(k.item,"gm").replace(/bull/g,k.bullet).getRegex(),k.list=i(k.list).replace(/bull/g,k.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+k.def.source+")").getRegex(),k._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",k._comment=//,k.html=i(k.html,"i").replace("comment",k._comment).replace("tag",k._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),k.paragraph=i(k.paragraph).replace("hr",k.hr).replace("heading",k.heading).replace("lheading",k.lheading).replace("tag",k._tag).getRegex(),k.blockquote=i(k.blockquote).replace("paragraph",k.paragraph).getRegex(),k.normal=d({},k),k.gfm=d({},k.normal,{fences:/^ {0,3}(`{3,}|~{3,})([^`\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),k.gfm.paragraph=i(k.paragraph).replace("(?!","(?!"+k.gfm.fences.source.replace("\\1","\\2")+"|"+k.list.source.replace("\\1","\\3")+"|").getRegex(),k.tables=d({},k.gfm,{nptable:/^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,table:/^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/}),k.pedantic=d({},k.normal,{html:i("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?\\1> *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",k._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/}),a.rules=k,a.lex=function(e,t){return new a(t).lex(e)},a.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},a.prototype.token=function(e,t){var n,r,s,i,l,o,a,h,p,u,c,g,f,d,m,b;for(e=e.replace(/^ +$/gm,"");e;)if((s=this.rules.newline.exec(e))&&(e=e.substring(s[0].length),1 ?/gm,""),this.token(s,t),this.tokens.push({type:"blockquote_end"});else if(s=this.rules.list.exec(e)){for(e=e.substring(s[0].length),a={type:"list_start",ordered:d=1<(i=s[2]).length,start:d?+i:"",loose:!1},this.tokens.push(a),n=!(h=[]),f=(s=s[0].match(this.rules.item)).length,c=0;c?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:f,tag:"^comment|^[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*"<\[])\*(?!\*)|^_([^\s][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s"<\[][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:f,text:/^(`+|[^`])[\s\S]*?(?=[\\?@\\[^_{|}~",n.em=i(n.em).replace(/punctuation/g,n._punctuation).getRegex(),n._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,n._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,n._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,n.autolink=i(n.autolink).replace("scheme",n._scheme).replace("email",n._email).getRegex(),n._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,n.tag=i(n.tag).replace("comment",k._comment).replace("attribute",n._attribute).getRegex(),n._label=/(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/,n._href=/\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f\\]*\)|[^\s\x00-\x1f()\\])*?)/,n._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,n.link=i(n.link).replace("label",n._label).replace("href",n._href).replace("title",n._title).getRegex(),n.reflink=i(n.reflink).replace("label",n._label).getRegex(),n.normal=d({},n),n.pedantic=d({},n.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:i(/^!?\[(label)\]\((.*?)\)/).replace("label",n._label).getRegex(),reflink:i(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",n._label).getRegex()}),n.gfm=d({},n.normal,{escape:i(n.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:i(n.text).replace("]|","~]|").replace("|$","|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&'*+/=?^_`{\\|}~-]+@|$").getRegex()}),n.gfm.url=i(n.gfm.url,"i").replace("email",n.gfm._extended_email).getRegex(),n.breaks=d({},n.gfm,{br:i(n.br).replace("{2,}","*").getRegex(),text:i(n.gfm.text).replace("{2,}","*").getRegex()}),h.rules=n,h.output=function(e,t,n){return new h(t,n).output(e)},h.prototype.output=function(e){for(var t,n,r,s,i,l,o="";e;)if(i=this.rules.escape.exec(e))e=e.substring(i[0].length),o+=u(i[1]);else if(i=this.rules.tag.exec(e))!this.inLink&&/^/i.test(i[0])&&(this.inLink=!1),!this.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(i[0])?this.inRawBlock=!0:this.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(i[0])&&(this.inRawBlock=!1),e=e.substring(i[0].length),o+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(i[0]):u(i[0]):i[0];else if(i=this.rules.link.exec(e))e=e.substring(i[0].length),this.inLink=!0,r=i[2],this.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r))?(r=t[1],s=t[3]):s="":s=i[3]?i[3].slice(1,-1):"",r=r.trim().replace(/^<([\s\S]*)>$/,"$1"),o+=this.outputLink(i,{href:h.escapes(r),title:h.escapes(s)}),this.inLink=!1;else if((i=this.rules.reflink.exec(e))||(i=this.rules.nolink.exec(e))){if(e=e.substring(i[0].length),t=(i[2]||i[1]).replace(/\s+/g," "),!(t=this.links[t.toLowerCase()])||!t.href){o+=i[0].charAt(0),e=i[0].substring(1)+e;continue}this.inLink=!0,o+=this.outputLink(i,t),this.inLink=!1}else if(i=this.rules.strong.exec(e))e=e.substring(i[0].length),o+=this.renderer.strong(this.output(i[4]||i[3]||i[2]||i[1]));else if(i=this.rules.em.exec(e))e=e.substring(i[0].length),o+=this.renderer.em(this.output(i[6]||i[5]||i[4]||i[3]||i[2]||i[1]));else if(i=this.rules.code.exec(e))e=e.substring(i[0].length),o+=this.renderer.codespan(u(i[2].trim(),!0));else if(i=this.rules.br.exec(e))e=e.substring(i[0].length),o+=this.renderer.br();else if(i=this.rules.del.exec(e))e=e.substring(i[0].length),o+=this.renderer.del(this.output(i[1]));else if(i=this.rules.autolink.exec(e))e=e.substring(i[0].length),r="@"===i[2]?"mailto:"+(n=u(this.mangle(i[1]))):n=u(i[1]),o+=this.renderer.link(r,null,n);else if(this.inLink||!(i=this.rules.url.exec(e))){if(i=this.rules.text.exec(e))e=e.substring(i[0].length),this.inRawBlock?o+=this.renderer.text(i[0]):o+=this.renderer.text(u(this.smartypants(i[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else{if("@"===i[2])r="mailto:"+(n=u(i[0]));else{for(;l=i[0],i[0]=this.rules._backpedal.exec(i[0])[0],l!==i[0];);n=u(i[0]),r="www."===i[1]?"http://"+n:n}e=e.substring(i[0].length),o+=this.renderer.link(r,null,n)}return o},h.escapes=function(e){return e?e.replace(h.rules._escapes,"$1"):e},h.prototype.outputLink=function(e,t){var n=t.href,r=t.title?u(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,u(e[1]))},h.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},h.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,s=0;s'+(n?e:u(e,!0))+"
\n":""+(n?e:u(e,!0))+"
"},r.prototype.blockquote=function(e){return"\n"+e+"
\n"},r.prototype.html=function(e){return e},r.prototype.heading=function(e,t,n,r){return this.options.headerIds?"\n":""+e+"\n"},r.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"},r.prototype.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+""+r+">\n"},r.prototype.listitem=function(e){return""+e+"\n"},r.prototype.checkbox=function(e){return" "},r.prototype.paragraph=function(e){return""+e+"
\n"},r.prototype.table=function(e,t){return t&&(t=""+t+""),"\n"},r.prototype.tablerow=function(e){return"\n"+e+"
\n"},r.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+""+n+">\n"},r.prototype.strong=function(e){return""+e+""},r.prototype.em=function(e){return""+e+""},r.prototype.codespan=function(e){return""+e+"
"},r.prototype.br=function(){return this.options.xhtml?"
":"
"},r.prototype.del=function(e){return""+e+""},r.prototype.link=function(e,t,n){if(null===(e=l(this.options.sanitize,this.options.baseUrl,e)))return n;var r='"+n+""},r.prototype.image=function(e,t,n){if(null===(e=l(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
":">"},r.prototype.text=function(e){return e},s.prototype.strong=s.prototype.em=s.prototype.codespan=s.prototype.del=s.prototype.text=function(e){return e},s.prototype.link=s.prototype.image=function(e,t,n){return""+n},s.prototype.br=function(){return""},p.parse=function(e,t){return new p(t).parse(e)},p.prototype.parse=function(e){this.inline=new h(e.links,this.options),this.inlineText=new h(e.links,d({},this.options,{renderer:new s})),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},p.prototype.next=function(){return this.token=this.tokens.pop()},p.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},p.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},p.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,c(this.inlineText.output(this.token.text)),this.slugger);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,s="",i="";for(n="",e=0;e?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},u.escapeTest=/[&<>"']/,u.escapeReplace=/[&<>"']/g,u.replacements={"&":"&","<":"<",">":">",'"':""","'":"'"},u.escapeTestNoEncode=/[<>"']|&(?!#?\w+;)/,u.escapeReplaceNoEncode=/[<>"']|&(?!#?\w+;)/g;var o={},g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;function f(){}function d(e){for(var t,n,r=1;rt)n.splice(t);else for(;n.lengthAn error occurred:
"+u(e.message+"",!0)+"
";throw e}}f.exec=f,m.options=m.setOptions=function(e){return d(m.defaults,e),m},m.getDefaults=function(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:new r,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tables:!0,xhtml:!1}},m.defaults=m.getDefaults(),m.Parser=p,m.parser=p.parse,m.Renderer=r,m.TextRenderer=s,m.Lexer=a,m.lexer=a.lex,m.InlineLexer=h,m.inlineLexer=h.output,m.Slugger=t,m.parse=m,"undefined"!=typeof module&&"object"==typeof exports?module.exports=m:"function"==typeof define&&define.amd?define(function(){return m}):e.marked=m}(this||("undefined"!=typeof window?window:global));
--------------------------------------------------------------------------------
/src/slideshow/reveal.d.ts:
--------------------------------------------------------------------------------
1 | export interface RevealStatic {
2 | /**
3 | * The reveal.js version
4 | */
5 | VERSION: string;
6 |
7 | /**
8 | * Starts up the presentation if the client is capable.
9 | */
10 | initialize: (config?: RevealOptions) => void;
11 | /**
12 | * Applies the configuration settings from the config
13 | * object. May be called multiple times.
14 | */
15 | configure: (diff: RevealOptions) => void;
16 |
17 | /**
18 | * Steps from the current point in the presentation to the
19 | * slide which matches the specified horizontal and vertical
20 | * indices.
21 | *
22 | * @param {number} [h=indexh] Horizontal index of the target slide
23 | * @param {number} [v=indexv] Vertical index of the target slide
24 | * @param {number} [f] Index of a fragment within the
25 | * target slide to activate
26 | * @param {number} [o] Origin for use in multimaster environments
27 | */
28 | slide(indexh: number, indexv?: number, f?: number, o?: number): void;
29 | /**
30 | * Navigation methods
31 | */
32 | left(): void;
33 | /**
34 | * Navigation methods
35 | */
36 | right(): void;
37 | /**
38 | * Navigation methods
39 | */
40 | up(): void;
41 | /**
42 | * Navigation methods
43 | */
44 | down(): void;
45 | /**
46 | * Navigates backwards, prioritized in the following order:
47 | * 1) Previous fragment
48 | * 2) Previous vertical slide
49 | * 3) Previous horizontal slide
50 | */
51 | prev(): void;
52 | /**
53 | * The reverse of #navigatePrev().
54 | */
55 | next(): void;
56 |
57 | /**
58 | * Navigate to the specified slide fragment.
59 | *
60 | * @param {?number} index The index of the fragment that
61 | * should be shown, -1 means all are invisible
62 | * @param {number} offset Integer offset to apply to the
63 | * fragment index
64 | *
65 | * @return {boolean} true if a change was made in any
66 | * fragments visibility as part of this call
67 | */
68 | navigateFragment(index: number | null, offset: number): boolean;
69 | /**
70 | * Navigate to the previous slide fragment.
71 | *
72 | * @return {boolean} true if there was a previous fragment,
73 | * false otherwise
74 | */
75 | prevFragment(): boolean;
76 | /**
77 | * Navigate to the next slide fragment.
78 | *
79 | * @return {boolean} true if there was a next fragment,
80 | * false otherwise
81 | */
82 | nextFragment(): boolean;
83 |
84 | /**
85 | * Randomize the order of slides
86 | */
87 | shuffle(): void;
88 |
89 | /**
90 | * Toggles the overview mode on/off
91 | * @param override
92 | */
93 | toggleOverview(override?: boolean): void;
94 | /**
95 | * Toggles the "black screen" mode on/off
96 | * @param override
97 | */
98 | togglePause(override?: boolean): void;
99 | /**
100 | * Toggles the auto slide mode on/off
101 | * @param override
102 | */
103 | toggleAutoSlide(override?: boolean): void;
104 | /**
105 | * Open or close help overlay window.
106 | *
107 | * @param {Boolean} [override] Flag which overrides the
108 | * toggle logic and forcibly sets the desired state. True means
109 | * help is open, false means it's closed.
110 | */
111 | toggleHelp(override?: boolean): void;
112 |
113 | /**
114 | * Returns the previous slide element, may be null
115 | */
116 | getPreviousSlide(): Element | null;
117 | /**
118 | * Returns the current slide element
119 | */
120 | getCurrentSlide(): Element;
121 |
122 | /**
123 | * Returns the indices of the current, or specified, slide
124 | * @param slide
125 | */
126 | getIndices(slide?: Element): { h: number; v: number };
127 | /**
128 | * Presentation progress on range of 0-1
129 | */
130 | getProgress(): number;
131 | /**
132 | * Returns the total number of slides
133 | */
134 | getTotalSlides(): number;
135 |
136 | /**
137 | * Returns the speaker notes string for a slide, or null
138 | * @param slide
139 | */
140 | getSlideNotes(slide?: Element): string | null;
141 |
142 | /**
143 | * Forward event binding to the reveal DOM element
144 | * @param type
145 | * @param listener
146 | * @param useCapture
147 | */
148 | addEventListener(type: string, listener: (event: any) => void, useCapture?: boolean): void;
149 | /**
150 | * Forward event binding to the reveal DOM element
151 | * @param type
152 | * @param listener
153 | * @param useCapture
154 | */
155 | removeEventListener(type: string, listener: (event: any) => void, useCapture?: boolean): void;
156 |
157 | /**
158 | * Returns true if we're currently on the first slide
159 | */
160 | isFirstSlide(): boolean;
161 | /**
162 | * Returns true if we're currently on the last slide
163 | */
164 | isLastSlide(): boolean;
165 | /**
166 | * Returns true if we're on the last slide in the current vertical stack
167 | */
168 | isLastVerticalSlide(): boolean;
169 | /**
170 | * Checks if we are currently in the paused mode.
171 | */
172 | isPaused(): boolean;
173 | /**
174 | * Checks if the overview is currently active.
175 | *
176 | * @return {Boolean} true if the overview is active,
177 | * false otherwise
178 | */
179 | isOverview(): boolean;
180 | /**
181 | * Checks if the auto slide mode is currently on.
182 | */
183 | isAutoSliding(): boolean;
184 |
185 | /**
186 | * Forces an update in slide layout
187 | */
188 | layout(): void;
189 | /**
190 | * Adds all internal event listeners (such as keyboard)
191 | */
192 | addEventListeners(): void;
193 | /**
194 | * Removes all internal event listeners (such as keyboard)
195 | */
196 | removeEventListeners(): void;
197 | /**
198 | * Returns the slide element at the specified index
199 | * @param x
200 | * @param y
201 | */
202 | getSlide(x: number, y?: number): Element;
203 | /**
204 | * Returns the current scale of the presentation content
205 | */
206 | getScale(): number;
207 | /**
208 | * Returns the current configuration object
209 | */
210 | getConfig(): RevealOptions;
211 | /**
212 | * Helper method, retrieves query string as a key/value hash
213 | */
214 | getQueryHash(): Record;
215 | /**
216 | * Facility for persisting and restoring the presentation state
217 | * @param state
218 | */
219 | setState(state: any): void;
220 | /**
221 | * Facility for persisting and restoring the presentation state
222 | */
223 | getState(): any;
224 |
225 | /**
226 | * update slides after dynamic changes
227 | */
228 | sync(): void;
229 | /**
230 | * Updates reveal.js to keep in sync with new slide attributes. For
231 | * example, if you add a new `data-background-image` you can call
232 | * this to have reveal.js render the new background image.
233 | *
234 | * Similar to #sync() but more efficient when you only need to
235 | * refresh a specific slide.
236 | *
237 | * @param {HTMLElement} slide
238 | */
239 | syncSlide(slide: HTMLElement): void;
240 | /**
241 | * Formats the fragments on the given slide so that they have
242 | * valid indices. Call this if fragments are changed in the DOM
243 | * after reveal.js has already initialized.
244 | *
245 | * @param {HTMLElement} slide
246 | * @return {Array} a list of the HTML fragments that were synced
247 | */
248 | syncFragments(slide: HTMLElement): HTMLElement[];
249 | /**
250 | * Checks if reveal.js has been loaded and is ready for use
251 | */
252 | isReady(): boolean;
253 |
254 | /**
255 | * @alias slide
256 | * @deprecated
257 | */
258 | navigateTo(indexh: number, indexv?: number, f?: number, o?: number): void;
259 | /**
260 | * @alias left
261 | * @deprecated
262 | */
263 | navigateLeft(): void;
264 | /**
265 | * @alias right
266 | * @deprecated
267 | */
268 | navigateRight(): void;
269 | /**
270 | * @alias up
271 | * @deprecated
272 | */
273 | navigateUp(): void;
274 | /**
275 | * @alias down
276 | * @deprecated
277 | */
278 | navigateDown(): void;
279 | /**
280 | * @alias prev
281 | * @deprecated
282 | */
283 | navigatePrev(): void;
284 | /**
285 | * @alias next
286 | * @deprecated
287 | */
288 | navigateNext(): void;
289 |
290 | /**
291 | * Determine what available routes there are for navigation.
292 | *
293 | * @return {{left: boolean, right: boolean, up: boolean, down: boolean}}
294 | */
295 | availableRoutes(): { left: boolean; right: boolean; up: boolean; down: boolean };
296 | /**
297 | * Returns an object describing the available fragment
298 | * directions.
299 | *
300 | * @return {{prev: boolean, next: boolean}}
301 | */
302 | availableFragments(): { prev: boolean; next: boolean };
303 | /**
304 | * Called when the given slide is within the configured view
305 | * distance. Shows the slide element and loads any content
306 | * that is set to load lazily (data-src).
307 | *
308 | * @param {HTMLElement} slide Slide to show
309 | */
310 | loadSlide(slide: HTMLElement): void;
311 | /**
312 | * Unloads and hides the given slide. This is called when the
313 | * slide is moved outside of the configured view distance.
314 | *
315 | * @param {HTMLElement} slide
316 | */
317 | unloadSlide(): HTMLElement;
318 | /**
319 | * Returns the number of past slides. This can be used as a global
320 | * flattened index for slides.
321 | *
322 | * @return {number} Past slide count
323 | */
324 | getSlidePastCount(): number;
325 | /**
326 | * Returns an array of objects where each object represents the
327 | * attributes on its respective slide.
328 | */
329 | getSlidesAttributes(): Record[];
330 | /**
331 | * Retrieves all slides in this presentation.
332 | */
333 | getSlides(): Element[];
334 | /**
335 | * Returns the background element for the given slide.
336 | * All slides, even the ones with no background properties
337 | * defined, have a background element so as long as the
338 | * index is valid an element will be returned.
339 | *
340 | * @param {mixed} x Horizontal background index OR a slide
341 | * HTML element
342 | * @param {number} y Vertical background index
343 | * @return {(HTMLElement[]|*)}
344 | */
345 | getSlideBackground(x: number | Element, y: number): HTMLElement[] | undefined;
346 | /**
347 | * Returns the top-level DOM element
348 | */
349 | getRevealElement(): Element | Element[];
350 | /**
351 | * Returns a hash with all registered plugins
352 | */
353 | getPlugins(): Record;
354 | /**
355 | * Add a custom key binding with optional description to
356 | * be added to the help screen.
357 | */
358 | addKeyBinding(
359 | binding:
360 | | string
361 | | {
362 | keyCode: string;
363 | key?: string;
364 | description?: string;
365 | },
366 | callback: () => void
367 | ): void;
368 | /**
369 | * Removes the specified custom key binding.
370 | */
371 | removeKeyBinding(keyCode: string): void;
372 | /**
373 | * Registers a new plugin with this reveal.js instance.
374 | *
375 | * reveal.js waits for all regisered plugins to initialize
376 | * before considering itself ready, as long as the plugin
377 | * is registered before calling `Reveal.initialize()`.
378 | */
379 | registerPlugin(id: string, plugin: any): any;
380 | /**
381 | * Checks if a specific plugin has been registered.
382 | *
383 | * @param {String} id Unique plugin identifier
384 | */
385 | hasPlugin(id: string): boolean;
386 | /**
387 | * Returns the specific plugin instance, if a plugin
388 | * with the given ID has been registered.
389 | *
390 | * @param {String} id Unique plugin identifier
391 | */
392 | getPlugin(id: string): any;
393 | /**
394 | * Programmatically triggers a keyboard event
395 | */
396 | triggerKey(keyCode: string): void;
397 | /**
398 | * Registers a new shortcut to include in the help overlay
399 | */
400 | registerKeyboardShortcut(key: string, value: any): void;
401 | }
402 |
403 | interface RevealOptions {
404 | /**
405 | * Display presentation control arrows
406 | * @default true
407 | */
408 | controls?: boolean;
409 | /**
410 | * Help the user learn the controls by providing hints, for example by
411 | * bouncing the down arrow when they first encounter a vertical slide
412 | * @default true
413 | */
414 | controlsTutorial?: boolean;
415 | /**
416 | * Determines where controls appear, "edges" or "bottom-right"
417 | * @default "bottom-right"
418 | */
419 | controlsLayout?: "edges" | "bottom-right";
420 | /**
421 | * Visibility rule for backwards navigation arrows; "faded", "hidden"
422 | * or "visible"
423 | * @default "faded"
424 | */
425 | controlsBackArrows?: "faded" | "hidden" | "visible";
426 | /**
427 | * Display a presentation progress bar
428 | * @default true
429 | */
430 | progress?: boolean;
431 | /**
432 | * Display the page number of the current slide
433 | * - true: Show slide number
434 | * - false: Hide slide number
435 | *
436 | * Can optionally be set as a string that specifies the number formatting:
437 | * - "h.v": Horizontal . vertical slide number (default)
438 | * - "h/v": Horizontal / vertical slide number
439 | * - "c": Flattened slide number
440 | * - "c/t": Flattened slide number / total slides
441 | *
442 | * Alternatively, you can provide a function that returns the slide
443 | * number for the current slide. The function needs to return an array
444 | * with one string [slideNumber] or three strings [n1,delimiter,n2].
445 | * See #formatSlideNumber().
446 | *
447 | *
448 | * @default false
449 | */
450 | slideNumber?: boolean | string | (() => [string] | [string, string, string]);
451 | /**
452 | * Can be used to limit the contexts in which the slide number appears
453 | * - "all": Always show the slide number
454 | * - "print": Only when printing to PDF
455 | * - "speaker": Only in the speaker view
456 | *
457 | * @default "all"
458 | */
459 | showSlideNumber?: "all" | "print" | "speaker";
460 |
461 | /**
462 | * Push each slide change to the browser history. Implies `hash: true`
463 | * @default false
464 | */
465 | history?: boolean;
466 |
467 | /**
468 | * Enable keyboard shortcuts for navigation
469 | *
470 | *
471 | * @default true
472 | */
473 | keyboard?: boolean | Record void)>;
474 | /**
475 | * Optional function that blocks keyboard events when retuning false
476 | * @default null
477 | */
478 | keyboardCondition?: (() => boolean) | null;
479 | /**
480 | * Enable the slide overview mode
481 | * @default true
482 | */
483 | overview?: boolean;
484 | /**
485 | * Vertical centering of slides
486 | * @default true
487 | */
488 | center?: boolean;
489 | /**
490 | * Enables touch navigation on devices with touch input
491 | * @default true
492 | */
493 | touch?: boolean;
494 | /**
495 | * Loop the presentation
496 | * @default true
497 | */
498 | loop?: boolean;
499 | /**
500 | * Change the presentation direction to be RTL
501 | * @default true
502 | */
503 | rtl?: boolean;
504 | /**
505 | * Randomizes the order of slides each time the presentation loads
506 | * @default false
507 | */
508 | shuffle?: boolean;
509 | /**
510 | * Turns fragments on and off globally
511 | * @default true
512 | */
513 | fragments?: boolean;
514 | /**
515 | * Flags whether to include the current fragment in the URL,
516 | * so that reloading brings you to the same fragment position
517 | * @default false
518 | */
519 | fragmentInURL?: boolean;
520 | /**
521 | * Flags if the presentation is running in an embedded mode,
522 | * i.e. contained within a limited portion of the screen
523 | * @default false
524 | */
525 | embedded?: boolean;
526 | /**
527 | * Flags if we should show a help overlay when the question-mark
528 | * key is pressed
529 | * @default true
530 | */
531 | help?: boolean;
532 | /**
533 | * Flags if speaker notes should be visible to all viewers
534 | * @default false
535 | */
536 | showNotes?: boolean;
537 | /**
538 | * Controls automatic progression to the next slide
539 | * - 0: Auto-sliding only happens if the data-autoslide HTML attribute
540 | * is present on the current slide or fragment
541 | * - 1+: All slides will progress automatically at the given interval
542 | * - false: No auto-sliding, even if data-autoslide is present
543 | *
544 | * @default 0
545 | */
546 | autoSlide?: number | false;
547 | /**
548 | * Stop auto-sliding after user input
549 | * @default true
550 | */
551 | autoSlideStoppable?: boolean;
552 | /**
553 | * Use this method for navigation when auto-sliding (defaults to navigateNext)
554 | * @default navigateNext
555 | */
556 | autoSlideMethod?: any;
557 | /**
558 | * Enable slide navigation via mouse wheel
559 | * @default false
560 | */
561 | mouseWheel?: boolean;
562 | /**
563 | * Hides the address bar on mobile devices
564 | * @default true
565 | */
566 | hideAddressBar?: boolean;
567 | /**
568 | * Opens links in an iframe preview overlay
569 | * Add `data-preview-link` and `data-preview-link="false"` to customise each link
570 | * individually
571 | * @default false
572 | */
573 | previewLinks?: boolean;
574 | /**
575 | * Transition style
576 | * @default "slide"
577 | */
578 | transition?: "none" | "fade" | "slide" | "convex" | "concave" | "zoom";
579 | /**
580 | * Transition speed
581 | * @default "default"
582 | */
583 | transitionSpeed?: "default" | "fast" | "slow";
584 | /**
585 | * Transition style for full page slide backgrounds
586 | * @default "fade"
587 | */
588 | backgroundTransition?: "none" | "fade" | "slide" | "convex" | "concave" | "zoom";
589 | /**
590 | * Number of slides away from the current that are visible
591 | * @default 3
592 | */
593 | viewDistance?: number;
594 |
595 | /**
596 | * Parallax background image
597 | * CSS syntax, e.g. "a.jpg"
598 | * https://github.com/hakimel/reveal.js/#parallax-background
599 | * @default ""
600 | */
601 | parallaxBackgroundImage?: string;
602 |
603 | /**
604 | * Parallax background size
605 | * CSS syntax, e.g. "3000px 2000px"
606 | * @default ""
607 | */
608 | parallaxBackgroundSize?: string;
609 |
610 | /**
611 | * Number of pixels to move the parallax background per slide
612 | * - Calculated automatically unless specified
613 | * - Set to 0 to disable movement along an axis
614 | * @default null
615 | */
616 | parallaxBackgroundHorizontal?: number | null;
617 | /**
618 | * Number of pixels to move the parallax background per slide
619 | * - Calculated automatically unless specified
620 | * - Set to 0 to disable movement along an axis
621 | * @default null
622 | */
623 | parallaxBackgroundVertical?: number | null;
624 | /**
625 | * Parallax background repeat
626 | * @default ""
627 | */
628 | parallaxBackgroundRepeat?: "repeat" | "repeat-x" | "repeat-y" | "no-repeat" | "initial" | "inherit";
629 | /**
630 | * Parallax background position
631 | * CSS syntax, e.g. "top left"
632 | * @default ""
633 | */
634 | parallaxBackgroundPosition?: string;
635 | /**
636 | * Apply a 3D roll to links on hover
637 | * @default false
638 | */
639 | rollingLinks?: boolean;
640 | theme?: string;
641 |
642 | /**
643 | * The "normal" size of the presentation, aspect ratio will be preserved
644 | * when the presentation is scaled to fit different resolutions
645 | *
646 | *
647 | * @default 960
648 | */
649 | width?: number | string;
650 | /**
651 | * The "normal" size of the presentation, aspect ratio will be preserved
652 | * when the presentation is scaled to fit different resolutions
653 | *
654 | *
655 | * @default 700
656 | */
657 | height?: number | string;
658 | /**
659 | * Factor of the display size that should remain empty around the content
660 | * @default 0.04
661 | */
662 | margin?: number | string;
663 | /**
664 | * Bounds for smallest/largest possible scale to apply to content
665 | * @default 0.2
666 | */
667 | minScale?: number | string;
668 | /**
669 | * Bounds for smallest/largest possible scale to apply to content
670 | * @default 2.0
671 | */
672 | maxScale?: number | string;
673 |
674 | /**
675 | * Script dependencies to load
676 | * https://github.com/hakimel/reveal.js/#dependencies>
677 | */
678 | dependencies?: RevealDependency[];
679 |
680 | /**
681 | * Exposes the reveal.js API through window.postMessage
682 | * @default true
683 | */
684 | postMessage?: boolean;
685 |
686 | /**
687 | * Dispatches all reveal.js events to the parent window through postMessage
688 | * @default false
689 | */
690 | postMessageEvents?: boolean;
691 |
692 | /**
693 | * https://github.com/hakimel/reveal.js/#multiplexing
694 | */
695 | multiplex?: MultiplexConfig;
696 |
697 | /**
698 | * https://github.com/hakimel/reveal.js/#mathjax
699 | */
700 | math?: MathConfig;
701 |
702 | /**
703 | * Use 1 based indexing for # links to match slide number (default is zero based)
704 | * @default false
705 | */
706 | hashOneBasedIndex?: boolean;
707 | /**
708 | * Add the current slide number to the URL hash so that reloading the
709 | * page/copying the URL will return you to the same slide
710 | * @default false
711 | */
712 | hash?: boolean;
713 |
714 | /**
715 | * Disables the default reveal.js slide layout so that you can use
716 | * custom CSS layout
717 | * @default false
718 | */
719 | disableLayout?: boolean;
720 |
721 | /**
722 | * Changes the behavior of our navigation directions.
723 | *
724 | * "default"
725 | * Left/right arrow keys step between horizontal slides, up/down
726 | * arrow keys step between vertical slides. Space key steps through
727 | * all slides (both horizontal and vertical).
728 | *
729 | * "linear"
730 | * Removes the up/down arrows. Left/right arrows step through all
731 | * slides (both horizontal and vertical).
732 | *
733 | * "grid"
734 | * When this is enabled, stepping left/right from a vertical stack
735 | * to an adjacent vertical stack will land you at the same vertical
736 | * index.
737 | *
738 | * Consider a deck with six slides ordered in two vertical stacks:
739 | * 1.1 2.1
740 | * 1.2 2.2
741 | * 1.3 2.3
742 | *
743 | * If you're on slide 1.3 and navigate right, you will normally move
744 | * from 1.3 -> 2.1. If "grid" is used, the same navigation takes you
745 | * from 1.3 -> 2.3.
746 | */
747 | navigationMode?: "default" | "linear" | "grid";
748 |
749 | /**
750 | * Flags if it should be possible to pause the presentation (blackout)
751 | * @default true
752 | */
753 | pause?: boolean;
754 |
755 | /**
756 | * Global override for autolaying embedded media (video/audio/iframe)
757 | * - null: Media will only autoplay if data-autoplay is present
758 | * - true: All media will autoplay, regardless of individual setting
759 | * - false: No media will autoplay, regardless of individual setting
760 | *
761 | * @default null
762 | */
763 | autoplayMedia?: boolean | null;
764 |
765 | /**
766 | * Global override for preloading lazy-loaded iframes
767 | * - null: Iframes with data-src AND data-preload will be loaded when within
768 | * the viewDistance, iframes with only data-src will be loaded when visible
769 | * - true: All iframes with data-src will be loaded when within the viewDistance
770 | * - false: All iframes with data-src will be loaded only when visible
771 | *
772 | * @default null
773 | */
774 | preloadIframes?: boolean | null;
775 |
776 | /**
777 | * Specify the average time in seconds that you think you will spend
778 | * presenting each slide. This is used to show a pacing timer in the
779 | * speaker view
780 | * @default null
781 | */
782 | defaultTiming?: number | null;
783 |
784 | /**
785 | * Focuses body when page changes visibility to ensure keyboard shortcuts work
786 | * @default true
787 | */
788 | focusBodyOnPageVisibilityChange?: boolean;
789 |
790 | /**
791 | * The maximum number of pages a single slide can expand onto when printing
792 | * to PDF, unlimited by default
793 | * @default Number.POSITIVE_INFINITY
794 | */
795 | pdfMaxPagesPerSlide?: number;
796 |
797 | /**
798 | * Prints each fragment on a separate slide
799 | * @default true
800 | */
801 | pdfSeparateFragments?: boolean;
802 |
803 | /**
804 | * Offset used to reduce the height of content within exported PDF pages.
805 | * This exists to account for environment differences based on how you
806 | * print to PDF. CLI printing options, like phantomjs and wkpdf, can end
807 | * on precisely the total height of the document whereas in-browser
808 | * printing has to end one pixel before.
809 | */
810 | pdfPageHeightOffset?: number;
811 |
812 | /**
813 | * The display mode that will be used to show slides
814 | * @default "block"
815 | */
816 | display?: string;
817 |
818 | /**
819 | * Hide cursor if inactive
820 | * @default true
821 | */
822 | hideInactiveCursor?: boolean;
823 |
824 | /**
825 | * Time before the cursor is hidden (in ms)
826 | * @default 5000
827 | */
828 | hideCursorTime?: number;
829 | }
830 |
831 | /**
832 | * https://github.com/hakimel/reveal.js/#slide-changed-event
833 | */
834 | interface SlideEvent {
835 | previousSlide?: Element;
836 | currentSlide: Element;
837 | indexh: number;
838 | indexv?: number;
839 | }
840 |
841 | /**
842 | * https://github.com/hakimel/reveal.js/#fragment-events
843 | */
844 | interface FragmentEvent {
845 | fragment: Element;
846 | }
847 |
848 | /**
849 | * https://github.com/hakimel/reveal.js/#multiplexing
850 | */
851 | interface MultiplexConfig {
852 | /**
853 | * Obtained from the socket.io server. Gives this (the master) control of the presentation
854 | */
855 | secret?: string;
856 | /**
857 | * Obtained from the socket.io server
858 | */
859 | id: string;
860 | /**
861 | * Location of socket.io server
862 | */
863 | url: string;
864 | }
865 |
866 | /**
867 | * https://github.com/hakimel/reveal.js/#mathjax
868 | */
869 | interface MathConfig {
870 | /**
871 | * Obtained from the socket.io server. Gives this (the master) control of the presentation
872 | */
873 | mathjax: string;
874 | /**
875 | * Obtained from the socket.io server
876 | */
877 | config: string;
878 | }
879 |
880 | /**
881 | * https://github.com/hakimel/reveal.js/#dependencies
882 | */
883 | interface RevealDependency {
884 | src: string;
885 | condition?: () => boolean;
886 | async?: boolean;
887 | callback?: () => void;
888 | }
889 |
--------------------------------------------------------------------------------
/src/slideshow/slideshow.ts:
--------------------------------------------------------------------------------
1 | declare const sandbox: ReturnType;
2 |
3 | import reveal from "reveal.js"
4 | export const revealJS = reveal as import("./reveal").RevealStatic
5 |
6 | export const startSlides = (url: string) => {
7 | // Expects a URL like https://gist.github.com/orta/d7dbd4cdb8d1f99c52871fb15db620bc
8 | // Convert to: https://gist.githubusercontent.com/orta/d7dbd4cdb8d1f99c52871fb15db620bc/raw/index.md
9 | //
10 | const rawURL = url.replace("https://gist.github.com", "https://gist.githubusercontent.com")
11 | return fetch(rawURL + "/raw/index.md", {cache: "no-store"}).then(r => {
12 | return r.text()
13 | }).then(markdown => {
14 | const main = document.body
15 | const divReveal = document.createElement("div")
16 | divReveal.className = "reveal"
17 | main.insertBefore(divReveal, main.firstChild)
18 |
19 | const div = document.createElement("div")
20 | div.className = "slides"
21 | divReveal.appendChild(div)
22 |
23 | const section = document.createElement("section")
24 | section.setAttribute("data-markdown", "")
25 | section.setAttribute("data-separator", "---")
26 | div.appendChild(section)
27 |
28 | const textarea = document.createElement("textarea")
29 | textarea.setAttribute("data-template", "")
30 | textarea.textContent = markdown
31 | section.appendChild(textarea)
32 |
33 |
34 | const addCSS = (href: string) => {
35 | var link = document.createElement("link");
36 | link.type = "text/css";
37 | link.rel = "stylesheet";
38 | link.href = href;
39 | document.head.appendChild(link)
40 | }
41 |
42 | const isDev = document.location.host.includes("localhost")
43 | const unpkgURL = "https://unpkg.com/typescript-playground-presentation-mode/dist/slideshow.css"
44 | const href2 = isDev ? "http://localhost:5000/slideshow.css" : unpkgURL
45 | addCSS(href2)
46 |
47 | revealJS.initialize({
48 | keyboard: {
49 | 27: function() {
50 | const top = document.getElementsByClassName("raised")[0]
51 | top.scrollIntoView(true)
52 | sandbox.editor.focus()
53 | },
54 | },
55 | controlsTutorial: false,
56 | overview: false,
57 | fragments: false,
58 | })
59 |
60 | // All this faff is because the viewport will be at the bottom briefly during initialization,
61 | // which means the first slide is way off, so we force it to the top, make it invisivle, delay a
62 | // few ms do a re-layout and show the slides in the right position
63 | window.scrollTo({ top: 0 })
64 | const element = revealJS.getRevealElement() as HTMLElement
65 | element.style.opacity = "0"
66 | setTimeout(() => {
67 | revealJS.layout()
68 | element.style.opacity = "100"
69 | }, 300)
70 |
71 | // Hook into the reveal JS slide changed notifications so that we can update monaco underneath
72 | revealJS.addEventListener("slidechanged", (deets: SlideChanged) => {
73 | if (deets.currentSlide && deets.currentSlide.getElementsByTagName("playground")) {
74 | const code = deets.currentSlide.getElementsByTagName("playground")[0]!
75 | if (code && code.textContent) {
76 | sandbox.setText(code.textContent.trim())
77 | }
78 | }
79 | })
80 | })
81 |
82 | // rElement.focus()/
83 |
84 | }
85 |
86 | interface SlideChanged {
87 | indexh: number
88 | indexv: number
89 | previousSlide: Element
90 | currentSlide: Element
91 | origin: any
92 | }
93 |
--------------------------------------------------------------------------------
/src/vendor/ds/createDesignSystem.d.ts:
--------------------------------------------------------------------------------
1 | import type { Sandbox } from "../sandbox";
2 | import type { DiagnosticRelatedInformation, Node } from "typescript";
3 | export declare type LocalStorageOption = {
4 | blurb: string;
5 | flag: string;
6 | display: string;
7 | emptyImpliesEnabled?: true;
8 | oneline?: true;
9 | requireRestart?: true;
10 | onchange?: (newValue: boolean) => void;
11 | };
12 | export declare type OptionsListConfig = {
13 | style: "separated" | "rows";
14 | requireRestart?: true;
15 | };
16 | export declare const createDesignSystem: (sandbox: Sandbox) => (container: Element) => {
17 | /** Clear the sidebar */
18 | clear: () => void;
19 | /** Present code in a pre > code */
20 | code: (code: string) => HTMLElement;
21 | /** Ideally only use this once, and maybe even prefer using subtitles everywhere */
22 | title: (title: string) => HTMLElement;
23 | /** Used to denote sections, give info etc */
24 | subtitle: (subtitle: string) => HTMLElement;
25 | /** Used to show a paragraph */
26 | p: (subtitle: string) => HTMLElement;
27 | /** When you can't do something, or have nothing to show */
28 | showEmptyScreen: (message: string) => HTMLDivElement;
29 | /**
30 | * Shows a list of hoverable, and selectable items (errors, highlights etc) which have code representation.
31 | * The type is quite small, so it should be very feasible for you to massage other data to fit into this function
32 | */
33 | listDiags: (model: import("monaco-editor").editor.ITextModel, diags: DiagnosticRelatedInformation[]) => HTMLUListElement;
34 | /** Shows a single option in local storage (adds an li to the container BTW) */
35 | localStorageOption: (setting: LocalStorageOption) => HTMLLIElement;
36 | /** Uses localStorageOption to create a list of options */
37 | showOptionList: (options: LocalStorageOption[], style: OptionsListConfig) => void;
38 | /** Shows a full-width text input */
39 | createTextInput: (config: {
40 | id: string;
41 | placeholder: string;
42 | onChanged?: ((text: string, input: HTMLInputElement) => void) | undefined;
43 | onEnter: (text: string, input: HTMLInputElement) => void;
44 | value?: string | undefined;
45 | keepValueAcrossReloads?: true | undefined;
46 | isEnabled?: ((input: HTMLInputElement) => boolean) | undefined;
47 | }) => HTMLFormElement;
48 | /** Renders an AST tree */
49 | createASTTree: (node: Node) => HTMLDivElement;
50 | /** Creates an input button */
51 | button: (settings: {
52 | label: string;
53 | onclick?: ((ev: MouseEvent) => void) | undefined;
54 | }) => HTMLInputElement;
55 | /** Used to re-create a UI like the tab bar at the top of the plugins section */
56 | createTabBar: () => HTMLDivElement;
57 | /** Used with createTabBar to add buttons */
58 | createTabButton: (text: string) => HTMLButtonElement;
59 | /** A general "restart your browser" message */
60 | declareRestartRequired: (i?: ((key: string) => string) | undefined) => void;
61 | };
62 |
--------------------------------------------------------------------------------
/src/vendor/playground.d.ts:
--------------------------------------------------------------------------------
1 | declare type Sandbox = import("./sandbox").Sandbox;
2 | declare type Monaco = typeof import("monaco-editor");
3 | import { PluginUtils } from "./pluginUtils";
4 | import type React from "react";
5 | export { PluginUtils } from "./pluginUtils";
6 | export declare type PluginFactory = {
7 | (i: (key: string, components?: any) => string, utils: PluginUtils): PlaygroundPlugin;
8 | };
9 | /** The interface of all sidebar plugins */
10 | export interface PlaygroundPlugin {
11 | /** Not public facing, but used by the playground to uniquely identify plugins */
12 | id: string;
13 | /** To show in the tabs */
14 | displayName: string;
15 | /** Should this plugin be selected when the plugin is first loaded? Lets you check for query vars etc to load a particular plugin */
16 | shouldBeSelected?: () => boolean;
17 | /** Before we show the tab, use this to set up your HTML - it will all be removed by the playground when someone navigates off the tab */
18 | willMount?: (sandbox: Sandbox, container: HTMLDivElement) => void;
19 | /** After we show the tab */
20 | didMount?: (sandbox: Sandbox, container: HTMLDivElement) => void;
21 | /** Model changes while this plugin is actively selected */
22 | modelChanged?: (sandbox: Sandbox, model: import("monaco-editor").editor.ITextModel, container: HTMLDivElement) => void;
23 | /** Delayed model changes while this plugin is actively selected, useful when you are working with the TS API because it won't run on every keypress */
24 | modelChangedDebounce?: (sandbox: Sandbox, model: import("monaco-editor").editor.ITextModel, container: HTMLDivElement) => void;
25 | /** Before we remove the tab */
26 | willUnmount?: (sandbox: Sandbox, container: HTMLDivElement) => void;
27 | /** After we remove the tab */
28 | didUnmount?: (sandbox: Sandbox, container: HTMLDivElement) => void;
29 | /** An object you can use to keep data around in the scope of your plugin object */
30 | data?: any;
31 | }
32 | interface PlaygroundConfig {
33 | /** Language like "en" / "ja" etc */
34 | lang: string;
35 | /** Site prefix, like "v2" during the pre-release */
36 | prefix: string;
37 | /** Optional plugins so that we can re-use the playground with different sidebars */
38 | plugins?: PluginFactory[];
39 | /** Should this playground load up custom plugins from localStorage? */
40 | supportCustomPlugins: boolean;
41 | }
42 | export declare const setupPlayground: (sandbox: Sandbox, monaco: Monaco, config: PlaygroundConfig, i: (key: string) => string, react: typeof React) => {
43 | exporter: {
44 | openProjectInStackBlitz: () => void;
45 | openProjectInCodeSandbox: () => void;
46 | reportIssue: () => Promise;
47 | copyAsMarkdownIssue: () => Promise;
48 | copyForChat: () => void;
49 | copyForChatWithPreview: () => void;
50 | openInTSAST: () => void;
51 | };
52 | // ui: import("./createUI").UI;
53 | registerPlugin: (plugin: PlaygroundPlugin) => void;
54 | plugins: PlaygroundPlugin[];
55 | getCurrentPlugin: () => PlaygroundPlugin;
56 | tabs: HTMLButtonElement[];
57 | setDidUpdateTab: (func: (newPlugin: PlaygroundPlugin, previousPlugin: PlaygroundPlugin) => void) => void;
58 | createUtils: (sb: any, react: typeof React) => {
59 | el: (str: string, elementType: string, container: Element) => HTMLElement;
60 | requireURL: (path: string) => string;
61 | react: typeof React;
62 | createDesignSystem: (container: Element) => {
63 | clear: () => void;
64 | code: (code: string) => HTMLElement;
65 | title: (title: string) => HTMLElement;
66 | subtitle: (subtitle: string) => HTMLElement;
67 | p: (subtitle: string) => HTMLElement;
68 | showEmptyScreen: (message: string) => HTMLDivElement;
69 | listDiags: (model: import("monaco-editor").editor.ITextModel, diags: import("typescript").DiagnosticRelatedInformation[]) => HTMLUListElement;
70 | localStorageOption: (setting: import("./ds/createDesignSystem").LocalStorageOption) => HTMLLIElement;
71 | showOptionList: (options: import("./ds/createDesignSystem").LocalStorageOption[], style: import("./ds/createDesignSystem").OptionsListConfig) => void;
72 | createTextInput: (config: {
73 | id: string;
74 | placeholder: string;
75 | onChanged?: ((text: string, input: HTMLInputElement) => void) | undefined;
76 | onEnter: (text: string, input: HTMLInputElement) => void;
77 | value?: string | undefined;
78 | keepValueAcrossReloads?: true | undefined;
79 | isEnabled?: ((input: HTMLInputElement) => boolean) | undefined;
80 | }) => HTMLFormElement;
81 | createASTTree: (node: import("typescript").Node) => HTMLDivElement;
82 | button: (settings: {
83 | label: string;
84 | onclick?: ((ev: MouseEvent) => void) | undefined;
85 | }) => HTMLInputElement;
86 | createTabBar: () => HTMLDivElement;
87 | createTabButton: (text: string) => HTMLButtonElement;
88 | declareRestartRequired: (i?: ((key: string) => string) | undefined) => void;
89 | };
90 | flashHTMLElement: (element: HTMLElement) => void;
91 | setNotifications: (pluginID: string, amount: number) => void;
92 | };
93 | };
94 | export declare type Playground = ReturnType;
95 |
--------------------------------------------------------------------------------
/src/vendor/pluginUtils.d.ts:
--------------------------------------------------------------------------------
1 | import type React from "react";
2 | /** Creates a set of util functions which is exposed to Plugins to make it easier to build consistent UIs */
3 | export declare const createUtils: (sb: any, react: typeof React) => {
4 | /** Use this to make a few dumb element generation funcs */
5 | el: (str: string, elementType: string, container: Element) => HTMLElement;
6 | /** Get a relative URL for something in your dist folder depending on if you're in dev mode or not */
7 | requireURL: (path: string) => string;
8 | /** The Gatsby copy of React */
9 | react: typeof React;
10 | /**
11 | * The playground plugin design system. Calling any of the functions will append the
12 | * element to the container you pass into the first param, and return the HTMLElement
13 | */
14 | createDesignSystem: (container: Element) => {
15 | clear: () => void;
16 | code: (code: string) => HTMLElement;
17 | title: (title: string) => HTMLElement;
18 | subtitle: (subtitle: string) => HTMLElement;
19 | p: (subtitle: string) => HTMLElement;
20 | showEmptyScreen: (message: string) => HTMLDivElement;
21 | listDiags: (model: import("monaco-editor").editor.ITextModel, diags: import("typescript").DiagnosticRelatedInformation[]) => HTMLUListElement;
22 | localStorageOption: (setting: import("./ds/createDesignSystem").LocalStorageOption) => HTMLLIElement;
23 | showOptionList: (options: import("./ds/createDesignSystem").LocalStorageOption[], style: import("./ds/createDesignSystem").OptionsListConfig) => void;
24 | createTextInput: (config: {
25 | id: string;
26 | placeholder: string;
27 | onChanged?: ((text: string, input: HTMLInputElement) => void) | undefined;
28 | onEnter: (text: string, input: HTMLInputElement) => void;
29 | value?: string | undefined;
30 | keepValueAcrossReloads?: true | undefined;
31 | isEnabled?: ((input: HTMLInputElement) => boolean) | undefined;
32 | }) => HTMLFormElement;
33 | createASTTree: (node: import("typescript").Node) => HTMLDivElement;
34 | button: (settings: {
35 | label: string;
36 | onclick?: ((ev: MouseEvent) => void) | undefined;
37 | }) => HTMLInputElement;
38 | createTabBar: () => HTMLDivElement;
39 | createTabButton: (text: string) => HTMLButtonElement;
40 | declareRestartRequired: (i?: ((key: string) => string) | undefined) => void;
41 | };
42 | /** Flashes a HTML Element */
43 | flashHTMLElement: (element: HTMLElement) => void;
44 | /** Add a little red button in the top corner of a plugin tab with a number */
45 | setNotifications: (pluginID: string, amount: number) => void;
46 | };
47 | export declare type PluginUtils = ReturnType;
48 |
--------------------------------------------------------------------------------
/src/vendor/sandbox.d.ts:
--------------------------------------------------------------------------------
1 | import { TypeScriptWorker } from "./tsWorker";// import { TypeScriptWorker } from "./tsWorker";
2 | // import lzstring from "./vendor/lzstring.min";
3 |
4 | import * as tsvfs from './typescript-vfs';
5 | declare type CompilerOptions = import("monaco-editor").languages.typescript.CompilerOptions;
6 | declare type Monaco = typeof import("monaco-editor");
7 | /**
8 | * These are settings for the playground which are the equivalent to props in React
9 | * any changes to it should require a new setup of the playground
10 | */
11 | export declare type PlaygroundConfig = {
12 | /** The default source code for the playground */
13 | text: string;
14 | /** Should it run the ts or js IDE services */
15 | useJavaScript: boolean;
16 | /** Compiler options which are automatically just forwarded on */
17 | compilerOptions: CompilerOptions;
18 | /** Optional monaco settings overrides */
19 | monacoSettings?: import("monaco-editor").editor.IEditorOptions;
20 | /** Acquire types via type acquisition */
21 | acquireTypes: boolean;
22 | /** Support twoslash compiler options */
23 | supportTwoslashCompilerOptions: boolean;
24 | /** Get the text via query params and local storage, useful when the editor is the main experience */
25 | suppressAutomaticallyGettingDefaultText?: true;
26 | /** Suppress setting compiler options from the compiler flags from query params */
27 | suppressAutomaticallyGettingCompilerFlags?: true;
28 | /** Logging system */
29 | logger: {
30 | log: (...args: any[]) => void;
31 | error: (...args: any[]) => void;
32 | groupCollapsed: (...args: any[]) => void;
33 | groupEnd: (...args: any[]) => void;
34 | };
35 | } & ({
36 | domID: string;
37 | } | {
38 | elementToAppend: HTMLElement;
39 | });
40 | /** The default settings which we apply a partial over */
41 | export declare function defaultPlaygroundSettings(): {
42 | /** The default source code for the playground */
43 | text: string;
44 | /** Should it run the ts or js IDE services */
45 | useJavaScript: boolean;
46 | /** Compiler options which are automatically just forwarded on */
47 | compilerOptions: import("monaco-editor").languages.typescript.CompilerOptions;
48 | /** Optional monaco settings overrides */
49 | monacoSettings?: import("monaco-editor").editor.IEditorOptions | undefined;
50 | /** Acquire types via type acquisition */
51 | acquireTypes: boolean;
52 | /** Support twoslash compiler options */
53 | supportTwoslashCompilerOptions: boolean;
54 | /** Get the text via query params and local storage, useful when the editor is the main experience */
55 | suppressAutomaticallyGettingDefaultText?: true | undefined;
56 | /** Suppress setting compiler options from the compiler flags from query params */
57 | suppressAutomaticallyGettingCompilerFlags?: true | undefined;
58 | /** Logging system */
59 | logger: {
60 | log: (...args: any[]) => void;
61 | error: (...args: any[]) => void;
62 | groupCollapsed: (...args: any[]) => void;
63 | groupEnd: (...args: any[]) => void;
64 | };
65 | } & {
66 | domID: string;
67 | };
68 | /** Creates a sandbox editor, and returns a set of useful functions and the editor */
69 | export declare const createTypeScriptSandbox: (partialConfig: Partial, monaco: Monaco, ts: typeof import("typescript")) => {
70 | /** The same config you passed in */
71 | config: {
72 | text: string;
73 | useJavaScript: boolean;
74 | compilerOptions: CompilerOptions;
75 | monacoSettings?: import("monaco-editor").editor.IEditorOptions | undefined;
76 | acquireTypes: boolean;
77 | supportTwoslashCompilerOptions: boolean;
78 | suppressAutomaticallyGettingDefaultText?: true | undefined;
79 | suppressAutomaticallyGettingCompilerFlags?: true | undefined;
80 | logger: {
81 | log: (...args: any[]) => void;
82 | error: (...args: any[]) => void;
83 | groupCollapsed: (...args: any[]) => void;
84 | groupEnd: (...args: any[]) => void;
85 | };
86 | domID: string;
87 | };
88 | /** A list of TypeScript versions you can use with the TypeScript sandbox */
89 | supportedVersions: readonly ["3.9.2", "3.8.3", "3.8.2", "3.7.5", "3.6.3", "3.5.1", "3.3.3", "3.1.6", "3.0.1", "2.8.1", "2.7.2", "2.4.1"];
90 | /** The monaco editor instance */
91 | editor: import("monaco-editor").editor.IStandaloneCodeEditor;
92 | /** Either "typescript" or "javascript" depending on your config */
93 | language: string;
94 | /** The outer monaco module, the result of require("monaco-editor") */
95 | monaco: typeof import("monaco-editor");
96 | /** Gets a monaco-typescript worker, this will give you access to a language server. Note: prefer this for language server work because it happens on a webworker . */
97 | getWorkerProcess: () => Promise;
98 | /** A copy of require("@typescript/vfs") this can be used to quickly set up an in-memory compiler runs for ASTs, or to get complex language server results (anything above has to be serialized when passed)*/
99 | tsvfs: typeof tsvfs;
100 | /** Get all the different emitted files after TypeScript is run */
101 | getEmitResult: () => Promise;
102 | /** Gets just the JavaScript for your sandbox, will transpile if in TS only */
103 | getRunnableJS: () => Promise;
104 | /** Gets the DTS output of the main code in the editor */
105 | getDTSForCode: () => Promise;
106 | /** The monaco-editor dom node, used for showing/hiding the editor */
107 | getDomNode: () => HTMLElement;
108 | /** The model is an object which monaco uses to keep track of text in the editor. Use this to directly modify the text in the editor */
109 | getModel: () => import("monaco-editor").editor.ITextModel;
110 | /** Gets the text of the main model, which is the text in the editor */
111 | getText: () => string;
112 | /** Shortcut for setting the model's text content which would update the editor */
113 | setText: (text: string) => void;
114 | /** Gets the AST of the current text in monaco - uses `createTSProgram`, so the performance caveat applies there too */
115 | getAST: () => Promise;
116 | /** The module you get from require("typescript") */
117 | ts: typeof import("typescript");
118 | /** Create a new Program, a TypeScript data model which represents the entire project. As well as some of the
119 | * primitive objects you would normally need to do work with the files.
120 | *
121 | * The first time this is called it has to download all the DTS files which is needed for an exact compiler run. Which
122 | * at max is about 1.5MB - after that subsequent downloads of dts lib files come from localStorage.
123 | *
124 | * Try to use this sparingly as it can be computationally expensive, at the minimum you should be using the debounced setup.
125 | *
126 | * TODO: It would be good to create an easy way to have a single program instance which is updated for you
127 | * when the monaco model changes.
128 | */
129 | setupTSVFS: () => Promise<{
130 | program: import("typescript").Program;
131 | system: import("typescript").System;
132 | host: {
133 | compilerHost: import("typescript").CompilerHost;
134 | updateFile: (sourceFile: import("typescript").SourceFile) => boolean;
135 | };
136 | }>;
137 | /** Uses the above call setupTSVFS, but only returns the program */
138 | createTSProgram: () => Promise;
139 | /** The Sandbox's default compiler options */
140 | compilerDefaults: import("monaco-editor").languages.typescript.CompilerOptions;
141 | /** The Sandbox's current compiler options */
142 | getCompilerOptions: () => import("monaco-editor").languages.typescript.CompilerOptions;
143 | /** Replace the Sandbox's compiler options */
144 | setCompilerSettings: (opts: CompilerOptions) => void;
145 | /** Overwrite the Sandbox's compiler options */
146 | updateCompilerSetting: (key: keyof CompilerOptions, value: any) => void;
147 | /** Update a single compiler option in the SAndbox */
148 | updateCompilerSettings: (opts: CompilerOptions) => void;
149 | /** A way to get callbacks when compiler settings have changed */
150 | setDidUpdateCompilerSettings: (func: (opts: CompilerOptions) => void) => void;
151 | /** A copy of lzstring, which is used to archive/unarchive code */
152 | // lzstring: typeof lzstring;
153 | /** Returns compiler options found in the params of the current page */
154 | createURLQueryWithCompilerOptions: (sandbox: any, paramOverrides?: any) => string;
155 | /** Returns compiler options in the source code using twoslash notation */
156 | getTwoSlashComplierOptions: (code: string) => any;
157 | /** Gets to the current monaco-language, this is how you talk to the background webworkers */
158 | languageServiceDefaults: import("monaco-editor").languages.typescript.LanguageServiceDefaults;
159 | /** The path which represents the current file using the current compiler options */
160 | filepath: string;
161 | };
162 | export declare type Sandbox = ReturnType;
163 | export {};
164 |
--------------------------------------------------------------------------------
/src/vendor/tsWorker.d.ts:
--------------------------------------------------------------------------------
1 | import ts from 'typescript';
2 | export declare class TypeScriptWorker implements ts.LanguageServiceHost {
3 | private _ctx;
4 | private _extraLibs;
5 | private _languageService;
6 | private _compilerOptions;
7 | constructor(ctx: any, createData: any);
8 | getCompilationSettings(): ts.CompilerOptions;
9 | getScriptFileNames(): string[];
10 | private _getModel;
11 | getScriptVersion(fileName: string): string;
12 | getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined;
13 | getScriptKind?(fileName: string): ts.ScriptKind;
14 | getCurrentDirectory(): string;
15 | getDefaultLibFileName(options: ts.CompilerOptions): string;
16 | isDefaultLibFileName(fileName: string): boolean;
17 | private static clearFiles;
18 | getSyntacticDiagnostics(fileName: string): Promise;
19 | getSemanticDiagnostics(fileName: string): Promise;
20 | getSuggestionDiagnostics(fileName: string): Promise;
21 | getCompilerOptionsDiagnostics(fileName: string): Promise;
22 | getCompletionsAtPosition(fileName: string, position: number): Promise;
23 | getCompletionEntryDetails(fileName: string, position: number, entry: string): Promise;
24 | getSignatureHelpItems(fileName: string, position: number): Promise;
25 | getQuickInfoAtPosition(fileName: string, position: number): Promise;
26 | getOccurrencesAtPosition(fileName: string, position: number): Promise | undefined>;
27 | getDefinitionAtPosition(fileName: string, position: number): Promise | undefined>;
28 | getReferencesAtPosition(fileName: string, position: number): Promise;
29 | getNavigationBarItems(fileName: string): Promise;
30 | getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): Promise;
31 | getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): Promise;
32 | getFormattingEditsAfterKeystroke(fileName: string, postion: number, ch: string, options: ts.FormatCodeOptions): Promise;
33 | findRenameLocations(fileName: string, positon: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename: boolean): Promise;
34 | getRenameInfo(fileName: string, positon: number, options: ts.RenameInfoOptions): Promise;
35 | getEmitOutput(fileName: string): Promise;
36 | getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: ts.FormatCodeOptions): Promise>;
37 | updateExtraLibs(extraLibs: IExtraLibs): void;
38 | }
39 | export interface IExtraLib {
40 | content: string;
41 | version: number;
42 | }
43 | export interface IExtraLibs {
44 | [path: string]: IExtraLib;
45 | }
46 |
--------------------------------------------------------------------------------
/src/vendor/typescript-vfs.d.ts:
--------------------------------------------------------------------------------
1 |
2 | declare type System = import("typescript").System;
3 | declare type CompilerOptions = import("typescript").CompilerOptions;
4 | declare type CustomTransformers = import("typescript").CustomTransformers;
5 | declare type LanguageServiceHost = import("typescript").LanguageServiceHost;
6 | declare type CompilerHost = import("typescript").CompilerHost;
7 | declare type SourceFile = import("typescript").SourceFile;
8 | declare type TS = typeof import("typescript");
9 | export interface VirtualTypeScriptEnvironment {
10 | sys: System;
11 | languageService: import("typescript").LanguageService;
12 | getSourceFile: (fileName: string) => import("typescript").SourceFile | undefined;
13 | createFile: (fileName: string, content: string) => void;
14 | updateFile: (fileName: string, content: string, replaceTextSpan?: import("typescript").TextSpan) => void;
15 | }
16 | /**
17 | * Makes a virtual copy of the TypeScript environment. This is the main API you want to be using with
18 | * @typescript/vfs. A lot of the other exposed functions are used by this function to get set up.
19 | *
20 | * @param sys an object which conforms to the TS Sys (a shim over read/write access to the fs)
21 | * @param rootFiles a list of files which are considered inside the project
22 | * @param ts a copy pf the TypeScript module
23 | * @param compilerOptions the options for this compiler run
24 | * @param customTransformers custom transformers for this compiler run
25 | */
26 | export declare function createVirtualTypeScriptEnvironment(sys: System, rootFiles: string[], ts: TS, compilerOptions?: CompilerOptions, customTransformers?: CustomTransformers): VirtualTypeScriptEnvironment;
27 | /**
28 | * Grab the list of lib files for a particular target, will return a bit more than necessary (by including
29 | * the dom) but that's OK
30 | *
31 | * @param target The compiler settings target baseline
32 | * @param ts A copy of the TypeScript module
33 | */
34 | export declare const knownLibFilesForCompilerOptions: (compilerOptions: CompilerOptions, ts: TS) => string[];
35 | /**
36 | * Sets up a Map with lib contents by grabbing the necessary files from
37 | * the local copy of typescript via the file system.
38 | */
39 | export declare const createDefaultMapFromNodeModules: (compilerOptions: CompilerOptions, ts?: typeof import("typescript") | undefined) => Map;
40 | /**
41 | * Adds recursively files from the FS into the map based on the folder
42 | */
43 | export declare const addAllFilesFromFolder: (map: Map, workingDir: string) => void;
44 | /** Adds all files from node_modules/@types into the FS Map */
45 | export declare const addFilesForTypesIntoFolder: (map: Map) => void;
46 | /**
47 | * Create a virtual FS Map with the lib files from a particular TypeScript
48 | * version based on the target, Always includes dom ATM.
49 | *
50 | * @param options The compiler target, which dictates the libs to set up
51 | * @param version the versions of TypeScript which are supported
52 | * @param cache should the values be stored in local storage
53 | * @param ts a copy of the typescript import
54 | * @param lzstring an optional copy of the lz-string import
55 | * @param fetcher an optional replacement for the global fetch function (tests mainly)
56 | * @param storer an optional replacement for the localStorage global (tests mainly)
57 | */
58 | export declare const createDefaultMapFromCDN: (options: CompilerOptions, version: string, cache: boolean, ts: TS, lzstring?: any | undefined, fetcher?: typeof fetch | undefined, storer?: Storage | undefined) => Promise