`) — Array of values that occur for the given option in the current selection. Might be empty or contain only a single value.
264 |
265 | Example request:
266 |
267 | ```json
268 | {
269 | "api": "notebook",
270 | "version": 1,
271 | "rid": "1",
272 | "command": "getSelectionOption",
273 | "option": "FontFamily"
274 | }
275 | ```
276 |
277 | Example response:
278 |
279 | ```json
280 | {
281 | "rid": "1",
282 | "success": true,
283 | "values": [
284 | "\"Source Code Pro\"",
285 | "\"Source Sans Pro\""
286 | ]
287 | }
288 | ```
289 |
290 | ### Selection
291 |
292 | #### getSelection
293 |
294 | Gets information about the current selection.
295 |
296 | + Response
297 |
298 | + `elements` (`Array.<{type: "cell"|"group", id: string}>`) — List of elements (cells or cell groups) selected via their cell brackets. Empty array if no cell brackets are selected.
299 | + `separator` (`?{cellBefore: ?{cellId: string}, cellAfter: ?{cellId: string}}`) — If the selection is between cells, this gives the cell before and the cell after the separator. Either of them or `separator` itself can be `null`.
300 | + `inCell` (`?{cellId: string}`) — The cell the selection is inside (i.e. on the box level), if any. This is particularly the case when editing a cell. If the selection is on the cell (bracket) level, `inCell` is `null`.
301 | + `cursorPosition` (`?{left: number, top: number}`) — Cursor position, if a cell is edited. The position is relative to the document offset. This takes into account the scroll position.
302 |
303 | Example request:
304 |
305 | ```json
306 | {
307 | "api": "notebook",
308 | "version": 1,
309 | "rid": "1",
310 | "command": "getSelection"
311 | }
312 | ```
313 |
314 | Example response:
315 |
316 | ```json
317 | {
318 | "rid": "1",
319 | "success": true,
320 | "cells": [],
321 | "inCell": {"cellId": "1"},
322 | "cursorPosition": {"left": 80, "top": 300}
323 | }
324 | ```
325 |
326 | #### selectElements
327 |
328 | Selects elements (cell brackets).
329 |
330 | + Parameters
331 |
332 | + `elements` (`Array.<{id: string}>`) — List of IDs of elements to select. Elements that cannot be found are ignored.
333 |
334 | + Response
335 |
336 | + `elements` (`Array.<{type: "cell"|"group", id: string}>`) — List of elements that have been found and are selected now.
337 |
338 |
339 | #### selectSeparatorBeforeElement
340 |
341 | Moves the selection to the separator before a cell or cell group.
342 |
343 | + Parameters
344 |
345 | + `id` (`?string`) — ID of the element before which the separator should be. If `null`, the selection is moved to the end of the notebook.
346 |
347 | + Errors
348 |
349 | + `"ElementNotFound"`
350 |
351 | #### selectSeparatorAfterElement
352 |
353 | Moves the selection to the separator after a cell or cell group.
354 |
355 | + Parameters
356 |
357 | + `id` (`?string`) — ID of the element after which the separator should be. If `null`, the selection is moved to the beginning of the notebook.
358 |
359 | + Errors
360 |
361 | + `"ElementNotFound"`
362 |
363 | ### Dimensions
364 |
365 | #### getDimensions
366 |
367 | Returns the dimensions of the notebook content.
368 |
369 | + Response
370 |
371 | + `width` (`number`) — The width of the notebook content (in pixels). Note that a notebook will always fill any available (maximum) width. If there is a horizontal scrollbar, the reported width may be larger than the maximum width available to the notebook. Providing the reported width as horizontal space to the notebook usually ensures that there is no horizontal scrollbar necessary.
372 | + `height` (`number`) — The height of the notebook content (in pixels). This does not include any unused vertical space that would be available to the notebook. It does include the height of the horizontal scrollbar, in case there is one. Providing the reported height as vertical space to the notebook usually ensures that there is no vertical scrollbar necessary.
373 |
374 | ### Scrolling
375 |
376 | #### getScrollPosition
377 |
378 | Returns the current scroll position in the notebook.
379 |
380 | + Response
381 |
382 | + `left` (`number`) — Number of pixels scrolled in horizontal direction (increases when scrolling to the right).
383 | + `top` (`number`) — Number of pixels scrolled in vertical direction (increases when scrolling down).
384 |
385 | #### setScrollPosition
386 |
387 | Scrolls to the specified position in the notebook.
388 |
389 | + Parameters
390 |
391 | + `left` (`number`) — Number of pixels to scroll to in horizontal direction (increases when scrolling to the right).
392 | + `top` (`number`) — Number of pixels to scroll to in vertical direction (increases when scrolling down).
393 |
394 | #### scrollToElement
395 |
396 | Scrolls the specified element into view. [Cloud 1.56]
397 |
398 | + Parameters
399 |
400 | + `id` — ID of the element to scroll into view.
401 |
402 | + Errors
403 |
404 | + `"ElementNotFound"` — The specified element does not exist.
405 |
406 | #### scrollToSelection
407 |
408 | Scrolls the currently selected element(s) into view. [Cloud 1.56]
409 |
410 | ### Evaluation
411 |
412 | #### evaluateExpression
413 |
414 | Evaluates a Wolfram Language expression.
415 |
416 | The API responds with the resulting expression when the evaluation is finished.
417 |
418 | + Parameters
419 |
420 | + `expression` (`string` or `exprjson`) — Wolfram Language expression to evaluate.
421 | + `originatingCellId` = `null` (optional, `?string`) — ID of the cell the evaluation is supposed to be originating from (for the purpose of `EvaluationCell[]`).
422 |
423 | + Response
424 |
425 | + `result` (`exprjson`) — The result of the evaluation in JSON expression representation (see below).
426 |
427 | + Errors
428 |
429 | + `"EvaluationError"` — There was some error during the evaluation, e.g. the kernel was not reachable.
430 | + `"InsufficientPermissions"`
431 |
432 | Example request:
433 |
434 | {
435 | "api": "notebook",
436 | "version": 1,
437 | "rid": "1",
438 | "command": "evaluateExpression"
439 | "expression": "f[x, 1 + 2]"
440 | }
441 |
442 | Example response:
443 |
444 | {
445 | "rid": "1",
446 | "success": true,
447 | "result": {"head": "f", "args": ["x", 3]}
448 | }
449 |
450 | #### evaluateInDynamicModule
451 |
452 | Evaluates a Wolfram Language expression inside a [DynamicModule](https://reference.wolfram.com/language/ref/DynamicModule.html), localizing variables as necessary. [Cloud 1.56]
453 |
454 | + Parameters
455 |
456 | + `cellId` (`string`) — ID of the cell that contains the `DynamicModuleBox`.
457 | + `boxId` (`?string`) — `BoxID` value of the `DynamicModuleBox` to search for. If not specified, the first `DynamicModuleBox` in a breadth-first search is chosen.
458 | + `expression` (`string` or `exprjson`) — Wolfram Language expression to evaluate.
459 |
460 | + Response
461 |
462 | + `result` (`exprjson`) — The result of the evaluation in JSON expression representation (see below).
463 |
464 | + Errors
465 |
466 | + `"EvaluationError"` — There was some error during the evaluation, e.g. the kernel was not reachable.
467 | + `"InsufficientPermissions"`
468 |
469 | #### clickButton
470 |
471 | Simulates clicking of a button, i.e. evaluates its `ButtonFunction`. [Cloud 1.56]
472 |
473 | + Parameters
474 |
475 | + `cellId` (`string`) — ID of the cell that contains the `ButtonBox`.
476 | + `boxId` (`?string`) — `BoxID` value of the `ButtonBox` to search for. If not specified, the first `ButtonBox ` in a breadth-first search is chosen.
477 |
478 | + Errors
479 |
480 | + `"NoBox"` — The specified `ButtonBox` was not found.
481 |
482 | ### DynamicModule variables
483 |
484 | #### getDynamicModuleVariable
485 |
486 | Retrieves the value of a [DynamicModule](https://reference.wolfram.com/language/ref/DynamicModule.html) variable.
487 |
488 | + Parameters
489 |
490 | + `cellId` (`string`) — ID of the cell that contains the `DynamicModuleBox`.
491 | + `boxId` (`?string`) — `BoxID` value of the `DynamicModuleBox` to search for. If not specified, the first `DynamicModuleBox` in a breadth-first search is chosen. [Cloud 1.56]
492 | + `name` (`string`) — Name of the `DynamicModule` variable to retrieve.
493 | + `useExactName` = `false` (`?boolean`) — Whether to require an exact name match. If set to `false` (the default), the provided name does not have to contain prefixes (such as ```$CellContext` ```) and suffixes (such as `$$`) that are typically added behind the scenes by `DynamicModule`.
494 |
495 | + Response
496 |
497 | + `value` (`exprjson`) — The value of the variable in JSON expression representation (see [below](#expressionjson)).
498 |
499 | + Errors
500 |
501 | + `"CellNotFound"` — The specified cell does not exist.
502 | + `"NoDynamicModule"` — There is no `DynamicModuleBox` in the specified cell (with the given `BoxID`, if `boxId` is specified).
503 | + `"UnknownVariableName"` — The `DynamicModuleBox` does not contain the specified variable.
504 |
505 | #### setDynamicModuleVariable
506 |
507 | Sets the value of a [DynamicModule](https://reference.wolfram.com/language/ref/DynamicModule.html) variable.
508 |
509 | + Parameters
510 |
511 | + `cellId` (`string`) — ID of the cell that contains the `DynamicModuleBox`.
512 | + `boxId` (`?string`) — `BoxID` value of the `DynamicModuleBox` to search for. If not specified, the first `DynamicModuleBox` in a breadth-first search is chosen. [Cloud 1.56]
513 | + `name` (`string`) — Name of the DynamicModule variable to change.
514 | + `useExactName` = `false` (`?boolean`) — Whether to require an exact name match. If set to `false` (the default), the provided name does not have to contain prefixes (such as ```$CellContext` ```) and suffixes (such as `$$`) that are typically added behind the scenes by `DynamicModule`.
515 | + `value` (`exprjson`) — The new value of the variable in JSON expression representation (see [below](#expressionjson)).
516 |
517 | + Errors
518 |
519 | + `"CellNotFound"` — The specified cell does not exist.
520 | + `"NoDynamicModule"` — There is no `DynamicModuleBox` in the specified cell (with the given `BoxID`, if `boxId` is specified).
521 | + `"UnknownVariableName"` — The `DynamicModuleBox` does not contain the specified variable.
522 |
523 | Example request (setting a variable `x` to `N[Pi, 30]`):
524 |
525 | {
526 | "api": "notebook",
527 | "version": 1,
528 | "rid": "1",
529 | "command": "setDynamicModuleVariable"
530 | "cellId": "42",
531 | "name": "x",
532 | "value": ["N", "Pi", 30]
533 | }
534 |
535 | ### Cell rendering
536 |
537 | #### getCellRenderingMethod
538 |
539 | Returns the rendering method (mode) used by a given cell.
540 |
541 | There are currently four different rendering methods, as shown here.
542 |
543 | | Method | Meaning |
544 | |----------|---------|
545 | | `boxes` | live-rendered |
546 | | `static` | rendered as static HTML, from the HTML cache |
547 | | `image` | rendered as a rasterized image |
548 | | `none` | rendered as a general placeholer |
549 |
550 | + Parameters
551 |
552 | + `cellId` (`string`) — The ID of the cell.
553 |
554 | + Response
555 |
556 | + `method` (`string`) — The method used to render the given cell.
557 |
558 | + Errors
559 |
560 | + `"CellNotFound"` — The cell ID given by `cellId` was not found.
561 |
562 | ## Events
563 |
564 | ### Initial render progress
565 |
566 | See [Notebook Loading Phases](./NotebookLoadingPhases.md) for more information.
567 |
568 | #### first-paint-done (singular)
569 |
570 | Fired when either static HTML is shown for the notebook (see [Server-Side Rendering](./ServerSideRendering.md)) or the notebook starts rendering individual cells.
571 |
572 | + Fields
573 |
574 | + `showingStaticHTML` (`boolean`) — Whether the notebook is showing a piece of static HTML.
575 |
576 | #### initial-render-progress
577 |
578 | Fired when progress is made during the initial render phase.
579 |
580 | + Fields
581 |
582 | + `cellsRendered` (`number`) — Number of cells that have already been "live-rendered".
583 | + `cellsTotal` (`number`) — Total number of cells that are visible in the notebook.
584 |
585 | #### initial-render-done (singular)
586 |
587 | Fired when the initial render phase is done, i.e. all visible cells have been live-rendered.
588 |
589 | ### Selection
590 |
591 | #### selection-change
592 |
593 | Fired when the notebook selection changes.
594 |
595 | + Fields
596 |
597 | + `elements` (`Array.<{type: "cell"|"group", id: string}>`) — List of elements (cells or cell groups) selected via their cell brackets.
598 | + `separator` (`?{cellBefore: ?{cellId: string}, cellAfter: ?{cellId: string}}`) — If the selection is between cells, this gives the cell before and the cell after the separator.
599 | + `inCell` (`?{cellId: string}`) — The cell the selection is inside (i.e. on the box level), if any. This is particularly the case when editing a cell.
600 |
601 | ### Evaluation
602 |
603 | #### evaluation-start
604 |
605 | Fired when an evaluation starts.
606 |
607 | Currently, only one kernel evaluation can happen at any time. However, this might change in the future. Then this API might change as well.
608 |
609 | + Fields
610 |
611 | + `isCellEvaluation` (`boolean`) — `true` if the evaluation is a whole-cell evaluation (e.g. from pressing Shift+Enter). `false` if the evaluation is triggered by a `Dynamic` or some other dynamic control (e.g. a `Button`).
612 |
613 | #### evaluation-stop
614 |
615 | Fired when an evaluation ends.
616 |
617 | ### Dimensions
618 |
619 | #### resize
620 |
621 | Fired when the notebook dimensions change. See [`getDimensions`](#getdimensions) for details.
622 |
623 | + Fields
624 |
625 | + `width` (`number`) — Width of the notebook content (in pixels).
626 | + `height` (`number`) — Height of the notebook content (in pixels).
627 |
628 | ### Scrolling
629 |
630 | #### scroll-position-change
631 |
632 | Fired when the scroll position changes.
633 |
634 | + Fields (same as `getScrollPosition`)
635 |
636 | + `left` (`number`) — Number of pixels scrolled in horizontal direction (increases when scrolling to the right).
637 | + `top` (`number`) — Number of pixels scrolled in vertical direction (increases when scrolling down).
638 |
639 |
640 | ## ExpressionJSON
641 |
642 | Some API methods accept or return WL expressions in the [ExpressionJSON](https://reference.wolfram.com/language/ref/format/ExpressionJSON.html) format:
643 |
644 | | WL | WL example | JSON | JSON example|
645 | |----|------------|------|-------------|
646 | | Symbol | `foo` | string | `"foo"` |
647 | | String | `"text"` | string with enclosing single or double quotes | `"'text'"` or `"\"text\""` |
648 | | Machine-size Integer (up to 53 bits) | `342` | number | `342` |
649 | | Double-precision Real (up to 64 bits) | `2.5`, `1.073741824*^9` | number | `2.5`, `1.073741824e9` |
650 | | Arbitrary-length Integer | `18014398509481984` | string | `"18014398509481984"` |
651 | | Arbitrary-precision Real | ```3.5074`15.65*^451``` | string | ```"3.5074`15.65*^451"``` |
652 | | Booleans | `True`, `False` | boolean | `true`, `false` |
653 | | Null | `Null` | null | `null` |
654 | | Expression | `f[x, y]` | array with head at index 0, followed by parts | `["f", "x", "y"]` |
655 |
656 | Note that there are several ways to represent the same expression, e.g. `True` can be represented as `true` or `"True"` in ExpressionJSON and a number such as `123` can be represented as the JSON number `123` or as the JSON string `"123"`. When the Notebook API returns expression data, it usually serializes it in the shortest form. However, that is not guaranteed, and readers of the format should make sure to accept all possible forms.
657 |
658 | As a courtesy, API methods also accept single strings containing the WL expression in [InputForm](https://reference.wolfram.com/language/ref/InputForm.html) (e.g. the string `"1+2"`) or [FullForm](https://reference.wolfram.com/language/ref/FullForm.html) (e.g. `"Plus[1,2]"`; `FullForm` is a subset of `InputForm`). A WL parser implemented in JavaScript is used to parse the given expression. However, there is some performance overhead to that and it has some limitations (e.g. not all operators might be supported), so it is generally recommended to use proper ExpressionJSON instead.
659 |
660 | Note that there is no ambiguity between ExpressionJSON and expressions given in InputForm, since all strings in ExpressionJSON contain the InputForm of the corresponding WL expression.
661 |
--------------------------------------------------------------------------------
/docs/NotebookLoadingPhases.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: NotebookLoadingPhases
3 | title: Notebook Loading Phases
4 | ---
5 |
6 | ## Rendering phases
7 |
8 | Notebooks depend on various things that are loaded asynchronously, e.g. the actual notebook content, CSS, JavaScript, fonts and (potentially) results from kernel evaluations. While things are loading, static pieces of HTML are rendered if available (see [server-side rendering](./ServerSideRendering.md)). Rendering generally goes through the following phases:
9 |
10 | 1. Nothing is displayed initially.
11 | 2. Once critical CSS and fonts are loaded: Static HTML is displayed, if available; the event `first-paint-done` with `{showingStaticHTML: true}` is fired.
12 | 3. Once the main JavaScript code and notebook content data is loaded: Static HTML is reused as a whole (albeit in a slightly different container structure); the event `initial-render-progress` with `{cellsRendered: 0, cellsTotal: -1}` is fired.
13 | 4. Once other dependencies, such as the notebook stylesheet, are loaded and notebook-level options are resolved (possibly relying on kernel evaluations): Static HTML for individual cells is rendered; the event `initial-render-progress` with `{cellsRendered: 0, cellsTotal: N}` is fired with the actual number `N` of initially visible cells. If no static HTML was available initially, the event `first-paint-done` is fired at this point. The notebook also starts fetching static HTML for cells that were not present in the initial static HTML.
14 | 5. Each cell might require additional dependencies (e.g. fonts), resolution of `Dynamic` option values, resolution of `Dynamic` content, etc. Once a cell becomes ready, it is "live-rendered", while other non-ready cells are still rendered using static HTML; the event `initial-render-progress` with `{cellsRendered: M, cellsTotal: N}` is fired accordingly.
15 | 6. Once all cells have been live-rendered: The event `initial-render-done` is fired.
16 |
17 | If no static HTML is available for the notebook as a whole or for individual cells, a loading background is displayed in their place until they are live-rendered.
18 |
19 | ## Progress indicator
20 |
21 | By default, notebooks show a (blue) progress indicator at the top during the initial render phase. It can be turned off by setting the option `showRenderProgress: false`. The progress indicator distinguishes between two groups of phases:
22 |
23 | 1. (Phases 1–3 above.) An indeterminate progress indicator is shown.
24 | 2. (Phases 4–6 above.) A determinate progress indicator is shown, based on the number of rendered vs. total cells, as long as there are at least three cells in the notebook. If there are fewer than three cells, another indeterminate progress indicator is shown (since a determinate progress indicator would jump too much and not give a real impression of progress).
25 |
26 | Once the initial render phase is over, the progress indicator is hidden.
27 |
--------------------------------------------------------------------------------
/docs/ServerSideRendering.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: ServerSideRendering
3 | title: Server-Side Rendering
4 | ---
5 |
6 | In some cases, you might want to include (static) HTML for a notebook on the HTML page rendered by your server so it can be shown even before the necessary JavaScript code is loaded and executed. This reduces the time until the user sees the notebook, and it also helps search engines to index your notebook content. Once your JavaScript code executes, you can use the function [WolframNotebookEmbedder.embed](./LibraryInterface.md) as usual to embed the notebook into the same container node, and it will transition seamlessly from the static view to "live" (interactive) rendering. The same happens on [wolframcloud.com](https://www.wolframcloud.com) as well.
7 |
8 | Static HTML is generated ("pre-rendered") for each cloud notebook whenever it is created or changed. You can access it through an HTTP API, by making a `GET` request to
9 |
10 | https://www.wolframcloud.com/statichtml/{path}
11 |
12 | where `{path}` is the notebook's cloud object path, which might be a UUID (e.g. `4beadfbb-84dd-4b26-87b6-bcd30b9abd65` for a cloud object at `https://www.wolframcloud.com/obj/4beadfbb-84dd-4b26-87b6-bcd30b9abd65`) or a user base URL + folder/file name (e.g. `myname/foo/bar.nb` for a cloud object at `https://www.wolframcloud.com/obj/myname/foo/bar.nb`).
13 |
14 | This API returns a piece of static HTML that can be included right on your page by your server-side code. You might want to cache the response from the `/statichtml` API on your server, so you don't have to request it whenever a user visits your website.
15 |
16 | ## How to integrate this API into your website or application
17 |
18 | A typical sequence of events would be:
19 |
20 | 1. A user makes a request to your server to open your website, which includes an embedded notebook.
21 | 2. Your server makes a request to `https://www.wolframcloud.com/statichtml/{path}` to fetch the static HTML for the embedded notebook, or it uses an existing cache for that static HTML.
22 | 3. Your server returns an HTML page to the user, which includes the static HTML of the notebook inside the HTML element where the notebook is supposed to be embedded.
23 | 4. In your JavaScript code, you call `WolframNotebookEmbedder.embed` to embed the notebook into the same HTML element, which causes the notebook to "live-render" on the client side. See [Notebook Loading Phases](./NotebookLoadingPhases.md) for more information about what happens then.
24 |
25 | To summarize:
26 |
27 | Wolfram Cloud
28 | ^ |
29 | | | static HTML for notebook
30 | /statichtml API | |
31 | | v
32 | Your server
33 | ^ |
34 | | | your website including static notebook HTML
35 | request | | and JS code using WolframNotebookEmbedder
36 | | v
37 | User of your website
38 |
39 |
40 | If you do not have active code running on your server but just a static HTML page, you could also use this API to generate HTML for the notebook once and then include that right in your static HTML. The downsides of this approach are that the HTML will not automatically update if the notebook is changed, and it will not be kept in sync with newer Wolfram Cloud versions (potentially resulting in rendering inconsistencies).
41 |
42 | ## Parameters
43 |
44 | ### Waiting for HTML to be available using `maxwaitmillis`
45 |
46 | Sometimes, there might be no HTML for a notebook available yet, e.g. when it has just been edited and the cloud server has not had a chance to pre-render it yet. In that case, the API will return an empty response. However, you can tell the API to wait up to a certain time and return static HTML once it becomes available. That's what the query parameter `maxwaitmillis` is for, e.g.
47 |
48 | https://www.wolframcloud.com/statichtml/4beadfbb-84dd-4b26-87b6-bcd30b9abd65?maxwaitmillis=500
49 |
50 | would wait up to 500 milliseconds in case there is no HTML available yet and return once it becomes available. If the cloud server has not finished generating HTML after half a second, the API will return an empty response.
51 |
52 | The maximum accepted value for `maxwaitmillis` is 20,000 (20 seconds). Typically, using rather low values (not longer than 1 second) is recommended, since this would delay the initial response from your server (while it is waiting for the cloud server to return HTML) and thus the loading of the whole page.
53 |
54 | ### Specifying a notebook width using `width`
55 |
56 | Parts of the static HTML might depend on the page width, e.g. to determine where to line-wrap code cells. Since the page width is not usually known on the server, it can only assume a certain notebook width and return HTML for that, which will cause text to reflow on the client side (once the actual page width is known and "live" rendering kicks in). If you do know the notebook width in advance (e.g. because you are embedding the notebook at a fixed width), you can request HTML for that particular width using the `width` parameter to the API, e.g.
57 |
58 | https://www.wolframcloud.com/statichtml/4beadfbb-84dd-4b26-87b6-bcd30b9abd65?width=700
59 |
60 | would request HTML for a notebook width of 700 pixels. There is no guarantee that you get HTML for *exactly* that width, but the API will choose the best match out of the available pre-rendered HTML.
61 |
62 | ### Only including limited cell content using `limitcontent`
63 |
64 | By default, the content of all visible cells in the notebook is included in the returned static HTML. This is usually fine if the notebook is not too long and is shown in its entirety on the embedding website anyway.
65 |
66 | However, it can be a significant overhead for long notebooks, both in terms of assembling the static HTML on the cloud server (resulting in a longer response time for the `/statichtml` API) and in terms of longer download times for the client (resulting in a longer time to first paint for the viewer). To address this, you can set the parameter `limitcontent=true` to limit the content that is included in the static HTML.
67 |
68 | If this parameter is set to `true`, only cells "above the fold" (i.e. vertically within a few thousand pixels from the notebook start) are included, plus some other simple, textual cells that do not increase the overall size of the static HTML by much. Other cells are only included as empty placeholders. At the bottom of the notebook (below any non-placeholder cell), a special background is used to indicate that the content there is no available (yet).
69 |
70 | Once client-side rendering of the notebook starts, the static HTML for all placeholder cells will be fetched asynchronously, which is used until the client-side rendering of each cell completes.
71 |
72 | This limited initial static HTML is what effectively happens for notebooks on [wolframcloud.com](https://www.wolframcloud.com).
73 |
74 | This parameter is introduced in Cloud 1.56.
75 |
--------------------------------------------------------------------------------
/docs/Troubleshooting.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: Troubleshooting
3 | title: Troubleshooting
4 | ---
5 |
6 | ## Loading
7 |
8 | **The embedded notebook does not load.**
9 |
10 | Please double-check that the embedded cloud notebook is *public*, e.g. by opening its URL in an incognito window of your browser (where you are not logged in to the Wolfram Cloud). In the Wolfram Language, you can determine permissions of a cloud object using
11 |
12 | ```wl
13 | CloudObjectInformation[CloudObject["..."], "Permissions"]
14 | ```
15 |
16 | and you can make a cloud object public by evaluating the following:
17 |
18 | ```wl
19 | SetPermissions[CloudObject["..."], All -> {"Read", "Interact"}]
20 | ```
21 |
22 | ## Styling
23 |
24 | **As soon as I embed a notebook, some styling on my page (outside the notebook) changes.**
25 |
26 | This might be a bug in our (notebook) CSS. We try to isolate CSS selectors as much as possible, but there might still be cases where styling "leaks out" of the notebook. Please file an issue with reproducible steps.
27 |
28 | **The styling of the notebook seems wrong.**
29 |
30 | This could be because your CSS definitions "leak into" the notebook. Since the notebook is just another DOM node on your page, it inherits any global CSS. Try to make your CSS selectors more specific so they do not affect the notebook container node. If isolating styles is a problem, you can always fall back to embedding your cloud notebook using an iframe, e.g.:
31 |
32 | ```html
33 |
34 | ```
35 |
36 | If you think there is an issue on the notebook side, please file an issue.
37 |
--------------------------------------------------------------------------------
/examples/basic.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Basic example
4 |
5 |
6 |
7 | Basic example
8 |
9 |
10 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/examples/borders.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Show borders example
4 |
9 |
10 |
11 |
12 | Show borders example
13 |
14 | Enter the URL of a cloud object:
15 |
16 | Embed Notebook
17 |
18 |
19 | Without borders (the default)
20 |
21 |
22 | With borders
23 |
24 |
25 |
26 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/examples/dimensions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dimensions examples
4 |
17 |
18 |
19 |
20 | Dimensions examples
21 |
22 | Enter the URL of a cloud object:
23 |
24 | Embed Notebook
25 |
26 |
27 | Infinite height granted to the notebook, width adapting to container node (the default)
28 | Current dimensions:
29 |
30 |
31 | Fixed maximum dimensions granted to the notebook
32 |
33 | Width:
34 | Maximum height:
35 |
36 | Current dimensions:
37 |
38 |
39 | Fixed dimensions set in CSS, notebook adapting accordingly
40 | Current dimensions:
41 |
42 |
43 | Relative dimensions set in CSS, notebook adapting accordingly
44 | Current dimensions:
45 |
46 |
47 |
48 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/examples/expr.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Notebook expression example
5 |
11 |
12 |
13 |
14 | Notebook expression example
15 |
16 | Enter a Notebook expression:
17 |
18 | Cloud Base:
19 |
20 | Embed Notebook
21 |
22 |
23 |
24 |
25 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/examples/manipulate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Manipulate example
4 |
9 |
10 |
11 |
12 | Manipulate example
13 |
14 | Enter the URL of a cloud object:
15 |
16 | Embed Notebook
17 |
18 |
19 | If the notebook's last cell contains a Manipulate
with a variable x
, this will reset it to 0:
20 | Reset x
21 |
22 |
23 |
24 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/examples/ssr.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Server-side rendering example
5 |
10 |
11 |
12 |
13 | Server-side rendering example
14 |
15 |
16 | Enter the URL of a cloud object:
17 |
18 |
19 |
20 | Load static HTML
21 | (this would usually happen in your server-side code)
22 |
23 |
24 | Embed live notebook
25 | (this always happens in the JavaScript code running on the client)
26 |
27 |
28 |
29 | Render state:
30 |
31 |
32 |
33 |
34 |
35 |
36 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/examples/url.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Notebook URL example
5 |
6 |
7 |
8 | Notebook expression example
9 |
10 | Enter a URL referencing a notebook file:
11 |
12 | Cloud Base:
13 |
14 | Embed Notebook
15 |
16 |
17 |
18 |
19 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wolfram-notebook-embedder",
3 | "version": "0.3.0",
4 | "description": "Library to embed Wolfram Cloud notebooks on websites.",
5 | "main": "dist/wolfram-notebook-embedder.js",
6 | "keywords": [
7 | "wolfram",
8 | "cloud",
9 | "notebook",
10 | "embedding"
11 | ],
12 | "license": "MIT",
13 | "files": [
14 | "dist/",
15 | "LICENSE",
16 | "README.md"
17 | ],
18 | "repository": {
19 | "type": "git",
20 | "url": "https://github.com/WolframResearch/wolfram-notebook-embedder.git"
21 | },
22 | "scripts": {
23 | "prepublishOnly": "npm-run-all build",
24 | "build": "npm-run-all transpile minify",
25 | "transpile": "rollup -c config/rollup.config.js",
26 | "copy-dist-to-examples": "cp -r ./dist ./examples",
27 | "serve-examples": "serve examples",
28 | "minify": "uglifyjs dist/wolfram-notebook-embedder.js --compress --mangle --output dist/wolfram-notebook-embedder.min.js",
29 | "run-examples": "npm-run-all build copy-dist-to-examples serve-examples"
30 | },
31 | "devDependencies": {
32 | "@babel/core": "^7.15.5",
33 | "@babel/preset-env": "^7.15.6",
34 | "@rollup/plugin-babel": "^5.3.0",
35 | "@rollup/plugin-node-resolve": "^13.0.5",
36 | "npm-run-all": "^4.1.5",
37 | "rollup": "^2.58.0",
38 | "serve": "^12.0.1",
39 | "uglify-js": "^3.14.2"
40 | },
41 | "dependencies": {}
42 | }
43 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | const installedScripts = {};
2 | const libraryLoading = {};
3 | let counter = 0;
4 | let isStyleInsertionPatched = false;
5 | const insertedStyles = [];
6 | const styleInsertionCallbacks = [];
7 |
8 | function installScript(url) {
9 | if (!installedScripts[url]) {
10 | const script = document.createElement('script');
11 | script.type = 'text/javascript';
12 | script.src = url;
13 | const head = document.getElementsByTagName('head')[0];
14 | head.appendChild(script);
15 | installedScripts[url] = true;
16 | }
17 | }
18 |
19 | function loadLibrary(libraryURL) {
20 | if (!libraryLoading[libraryURL]) {
21 | libraryLoading[libraryURL] = new Promise((resolve, reject) => {
22 | const script = document.createElement('script');
23 | script.type = 'text/javascript';
24 | script.onerror = reject;
25 | let callbackName;
26 | do {
27 | callbackName = '_wolframNotebookEmbedderCallback' + (++counter);
28 | } while (window[callbackName]);
29 | window[callbackName] = (lib) => {
30 | delete window[callbackName];
31 | resolve(lib);
32 | };
33 | script.src = libraryURL + '?callback=' + callbackName;
34 | const head = document.getElementsByTagName('head')[0];
35 | head.appendChild(script);
36 | });
37 | }
38 | return libraryLoading[libraryURL];
39 | }
40 |
41 | /**
42 | * Splits a string into two parts at the first occurrence of any of the given separators.
43 | * @param s String to split.
44 | * @param separators Array of separators. Whichever separator occurs first in the string
45 | * is where the split happens.
46 | * @returns The part before the separator and the part after it.
47 | * If no separator occurs in the string, `[null, null]` is returned.
48 | */
49 | function split(s, separators) {
50 | let before = null;
51 | let after = null;
52 | for (let i = 0; i < separators.length; ++i) {
53 | const sep = separators[i];
54 | const index = s.indexOf(sep);
55 | if (index >= 0 && (before === null || index < before.length)) {
56 | before = s.substring(0, index);
57 | after = s.substring(index + sep.length);
58 | }
59 | }
60 | return [before, after];
61 | }
62 |
63 | function isNotebookStyleElement(element, domains) {
64 | const name = element.tagName.toLowerCase();
65 | if (name === 'link' && (element.rel === 'stylesheet' || element.type === 'text/css')) {
66 | return domains.some(domain => element.href.startsWith(domain));
67 | } else if (name === 'style') {
68 | if (element.dataset.isWolframNotebookStyle || element.innerText.indexOf('._ccc') >= 0) {
69 | return true;
70 | }
71 | if (element.id === 'erd_scroll_detection_scrollbar_style') {
72 | return true;
73 | }
74 | }
75 | return false;
76 | }
77 |
78 | function patchShadowStyleInsertion(container, domains) {
79 | function callback(element, allowMove) {
80 | // When inserting the style element for the first time, use the original element,
81 | // to make sure that onload and onerror handlers are preserved.
82 | // For subsequent insertions (second embedded notebook and beyond), clone the element.
83 | const styleElement = allowMove && !element.didInsertWithoutCloning ? element : element.cloneNode(true);
84 | element.didInsertWithoutCloning = true;
85 | container.appendChild(styleElement);
86 | }
87 |
88 | function handleStyleElement(element, allowMove) {
89 | if (isNotebookStyleElement(element, domains)) {
90 | insertedStyles.push(element);
91 | styleInsertionCallbacks.forEach(cb => {
92 | cb(element, allowMove);
93 | });
94 | return true;
95 | }
96 | return false;
97 | }
98 |
99 | if (!isStyleInsertionPatched) {
100 | // There might be notebook-related or
--------------------------------------------------------------------------------
/website/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/wolfram-notebook-embedder/a335c6c871fe1cbcd8d446df5ea22a5d86bac375/website/static/img/favicon.ico
--------------------------------------------------------------------------------
/website/static/img/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/wolfram-notebook-embedder/a335c6c871fe1cbcd8d446df5ea22a5d86bac375/website/static/img/hero.png
--------------------------------------------------------------------------------
/website/static/img/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/website/static/img/scriptable-control.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/website/static/img/seamless-embedding.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------