PageSourceSearch

https://slidesdown.github.io/init.js

js slidesdown.github.io collected 2026-10-03 09:58:08 UTC 11,402 bytes, 279 lines download raw bytes

1// INFO: the non-esm plugins need reveal JS in scope so it can't be imported
2// here
3// import Reveal from "revealjs";
4import RevealHighlight from "reveal-highlight";
5import RevealMath from "reveal-math";
6import RevealNotes from "reveal-notes";
7import RevealSearch from "reveal-search";
8import RevealZoom from "reveal-zoom";
9import RevealECharts from "reveal-echarts";
10import RevealMermaid from "reveal-mermaid";
11// import RevealApexchart from "reveal-apexchart";
12// import RevealChartjs from "reveal-chartjs";
13// INFO: non-esm therefore they can't be properly imported:
14// import * as PdfExport from "reveal-pdfexport";
15// import * as RevealChalkboard from "reveal-chalkboard";
16// import * as RevealCustomControls from "reveal-customcontrols";
17import SlidesDown from "slidesdown";
18
19// computeURL builds a URL to a raw markdown file from a short human-typable
20// string, e.g. it turns github.com/slidesdown/slidesdown into
21// https://raw.githubusercontent.com/slidsedown/slidesdown/main/SLIDES.md
22function computeURL(defaults, url) {
23  if (!(defaults.branch && defaults.resource)) {
24    console.error("Default branch and/or resource unset");
25    return;
26  }
27  const decodedURL = decodeURI(url);
28  let match = "";
29  const githubRegExp = new RegExp(
30    /^(?:https:\/\/)?github\.com\/(?<owner>[a-zA-Z0-9_-]+)\/(?<repo>[a-zA-Z0-9_-]+)(?:(?:\/((?<blob>blob)|(?<tree>tree)))?(?:\/(?<dir_or_branch>[^/]+?))?(?:\/(?<resource>.*)))?$/,
31  );
32  // resource is not considered for gists, because there's no safe way to
33  // determine the resource's name from the provided anchor tag
34  const gistRegExp = new RegExp(
35    /^(?:https:\/\/)?gist\.github\.com\/(?<owner>[a-zA-Z0-9_-]+)\/(?<repo>[a-zA-Z0-9_-]+)\/?/,
36  );
37  // gistRegExp.exec("gist.github.com/jceb/4bfcfdcddd2020e5b7e521b9e1044f3b")
38  // gistRegExp.exec("https://gist.github.com/jceb/4bfcfdcddd2020e5b7e521b9e1044f3b")
39  // gistRegExp.exec("https://gist.github.com/jceb/4bfcfdcddd2020e5b7e521b9e1044f3b#file-230911_dif_wg_id_presentation-md")
40  // gistRegExp.exec("https://gist.github.com/jceb/4bfcfdcddd2020e5b7e521b9e1044f3b/#file-230911_dif_wg_id_presentation-md")
41  // gistRegExp.exec("https://gist.githubusercontent.com/jceb/4bfcfdcddd2020e5b7e521b9e1044f3b/raw/dd6e852ccb04c1690a7e96eb77008240e0fbf69f/SLIDES.md")
42  const srhtRegExp = new RegExp(
43    /^(?:https:\/\/)?(git\.)?sr\.ht\/(?<owner>~[a-zA-Z0-9_-]+)\/(?<repo>[a-zA-Z0-9_-]+)(?:(?:\/((?<blob>blob)|(?<tree>tree)))?(?:\/(?<dir_or_branch>[^/]+?))?(?:\/(item\/)?(?<resource>.*)))?$/,
44  );
45  // srhtRegExp.exec("https://git.sr.ht/~jceb/test")
46  // srhtRegExp.exec("https://git.sr.ht/~jceb/test/SLIDES.md")
47  // srhtRegExp.exec("https://git.sr.ht/~jceb/test/tree")
48  // srhtRegExp.exec("https://git.sr.ht/~jceb/test/tree/SLIDES.md")
49  // srhtRegExp.exec("https://git.sr.ht/~jceb/test/tree/main/item/SLIDES.md")
50  // srhtRegExp.exec("sr.ht/~jceb/test/tree/main/item/SLIDES.md")
51  // srhtRegExp.exec("sr.ht/~jceb/test/SLIDES.md")
52  if ((match = githubRegExp.exec(decodedURL)) !== null) {
53    let resource = `${defaults.branch}/${defaults.resource}`;
54    // if tree is present, then the default resouce name must be appended
55    if ((match.groups.blob | match.groups.tree) && match.groups.dir_or_branch) {
56      // if tree or blob are present, then dir_or_branch is the branch - perfect, I can build the URL with confidence
57      resource = `${match.groups.dir_or_branch}/${
58        match.groups.resource ? match.groups.resource : defaults.resource
59      }`;
60    } else if (match.groups.blob && match.groups.dir_or_branch) {
61      // if tree or blob are not present, then dir_or_branch must be a dir but the branch name can't be determined
62      resource = `${match.groups.dir_or_branch}/${
63        match.groups.resource ? match.groups.resource : defaults.resource
64      }`;
65    } else {
66      if (match.groups.dir_or_branch) {
67        resource = `${defaults.branch}/${match.groups.dir_or_branch}/${
68          match.groups.resource ? match.groups.resource : defaults.resource
69        }`;
70      } else {
71        resource = `${defaults.branch}/${
72          match.groups.resource ? match.groups.resource : defaults.resource
73        }`;
74      }
75    }
76    return `https://raw.githubusercontent.com/${match.groups.owner}/${match.groups.repo}/${resource}`;
77  } else if ((match = gistRegExp.exec(decodedURL)) !== null) {
78    return `https://gist.githubusercontent.com/${match.groups.owner}/${match.groups.repo}/raw/SLIDES.md`;
79  } else if ((match = srhtRegExp.exec(decodedURL)) !== null) {
80    // INFO: support for sr.ht is currently broken due to missing CORS headers on 
80sr.ht's side
81    let resource = `${defaults.branch}/${defaults.resource}`;
82    // if tree is present, then the default resouce name must be appended
83    if ((match.groups.blob | match.groups.tree) && match.groups.dir_or_branch) {
84      // if tree or blob are present, then dir_or_branch is the branch - perfect, I can build the URL with confidence
85      resource = `${match.groups.dir_or_branch}/${
86        match.groups.resource ? match.groups.resource : defaults.resource
87      }`;
88    } else if (match.groups.blob && match.groups.dir_or_branch) {
89      // if tree or blob are not present, then dir_or_branch must be a dir but the branch name can't be determined
90      resource = `${match.groups.dir_or_branch}/${
91        match.groups.resource ? match.groups.resource : defaults.resource
92      }`;
93    } else {
94      if (match.groups.dir_or_branch) {
95        resource = `${defaults.branch}/${match.groups.dir_or_branch}/${
96          match.groups.resource ? match.groups.resource : defaults.resource
97        }`;
98      } else {
99        resource = `${defaults.branch}/${
100          match.groups.resource ? match.groups.resource : defaults.resource
101        }`;
102      }
103    }
104    return `https://git.sr.ht/${match.groups.owner}/${match.groups.repo}/blob/${resource}`;
105  }
106  return decodedURL;
107}
108
109async function main(defaults) {
110  if (!(defaults.branch && defaults.resource && defaults.markdownElementId)) {
111    console.error(
112      "Default branch, resource  and/or markdownElementId are not set",
113    );
114    return;
115  }
116  const mdSection = document.getElementById(defaults.markdownElementId);
117  if (!mdSection) {
118    console.error(
119      `Couldn't find markdown element with id: ${defaults.markdownElementId}`,
120    );
121    return;
122  }
123  const customSlidesBase64Gzip = new URLSearchParams(
124    new URL(document.URL).search,
125  ).get("slides64");
126  if (customSlidesBase64Gzip) {
127    async function decompressBlob(blob) {
128      const decompressedStream = blob.pipeThrough(
129        new DecompressionStream("gzip"),
130      );
131      return await new Response(decompressedStream).blob();
132    }
133    const slidesGz = Uint8Array.from(
134      atob(
135        decodeURI(
136          customSlidesBase64Gzip.replaceAll("-", "+").replaceAll("_", "/"),
137        ),
138      ),
139      (c) => c.charCodeAt(0),
140    );
141    // function buf2hex(buffer) { // buffer is an ArrayBuffer
142    //   return [...new Uint8Array(buffer)]
143    //     .map(x => x.toString(16).padStart(2, '0'))
144    //     .join('');
145    // }
146    const blob = await decompressBlob(
147      new Blob([slidesGz], { type: "application/octet-stream" }).stream(),
148    );
149    const text = await blob.text();
150    mdSection.setAttribute("data-markdown", "<<load-plain-markdown>>");
151    mdSection.setAttribute("data-markdown-plain", text);
152  } else {
153    const customSlidesURL = new URLSearchParams(new URL(document.URL).search)
154      .get("slides");
155    let slidesURL = customSlidesURL
156      ? customSlidesURL
157      : `github.com/slidesdown/slidesdown/blob/${defaults.branch}/${defaults.resource}`;
158
159    slidesURL = computeURL(defaults, slidesURL);
160
161    if (!slidesURL) {
162      console.error("Couldn't compute slides URL");
163      return;
164    }
165    mdSection.setAttribute("data-markdown", slidesURL);
166  }
167  const multiplexBase64 = new URLSearchParams(new URL(document.URL).search).get(
168    "multiplex64",
169  );
170  let multiplex = {};
171  let dependencies = [];
172  if (multiplexBase64) {
173    multiplex = JSON.parse(atob(
174      decodeURI(
175        multiplexBase64.replaceAll("-", "+").replaceAll("_", "/"),
176      ),
177    ));
178    multiplex = {
179      secret: multiplex?.secret || null,
180      id: multiplex?.id || null,
181      url: "/",
182      // url: "https://reveal-multiplex.glitch.me"
183    };
184    const minium_secret_length = 20;
185    if (
186      typeof multiplex.id != "string" &&
187      multiplex.id.length < minium_secret_length
188    ) {
189      multiplex = {};
190    }
191    if (multiplex?.id) {
192      dependencies.push({ src: "/socket.io/socket.io.js", async: true });
193      // dependencies.push({ src: 'https://reveal-multiplex.glitch.me/socket.io/socket.io.js', async: true })
194    }
195    if (multiplex?.secret) {
196      dependencies.push({ src: "/vendor/multiplex/master.js", async: true });
197      // dependencies.push({ src: 'https://reveal-multiplex.glitch.me/master.js', async: true })
198    } else {
199      dependencies.push({ src: "/vendor/multiplex/client.js", async: true });
200      // dependencies.push({ src: 'https://reveal-multiplex.glitch.me/client.js', async: true })
201    }
202  }
203  // initialize presentation
204  Reveal.slidesdownLoader = () => {
205    window.location.href = "/loader.html";
206  };
207  Reveal.initialize({
208    multiplex,
209    dependencies,
210    hash: true,
211    // mathjax2: {
212    //   mathjax: "/vendor/mathjax/MathJax.js"
213    // },
214    mathjax3: {
215      mathjax: "/vendor/mathjax/tex-mml-chtml.js",
216    },
217    plugins: [
218      SlidesDown,
219      RevealHighlight,
220      RevealMath.MathJax3(),
221      RevealNotes,
222      RevealSearch,
223      RevealZoom,
224      // Source: https://github.com/McShelby/reveal-pdfexport
225      PdfExport,
226      // Source: https://github.com/rajgoel/reveal.js-plugins/tree/master/chalkboard
227      RevealChalkboard,
228      // Source: https://github.com/rajgoel/reveal.js-plugins/tree/master/cu
228stomcontrols
229      RevealCustomControls,
230      // Source: https://github.com/rajgoel/reveal.js-plugins/tree/master/anything
231      // RevealAnything,
232      // RevealChartjs,
233      // RevealApexchart,
234      RevealECharts,
235      RevealMermaid,
236    ],
237    customcontrols: {
238      collapseIcon: '<div class="i-fa6-solid-chevron-down"></div>',
239      expandIcon: '<div class="i-fa6-solid-chevron-up"></div>',
240      controls: [
241        {
242          icon: '<div class="i-fa6-solid-folder-open"></div>',
243          title: "Open another presentation",
244          action: "Reveal.slidesdownLoader();",
245        },
246        {
247          icon: '<div class="i-fa6-solid-table-cells"></div>',
248          id: "toggle-overview",
249          title: "Toggle overview (O)",
250          action: "Reveal.toggleOverview();",
251        },
252        {
253          icon: '<div class="i-fa6-solid-square-pen"></div>',
254          title: "Toggle chalkboard (B)",
255          action: "RevealChalkboard.toggleChalkboard();",
256        },
257        {
258          icon: '<div class="i-fa6-solid-pen"></div>',
259          title: "Toggle notes canvas (C)",
260          action: "RevealChalkboard.toggleNotesCanvas();",
261        },
262        {
263          icon: '<div class="i-fa6-solid-print"></div>',
264          title: "Toggle print view (E)",
265          action: "PdfExport.togglePdfExport();",
266        },
267      ],
268    },
269  }).then(() => {
270    Reveal.sync(); // workaround to make the first slide center properly after adding slides
271    console.debug("initialization finished");
272  });
273}
274
275main({
276  branch: "main",
277  resource: "SLIDES.md",
278  markdownElementId: "markdown",
279});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.