├── .devcontainer └── devcontainer.json ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── community-example.yml │ ├── config.yml │ ├── feature-request.yml │ └── question.yml └── workflows │ └── publish-demo.yml ├── .gitignore ├── README.md ├── _extensions └── webr │ ├── _extension.yml │ ├── qwebr-cell-elements.js │ ├── qwebr-cell-initialization.js │ ├── qwebr-compute-engine.js │ ├── qwebr-document-engine-initialization.js │ ├── qwebr-document-history.js │ ├── qwebr-document-settings.js │ ├── qwebr-document-status.js │ ├── qwebr-monaco-editor-element.js │ ├── qwebr-monaco-editor-init.html │ ├── qwebr-styling.css │ ├── qwebr-theme-switch.js │ ├── template.qmd │ └── webr.lua ├── _publish.yml ├── docs ├── .gitignore ├── CNAME ├── _extensions ├── _quarto.yml ├── demos │ ├── qwebr-auto-run.qmd │ ├── qwebr-code-cell-options.qmd │ ├── qwebr-custom-repository.qmd │ ├── qwebr-editor-options.qmd │ ├── qwebr-feature-demos.qmd │ ├── qwebr-global-cell-defaults.qmd │ ├── qwebr-long-running-execution-interactive-locking.qmd │ ├── qwebr-non-interactive-areas.qmd │ ├── qwebr-read-only.qmd │ └── qwebr-setting-options-in-document-yaml.qmd ├── images │ └── rstudio-render-button.png ├── index.qmd ├── qwebr-acknowledgements.md ├── qwebr-cell-options.qmd ├── qwebr-code-cell-demos.qmd ├── qwebr-communication-channels.qmd ├── qwebr-community-examples.qmd ├── qwebr-deployment-templates.qmd ├── qwebr-developer-resources.qmd ├── qwebr-extension-website.qmd ├── qwebr-faq.qmd ├── qwebr-first-steps.qmd ├── qwebr-internal-cell.qmd ├── qwebr-loading-data.qmd ├── qwebr-meta-options.qmd ├── qwebr-release-notes.qmd ├── qwebr-theming.qmd ├── qwebr-troubleshooting.qmd └── qwebr-using-r-packages.qmd ├── examples ├── blog │ ├── .gitignore │ ├── _extensions │ ├── _quarto.yml │ ├── about.qmd │ ├── index.qmd │ ├── posts │ │ ├── _metadata.yml │ │ ├── embed-slides │ │ │ ├── image.jpg │ │ │ └── index.qmd │ │ └── post-with-code │ │ │ ├── image.jpg │ │ │ └── index.qmd │ ├── profile.jpg │ └── styles.css ├── book │ ├── .gitignore │ ├── _extensions │ ├── _quarto.yml │ ├── example-page.qmd │ ├── index.qmd │ └── slide-embed.qmd ├── html-document │ ├── .gitignore │ ├── _extensions │ ├── _quarto.yml │ └── index.qmd ├── readme │ ├── _extensions │ ├── _quarto.yml │ └── index.qmd ├── revealjs │ ├── .gitignore │ ├── _extensions │ ├── _quarto.yml │ └── index.qmd └── website │ ├── .gitignore │ ├── _extensions │ ├── _quarto.yml │ ├── example-page.qmd │ ├── index.qmd │ └── slide-embed.qmd ├── quarto-webr.code-workspace ├── tests ├── .gitignore ├── _extensions ├── _quarto.yml ├── index.qmd ├── qwebr-test-editor-options.qmd ├── qwebr-test-escape-html-output-characters.qmd ├── qwebr-test-global-cell-options.qmd ├── qwebr-test-help-documentation.qmd ├── qwebr-test-interactive-with-keyboard-shortcut.qmd ├── qwebr-test-internal-cell.qmd ├── qwebr-test-multiple-cells.qmd ├── qwebr-test-non-interactive-chained-cells.qmd ├── qwebr-test-non-interactive-context-with-packages.qmd ├── qwebr-test-non-interactive-setup-with-packages-and-interactive.qmd ├── qwebr-test-non-interactive-setup-with-packages.qmd ├── qwebr-test-option-space-removal.qmd ├── qwebr-test-output-classes.qmd ├── qwebr-test-output-graph.qmd ├── qwebr-test-output-stderr-result-suppression.qmd ├── qwebr-test-packages-autoload.qmd ├── qwebr-test-packages-multi.qmd ├── qwebr-test-repo-key.qmd ├── qwebr-test-revealjs.qmd ├── qwebr-test-run-built-in.qmd ├── qwebr-test-run-latest.qmd ├── qwebr-test-self-contained.qmd ├── qwebr-test-service-worker-version.qmd ├── qwebr-test-service-worker.qmd ├── qwebr-test-shim-install.qmd ├── qwebr-test-status-header-no-title.qmd ├── qwebr-test-status-header-suppressed-html copy.qmd ├── qwebr-test-status-header-suppressed-revealjs.qmd └── qwebr-test-theme-switch.qmd └── update-quarto-dev.sh /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // Config options: https://github.com/rocker-org/devcontainer-templates/tree/main/src/r-ver 2 | { 3 | "name": "R (rocker/r-ver base)", 4 | "image": "ghcr.io/rocker-org/devcontainer/r-ver:4.3", 5 | // Add software 6 | "features": { 7 | // R package config: https://github.com/rocker-org/devcontainer-features/blob/main/src/r-packages/README.md 8 | "ghcr.io/rocker-org/devcontainer-features/r-packages:1": { 9 | "packages": "cli,rlang,knitr", 10 | "installSystemRequirements": true 11 | }, 12 | // Quarto configuration : https://github.com/rocker-org/devcontainer-features/blob/main/src/quarto-cli/README.md 13 | "ghcr.io/rocker-org/devcontainer-features/quarto-cli:1": { 14 | "installTinyTex": true, 15 | "version": "prerelease" 16 | } 17 | }, 18 | "customizations": { 19 | "vscode": { 20 | "extensions": [ 21 | "quarto.quarto", 22 | "sumneko.lua", 23 | "peakchen90.open-html-in-browser" 24 | ] 25 | }, 26 | "codespaces": { 27 | "openFiles": [ 28 | "examples/readme/index.qmd" 29 | ] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [coatless] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: Report an error or unexpected behavior 3 | labels: ['t: bug', 's: triage-needed'] 4 | title: "[Bug]: " 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Welcome to the quarto-webr Extension GitHub repository! 10 | 11 | We're sorry to hear that you might have encounter a bug; we're happy that you want to let us know so that we can make the extension even better. 12 | 13 | Thank you in advance for your feedback. 14 | 15 | - type: textarea 16 | attributes: 17 | label: Bug description 18 | description: Description of the bug and why you think its a bug. 19 | placeholder: Please describe the bug here. 20 | 21 | - type: textarea 22 | attributes: 23 | label: Steps to reproduce 24 | description: | 25 | Tell us how to reproduce this bug. 26 | 27 | Please include a minimal, fully reproducible example as a self-contained Quarto document or a link to a Git repository. 28 | placeholder: | 29 | You can share a Quarto document using the following syntax, _i.e._, using more backticks than you have in your document (usually four ` ```` `). 30 | 31 | ````qmd 32 | --- 33 | title: "Reproducible webR powered Quarto Document" 34 | format: html 35 | filter: 36 | - webr 37 | --- 38 | 39 | This is a reproducible Quarto document using `format: html` with 40 | the `webr` filter active. It contains a webr code cell that 41 | should create a plot using the cars data. 42 | 43 | ```{webr-r} 44 | plot(cars) 45 | ``` 46 | 47 | The end. 48 | ```` 49 | 50 | - type: textarea 51 | attributes: 52 | label: Your environment 53 | description: | 54 | Please document the IDE (_e.g._ RStudio, VSCode, NVim), its version, and the operating system you're running (_e.g., MacOS Ventura 13.4, Windows 11, Linux Debian 11, _etc._). 55 | placeholder: | 56 | - IDE: RStudio 2023.06.2+561 57 | - OS: MacOS Ventura 13.4 58 | 59 | - type: textarea 60 | attributes: 61 | label: Quarto check output 62 | description: | 63 | Please provide the output of `quarto check` so we know which version of quarto and its dependencies you're running. 64 | placeholder: | 65 | ```bash 66 | quarto check 67 | ``` 68 | 69 | - type: markdown 70 | attributes: 71 | value: "_Thanks for submitting this bug report!_" -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/community-example.yml: -------------------------------------------------------------------------------- 1 | name: Example 2 | description: Contribute an Example 3 | labels: ['t: documentation', 't: community-example'] 4 | title: "[Example]: " 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | We appreciate you taking the time out of your day to let us know about the example! 10 | We love to include links to videos, talks, notebooks, course websites, workshops, blog posts, and so on! 11 | 12 | **Thank you for letting us know!** 13 | - type: textarea 14 | attributes: 15 | label: What's your question? 16 | description: | 17 | Feel free to just start writing about the example! 18 | validations: 19 | required: true 20 | - type: markdown 21 | attributes: 22 | value: | 23 | _Thank you for opening this issue to let us know about the example!_ -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Ask for a feature to be added 3 | labels: ['t: feature-request'] 4 | title: "[Feature]: " 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | First, please check [`quarto-webr` Issue Tracker](https://github.com/coatless/quarto-webr/issues?q=is%3Aissue+) to see if your feature request has already been discussed. 10 | If it has, please consider adding a comment to the existing issue instead of creating a new one. 11 | 12 | After checking, if you are not sure if your feature request has already been discussed, please create a new issue. 13 | We look forward to hearing from you. 14 | 15 | Finally, try to describe the best you can what you want to achieve and why you think it is important. 16 | This will help us to understand your request and prioritise it. 17 | 18 | _Thank you for opening this feature request!_ 19 | - type: textarea 20 | attributes: 21 | label: Feature Description 22 | description: Please discuss your feature request here! 23 | validations: 24 | required: true 25 | - type: markdown 26 | attributes: 27 | value: | 28 | _Thank you for opening this feature request!_ -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yml: -------------------------------------------------------------------------------- 1 | name: Question 2 | description: Ask a question 3 | labels: ['t: question', 's: question-needs-answer'] 4 | title: "[Q&A]: " 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | **Before You Begin:** 10 | 1. Check the [**quarto-webr Issue Tracker**](https://github.com/coatless/quarto-webr/issues?q=is%3Aissue+) to ensure your question hasn't already been addressed. 11 | 12 | 2. If you're uncertain, feel free to create a new issue; we appreciate your engagement. 13 | 14 | **Creating a New Issue:** 15 | 16 | If you're creating a new issue, please provide the following information: 17 | 18 | 1. **Description**: Clearly state your question or problem. 19 | 20 | 2. **Goal**: Explain what you're trying to achieve or the challenge you're facing. 21 | 22 | 3. **Significance**: Share why this issue matters to you or the project. 23 | 24 | 4. **Additional Information**: Include any relevant context, such as your system setup, actions taken so far, and any potential solutions you've considered. 25 | 26 | **Thank you for reaching out!** 27 | - type: textarea 28 | attributes: 29 | label: What's your question? 30 | description: | 31 | You can include webR-powered Quarto document code with your question by using: 32 | 33 | ````qmd 34 | --- 35 | title: "Hello quarto-webr!" 36 | format: html 37 | filters: 38 | - webr 39 | --- 40 | 41 | ```{webr-r} 42 | 1 + 1 43 | ``` 44 | ```` 45 | 46 | validations: 47 | required: true 48 | - type: markdown 49 | attributes: 50 | value: | 51 | _Thank you for opening this issue to ask a question!_ -------------------------------------------------------------------------------- /.github/workflows/publish-demo.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [main, master] 4 | release: 5 | types: [published] 6 | workflow_dispatch: {} 7 | 8 | name: doc-website 9 | 10 | jobs: 11 | demo-website: 12 | runs-on: ubuntu-latest 13 | # Only restrict concurrency for non-PR jobs 14 | concurrency: 15 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 16 | permissions: 17 | contents: write 18 | steps: 19 | - name: "Check out repository" 20 | uses: actions/checkout@v4 21 | 22 | # To render using knitr, we need a few more setup steps... 23 | # If we didn't want the examples to use `engine: knitr`, we could 24 | # skip a few of the setup steps. 25 | - name: "Setup pandoc" 26 | uses: r-lib/actions/setup-pandoc@v2 27 | 28 | - name: "Setup R" 29 | uses: r-lib/actions/setup-r@v2 30 | 31 | - name: "Setup R dependencies for Quarto's knitr engine" 32 | uses: r-lib/actions/setup-r-dependencies@v2 33 | with: 34 | packages: 35 | any::knitr 36 | any::rmarkdown 37 | any::downlit 38 | any::xml2 39 | 40 | # Back to our regularly scheduled Quarto output 41 | - name: "Set up Quarto" 42 | uses: quarto-dev/quarto-actions/setup@v2 43 | with: 44 | version: "pre-release" 45 | 46 | # Generate the documentation website 47 | - name: Render Documentation website 48 | uses: quarto-dev/quarto-actions/render@v2 49 | with: 50 | path: "docs" 51 | 52 | # Attempt to render the nested deployment template Quarto projects 53 | - name: Render README demo 54 | uses: quarto-dev/quarto-actions/render@v2 55 | with: 56 | path: "examples/readme/index.qmd" 57 | 58 | - name: Render sample deployment RevealJS presentation template 59 | uses: quarto-dev/quarto-actions/render@v2 60 | with: 61 | path: "examples/revealjs/index.qmd" 62 | 63 | - name: Render sample deployment HTML document template 64 | uses: quarto-dev/quarto-actions/render@v2 65 | with: 66 | path: "examples/html-document/index.qmd" 67 | 68 | - name: Render sample deployment website template 69 | uses: quarto-dev/quarto-actions/render@v2 70 | with: 71 | path: "examples/website" 72 | 73 | - name: Render sample deployment blog template 74 | uses: quarto-dev/quarto-actions/render@v2 75 | with: 76 | path: "examples/blog" 77 | 78 | - name: Render sample deployment book template 79 | uses: quarto-dev/quarto-actions/render@v2 80 | with: 81 | path: "examples/book" 82 | 83 | - name: Render test suite 84 | uses: quarto-dev/quarto-actions/render@v2 85 | with: 86 | path: "tests" 87 | 88 | # Collect the output into the staging/ directory 89 | - name: Copy documentation portal & examples into the staging directory 90 | run: | 91 | mkdir -p staging/{examples,tests} && \ 92 | cp -rp docs/_site/* staging/ && \ 93 | cp -rp tests/_site/* staging/tests/ && \ 94 | cp -rp examples/book/_book staging/examples/book && \ 95 | cp -rp examples/website/_site staging/examples/website && \ 96 | cp -rp examples/blog/_site staging/examples/blog && \ 97 | cp -rp examples/html-document/ staging/examples/html-document && \ 98 | cp -rp examples/revealjs/ staging/examples/revealjs && \ 99 | cp -rp examples/readme/ staging/examples/readme 100 | 101 | # Remove symlinks 102 | - name: Delete symlinks 103 | run: | 104 | rm -rf staging/examples/*/_extensions && \ 105 | rm -rf staging/tests/_extensions 106 | 107 | # Publish the docs directory onto gh-pages 108 | - name: Deploy 🚀 109 | uses: JamesIves/github-pages-deploy-action@v4 110 | with: 111 | folder: staging # The folder the action should deploy. 112 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.luarc.json 2 | *.luarc.json 3 | *.DS_Store 4 | webr-worker.js 5 | webr-serviceworker.js 6 | *.csv 7 | *_files 8 | docs/_site/* 9 | tests/_site/* 10 | *.html 11 | !_extensions/*/* 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webR Extension for Quarto 2 | 3 | > [!IMPORTANT] 4 | > 5 | > Looking for the official Quarto WebAssembly backend? Check out [`quarto-live`](https://github.com/r-wasm/quarto-live)! 6 | 7 | This community developed Quarto extension enables the [webR](https://docs.r-wasm.org/webr/latest/) code cell within various [Quarto](https://quarto.org/) formats, including [HTML](https://quarto.org/docs/output-formats/html-basics.html), [RevealJS](https://quarto.org/docs/presentations/revealjs/), [Websites](https://quarto.org/docs/websites/), [Blogs](https://quarto.org/docs/websites/website-blog.html), and [Books](https://quarto.org/docs/books). 8 | 9 | ![`quarto-webr` Filter in Action](https://i.imgur.com/JIQZIZ8.gif) 10 | 11 | Take a look at a live example of the extension in action [here](https://quarto-webr.thecoatlessprofessor.com/examples/readme)! To delve deeper into the extension's capabilities, see our comprehensive [documentation website](https://quarto-webr.thecoatlessprofessor.com/). 12 | 13 | Looking for a Python version? Check out [`quarto-pyodide`](https://github.com/coatless-quarto/pyodide)! 14 | 15 | > [!NOTE] 16 | > Please note that the `{quarto-webr}` Quarto extension is a community-driven initiative and is **not** affiliated with Posit, Quarto, or the main [webR](https://docs.r-wasm.org/webr/latest/) project. Its evolution and maintenance stem solely from the collective efforts of community members. 17 | 18 | ## Background 19 | 20 | If you're new to [webR](https://docs.r-wasm.org/webr/latest/), this cutting-edge technology empowers you to: 21 | 22 | > "run R code in the browser without the need for an R server to execute the code." 23 | 24 | For a deeper understanding of [webR](https://docs.r-wasm.org/webr/latest/), explore the following resources: 25 | 26 | - [webR Documentation](https://docs.r-wasm.org/webr/latest/) 27 | - [webR Source Code](https://github.com/r-wasm/webr/) 28 | 29 | ## Quick Start Video Guide 30 | 31 | For those new to Quarto and Quarto Extensions, we highly recommend checking out this informative [YouTube video](https://youtu.be/DoRR2S5lLvk?t=5) to get started quickly: 32 | 33 | [![Creating your first webR-powered Quarto Document inside of RStudio](https://i3.ytimg.com/vi/DoRR2S5lLvk/maxresdefault.jpg)](https://youtu.be/DoRR2S5lLvk?t=5) 34 | 35 | ## Installation 36 | 37 | To use this extension in a [Quarto project](https://quarto.org/docs/projects/quarto-projects.html), install it from within the project's working directory by typing into **Terminal**: 38 | 39 | ``` bash 40 | quarto add coatless/quarto-webr 41 | ``` 42 | 43 | ![Demonstration of using the Terminal tab to install the extension.](https://i.imgur.com/aVuBdyN.png) 44 | 45 | After the installation process is finished, the extension will be readily available for Quarto documents within the designated working directory. Please note that if you are working on projects located in different directories, you will need to repeat this installation step for each of those directories. 46 | 47 | ## Usage 48 | 49 | For each document, place the `webr` filter in the document's header: 50 | 51 | ```yaml 52 | filters: 53 | - webr 54 | ``` 55 | 56 | Then, place the R code for `webR` in a code block marked with `{webr-r}` 57 | 58 | ````markdown 59 | --- 60 | title: webR in Quarto HTML Documents 61 | format: html 62 | engine: knitr 63 | filters: 64 | - webr 65 | --- 66 | 67 | This is a webR-enabled code cell in a Quarto HTML document. 68 | 69 | ```{webr-r} 70 | fit = lm(mpg ~ am, data = mtcars) 71 | 72 | summary(fit) 73 | ``` 74 | ```` 75 | 76 | The rendered document can be viewed online [here](https://quarto-webr.thecoatlessprofessor.com/examples/readme). 77 | 78 | **Note:** If you don't specify the `engine: knitr`, the default compute engine used will be `jupyter`. This could trigger prompts to install Python. However, if you specify `engine: knitr`, there's no need to install Python. 79 | 80 | There are many more customization options that are available. Please see the [customization documentation](https://quarto-webr.thecoatlessprofessor.com/qwebr-meta-options.html) for more examples. 81 | 82 | For specific deployment usage cases, please see [Templates](https://quarto-webr.thecoatlessprofessor.com/qwebr-deployment-templates.html). 83 | 84 | ## Help 85 | 86 | For troubleshooting help, please see our [troubleshooting page](https://quarto-webr.thecoatlessprofessor.com/qwebr-troubleshooting.html). 87 | 88 | To report a bug, please [add an issue](https://github.com/coatless/quarto-webr/issues/new) to the repository's [bug tracker](https://github.com/coatless/quarto-webr/issues). 89 | 90 | Want to contribute a feature? Please open an issue ticket to discuss the feature before sending a pull request. 91 | 92 | ## Acknowledgements 93 | 94 | Please see our [acknowledgements page](https://quarto-webr.thecoatlessprofessor.com/qwebr-acknowledgements.html). 95 | -------------------------------------------------------------------------------- /_extensions/webr/_extension.yml: -------------------------------------------------------------------------------- 1 | name: webr 2 | title: Embedded webr code cells 3 | author: James Joseph Balamuta 4 | version: 0.4.3-dev.2 5 | quarto-required: ">=1.4.554" 6 | contributes: 7 | filters: 8 | - webr.lua 9 | -------------------------------------------------------------------------------- /_extensions/webr/qwebr-cell-initialization.js: -------------------------------------------------------------------------------- 1 | // Handle cell initialization initialization 2 | qwebrCellDetails.map( 3 | (entry) => { 4 | // Handle the creation of the element 5 | qwebrCreateHTMLElement(entry); 6 | // In the event of interactive, initialize the monaco editor 7 | if (entry.options.context == EvalTypes.Interactive) { 8 | qwebrCreateMonacoEditorInstance(entry); 9 | } 10 | } 11 | ); 12 | 13 | // Identify non-interactive cells (in order) 14 | const filteredEntries = qwebrCellDetails.filter(entry => { 15 | const contextOption = entry.options && entry.options.context; 16 | return ['output', 'setup'].includes(contextOption) || (contextOption == "interactive" && entry.options && entry.options.autorun === 'true'); 17 | }); 18 | 19 | // Condition non-interactive cells to only be run after webR finishes its initialization. 20 | qwebrInstance.then( 21 | async () => { 22 | const nHiddenCells = filteredEntries.length; 23 | var currentHiddenCell = 0; 24 | 25 | 26 | // Modify button state 27 | qwebrSetInteractiveButtonState(`🟡 Running hidden code cells ...`, false); 28 | 29 | // Begin processing non-interactive sections 30 | // Due to the iteration policy, we must use a for() loop. 31 | // Otherwise, we would need to switch to using reduce with an empty 32 | // starting promise 33 | for (const entry of filteredEntries) { 34 | 35 | // Determine cell being examined 36 | currentHiddenCell = currentHiddenCell + 1; 37 | const formattedMessage = `Evaluating hidden cell ${currentHiddenCell} out of ${nHiddenCells}`; 38 | 39 | // Update the document status header 40 | if (qwebrShowStartupMessage) { 41 | qwebrUpdateStatusHeader(formattedMessage); 42 | } 43 | 44 | // Display the update in non-active areas 45 | qwebrUpdateStatusMessage(formattedMessage); 46 | 47 | // Extract details on the active cell 48 | const evalType = entry.options.context; 49 | const cellCode = entry.code; 50 | const qwebrCounter = entry.id; 51 | 52 | if (['output', 'setup'].includes(evalType)) { 53 | // Disable further global status updates 54 | const activeContainer = document.getElementById(`qwebr-non-interactive-loading-container-${qwebrCounter}`); 55 | activeContainer.classList.remove('qwebr-cell-needs-evaluation'); 56 | activeContainer.classList.add('qwebr-cell-evaluated'); 57 | 58 | // Update status on the code cell 59 | const activeStatus = document.getElementById(`qwebr-status-text-${qwebrCounter}`); 60 | activeStatus.innerText = " Evaluating hidden code cell..."; 61 | activeStatus.classList.remove('qwebr-cell-needs-evaluation'); 62 | activeStatus.classList.add('qwebr-cell-evaluated'); 63 | } 64 | 65 | switch (evalType) { 66 | case 'interactive': 67 | // TODO: Make this more standardized. 68 | // At the moment, we're overriding the interactive status update by pretending its 69 | // output-like. 70 | const tempOptions = entry.options; 71 | tempOptions["context"] = "output" 72 | // Run the code in a non-interactive state that is geared to displaying output 73 | await qwebrExecuteCode(`${cellCode}`, qwebrCounter, tempOptions); 74 | break; 75 | case 'output': 76 | // Run the code in a non-interactive state that is geared to displaying output 77 | await qwebrExecuteCode(`${cellCode}`, qwebrCounter, entry.options); 78 | break; 79 | case 'setup': 80 | const activeDiv = document.getElementById(`qwebr-noninteractive-setup-area-${qwebrCounter}`); 81 | 82 | // Store code in history 83 | qwebrLogCodeToHistory(cellCode, entry.options); 84 | 85 | // Run the code in a non-interactive state with all output thrown away 86 | await mainWebR.evalRVoid(`${cellCode}`); 87 | break; 88 | default: 89 | break; 90 | } 91 | 92 | if (['output', 'setup'].includes(evalType)) { 93 | // Disable further global status updates 94 | const activeContainer = document.getElementById(`qwebr-non-interactive-loading-container-${qwebrCounter}`); 95 | // Disable visibility 96 | activeContainer.style.visibility = 'hidden'; 97 | activeContainer.style.display = 'none'; 98 | } 99 | } 100 | } 101 | ).then( 102 | () => { 103 | // Release document status as ready 104 | 105 | if (qwebrShowStartupMessage) { 106 | qwebrStartupMessage.innerText = "🟢 Ready!" 107 | } 108 | 109 | qwebrSetInteractiveButtonState( 110 | ` Run Code`, 111 | true 112 | ); 113 | } 114 | ); -------------------------------------------------------------------------------- /_extensions/webr/qwebr-document-engine-initialization.js: -------------------------------------------------------------------------------- 1 | // Function to install a single package 2 | async function qwebrInstallRPackage(packageName) { 3 | await mainWebR.evalRVoid(`webr::install('${packageName}');`); 4 | } 5 | 6 | // Function to load a single package 7 | async function qwebrLoadRPackage(packageName) { 8 | await mainWebR.evalRVoid(`require('${packageName}', quietly = TRUE)`); 9 | } 10 | 11 | // Generic function to process R packages 12 | async function qwebrProcessRPackagesWithStatus(packages, processType, displayStatusMessageUpdate = true) { 13 | // Switch between contexts 14 | const messagePrefix = processType === 'install' ? 'Installing' : 'Loading'; 15 | 16 | // Modify button state 17 | qwebrSetInteractiveButtonState(`🟡 ${messagePrefix} package ...`, false); 18 | 19 | // Iterate over packages 20 | for (let i = 0; i < packages.length; i++) { 21 | const activePackage = packages[i]; 22 | const formattedMessage = `${messagePrefix} package ${i + 1} out of ${packages.length}: ${activePackage}`; 23 | 24 | // Display the update in header 25 | if (displayStatusMessageUpdate) { 26 | qwebrUpdateStatusHeader(formattedMessage); 27 | } 28 | 29 | // Display the update in non-active areas 30 | qwebrUpdateStatusMessage(formattedMessage); 31 | 32 | // Run package installation 33 | if (processType === 'install') { 34 | await qwebrInstallRPackage(activePackage); 35 | } else { 36 | await qwebrLoadRPackage(activePackage); 37 | } 38 | } 39 | 40 | // Clean slate 41 | if (processType === 'load') { 42 | await mainWebR.flush(); 43 | } 44 | } 45 | 46 | // Start a timer 47 | const initializeWebRTimerStart = performance.now(); 48 | 49 | // Encase with a dynamic import statement 50 | globalThis.qwebrInstance = import(qwebrCustomizedWebROptions.baseURL + "webr.mjs").then( 51 | async ({ WebR, ChannelType }) => { 52 | // Populate WebR options with defaults or new values based on `webr` meta 53 | globalThis.mainWebR = new WebR(qwebrCustomizedWebROptions); 54 | 55 | // Initialization WebR 56 | await mainWebR.init(); 57 | 58 | // Setup a shelter 59 | globalThis.mainWebRCodeShelter = await new mainWebR.Shelter(); 60 | 61 | // Setup a pager to allow processing help documentation 62 | await mainWebR.evalRVoid('webr::pager_install()'); 63 | 64 | // Setup a viewer to allow processing htmlwidgets. 65 | // This might not be available in old webr version 66 | await mainWebR.evalRVoid('try({ webr::viewer_install() })'); 67 | 68 | // Override the existing install.packages() to use webr::install() 69 | await mainWebR.evalRVoid('webr::shim_install()'); 70 | 71 | // Specify the repositories to pull from 72 | // Note: webR does not use the `repos` option, but instead uses `webr_pkg_repos` 73 | // inside of `install()`. However, other R functions still pull from `repos`. 74 | await mainWebR.evalRVoid(` 75 | options( 76 | webr_pkg_repos = c(${qwebrPackageRepoURLS.map(repoURL => `'${repoURL}'`).join(',')}), 77 | repos = c(${qwebrPackageRepoURLS.map(repoURL => `'${repoURL}'`).join(',')}) 78 | ) 79 | `); 80 | 81 | // Check to see if any packages need to be installed 82 | if (qwebrSetupRPackages) { 83 | // Obtain only a unique list of packages 84 | const uniqueRPackageList = Array.from(new Set(qwebrInstallRPackagesList)); 85 | 86 | // Install R packages one at a time (either silently or with a status update) 87 | await qwebrProcessRPackagesWithStatus(uniqueRPackageList, 'install', qwebrShowStartupMessage); 88 | 89 | if (qwebrAutoloadRPackages) { 90 | // Load R packages one at a time (either silently or with a status update) 91 | await qwebrProcessRPackagesWithStatus(uniqueRPackageList, 'load', qwebrShowStartupMessage); 92 | } 93 | } 94 | } 95 | ); 96 | 97 | // Stop timer 98 | const initializeWebRTimerEnd = performance.now(); 99 | -------------------------------------------------------------------------------- /_extensions/webr/qwebr-document-history.js: -------------------------------------------------------------------------------- 1 | // Define a global storage and retrieval solution ---- 2 | 3 | // Store commands executed in R 4 | globalThis.qwebrRCommandHistory = []; 5 | 6 | // Function to retrieve the command history 7 | globalThis.qwebrFormatRHistory = function() { 8 | return qwebrRCommandHistory.join("\n\n"); 9 | } 10 | 11 | // Retrieve HTML Elements ---- 12 | 13 | // Get the command modal 14 | const command_history_modal = document.getElementById("qwebr-history-modal"); 15 | 16 | // Get the button that opens the command modal 17 | const command_history_btn = document.getElementById("qwebrRHistoryButton"); 18 | 19 | // Get the element that closes the command modal 20 | const command_history_close_span = document.getElementById("qwebr-command-history-close-btn"); 21 | 22 | // Get the download button for r history information 23 | const command_history_download_btn = document.getElementById("qwebr-download-history-btn"); 24 | 25 | // Plug in command history into modal/download button ---- 26 | 27 | // Function to populate the modal with command history 28 | function populateCommandHistoryModal() { 29 | document.getElementById("qwebr-command-history-contents").innerHTML = qwebrFormatRHistory() || "No commands have been executed yet."; 30 | } 31 | 32 | // Function to format the current date and time to 33 | // a string with the format YYYY-MM-DD-HH-MM-SS 34 | function formatDateTime() { 35 | const now = new Date(); 36 | 37 | const year = now.getFullYear(); 38 | const day = String(now.getDate()).padStart(2, '0'); 39 | const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are zero-based 40 | const hours = String(now.getHours()).padStart(2, '0'); 41 | const minutes = String(now.getMinutes()).padStart(2, '0'); 42 | const seconds = String(now.getSeconds()).padStart(2, '0'); 43 | 44 | return `${year}-${month}-${day}-${hours}-${minutes}-${seconds}`; 45 | } 46 | 47 | 48 | // Function to convert document title with datetime to a safe filename 49 | function safeFileName() { 50 | // Get the current page title 51 | let pageTitle = document.title; 52 | 53 | // Combine the current page title with the current date and time 54 | let pageNameWithDateTime = `Rhistory-${pageTitle}-${formatDateTime()}`; 55 | 56 | // Replace unsafe characters with safe alternatives 57 | let safeFilename = pageNameWithDateTime.replace(/[\\/:\*\?! "<>\|]/g, '-'); 58 | 59 | return safeFilename; 60 | } 61 | 62 | 63 | // Function to download list contents as text file 64 | function downloadRHistory() { 65 | // Get the current page title + datetime and use it as the filename 66 | const filename = `${safeFileName()}.R`; 67 | 68 | // Get the text contents of the R History list 69 | const text = qwebrFormatRHistory(); 70 | 71 | // Create a new Blob object with the text contents 72 | const blob = new Blob([text], { type: 'text/plain' }); 73 | 74 | // Create a new anchor element for the download 75 | const a = document.createElement('a'); 76 | a.style.display = 'none'; 77 | a.href = URL.createObjectURL(blob); 78 | a.download = filename; 79 | 80 | // Append the anchor to the body, click it, and remove it 81 | document.body.appendChild(a); 82 | a.click(); 83 | document.body.removeChild(a); 84 | } 85 | 86 | // Register event handlers ---- 87 | 88 | // When the user clicks the View R History button, open the command modal 89 | command_history_btn.onclick = function() { 90 | populateCommandHistoryModal(); 91 | command_history_modal.style.display = "block"; 92 | } 93 | 94 | // When the user clicks on (x), close the command modal 95 | command_history_close_span.onclick = function() { 96 | command_history_modal.style.display = "none"; 97 | } 98 | 99 | // When the user clicks anywhere outside of the command modal, close it 100 | window.onclick = function(event) { 101 | if (event.target == command_history_modal) { 102 | command_history_modal.style.display = "none"; 103 | } 104 | } 105 | 106 | // Add an onclick event listener to the download button so that 107 | // the user can download the R history as a text file 108 | command_history_download_btn.onclick = function() { 109 | downloadRHistory(); 110 | }; -------------------------------------------------------------------------------- /_extensions/webr/qwebr-document-settings.js: -------------------------------------------------------------------------------- 1 | // Document level settings ---- 2 | 3 | // Determine if we need to install R packages 4 | globalThis.qwebrInstallRPackagesList = [{{INSTALLRPACKAGESLIST}}]; 5 | 6 | // Specify possible locations to search for the repository 7 | globalThis.qwebrPackageRepoURLS = [{{RPACKAGEREPOURLS}}]; 8 | 9 | // Check to see if we have an empty array, if we do set to skip the installation. 10 | globalThis.qwebrSetupRPackages = !(qwebrInstallRPackagesList.indexOf("") !== -1); 11 | globalThis.qwebrAutoloadRPackages = {{AUTOLOADRPACKAGES}}; 12 | 13 | // Display a startup message? 14 | globalThis.qwebrShowStartupMessage = {{SHOWSTARTUPMESSAGE}}; 15 | globalThis.qwebrShowHeaderMessage = {{SHOWHEADERMESSAGE}}; 16 | 17 | // Describe the webR settings that should be used 18 | globalThis.qwebrCustomizedWebROptions = { 19 | "baseURL": "{{BASEURL}}", 20 | "serviceWorkerUrl": "{{SERVICEWORKERURL}}", 21 | "homedir": "{{HOMEDIR}}", 22 | "channelType": "{{CHANNELTYPE}}" 23 | }; 24 | 25 | // Store cell data 26 | globalThis.qwebrCellDetails = {{QWEBRCELLDETAILS}}; 27 | -------------------------------------------------------------------------------- /_extensions/webr/qwebr-monaco-editor-element.js: -------------------------------------------------------------------------------- 1 | // Global array to store Monaco Editor instances 2 | globalThis.qwebrEditorInstances = []; 3 | 4 | function isValidCodeLineNumbers(stringCodeLineNumbers) { 5 | // Regular expression to match valid input strings 6 | const regex = /^(\d+(-\d+)?)(,\d+(-\d+)?)*$/; 7 | return regex.test(stringCodeLineNumbers); 8 | } 9 | 10 | // Function that builds and registers a Monaco Editor instance 11 | globalThis.qwebrCreateMonacoEditorInstance = function (cellData) { 12 | 13 | const initialCode = cellData.code; 14 | const qwebrCounter = cellData.id; 15 | const qwebrOptions = cellData.options; 16 | 17 | // Retrieve the previously created document elements 18 | let runButton = document.getElementById(`qwebr-button-run-${qwebrCounter}`); 19 | let resetButton = document.getElementById(`qwebr-button-reset-${qwebrCounter}`); 20 | let copyButton = document.getElementById(`qwebr-button-copy-${qwebrCounter}`); 21 | let editorDiv = document.getElementById(`qwebr-editor-${qwebrCounter}`); 22 | 23 | // Load the Monaco Editor and create an instance 24 | let editor; 25 | require(['vs/editor/editor.main'], function () { 26 | editor = monaco.editor.create(editorDiv, { 27 | value: initialCode, 28 | language: 'r', 29 | theme: 'vs-light', 30 | automaticLayout: true, // Works wonderfully with RevealJS 31 | scrollBeyondLastLine: false, 32 | minimap: { 33 | enabled: false 34 | }, 35 | fontSize: qwebrScaledFontSize(editorDiv, qwebrOptions), 36 | renderLineHighlight: "none", // Disable current line highlighting 37 | hideCursorInOverviewRuler: true, // Remove cursor indictor in right hand side scroll bar 38 | readOnly: qwebrOptions['read-only'] ?? false, 39 | quickSuggestions: qwebrOptions['editor-quick-suggestions'] ?? false, 40 | wordWrap: (qwebrOptions['editor-word-wrap'] == 'true' ? "on" : "off") 41 | }); 42 | 43 | // Store the official counter ID to be used in keyboard shortcuts 44 | editor.__qwebrCounter = qwebrCounter; 45 | 46 | // Store the official div container ID 47 | editor.__qwebrEditorId = `qwebr-editor-${qwebrCounter}`; 48 | 49 | // Store the initial code value and options 50 | editor.__qwebrinitialCode = initialCode; 51 | editor.__qwebrOptions = qwebrOptions; 52 | 53 | // Set at the model level the preferred end of line (EOL) character to LF. 54 | // This prevent `\r\n` from being given to the webR engine if the user is on Windows. 55 | // See details in: https://github.com/coatless/quarto-webr/issues/94 56 | // Associated error text: 57 | // Error: :1:7 unexpected input 58 | 59 | // Retrieve the underlying model 60 | const model = editor.getModel(); 61 | // Set EOL for the model 62 | model.setEOL(monaco.editor.EndOfLineSequence.LF); 63 | 64 | // Dynamically modify the height of the editor window if new lines are added. 65 | let ignoreEvent = false; 66 | const updateHeight = () => { 67 | // Increment editor height by 2 to prevent vertical scroll bar from appearing 68 | const contentHeight = editor.getContentHeight() + 2; 69 | 70 | // Retrieve editor-max-height option 71 | const maxEditorHeight = qwebrOptions['editor-max-height']; 72 | 73 | // If editor-max-height is missing, allow infinite growth. Otherwise, threshold. 74 | const editorHeight = !maxEditorHeight ? contentHeight : Math.min(contentHeight, maxEditorHeight); 75 | 76 | // We're avoiding a width change 77 | //editorDiv.style.width = `${width}px`; 78 | editorDiv.style.height = `${editorHeight}px`; 79 | try { 80 | ignoreEvent = true; 81 | 82 | // The key to resizing is this call 83 | editor.layout(); 84 | } finally { 85 | ignoreEvent = false; 86 | } 87 | }; 88 | 89 | // Function to generate decorations to highlight lines 90 | // in the editor based on input string. 91 | function decoratorHighlightLines(codeLineNumbers) { 92 | // Store the lines to be lighlight 93 | let linesToHighlight = []; 94 | 95 | // Parse the codeLineNumbers string to get the line numbers to highlight 96 | // First, split the string by commas 97 | codeLineNumbers.split(',').forEach(part => { 98 | // Check if we have a range of lines 99 | if (part.includes('-')) { 100 | // Handle range of lines (e.g., "6-8") 101 | const [start, end] = part.split('-').map(Number); 102 | for (let i = start; i <= end; i++) { 103 | linesToHighlight.push(i); 104 | } 105 | } else { 106 | // Handle single line (e.g., "7") 107 | linesToHighlight.push(Number(part)); 108 | } 109 | }); 110 | 111 | // Create monaco decorations for the lines to highlight 112 | const decorations = linesToHighlight.map(lineNumber => ({ 113 | range: new monaco.Range(lineNumber, 1, lineNumber, 1), 114 | options: { 115 | isWholeLine: true, 116 | className: 'qwebr-editor-highlight-line' 117 | } 118 | })); 119 | 120 | // Return decorations to be applied to the editor 121 | return decorations; 122 | } 123 | 124 | // Ensure that the editor-code-line-numbers option is set and valid 125 | // then apply styling 126 | if (qwebrOptions['editor-code-line-numbers']) { 127 | // Remove all whitespace from the string 128 | const codeLineNumbers = qwebrOptions['editor-code-line-numbers'].replace(/\s/g,''); 129 | // Check if the string is valid for line numbers, e.g., "1,3-5,7" 130 | if (isValidCodeLineNumbers(codeLineNumbers)) { 131 | // Apply the decorations to the editor 132 | editor.createDecorationsCollection(decoratorHighlightLines(codeLineNumbers)); 133 | } else { 134 | // Warn the user that the input is invalid 135 | console.warn(`Invalid "editor-code-line-numbers" value in code cell ${qwebrOptions['label']}: ${codeLineNumbers}`); 136 | } 137 | } 138 | 139 | // Helper function to check if selected text is empty 140 | function isEmptyCodeText(selectedCodeText) { 141 | return (selectedCodeText === null || selectedCodeText === undefined || selectedCodeText === ""); 142 | } 143 | 144 | // Registry of keyboard shortcuts that should be re-added to each editor window 145 | // when focus changes. 146 | const addWebRKeyboardShortCutCommands = () => { 147 | // Add a keydown event listener for Shift+Enter to run all code in cell 148 | editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, () => { 149 | 150 | // Retrieve all text inside the editor 151 | qwebrExecuteCode(editor.getValue(), editor.__qwebrCounter, editor.__qwebrOptions); 152 | }); 153 | 154 | // Add a keydown event listener for CMD/Ctrl+Enter to run selected code 155 | editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => { 156 | 157 | // Get the selected text from the editor 158 | const selectedText = editor.getModel().getValueInRange(editor.getSelection()); 159 | // Check if no code is selected 160 | if (isEmptyCodeText(selectedText)) { 161 | // Obtain the current cursor position 162 | let currentPosition = editor.getPosition(); 163 | // Retrieve the current line content 164 | let currentLine = editor.getModel().getLineContent(currentPosition.lineNumber); 165 | 166 | // Propose a new position to move the cursor to 167 | let newPosition = new monaco.Position(currentPosition.lineNumber + 1, 1); 168 | 169 | // Check if the new position is beyond the last line of the editor 170 | if (newPosition.lineNumber > editor.getModel().getLineCount()) { 171 | // Add a new line at the end of the editor 172 | editor.executeEdits("addNewLine", [{ 173 | range: new monaco.Range(newPosition.lineNumber, 1, newPosition.lineNumber, 1), 174 | text: "\n", 175 | forceMoveMarkers: true, 176 | }]); 177 | } 178 | 179 | // Run the entire line of code. 180 | qwebrExecuteCode(currentLine, editor.__qwebrCounter, editor.__qwebrOptions); 181 | 182 | // Move cursor to new position 183 | editor.setPosition(newPosition); 184 | } else { 185 | // Code to run when Ctrl+Enter is pressed with selected code 186 | qwebrExecuteCode(selectedText, editor.__qwebrCounter, editor.__qwebrOptions); 187 | } 188 | }); 189 | } 190 | 191 | // Register an on focus event handler for when a code cell is selected to update 192 | // what keyboard shortcut commands should work. 193 | // This is a workaround to fix a regression that happened with multiple 194 | // editor windows since Monaco 0.32.0 195 | // https://github.com/microsoft/monaco-editor/issues/2947 196 | editor.onDidFocusEditorText(addWebRKeyboardShortCutCommands); 197 | 198 | // Register an on change event for when new code is added to the editor window 199 | editor.onDidContentSizeChange(updateHeight); 200 | 201 | // Manually re-update height to account for the content we inserted into the call 202 | updateHeight(); 203 | 204 | // Store the editor instance in the global dictionary 205 | qwebrEditorInstances[editor.__qwebrCounter] = editor; 206 | 207 | }); 208 | 209 | // Add a click event listener to the run button 210 | runButton.onclick = function () { 211 | qwebrExecuteCode(editor.getValue(), editor.__qwebrCounter, editor.__qwebrOptions); 212 | }; 213 | 214 | // Add a click event listener to the reset button 215 | copyButton.onclick = function () { 216 | // Retrieve current code data 217 | const data = editor.getValue(); 218 | 219 | // Write code data onto the clipboard. 220 | navigator.clipboard.writeText(data || ""); 221 | }; 222 | 223 | // Add a click event listener to the copy button 224 | resetButton.onclick = function () { 225 | editor.setValue(editor.__qwebrinitialCode); 226 | }; 227 | 228 | } -------------------------------------------------------------------------------- /_extensions/webr/qwebr-monaco-editor-init.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /_extensions/webr/qwebr-styling.css: -------------------------------------------------------------------------------- 1 | .monaco-editor pre { 2 | background-color: unset !important; 3 | } 4 | 5 | .qwebr-editor-toolbar { 6 | width: 100%; 7 | display: flex; 8 | justify-content: space-between; 9 | box-sizing: border-box; 10 | } 11 | 12 | .qwebr-editor-toolbar-left-buttons, .qwebr-editor-toolbar-right-buttons { 13 | display: flex; 14 | } 15 | 16 | .qwebr-non-interactive-loading-container.qwebr-cell-needs-evaluation, .qwebr-non-interactive-loading-container.qwebr-cell-evaluated { 17 | justify-content: center; 18 | display: flex; 19 | background-color: rgba(250, 250, 250, 0.65); 20 | border: 1px solid rgba(233, 236, 239, 0.65); 21 | border-radius: 0.5rem; 22 | margin-top: 15px; 23 | margin-bottom: 15px; 24 | } 25 | 26 | .qwebr-r-project-logo { 27 | color: #2767B0; /* R Project's blue color */ 28 | } 29 | 30 | .qwebr-icon-status-spinner { 31 | color: #7894c4; 32 | } 33 | 34 | .qwebr-icon-run-code { 35 | color: #0d9c29 36 | } 37 | 38 | body.quarto-light .qwebr-output-code-stdout { 39 | color: #111; 40 | } 41 | 42 | body.quarto-dark .qwebr-output-code-stdout { 43 | color: #EEE; 44 | } 45 | 46 | .qwebr-output-code-stderr { 47 | color: #db4133; 48 | } 49 | 50 | body.quarto-light .qwebr-editor { 51 | border: 1px solid #EEEEEE; 52 | } 53 | 54 | body.quarto-light .qwebr-editor-toolbar { 55 | background-color: #EEEEEE; 56 | padding: 0.2rem 0.5rem; 57 | } 58 | 59 | body.quarto-dark .qwebr-editor { 60 | border: 1px solid #111; 61 | } 62 | 63 | body.quarto-dark .qwebr-editor-toolbar { 64 | background-color: #111; 65 | padding: 0.2rem 0.5rem; 66 | } 67 | 68 | .qwebr-button { 69 | display: inline-block; 70 | font-weight: 400; 71 | line-height: 1; 72 | text-decoration: none; 73 | text-align: center; 74 | padding: 0.375rem 0.75rem; 75 | font-size: .9rem; 76 | border-radius: 0.25rem; 77 | transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; 78 | } 79 | 80 | body.quarto-light .qwebr-button { 81 | background-color: #EEEEEE; 82 | color: #000; 83 | border-color: #dee2e6; 84 | border: 1px solid rgba(0,0,0,0); 85 | } 86 | 87 | body.quarto-dark .qwebr-button { 88 | background-color: #111; 89 | color: #EEE; 90 | border-color: #dee2e6; 91 | border: 1px solid rgba(0,0,0,0); 92 | } 93 | 94 | body.quarto-light .qwebr-button:hover { 95 | color: #000; 96 | background-color: #d9dce0; 97 | border-color: #c8ccd0; 98 | } 99 | 100 | body.quarto-dark .qwebr-button:hover { 101 | color: #d9dce0; 102 | background-color: #323232; 103 | border-color: #d9dce0; 104 | } 105 | 106 | .qwebr-button:disabled,.qwebr-button.disabled,fieldset:disabled .qwebr-button { 107 | pointer-events: none; 108 | opacity: .65 109 | } 110 | 111 | .qwebr-button-reset { 112 | color: #696969; /*#4682b4;*/ 113 | } 114 | 115 | .qwebr-button-copy { 116 | color: #696969; 117 | } 118 | 119 | /* Style the code highlight lines */ 120 | body.quarto-light .qwebr-editor-highlight-line { 121 | background-color: lightblue; 122 | } 123 | 124 | body.quarto-dark .qwebr-editor-highlight-line { 125 | background-color: darkblue; 126 | } 127 | 128 | /* Style the modal pop-up */ 129 | 130 | /* The Modal (background) */ 131 | .qwebr-modal { 132 | display: none; /* Hidden by default */ 133 | position: fixed; /* Stay in place */ 134 | z-index: 1; /* Sit on top */ 135 | left: 0; 136 | top: 0; 137 | width: 100%; /* Full width */ 138 | height: 100%; /* Full height */ 139 | overflow: auto; /* Enable scroll if needed */ 140 | background-color: rgb(0,0,0); /* Fallback color */ 141 | background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ 142 | padding-top: 60px; 143 | } 144 | 145 | /* Modal Content */ 146 | .qwebr-modal-content { 147 | background-color: #fefefe; 148 | margin: 5% auto; /* 15% from the top and centered */ 149 | padding: 20px; 150 | border: 1px solid #888; 151 | width: 80%; /* Could be more or less, depending on screen size */ 152 | } 153 | 154 | .qwebr-modal-content-code { 155 | max-height: 50vh; 156 | min-height: 5vh; 157 | overflow: scroll; 158 | border: 1px solid #888; 159 | } 160 | 161 | /* The Close Button */ 162 | .qwebr-modal-close { 163 | color: #aaa; 164 | float: right; 165 | font-size: 28px; 166 | font-weight: bold; 167 | } 168 | 169 | .qwebr-modal-close:hover, 170 | .qwebr-modal-close:focus { 171 | color: black; 172 | text-decoration: none; 173 | cursor: pointer; 174 | } 175 | 176 | .qwebr-download-btn { 177 | margin-top: 10px; 178 | text-decoration: none !important; 179 | } 180 | 181 | /* Styling to download image that is created */ 182 | 183 | .qwebr-canvas-image { 184 | position: relative; 185 | display: inline-block; 186 | margin: 10px; 187 | } 188 | 189 | .qwebr-canvas-image-download-btn { 190 | position: absolute; 191 | top: 10px; 192 | right: 10px; 193 | padding: 5px 10px; 194 | background-color: #007BFF; 195 | color: white; 196 | border: none; 197 | cursor: pointer; 198 | display: none; 199 | } 200 | 201 | figure:hover .qwebr-canvas-image-download-btn { 202 | display: block; 203 | } 204 | 205 | /* Custom styling for RevealJS Presentations*/ 206 | 207 | /* Reset the style of the interactive area */ 208 | .reveal div.qwebr-interactive-area { 209 | display: block; 210 | box-shadow: none; 211 | max-width: 100%; 212 | max-height: 100%; 213 | margin: 0; 214 | padding: 0; 215 | } 216 | 217 | /* Provide space to entries */ 218 | .reveal div.qwebr-output-code-area pre div { 219 | margin: 1px 2px 1px 10px; 220 | } 221 | 222 | /* Collapse the inside code tags to avoid extra space between line outputs */ 223 | .reveal pre div code.qwebr-output-code-stdout, .reveal pre div code.qwebr-output-code-stderr { 224 | padding: 0; 225 | display: contents; 226 | } 227 | 228 | body.reveal.quarto-light pre div code.qwebr-output-code-stdout { 229 | color: #111; 230 | } 231 | 232 | body.reveal.quarto-dark pre div code.qwebr-output-code-stdout { 233 | color: #EEEEEE; 234 | } 235 | 236 | .reveal pre div code.qwebr-output-code-stderr { 237 | color: #db4133; 238 | } 239 | 240 | 241 | /* Create a border around console and output (does not effect graphs) */ 242 | body.reveal.quarto-light div.qwebr-console-area { 243 | border: 1px solid #EEEEEE; 244 | box-shadow: 2px 2px 10px #EEEEEE; 245 | } 246 | 247 | body.reveal.quarto-dark div.qwebr-console-area { 248 | border: 1px solid #111; 249 | box-shadow: 2px 2px 10px #111; 250 | } 251 | 252 | 253 | /* Cap output height and allow text to scroll */ 254 | /* TODO: Is there a better way to fit contents/max it parallel to the monaco editor size? */ 255 | .reveal div.qwebr-output-code-area pre { 256 | max-height: 400px; 257 | overflow: scroll; 258 | } 259 | 260 | iframe.qwebr-output-code-browse { 261 | width: 100%; 262 | 263 | /* 264 | TODO: How to make the height automatic according to the widget size, 265 | or respect the quarto code block options? 266 | */ 267 | min-height: 500px; 268 | } 269 | -------------------------------------------------------------------------------- /_extensions/webr/qwebr-theme-switch.js: -------------------------------------------------------------------------------- 1 | // Function to update Monaco Editors when body class changes 2 | function updateMonacoEditorsOnBodyClassChange() { 3 | // Select the body element 4 | const body = document.querySelector('body'); 5 | 6 | // Options for the observer (which mutations to observe) 7 | const observerOptions = { 8 | attributes: true, // Observe changes to attributes 9 | attributeFilter: ['class'] // Only observe changes to the 'class' attribute 10 | }; 11 | 12 | // Callback function to execute when mutations are observed 13 | const bodyClassChangeCallback = function(mutationsList, observer) { 14 | for(let mutation of mutationsList) { 15 | if (mutation.type === 'attributes' && mutation.attributeName === 'class') { 16 | // Class attribute has changed 17 | // Update all Monaco Editors on the page 18 | updateMonacoEditorTheme(); 19 | } 20 | } 21 | }; 22 | 23 | // Create an observer instance linked to the callback function 24 | const observer = new MutationObserver(bodyClassChangeCallback); 25 | 26 | // Start observing the target node for configured mutations 27 | observer.observe(body, observerOptions); 28 | } 29 | 30 | // Function to update all instances of Monaco Editors on the page 31 | function updateMonacoEditorTheme() { 32 | // Determine what VS Theme to use 33 | const vsThemeToUse = document.body.classList.contains("quarto-dark") ? 'vs-dark' : 'vs' ; 34 | 35 | // Iterate through all initialized Monaco Editors 36 | qwebrEditorInstances.forEach( function(editorInstance) { 37 | editorInstance.updateOptions({ theme: vsThemeToUse }); 38 | }); 39 | } 40 | 41 | // Call the function to start observing changes to body class 42 | updateMonacoEditorsOnBodyClassChange(); -------------------------------------------------------------------------------- /_extensions/webr/template.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "WebR-enabled code cell" 3 | format: html 4 | engine: knitr 5 | #webr: 6 | # show-startup-message: false # Disable display of webR initialization state 7 | # show-header-message: true # Display whether COOP&COEP headers are set for speed. 8 | # packages: ['ggplot2', 'dplyr'] # Pre-install dependencies 9 | # autoload-packages: false # Disable automatic library calls on R packages specified in packages. 10 | # repos: # Specify repositories to check for custom packages 11 | # - https://github-username.github.io/reponame 12 | # - https://username.r-universe.dev 13 | # channel-type: 'post-message' # Specify a specific communication channel type. 14 | # home-dir: "/home/rstudio" # Customize where the working directory is 15 | # base-url: '' # Base URL used for downloading R WebAssembly binaries 16 | # service-worker-url: '' # URL from where to load JavaScript worker scripts when loading webR with the ServiceWorker communication channel. 17 | filters: 18 | - webr 19 | --- 20 | 21 | ## Demo 22 | 23 | This is a webr-enabled code cell in a Quarto HTML document. 24 | 25 | ```{webr-r} 26 | 1 + 1 27 | ``` 28 | 29 | ```{webr-r} 30 | fit = lm(mpg ~ am, data = mtcars) 31 | summary(fit) 32 | ``` 33 | 34 | ```{webr-r} 35 | plot(pressure) 36 | ``` 37 | -------------------------------------------------------------------------------- /_publish.yml: -------------------------------------------------------------------------------- 1 | - source: webr-demo.qmd 2 | quarto-pub: 3 | - id: 2ae0a31d-b315-4617-a8a4-cda96a9abd3c 4 | url: 'https://coatless.quarto.pub/webr-enabled-code-cells' 5 | - source: webr-channel-type.qmd 6 | quarto-pub: 7 | - id: 9a6782cc-7f9a-4773-a43b-ddeae9944dfb 8 | url: 'https://coatless.quarto.pub/webr-communication-channel-options' 9 | - source: webr-internal-cell.qmd 10 | quarto-pub: 11 | - id: 9a086f67-3a62-4ac6-bd63-a5987751855a 12 | url: 'https://coatless.quarto.pub/hidden-webr-code-cells' 13 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | quarto-webr.thecoatlessprofessor.com -------------------------------------------------------------------------------- /docs/_extensions: -------------------------------------------------------------------------------- 1 | ../_extensions -------------------------------------------------------------------------------- /docs/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: website 3 | resources: 4 | - CNAME 5 | 6 | website: 7 | title: "quarto-webr" 8 | reader-mode: true 9 | repo-url: https://github.com/coatless/quarto-webr 10 | repo-actions: [edit, issue] 11 | repo-subdir: "docs" 12 | google-analytics: "G-S8CXP9TZG0" 13 | sidebar: 14 | style: "floating" 15 | search: true 16 | tools: 17 | - icon: github 18 | href: https://github.com/coatless/quarto-webr/ 19 | contents: 20 | - section: "Getting Started" 21 | contents: 22 | - href: qwebr-first-steps.qmd 23 | text: Your first webR-powered Quarto document 24 | - href: qwebr-code-cell-demos.qmd 25 | text: Exploring Interactive Code Cells 26 | - href: qwebr-using-r-packages.qmd 27 | text: Using R Packages 28 | - href: qwebr-internal-cell.qmd 29 | text: Hiding and Executing Code 30 | - href: qwebr-loading-data.qmd 31 | text: Loading Data 32 | - section: "Options Reference" 33 | contents: 34 | - href: qwebr-meta-options.qmd 35 | text: Document Options 36 | - href: qwebr-cell-options.qmd 37 | text: Code Cell Options 38 | - section: "Demos" 39 | contents: 40 | - href: demos/qwebr-feature-demos.qmd 41 | text: Feature Demos 42 | - href: qwebr-community-examples.qmd 43 | text: Community Examples 44 | - section: "Deployment" 45 | contents: 46 | - href: qwebr-deployment-templates.qmd 47 | text: Templates 48 | - href: qwebr-theming.qmd 49 | text: Theming Elements 50 | - href: qwebr-communication-channels.qmd 51 | text: Communication Channels 52 | - section: "Support" 53 | contents: 54 | - href: qwebr-troubleshooting.qmd 55 | text: Troubleshooting 56 | - href: qwebr-faq.qmd 57 | text: FAQ 58 | - href: https://github.com/coatless/quarto-webr/issues/new 59 | text: Submit an issue 60 | - section: "Extra Information" 61 | contents: 62 | - href: qwebr-release-notes.qmd 63 | text: Release Notes 64 | - href: qwebr-acknowledgements.md 65 | text: Acknowledgements 66 | - href: qwebr-developer-resources.qmd 67 | text: Developer Resources 68 | - href: qwebr-extension-website.qmd 69 | text: Extension Website Notes 70 | - href: https://quarto-webr.thecoatlessprofessor.com/tests/ 71 | text: Test Suite 72 | announcement: 73 | icon: info-circle 74 | dismissable: true 75 | content: "Looking for the official Quarto WebAssembly backend? Check out [`quarto-live`](https://github.com/r-wasm/quarto-live)!" 76 | type: primary 77 | body-footer: | 78 | :::{.callout-important} 79 | This Quarto extension is open source software and is **not affiliated with** Posit, Quarto, or webR. The extension is at best a community effort to simplify the integration of webR inside of Quarto generated documents. 80 | ::: 81 | 82 | format: 83 | html: 84 | toc: true 85 | 86 | # Allow quarto to switch between light and dark themes. 87 | theme: 88 | light: cosmo 89 | dark: darkly -------------------------------------------------------------------------------- /docs/demos/qwebr-auto-run.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Demo: Autorun Interactive Code Cells" 3 | engine: knitr 4 | webr: 5 | packages: ['ggplot2', 'gapminder'] 6 | filters: 7 | - webr 8 | --- 9 | 10 | # Overview 11 | 12 | This demo showcases the functionality of automatically executing code within an interactive area, revealing output before any modifications can be made to the document. 13 | 14 | ## `autorun` Option 15 | 16 | The `autorun` option works in tandem with the `interactive` context, enabling a non-interactive execution of code within the editable code area before any changes can be made to the area. 17 | 18 | To illustrate, let's imagine a situation where you are prompted to modify the statement "Hello ___!" In the default view of an interactive cell, the results are not initially displayed. 19 | 20 | ::: {.panel-tabset group="autoRunExmple"} 21 | #### `{quarto-webr}` Output 22 | ```{webr-r} 23 | #| context: interactive 24 | # Write your name here by replace ___ 25 | name <- "_____" 26 | print(paste0("Hello, ", name, "!")) 27 | ``` 28 | #### Cell Code 29 | ````md 30 | ```{webr-r} 31 | #| context: interactive 32 | # Write your name here by replace ___ 33 | name <- "_____" 34 | print(paste0("Hello, ", name, "!")) 35 | ``` 36 | ```` 37 | ::: 38 | 39 | By including `#| autorun: true`, we enable the display of results when the document first loads. Revisiting the previous example, the editable code area now presents a distinct output, prompting the user to "Fill in the blanks": 40 | 41 | ::: {.panel-tabset group="autoRunExmple"} 42 | #### `{quarto-webr}` Output 43 | ```{webr-r} 44 | #| context: interactive 45 | #| autorun: true 46 | # Write your name here by replace ___ 47 | name <- "_____" 48 | print(paste0("Hello, ", name, "!")) 49 | ``` 50 | #### Cell Code 51 | ````md 52 | ```{webr-r} 53 | #| context: interactive 54 | #| autorun: true 55 | # Write your name here by replace ___ 56 | name <- "_____" 57 | print(paste0("Hello, ", name, "!")) 58 | ``` 59 | ```` 60 | ::: 61 | 62 | 63 | ## Target Practice 64 | 65 | One key use of the non-interactive areas is to generate a targeted outcome and have iterative attempts to reach the desired output. 66 | 67 | For example, consider the `gapminder` data set. 68 | 69 | ::: {.panel-tabset group="gapminderRecreate"} 70 | #### `{quarto-webr}` Output 71 | ```{webr-r} 72 | #| context: output 73 | data("gapminder", package = "gapminder") 74 | head(gapminder) 75 | ``` 76 | #### Cell Code 77 | ```{{webr-r}} 78 | #| context: output 79 | data("gapminder", package = "gapminder") 80 | head(gapminder) 81 | ``` 82 | ::: 83 | 84 | How can we use `gapminder` data to re-create the following `ggplot2` graph? 85 | 86 | 87 | ::: {.panel-tabset} 88 | #### `{quarto-webr}` Output 89 | ```{webr-r} 90 | #| context: output 91 | #| fig-width: 5 92 | #| fig-height: 3 93 | #| out-width: 500px 94 | ggplot(gapminder, aes(lifeExp)) + 95 | geom_density(aes(fill=continent), alpha=1/4) + theme_bw() 96 | ``` 97 | #### Cell Code 98 | ```{{webr-r}} 99 | #| context: output 100 | #| fig-width: 5 101 | #| fig-height: 3 102 | #| out-width: 500px 103 | ggplot(gapminder, aes(lifeExp)) + 104 | geom_density(aes(fill=continent), alpha=1/4) + theme_bw() 105 | ``` 106 | ::: 107 | 108 | We've provided a code area for you to explore creating different kinds of graphs and have already run its contents! 109 | 110 | ::: {.panel-tabset} 111 | #### `{quarto-webr}` Output 112 | ```{webr-r} 113 | #| context: interactive 114 | #| autorun: true 115 | #| fig-width: 5 116 | #| fig-height: 3 117 | #| out-width: 500px 118 | ggplot(gapminder, aes(lifeExp)) + 119 | theme_bw() 120 | ``` 121 | #### Cell Code 122 | ```{{webr-r}} 123 | #| context: interactive 124 | #| autorun: true 125 | #| fig-width: 5 126 | #| fig-height: 3 127 | #| out-width: 500px 128 | ggplot(gapminder, aes(lifeExp)) + 129 | theme_bw() 130 | ``` 131 | ::: 132 | 133 | # Fin 134 | 135 | This demo illustrated the ease with which an interactive editable code area can seamlessly transition into a non-interactive mode, allow its results to be shown when the page loads. 136 | 137 | -------------------------------------------------------------------------------- /docs/demos/qwebr-code-cell-options.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Demo: Initial Code Cell Option Support" 3 | engine: knitr 4 | webr: 5 | packages: ['knitr', 'tinyplot'] 6 | repos: 7 | - https://grantmcdermott.r-universe.dev 8 | filters: 9 | - webr 10 | --- 11 | 12 | # Overview 13 | 14 | In this document, we will explore and demonstrate the various cell options available in `{webr-r}` code blocks. These options allow you to customize the behavior and appearance of your code outputs. These options can only be set during the authoring stage of the document. 15 | 16 | ## `context` Option 17 | 18 | The `context` option specifies how the cell should operate on the page. Let's use it to create an interactive code editor: 19 | 20 | ::: {.panel-tabset group="language"} 21 | #### `{quarto-webr}` Output 22 | ```{webr-r} 23 | #| context: interactive 24 | # Write your name here by replace ___ 25 | name <- "_____" 26 | print(paste0("Hello, ", name, "!")) 27 | ``` 28 | #### Cell Code 29 | ````md 30 | ```{webr-r} 31 | #| context: interactive 32 | 33 | # Write your name here by replace ___ 34 | name <- "_____" 35 | print(paste0("Hello, ", name, "!")) 36 | ``` 37 | ```` 38 | ::: 39 | 40 | In this code block, the `context: interactive` option is applied, allowing users to interactively input their name. 41 | 42 | Next, let's use the `context: setup` option to create a data set that can be used by later cells. 43 | 44 | ::: {.panel-tabset group="language"} 45 | #### `{quarto-webr}` Output 46 | ```{webr-r} 47 | #| context: setup 48 | 49 | # Generating a simple table 50 | data <- data.frame( 51 | Name = c("Alice", "Bob", "Charlie"), 52 | Age = c(25, 30, 22) 53 | ) 54 | ``` 55 | #### Cell Code 56 | ````md 57 | ```{webr-r} 58 | #| context: setup 59 | 60 | # Generating a simple table 61 | data <- data.frame( 62 | Name = c("Alice", "Bob", "Charlie"), 63 | Age = c(25, 30, 22) 64 | ) 65 | ``` 66 | ```` 67 | ::: 68 | 69 | :::{.callout-note} 70 | Once a `context:setup` is done running, the visual indicator will be removed from the document. 71 | ::: 72 | 73 | In a later block, we'll see a `context: output` that will only display the results. 74 | 75 | ## `results` Option 76 | 77 | The `results` option controls how text results are displayed. Let's use it to display raw text output: 78 | 79 | ::: {.panel-tabset group="language"} 80 | #### `{quarto-webr}` Output 81 | ```{webr-r} 82 | #| context: interactive 83 | #| results: asis 84 | knitr::kable(data, "html") 85 | ``` 86 | 87 | #### Cell Code 88 | ````md 89 | ```{webr-r} 90 | #| context: interactive 91 | #| results: asis 92 | knitr::kable(data, "html") 93 | ``` 94 | ```` 95 | ::: 96 | 97 | In the above code block, the `results: asis` option is used to display the raw text output of the `data` dataframe. 98 | 99 | If we use `results: markup`, then we'll end up seeing the HTML output: 100 | 101 | 102 | ::: {.panel-tabset group="language"} 103 | #### `{quarto-webr}` Output 104 | 105 | ```{webr-r} 106 | #| context: interactive 107 | #| results: markup 108 | knitr::kable(data, "html") 109 | ``` 110 | #### Cell Code 111 | ````md 112 | ```{webr-r} 113 | #| context: interactive 114 | #| results: markup 115 | 116 | knitr::kable(data, "html") 117 | ``` 118 | ```` 119 | ::: 120 | 121 | ## `fig-width` and `fig-height` Option 122 | 123 | The `fig-width` and `fig-height` options control the width and height of the plot generated in the code block. Let's use it to create a plot with a specific width: 124 | 125 | ::: {.panel-tabset group="language"} 126 | #### `{quarto-webr}` Output 127 | ```{webr-r} 128 | #| context: output 129 | #| fig-width: 6 130 | #| fig-height: 6 131 | 132 | tinyplot::tinyplot( 133 | ~ Petal.Length | Species, 134 | data = iris, 135 | type = "density", 136 | palette = "dark", fill = "by", 137 | grid = TRUE, 138 | main = "Distribution of petal lengths by species" 139 | ) 140 | ``` 141 | #### Cell Code 142 | ````md 143 | ```{webr-r} 144 | #| context: output 145 | #| fig-width: 6 146 | #| fig-height: 6 147 | 148 | # Generating a bar plot with a specific width 149 | tinyplot::tinyplot( 150 | ~ Petal.Length | Species, 151 | data = iris, 152 | type = "density", 153 | palette = "dark", fill = "by", 154 | grid = TRUE, 155 | main = "Distribution of petal lengths by species" 156 | ) 157 | ``` 158 | ```` 159 | ::: 160 | 161 | Here, the `fig-width: 6` and `fig-height: 6` option is utilized to set the width of the bar plot. 162 | 163 | In comparison, we have the default option of `7`: 164 | 165 | ::: {.panel-tabset group="language"} 166 | #### `{quarto-webr}` Output 167 | ```{webr-r} 168 | #| context: output 169 | 170 | tinyplot::tinyplot( 171 | ~ Petal.Length | Species, 172 | data = iris, 173 | type = "density", 174 | palette = "dark", fill = "by", 175 | grid = TRUE, 176 | main = "Distribution of petal lengths by species" 177 | ) 178 | ``` 179 | #### Cell Code 180 | ````md 181 | ```{webr-r} 182 | #| context: output 183 | 184 | tinyplot::tinyplot( 185 | ~ Petal.Length | Species, 186 | data = iris, 187 | type = "density", 188 | palette = "dark", fill = "by", 189 | grid = TRUE, 190 | main = "Distribution of petal lengths by species" 191 | ) 192 | ``` 193 | ```` 194 | ::: 195 | 196 | ## `out-width` and `out-height` Option 197 | 198 | The `out-width` and `out-height` options control physical space the plot will reside in. Let's revisit our previous example and constrain the output area by specifying `out-width: 500px` and `out-height: 500px`. 199 | 200 | 201 | ::: {.panel-tabset group="language"} 202 | #### `{quarto-webr}` Output 203 | ```{webr-r} 204 | #| context: output 205 | #| fig-width: 6 206 | #| fig-height: 6 207 | #| out-width: 500px 208 | #| out-height: 500px 209 | tinyplot::tinyplot( 210 | ~ Petal.Length | Species, 211 | data = iris, 212 | type = "density", 213 | palette = "dark", fill = "by", 214 | grid = TRUE, 215 | main = "Distribution of petal lengths by species" 216 | ) 217 | ``` 218 | #### Cell Code 219 | ````md 220 | ```{webr-r} 221 | #| context: output 222 | #| fig-width: 5 223 | #| fig-height: 5 224 | #| out-width: 500px 225 | #| out-height: 400px 226 | tinyplot::tinyplot( 227 | ~ Petal.Length | Species, 228 | data = iris, 229 | type = "density", 230 | palette = "dark", fill = "by", 231 | grid = TRUE, 232 | main = "Distribution of petal lengths by species" 233 | ) 234 | ``` 235 | ```` 236 | ::: 237 | 238 | 239 | ## Conclusion 240 | 241 | These examples demonstrate the versatility of `{webr-r}` cell options in customizing code block behavior and output. By incorporating these options into your documents, you can enhance the interactivity and visual presentation of your R code. 242 | 243 | Feel free to experiment with different combinations of these options to suit your specific needs! 244 | -------------------------------------------------------------------------------- /docs/demos/qwebr-custom-repository.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Demo: Custom R WASM Package Repository" 3 | engine: knitr 4 | webr: 5 | packages: ['demorwasmbinary'] 6 | repos: 7 | - https://tutorials.thecoatlessprofessor.com/webr-unified-gh-workflow/ 8 | filters: 9 | - webr 10 | --- 11 | 12 | # Overview 13 | 14 | In this example, we add a custom R WASM Package repository that contains `demorwasmbinary` R WASM package. The package is not available from the [main webR repository](https://repo.r-wasm.org/). 15 | 16 | The source of the custom repository can be viewed [here](https://github.com/coatless-tutorials/webr-unified-gh-workflow) and the rendered website using {pkgdown} can be viewed [here](https://tutorials.thecoatlessprofessor.com/webr-unified-gh-workflow/). Another approach would be to use [r-universe.dev](https://ropensci.org/blog/2023/11/17/runiverse-wasm/) 17 | to automatically build and supply R WASM package binaries. 18 | 19 | ## Specify `repos` key 20 | 21 | To automatically have the package installed and loaded like normal, please specify the name of the package in `packages` and where the custom repository is in `repos`. 22 | 23 | For this example, we would specify: 24 | 25 | ```yaml 26 | --- 27 | webr: 28 | packages: ['demorwasmbinary'] 29 | repos: 30 | - https://tutorials.thecoatlessprofessor.com/webr-unified-gh-workflow/ 31 | --- 32 | ``` 33 | 34 | :::{.callout-note} 35 | This version will ensure that any `webr-r` code cells inside of the document are not run prior to the package being present. 36 | ::: 37 | 38 | ## Specify `repos` in `webr::install()` 39 | 40 | Alternatively, we can avoid registering a repository and directly install 41 | from a custom repository by using `webr::install(pkg, repos = "...")`. 42 | 43 | For example, we can re-create the above statement using: 44 | 45 | ````md 46 | ```{webr-r} 47 | # context: setup 48 | # Install the binary from a custom repository 49 | webr::install( 50 | "demorwasmbinary", 51 | repos = "https://tutorials.thecoatlessprofessor.com/webr-unified-gh-workflow/" 52 | ) 53 | 54 | library("demorwasmbinary") 55 | ``` 56 | ```` 57 | 58 | # Explore the package 59 | 60 | Finally, let's use the package within a regular webR code cell, e.g. 61 | 62 | ```{webr-r} 63 | #| context: interactive 64 | # Check to see if the function works 65 | demorwasmbinary::in_webr() 66 | 67 | # View help documentation 68 | ?demorwasmbinary::in_webr 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/demos/qwebr-feature-demos.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Feature Demonstrations" 3 | --- 4 | 5 | Below is a list of different demonstrations of the extensions features. These demos were created to showcase different feature releases. 6 | 7 | - [Editor Options](qwebr-editor-options.qmd) 8 | - [Set Global Cell Options](qwebr-global-cell-defaults.qmd) 9 | - [Read-only Interactive Code Cells](qwebr-read-only.qmd) 10 | - [Autorun Interactive Code Cells](qwebr-auto-run.qmd) 11 | - [Initial Code Cell Option Support](qwebr-code-cell-options.qmd) 12 | - [Using Custom Repositories for R WASM Package binaries](qwebr-custom-repository.qmd) 13 | - [Revamped Noninteractive Areas](qwebr-non-interactive-areas.qmd) 14 | - [webR in RevealJS](https://quarto-webr.thecoatlessprofessor.com/examples/revealjs) 15 | - [Locking interactive areas when long runtime is present](qwebr-long-running-execution-interactive-locking.qmd) 16 | - [Setting Options in Document Header](qwebr-setting-options-in-document-yaml.qmd) 17 | - [webR in Quarto HTML Documents](https://quarto-webr.thecoatlessprofessor.com/examples/readme/) -------------------------------------------------------------------------------- /docs/demos/qwebr-global-cell-defaults.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Demo: Set Global Cell Options" 3 | engine: knitr 4 | webr: 5 | cell-options: 6 | out-width: "100%" 7 | autorun: true 8 | read-only: true 9 | filters: 10 | - webr 11 | --- 12 | 13 | :::{.callout-important} 14 | This feature is currently experimental and is included in 0.4.2-dev.1 build of `{quarto-webr}`. 15 | ::: 16 | 17 | # Overview 18 | 19 | This demo illustrates how to set cell-level options for the entire document by specifying them in the document header. Once established, these options govern the behavior and appearance of `{webr-r}` code cells. However, they can be overridden locally by specifying cell options within individual `{webr-r}` cells. 20 | 21 | ## `cell-options` Document Key 22 | 23 | To establish default cell behavior, you can utilize the `cell-options` subkey in `webr`. For instance, consider the following structure: 24 | 25 | ```yaml 26 | webr: 27 | cell-options: 28 | : 29 | ``` 30 | 31 | Here, `` and `` represent one of the [supported cell options](../qwebr-cell-options.qmd). 32 | 33 | ## Restricting Access 34 | 35 | An example use case is to prevent modifications to interactive code cells while ensuring their content is executed. In this document, we've defined the global behavior with: 36 | 37 | ```md 38 | --- 39 | title: "Demo: Set Global Cell Options" 40 | engine: knitr 41 | webr: 42 | cell-options: 43 | out-width: "100%" 44 | autorun: true 45 | read-only: true 46 | filters: 47 | - webr 48 | --- 49 | ``` 50 | 51 | Let's observe the outcome with a cell like this: 52 | 53 | ::: {.panel-tabset group="language"} 54 | #### `{quarto-webr}` Output 55 | ```{webr-r} 56 | fit = lm(mpg ~ am, data = mtcars) 57 | summary(fit) 58 | ``` 59 | #### Cell Code 60 | ````md 61 | ```{webr-r} 62 | fit = lm(mpg ~ am, data = mtcars) 63 | summary(fit) 64 | ``` 65 | ```` 66 | ::: 67 | 68 | Attempting to modify the cell will be ineffective. However, in the subsequent cell, we've specified a local option that overrides the document's default, allowing modification. Feel free to try modifying the cell below. 69 | 70 | ::: {.panel-tabset group="language"} 71 | #### `{quarto-webr}` Output 72 | ```{webr-r} 73 | #| read-only: false 74 | plot(fit) 75 | ``` 76 | #### Cell Code 77 | ````md 78 | ```{webr-r} 79 | #| read-only: false 80 | plot(fit) 81 | ``` 82 | ```` 83 | ::: 84 | 85 | # Conclusion 86 | 87 | This approach eliminates the need to repeatedly specify options across multiple cells within the document, consolidating them in a single location. Should the need arise, you can always override the behavior by specifying a local value for the cell. -------------------------------------------------------------------------------- /docs/demos/qwebr-long-running-execution-interactive-locking.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Demo: Locking interactive code" 3 | engine: knitr 4 | filters: 5 | - webr 6 | --- 7 | 8 | :::{.callout-important} 9 | We've slowed down each cell's execution time by 5 seconds by adding `Sys.sleep()` to emphasize code cell locking. 10 | ::: 11 | 12 | # Say Hi 13 | 14 | ```{webr-r} 15 | #| context: interactive 16 | print("Hello {quarto-webr} world!") 17 | Sys.sleep(5) # Sleep for 5 seconds 18 | ``` 19 | 20 | # Calculate 21 | 22 | ```{webr-r} 23 | #| context: interactive 24 | -3 + 5 25 | Sys.sleep(5) # Sleep for 5 seconds 26 | ``` 27 | 28 | # Help! 29 | 30 | ```{webr-r} 31 | #| context: interactive 32 | ?mean 33 | Sys.sleep(5) # Sleep for 5 seconds 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /docs/demos/qwebr-non-interactive-areas.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Demo: Revamped Noninteractive Areas" 3 | engine: knitr 4 | webr: 5 | packages: ['ggplot2', 'dplyr'] 6 | filters: 7 | - webr 8 | --- 9 | 10 | :::{.callout-important} 11 | We've slowed down each cell's execution time by about 1/2 of a second to show how the document is responding. 12 | ::: 13 | 14 | # Package dependencies 15 | 16 | The `quarto-webr` extension is set to automatically install and load the `ggplot2` and `dplyr` packages by specifying a `packages` key in the document's header. 17 | 18 | # Setup a hidden ggplot2 object 19 | 20 | From there, we're going to use the `context: setup` hidden cell to create a `ggplot2` object that uses the `mtcars` data set with the aesthetic mappings of `x = wt` and `y = mpg` called `g`. 21 | 22 | ```{webr-r} 23 | #| context: setup 24 | g <- ggplot(mtcars, aes(x = wt, y = mpg)) 25 | 26 | Sys.sleep(0.5) 27 | ``` 28 | 29 | # Generate a graph 30 | 31 | Let's move from setup to generating and displaying results by using `g` object created in `setup` within an `output` context: 32 | 33 | ```{webr-r} 34 | #| context: output 35 | g + geom_point() 36 | 37 | Sys.sleep(0.5) 38 | ``` 39 | 40 | # Re-use prior graph object 41 | 42 | Let's also re-use the base `g` but change the aesthetics so that colour is now present. 43 | 44 | ```{webr-r} 45 | #| context: output 46 | g + geom_point(aes(colour = factor(cyl))) 47 | Sys.sleep(0.5) 48 | ``` 49 | 50 | # Work with a hidden setup object 51 | 52 | Finally, let's make sure we can do some interesting things with the interactive session. 53 | 54 | :::{.callout-note} 55 | Changes inside of interactive cells do not propagate backwards in the document. 56 | ::: 57 | 58 | ```{webr-r} 59 | g 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/demos/qwebr-read-only.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Demo: Read-Only Code Cells" 3 | engine: knitr 4 | filters: 5 | - webr 6 | --- 7 | 8 | # Overview 9 | 10 | This demo shows how a code cell can be placed into a read-only mode. 11 | 12 | ## `read-only` Option 13 | 14 | The `read-only` option modifies the `interactive` context such that changes to the cell's code is not possible. 15 | 16 | For example, try modifying the value associated with `age` in the following cell. 17 | 18 | ::: {.panel-tabset group="readOnlyExmple"} 19 | #### `{quarto-webr}` Output 20 | ```{webr-r} 21 | #| context: interactive 22 | #| read-only: true 23 | # Try modifying the age variable 24 | age <- 42 25 | cat("Your age is: ", age, fill = TRUE) 26 | ``` 27 | #### Cell Code 28 | ````md 29 | ```{webr-r} 30 | #| context: interactive 31 | #| read-only: true 32 | # Try modifying age 33 | age <- 42 34 | cat("Your age is: ", age, fill = TRUE) 35 | ``` 36 | ```` 37 | ::: 38 | 39 | ## Constraining Modifications 40 | 41 | We can pair `read-only` with `autorun` to create a constrained example allowing us to focus on a single piece of the code. 42 | 43 | For example, let's say we want to understand what happens when we increase the number of observations randomly sampled from a normal distribution. We could define two interactive cells: 44 | 45 | 1. one cell exposing changes to the number of samples, e.g. `n`; and, 46 | 2. a second cell containing graphing code that is restricted from being modified. 47 | 48 | 49 | ::: {.panel-tabset group="readOnlyExmple"} 50 | #### `{quarto-webr}` Output 51 | 52 | Try different values for `n` by modifying the assignment statement. 53 | ```{webr-r} 54 | #| context: interactive 55 | #| autorun: true 56 | # Experiment with different sample sizes by 57 | # changing the n value and re-running the code 58 | # cell. 59 | n <- 100 60 | ``` 61 | 62 | Then, press "Run Code" to recreate the graph and see how the distribution changed: 63 | 64 | ```{webr-r} 65 | #| context: interactive 66 | #| autorun: true 67 | #| read-only: true 68 | samples = rnorm(n) 69 | hist(samples, 70 | main = "Randomly Sampled Normal Distribution", 71 | sub = paste("Based on", n, "samples"), 72 | xlab = "Sample Value" 73 | ) 74 | ``` 75 | 76 | #### Cell Code 77 | ````md 78 | ```{webr-r} 79 | #| context: interactive 80 | #| autorun: true 81 | # Experiment with different sample sizes by 82 | # changing the n value and re-running the code 83 | # cell. 84 | n <- 100 85 | ``` 86 | ```{webr-r} 87 | #| context: interactive 88 | #| autorun: true 89 | #| read-only: true 90 | samples = rnorm(n) 91 | hist(samples, 92 | main = "Randomly Sampled Normal Distribution", 93 | sub = paste("Based on", n, "samples"), 94 | xlab = "Sample Value" 95 | ) 96 | ``` 97 | ```` 98 | ::: 99 | 100 | # Fin 101 | 102 | In this demo, we saw the possibility of preventing modifications to a code cell area. 103 | -------------------------------------------------------------------------------- /docs/demos/qwebr-setting-options-in-document-yaml.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Demo: Setting Options in Document Header" 3 | format: html 4 | engine: knitr 5 | webr: 6 | packages: ['ggplot2', 'dplyr'] 7 | show-startup-message: true 8 | show-header-message: true 9 | autoload-packages: false 10 | filters: 11 | - webr 12 | --- 13 | 14 | # Demo 15 | 16 | webR-enabled code cells are established by using `{webr-r}` in a Quarto HTML document. 17 | 18 | ```{webr-r} 19 | library("ggplot2") 20 | 21 | ggplot() 22 | ``` -------------------------------------------------------------------------------- /docs/images/rstudio-render-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coatless/quarto-webr/8ad65f045e718ecfd45c0e5b2ec04998dd508c0f/docs/images/rstudio-render-button.png -------------------------------------------------------------------------------- /docs/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: Greetings from quarto-webr Wonderland! 3 | subtitle: Empowering Your Quarto Documents with R through webR 4 | format: html 5 | engine: knitr 6 | filters: 7 | - webr 8 | --- 9 | 10 | Welcome to the documentation portal for the community [`quarto-webr`](https://github.com/coatless/quarto-webr) extension – your key to unlocking the endless possibilities of [webR](https://docs.r-wasm.org/webr/latest/) within various [Quarto](https://quarto.org/) formats, including [HTML](https://quarto.org/docs/output-formats/html-basics.html), [RevealJS](https://quarto.org/docs/presentations/revealjs/), [Websites](https://quarto.org/docs/websites/), [Blogs](https://quarto.org/docs/websites/website-blog.html), and [Books](https://quarto.org/docs/books). 11 | 12 | Ready for an exciting journey into the world of webR's interactive code cells? Click the "Run Code" button below to experience it firsthand: 13 | 14 | ```{webr-r} 15 | # Fit a linear model 16 | model = lm(mpg ~ wt, data = mtcars) 17 | 18 | # Obtain a summary 19 | summary(model) 20 | ``` 21 | 22 | At its core, the community [`quarto-webr` extension](https://github.com/coatless/quarto-webr) is designed to empower you to run R code directly in your web browser using familiar reporting tools, all without the need for an external R server. Moreover, the extension abstracts away the need to know HTML or JavaScript to use webR. However, it's worth noting that you can also choose to unlock the full potential of webR and create more complex applications independently by directly using **[webR's JavaScript API](https://docs.r-wasm.org/webr/latest/evaluating.html)**, granting you unparalleled freedom to harness the power of R in innovative ways. 23 | 24 | With this in mind, let's dive in and kickstart your journey with interactive code cells by [creating our very first webR-powered Quarto document](qwebr-first-steps.qmd) or [exploring some examples](qwebr-code-cell-demos.qmd)! 25 | -------------------------------------------------------------------------------- /docs/qwebr-acknowledgements.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Acknowledgments and Collaborations" 3 | subtitle: "Bringing webR to Quarto" 4 | date: "03-11-2023" 5 | date-modified: last-modified 6 | aliases: 7 | - webr-acknowledgements.html 8 | --- 9 | 10 | We would like to express our heartfelt gratitude to several individuals and teams who played a pivotal role in bringing [`quarto-webr`](https://github.com/coatless/quarto-webr) to life as an extension for Quarto. Without their dedication and contributions, this project would not have been possible. 11 | 12 | ## quarto-webr Extension Core Developers 13 | 14 | - [James Joseph Balamuta](https://github.com/coatless) 15 | - [JooYoung Seo](https://github.com/jooyoungseo) for accessibility improvements. 16 | 17 | They played a pivotal role in shaping the development of this Quarto extension. 18 | 19 | ## webR Core Developers 20 | 21 | - [George Stagg](https://github.com/georgestagg) 22 | - [Lionel Henry](https://github.com/lionel-) 23 | 24 | Their tireless efforts and expertise in developing [webR](https://docs.r-wasm.org/webr/latest/) were instrumental in being able to even develop this extension for Quarto. We are immensely grateful for their contribution of the webR project. Further, we greatly appreciate them answering our questions and providing guidance throughout the development process. 25 | 26 | ## Early Testing Feedback 27 | 28 | We extend our sincere appreciation to the following individuals for providing early testing feedback on the extension: 29 | 30 | - [Eli E. Holmes](https://eeholmes.github.io/) 31 | - [Bob Rudis](https://rud.is/) 32 | 33 | Their insightful feedback and suggestions have been invaluable in refining and enhancing the functionality of the extension. 34 | 35 | ## Quarto Team Assistance 36 | 37 | We would like to acknowledge the Quarto team for their assistance in setting up a new code cell type, which greatly improved the overall functionality of the extension. You can view the discussion [here](https://github.com/quarto-dev/quarto-cli/discussions/4761#discussioncomment-5336636). 38 | 39 | ## Inspirations 40 | 41 | Our project built upon the initial proof of concept for a standalone Quarto HTML document, made possible by the work of the [coatless-r-n-d/webR-quarto-demos](https://github.com/coatless-r-n-d/webR-quarto-demos) repository. 42 | 43 | Additionally, we were inspired by the following public-facing examples from the webR Core developers that contributed to the initial standalone experiment: 44 | 45 | - [Source of Tidyverse Blog Post](https://github.com/tidyverse/tidyverse.org/pull/617/files) and [Minor fix](https://github.com/tidyverse/tidyverse.org/commit/72bb2dd7ca0b2f211498a891aa54f55ddcad5014) 46 | - [webR documentation landing page](https://github.com/r-wasm/webr/blob/53acd8861c44f1f167941d0a40f62b0cc23852da/src/docs/index.qmd#L23-L68) ([Live page](https://docs.r-wasm.org/webr/latest/)) 47 | 48 | # Fin 49 | 50 | Once again, thank you to everyone who contributed, collaborated, and provided support throughout this project. Your dedication and expertise have made this achievement possible. -------------------------------------------------------------------------------- /docs/qwebr-cell-options.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Code Cell Options" 3 | subtitle: "Supported Cell Options in `{webr-r}` Blocks" 4 | date: "01-30-2024" 5 | date-modified: last-modified 6 | format: 7 | html: 8 | toc: true 9 | engine: knitr 10 | --- 11 | 12 | This article provides an in-depth overview of cell options supported in `{webr-r}` code blocks. These options play a crucial role in influencing the execution and output of executable code blocks. It's important to note that these cell options are specified within comments at the top of a code block by using a hashpipe `#| option: value`. 13 | 14 | Here's an example of how you can use these options: 15 | 16 | ````md 17 | ```{webr-r} 18 | #| results: 'asis' 19 | #| fig-width: 5 20 | 21 | # R code here 22 | ``` 23 | ```` 24 | 25 | In this example, the cell options `results` is set to `'asis'`, and `fig-width` is set to `5` inches. 26 | 27 | These options can be customized to tailor the behavior of the code block based on your specific requirements. Understanding and using these options effectively can enhance the overall control and presentation of your code outputs. 28 | 29 | 30 | :::{.callout-important} 31 | The `{quarto-webr}` extension does not support all of the cell options from [Quarto](https://quarto.org/docs/reference/cells/cells-knitr.html) or [Knitr](https://yihui.org/knitr/options/). Please consult the tables below for details on what is available. 32 | ::: 33 | 34 | ## quarto-webr 35 | 36 | :::{.callout-note} 37 | Options listed here are unique to the `{quarto-webr}` extension and do not have a Quarto equivalent. 38 | ::: 39 | 40 | ### Run Options 41 | 42 | | Option | Default Value | Description | 43 | |----------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 44 | | `context` | `interactive` | Describe how the cell should operate on the page through either `interactive` (Runnable code editor), `output` (Output only of executed at runtime), or `setup` (execute code without seeing output at runtime). | 45 | | `autorun` | `false` | Allow `interactive` cells to be run during document initialization without a user pressing run code. | 46 | 47 | 48 | :::{.callout-note} 49 | For details regarding run options, please see [Hiding and Executing Code](qwebr-internal-cell.qmd). 50 | ::: 51 | 52 | 53 | ### Monaco Editor Options 54 | 55 | | Option | Default Value | Description | 56 | |----------------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| 57 | | `read-only` | `false` | Prevent code in `interactive` cells from being modified by disallowing code input. | 58 | | `editor-max-height` | `0` | Set a threshold to prevent infinite growth of the editor window. | 59 | | `editor-quick-suggestions` | `false` | Show a list of autocomplete variables and/or functions based on what was typed. | 60 | | `editor-font-scale` | `1` | Modify the size of code cell and output relative to the page font size. Values less than 1 shrink the text size and values greater than 1 increase the text size. | 61 | | `editor-word-wrap` | `true` | Allow long lines to be wrapped to avoid code going off the screen causing a scroll bar to appear. | 62 | 63 | 64 | 65 | ## Attributes 66 | 67 | | Option | Default Value | Description | 68 | |-----------|---------------|---------------------------------------------------| 69 | | `label` | `''` | Unique label for code cell. Useful for debugging. | 70 | | `classes` | `''` | Classes to apply to cell container | 71 | 72 | ## Cell Output 73 | 74 | | Option | Default Value | Description | 75 | |-----------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 76 | | `results` | `markup` | Controls how to display the text results through either: `markup` (Mark up text output with appropriate environments), `asis` (Write text output as-is, raw text results directly into the output document), or `hide` (Hide text output). | 77 | | `output` | `true` | Controls inclusion of results: `true` (all results), `false` (no results), or `'asis'` (output as-is, raw text results directly into the output document). | 78 | | `warning` | `true` | Preserve standard error output (`warning()`, `message()`, or `stop()`) in the output. | 79 | | `message` | `true` | See prior entry. | 80 | 81 | 82 | :::{.callout-important} 83 | At the present time, we cannot differentiate between the type of condition being sent to standard error. Thus, if either `warning` or `message` is set to `false`, the output for both will be surpressed. 84 | ::: 85 | 86 | ## Figures 87 | 88 | | Option | Default Value | Description | 89 | |--------------|---------------|-------------------------------------------------------------------------------------------------------------------------------| 90 | | `fig-cap` | `""` | Figure caption that should appear under the canvas | 91 | | `dpi` | `72` | Dots per inch to use in calculating pixel values for `fig-height` and `fig-width`, e.g. `dpi * inches = pixels`. | 92 | | `fig-width` | `7` | Width of the plot (in inches) | 93 | | `fig-height` | `5` | Height of the plot (in inches) | 94 | | `out-width` | `700px` | Width of the plot in the output document, which can be different from its physical `fig-width` such as `"100%"` or `"250px"`. | 95 | | `out-height` | `""` | Height of the plot in the output document, similar to `out-width`. | 96 | -------------------------------------------------------------------------------- /docs/qwebr-code-cell-demos.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Exploring Interactive Code Cells" 3 | subtitle: "Unleash the Power of Interactive R Code in Your Quarto Documents" 4 | author: "James Joseph Balamuta" 5 | date: "03-14-2023" 6 | date-modified: last-modified 7 | format: 8 | html: 9 | toc: true 10 | engine: knitr 11 | filters: 12 | - webr 13 | aliases: 14 | - webr-code-cell-demos.html 15 | --- 16 | 17 | Welcome to the world of interactive code cells, unlocked by the community `quarto-webr` extension. These cells allow you to run R code directly within your Quarto HTML documents, enabling real-time computations, dynamic visualizations, and more. Let's explore the impressive capabilities webR offers. 18 | 19 | # Creating webR-Enabled Code Cells 20 | 21 | To create a webR-enabled code cell, simply use the `{webr-r}` tag in your Quarto HTML document, like this: 22 | 23 | ```{webr-r} 24 | 1 + 1 25 | ``` 26 | 27 | For example, the code cell above, powered by `webr`, was generated by entering the following into the Quarto document: 28 | 29 | ```{{webr-r}} 30 | 1 + 1 31 | ``` 32 | 33 | # Sample Use Cases 34 | 35 | Now, let's delve into some practical scenarios where interactive code cells shine. 36 | 37 | ## Fit a Linear Regression Model 38 | 39 | We begin by using the "Hello World" example of statistics: fitting and analyzing a linear regression. 40 | 41 | ```{webr-r} 42 | fit <- lm(mpg ~ vs, data = mtcars) 43 | 44 | summary(fit) 45 | ``` 46 | 47 | ## Line-by-line Execution 48 | 49 | In this section, we'll explore the built-in keyboard shortcuts for executing code within the interactive code cell. You can run either the selected code or specific lines or the entire cell with the following keyboard shortcuts: 50 | 51 | - Run selected code: 52 | - macOS: + ↩/Return 53 | - Windows/Linux: Ctrl + ↩/Enter 54 | 55 | - To run the entire code cell, you can simply click the "Run code" button, or use the keyboard shortcut: 56 | - Shift + 57 | 58 | Feel free to try it out in the following code cell: 59 | 60 | ```{webr-r} 61 | # Try running selected code at the start of the line 62 | print("Hello quarto-webr World!") 63 | 64 | # Try highlight only -3 or 5 and pressing the keys required 65 | # for the "selected code" approach 66 | -3 + 5 67 | 68 | # Finally, try running the entire code cell by using Shift + ↩ 69 | ``` 70 | 71 | By using these shortcuts, you can run code conveniently and efficiently. This practice can also help you become familiar with keyboard shortcuts when transitioning to integrated development environments (IDEs) like [RStudio](https://posit.co/products/open-source/rstudio/) or [Visual Studio Code with R](https://code.visualstudio.com/docs/languages/r). 72 | 73 | 74 | ## Preventing Modifications to Code 75 | 76 | Code cells can be locked to their initial state by specifying `#| read-only: true`. The next code cell has such a feature implemented. Try modifying the expression `1 + 1` to any other value. 77 | 78 | ::: {.panel-tabset} 79 | ## `{quarto-webr}` Output 80 | 81 | ```{webr-r} 82 | #| read-only: true 83 | 1 + 1 84 | ``` 85 | 86 | ## Cell code 87 | 88 | ```{{webr-r}} 89 | #| read-only: true 90 | 1 + 1 91 | ``` 92 | ::: 93 | 94 | :::{.callout-note} 95 | This option can be paired with `autorun: true` to avoid having the user press the "Run code" button to see the output. 96 | ::: 97 | 98 | 99 | ## Drawing Attention to Code 100 | 101 | Lines of code can be highlighted using `editor-code-line-numbers` to draw attention to specific parts of the code. For example: 102 | 103 | - `editor-code-line-numbers: 1-3` will highlight lines 1 to 3. 104 | - `editor-code-line-numbers: 1,3,6` will highlight lines 1, 3, and 6. 105 | - `editor-code-line-numbers: 1,3-5,7` will highlight lines 1, 3 to 5, and 7. 106 | 107 | We can see the `1,3-5,7` example in the following code cell: 108 | 109 | ::: {.panel-tabset} 110 | ## `{quarto-webr}` Output 111 | 112 | ```{webr-r} 113 | #| read-only: true 114 | #| editor-code-line-numbers: 1,3-5,7 115 | 116 | # This is a comment 117 | 118 | 1 + 1 119 | 2 + 2 120 | 3 + 3 121 | 122 | # This is another comment 123 | ``` 124 | 125 | ## Cell code 126 | 127 | ```{{webr-r}} 128 | #| read-only: true 129 | #| editor-code-line-numbers: 1,3-5,7 130 | 131 | # This is a comment 132 | 133 | 1 + 1 134 | 2 + 2 135 | 3 + 3 136 | 137 | # This is another comment 138 | ``` 139 | ::: 140 | 141 | 142 | ## Create a Graph with Base R 143 | 144 | For this example, webR empowers us to create and visualize data plots interactively. We can tweak labels, colors, or even the variables being used on an as-needed basis to explore "What if ..." scenarios. For instance, what if we try changing the value `blue` to `orange` and run the code again. 145 | 146 | ```{webr-r} 147 | plot( 148 | mpg ~ wt, 149 | data = mtcars, 150 | col = "blue", 151 | xlab = "Miles/(US) gallon", 152 | ylab = "Weight (1000 lbs)", 153 | main = "Miles per Gallon and Weight of Cars", 154 | sub = "Source: 1974 Motor Trend US magazine." 155 | ) 156 | ``` 157 | 158 | 159 | 160 | ## Fill in the Blanks 161 | 162 | Another approach is to purposely leave out part of a command during an exercise to afford students structure in solving it. For example, we could have the question of: 163 | 164 | > Fill in the blank to have the following expression add up to **42**. 165 | 166 | ```{webr-r} 167 | 35 + ________ 168 | ``` 169 | 170 | ## Data Wrangle in Real Time 171 | 172 | Data manipulation is a crucial part of data analysis. In this example, we'll modify a data set in real-time and view the results. It's like changing ingredients while cooking to get the perfect dish! 173 | 174 | ```{webr-r} 175 | # Create a copy of the data 176 | mtcars2 <- mtcars 177 | 178 | # Change variable to a factor 179 | mtcars2$vs <- factor(mtcars2$vs, labels = c("V", "S")) 180 | 181 | modified_vs_data = data.frame( 182 | "original_vs" = mtcars$vs, 183 | "modified_vs" = mtcars2$vs 184 | ) 185 | 186 | head(modified_vs_data) 187 | ``` 188 | 189 | 190 | ## Working with R Packages 191 | 192 | You can incorporate R packages available in webR by installing them interactively using `webr::install()` within a `{webr-r}` code cell or by specifying them in the document's YAML. Once you've installed a package, you can harness its power just as you would in a traditional R environment. For more details, please refer to [Using R Packages](qwebr-using-r-packages.qmd). 193 | 194 | :::callout-note 195 | Please note that installing certain packages, such as `ggplot2`, may take some time depending on the [communication channel](qwebr-communication-channels.qmd) being used. 196 | ::: 197 | 198 | Let's take `ggplot2` as an example: 199 | 200 | ```{webr-r} 201 | webr::install("ggplot2") 202 | ``` 203 | 204 | With `ggplot2` now installed, let's create a graph with it! 205 | 206 | ```{webr-r} 207 | library(ggplot2) 208 | 209 | p <- ggplot(mpg, aes(class, hwy)) 210 | p + geom_boxplot() 211 | ``` 212 | 213 | ## Variable Definitions and Reuse 214 | 215 | Define variables in one code cell and reuse them in subsequent cells: 216 | 217 | ```{webr-r} 218 | name <- "James" 219 | age <- 42 220 | ``` 221 | 222 | ```{webr-r} 223 | message(name, " is ", age, " years old!") 224 | ``` 225 | 226 | ## Functions 227 | 228 | Functions can similarly be defined and used in one code cell or multiple code cells. 229 | 230 | ```{webr-r} 231 | say_hello = function(name) { 232 | msg = paste0("Hello ", name, "! Welcome to webR :)") 233 | return(msg) 234 | } 235 | 236 | say_hello("James") 237 | ``` 238 | 239 | ```{webr-r} 240 | say_hello("Hulya") 241 | ``` 242 | 243 | :::callout-note 244 | 245 | The function definition must be run before calling the function. Otherwise, there will be an error that is generated. 246 | ::: 247 | 248 | ## Handling Errors and Warnings 249 | 250 | When webR encounters an error while running R code, the error and warning messages are displayed to the user. 251 | 252 | For example, if the routine has a hard stop, the execution immediately ends, and the message is shared. 253 | 254 | ```{webr-r} 255 | stop("This is a hard error") 256 | ``` 257 | 258 | Similarly, if a variable is not found, then the code stops being evaluated and returns an error. 259 | ```{webr-r} 260 | variable_not_defined 261 | ``` 262 | 263 | Unlike errors, warning messages are allowed to propagate into the output without stopping the computation. 264 | 265 | ```{webr-r} 266 | warning("Uh-oh, there's a warning!") 267 | 268 | # Compute a value 269 | 1 + 1 270 | ``` 271 | 272 | This is even the case inside of complex functions. 273 | 274 | ```{webr-r} 275 | quadratic_roots <- function(a, b, c) { 276 | 277 | cat(paste0("Analyzing the quadratic equation: ", a, "x^2 + ", b, "x + ", c, ".")) 278 | 279 | discriminant <- (b^2) - (4*a*c) 280 | 281 | # Check if there are 2 solutions 282 | if(discriminant != 0) { 283 | 284 | # Are the solutions imaginary? 285 | if(discriminant < 0) { 286 | warning("There are no real-numbered roots for this quadratic equation.") 287 | discriminant <- as.complex(discriminant) 288 | } 289 | 290 | # Compute the solutions 291 | x_intercepts <- (-b + c(-1, 1) * sqrt(discriminant)) / (2*a) 292 | 293 | return(x_intercepts) 294 | } 295 | 296 | # When the discriminant is 0, compute a single solution. 297 | x_intercept <- (-b) / (2*a) 298 | 299 | return(x_intercept) 300 | } 301 | 302 | quadratic_roots(1, 3, 7) 303 | ``` 304 | 305 | ## Escaping Characters in a String 306 | 307 | Handle special characters in strings with ease: 308 | 309 | ```{webr-r} 310 | seven_seas <- "Ahoy, matey!\nLet's set sail for adventure!\n" 311 | seven_seas 312 | ``` 313 | 314 | ## Anonymous Function Definition 315 | 316 | Define and use anonymous functions seamlessly: 317 | 318 | ```{webr-r} 319 | add_one <- \(x) x + 1 320 | add_one(2) 321 | ``` 322 | 323 | ## Empty Code Cell 324 | 325 | Define an empty code cell by simply leaving it blank. 326 | 327 | ```{webr-r} 328 | 329 | ``` 330 | 331 | ## Pre-rendered Code Cell 332 | 333 | Any code using the usual `{r}` tag will be executed, and its output saved, just as if you were rendering a Quarto document without the webR extension: 334 | 335 | ```{r} 336 | message("Hello!") 337 | ``` 338 | 339 | # Fin 340 | 341 | These are just some of the powerful features and capabilities that webR brings to your Quarto HTML documents, making your data analysis and presentation more dynamic and engaging. Have an interesting example to share? Let us know [at our issue tracker](https://github.com/coatless/quarto-webr/issues)! 342 | -------------------------------------------------------------------------------- /docs/qwebr-deployment-templates.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Deployment Templates" 3 | date: "10-01-2023" 4 | date-modified: last-modified 5 | --- 6 | 7 | Discover a range of sample deployment templates for the community `quarto-webr` extension at our [GitHub repository](https://github.com/coatless/quarto-webr/tree/main/examples). These templates serve as convenient starting points for various web-based projects that harness the power of the `quarto-webr` extension, enabling interactive data analysis inside of a web browser. Whether you're embarking on an individual report, creating an interactive website, or compiling a digital book, these templates simplify the process, making it effortless to kickstart your own projects. 8 | 9 | # HTML Document Template 10 | 11 | This template is designed for creating standalone HTML documents with interactive webR functionality. It's suitable for individual reports or interactive documents. 12 | 13 | - **Example**: You can find an example of an HTML document template [here](https://quarto-webr.thecoatlessprofessor.com/examples/html-document/). 14 | - **Source Code**: Access the source code for this template [here](https://github.com/coatless/quarto-webr/tree/main/examples/html-document). 15 | 16 | # RevealJS Presentation Template 17 | 18 | This template is designed for creating standalone RevealJS presentations with interactive webR functionality. It's suitable for creating lecture slides. 19 | 20 | :::{.callout-important} 21 | This template requires a [**pre-release** version of Quarto that is 1.4.502 or greater](https://quarto.org/docs/download/prerelease) that contains an updated copy of `pandoc`. For more details, please see [Issue #14](https://github.com/coatless/quarto-webr/issues/14). 22 | ::: 23 | 24 | - **Example**: You can find an example of a RevealJS presentation template [here](https://quarto-webr.thecoatlessprofessor.com/examples/revealjs/). 25 | - **Source Code**: Access the source code for this template [here](https://github.com/coatless/quarto-webr/tree/main/examples/revealjs). 26 | 27 | # Website Template 28 | 29 | This template is meant for building interactive websites with multiple webR-powered pages. It's ideal for websites that have multiple piece of web content that requires interactive data analysis at the "top-level". 30 | 31 | - **Example**: Explore an example of a website template [here](https://quarto-webr.thecoatlessprofessor.com/examples/website/). 32 | - **Source Code**: Access the source code for this template [here](https://github.com/coatless/quarto-webr/tree/main/examples/website). 33 | 34 | # Blog Template 35 | 36 | For users who want to periodically use webR on their Quarto blog, please use the following template. 37 | 38 | - **Example**: Explore an example of a blog website template [here](https://quarto-webr.thecoatlessprofessor.com/examples/blog/). 39 | - **Source Code**: Access the source code for this template [here](https://github.com/coatless/quarto-webr/tree/main/examples/blog). 40 | 41 | # Book Template 42 | 43 | The book template is designed for creating interactive web-based books or documentation. It allows you to compile a collection of chapters, sections, and interactive content into a cohesive digital book. 44 | 45 | - **Example**: You can view an example of a book template [here](https://quarto-webr.thecoatlessprofessor.com/examples/book). 46 | - **Source Code**: Access the source code for this template [here](https://github.com/coatless/quarto-webr/tree/main/examples/book). 47 | -------------------------------------------------------------------------------- /docs/qwebr-developer-resources.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Developer Resources" 3 | author: "James Joseph Balamuta" 4 | date: "03-14-2023" 5 | date-modified: last-modified 6 | format: 7 | html: 8 | toc: true 9 | --- 10 | 11 | Want to contribute to the `quarto-webr` extension or customize it? This resource page guides you with essential tools and references. 12 | 13 | ## Mastering webR 14 | 15 | Understanding [webR](https://docs.r-wasm.org/webr/latest/), which powers the interactivity, is crucial for developing `quarto-webr`. Review these resources: 16 | 17 | - **[webR Documentation](https://docs.r-wasm.org/webr/latest/)**: Comprehensive guides and examples to deepen your webR knowledge. 18 | - **[webR Source Code](https://github.com/r-wasm/webr/)**: For the technically curious, explore the official webR project's development on GitHub. 19 | - **[Bob Rudis' Experiments with webR](https://rud.is/webr-experiments/)**: Discover diverse projects using the webR JavaScript API. 20 | 21 | These resources will help you master webR and, subsequently, your ability to create interactive code cells in HTML documents. Remember, webR is a versatile tool that can be used independently or alongside the community Quarto extension to unlock the magic of interactive code cells in HTML documents. 22 | 23 | Want to contribute to the `quarto-webr` extension or customize it? This resource page guides you with essential tools and references. 24 | 25 | ## Quarto Development Ecosystem 26 | 27 | For those interested in extending the `quarto-webr` extension or exploring broader extension development within the Quarto ecosystem, we recommend exploring the following supplementary resources. 28 | 29 | ### Quarto Documentation 30 | 31 | Get acquainted with Quarto's official extension documentation to deepen your understanding. 32 | 33 | - **[Filters Documentation](https://quarto.org/docs/extensions/filters.html)**: Learn the art of creating filters for Quarto documents, enabling you to customize content generation. 34 | 35 | - **[Lua Development Tips](https://quarto.org/docs/extensions/lua.html)**: Access development tips specific to Lua scripting within Quarto extensions. 36 | 37 | - **[Lua API](https://quarto.org/docs/extensions/lua-api.html)**: Explore the Lua API documentation to understand how to interact with Quarto's core functionality programmatically. 38 | 39 | ### Related Extensions 40 | 41 | For those intrigued by the broader world of extension development, we suggest the following Quarto extensions that can inspire your journey into extension development and functionality: 42 | 43 | - **[`quarto-ext/shinylive`](https://github.com/quarto-ext/shinylive)**: Explore the `shinylive` extension's codebase to understand how interactive content is implemented within Quarto documents. 44 | 45 | - **[`mcanouil/quarto-elevator`](https://github.com/mcanouil/quarto-elevator)**: Delve into the `quarto-elevator` extension to gain insights into adding new features to Quarto documents. 46 | 47 | - **[`shafayetShafee/downloadthis`](https://github.com/shafayetShafee/downloadthis/tree/main)**: Investigate the `downloadthis` extension to see how it facilitates downloads within Quarto documents. 48 | 49 | There are many more Quarto extensions to explore and learn from. For an up-to-date list, visit: 50 | 51 | 52 | ### Pandoc Essentials 53 | 54 | Pandoc plays a pivotal role in Quarto's document conversion process. To deepen your knowledge of Quarto, consider these Pandoc resources: 55 | 56 | - **[Example Filters](https://pandoc.org/lua-filters.html#examples)**: Draw inspiration from Pandoc's example filters to see how custom filters can be applied to your Quarto documents. 57 | 58 | - **[CodeBlock](https://pandoc.org/lua-filters.html#type-codeblock)**: Understand the significance of the `CodeBlock` element in Pandoc, often used for implementing extensions and custom functionality. 59 | 60 | # Fin 61 | 62 | With this wealth of resources at your disposal, you're well-equipped to embark on your development journey, whether you're diving into webR or contributing to the `quarto-webr` extension. Happy coding! 63 | -------------------------------------------------------------------------------- /docs/qwebr-extension-website.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Extension Website" 3 | subtitle: "Development notes for the quarto-webr website" 4 | author: "James Joseph Balamuta" 5 | date: "09-17-2023" 6 | date-modified: last-modified 7 | format: 8 | html: 9 | toc: true 10 | --- 11 | 12 | # Initializing the Project 13 | 14 | To get started, follow these steps to set up the Quarto extension website project: 15 | 16 | 1. Create a new directory named `docs/` within your repository using the following command: 17 | 18 | ```sh 19 | mkdir docs && cd $_ 20 | ``` 21 | 22 | 2. Initialize a Quarto website project by running the following command: 23 | 24 | ```sh 25 | quarto create project website . 26 | ``` 27 | 28 | # Incorporating the Extension 29 | 30 | To seamlessly integrate the extension into your project, you'll need to create a symbolic link to the `_extensions` folder containing the development version of the extension. This approach helps you avoid maintaining a duplicate copy of the extension in your Git repository history. 31 | 32 | Follow these steps: 33 | 34 | 1. Navigate to the `docs/` directory in your project. 35 | 36 | 2. Create a symbolic link to the `_extensions` folder using the following command: 37 | 38 | ```sh 39 | ln -s ../_extensions _extensions 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /docs/qwebr-faq.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Frequently Asked Questions" 3 | subtitle: "Find Answers to Common Queries About the community `quarto-webr` Extension" 4 | date: "10-01-2023" 5 | date-modified: last-modified 6 | engine: markdown 7 | format: 8 | html: 9 | toc: true 10 | aliases: 11 | - webr-faq.html 12 | --- 13 | 14 | Welcome to our Frequently Asked Questions (FAQ) page, your go-to resource for finding answers to common queries about the community `quarto-webr` extension. If you can't find the answer you're looking for, don't hesitate to reach out to our community for additional support by opening a [question](https://github.com/coatless/quarto-webr/issues/new?assignees=&labels=q%26a&projects=&template=question.yml&title=%5BQ%26A%5D%3A+) or a [bug report](https://github.com/coatless/quarto-webr/issues/new?assignees=&labels=bug%2Ctriage-needed&projects=&template=bug-report.yml&title=%5BBug%5D%3A+) on the [issue tracker](https://github.com/coatless/quarto-webr/issues). 15 | 16 | # Stability and Long Term Support 17 | 18 | > Q. Would you say the quarto-webr extension API is stable? Thinking about starting to convert course notes and wondering where the project is in terms of stability. 19 | 20 | Yes, the `quarto-webr` extension API can be considered stable for most practical purposes. It has undergone significant development and testing to ensure that it functions reliably and consistently within the Quarto framework. You can confidently start converting your course notes and materials using this extension. 21 | 22 | However, it's important to keep in mind a few considerations: 23 | 24 | 1. **Dependency on Quarto and webR projects:** The `quarto-webr` extension relies on the main `webR` project for its core functionality. While we actively maintain the `quarto-webr` extension and aim to keep it compatible with the latest versions of Quarto and `webR`, we cannot control what happens upstream at either project. Changes or updates to either project may occasionally require adjustments in the extension. For the most part, these adjustments will be largely hidden. 25 | 26 | 1. **Version compatibility:** It's important to note that the version of the R client and R packages that is downloaded for `webR` execution may affect your materials. It's advisable to periodically review and update your teaching materials, especially when major changes occur in R version or R package contents, just as before. 27 | 28 | 1. **Start with a small set:** When converting your course materials, it's a good practice to start with a small set of materials as a pilot. This allows you to familiarize yourself with the extension's functionality and raise/address any specific issues that may arise during the conversion process. Once you are comfortable with the workflow and have tested your materials, you should proceed with converting the rest of your course content. 29 | 30 | # Improving Performance 31 | 32 | > Q. What are your plans, if any, for scaling webR to handle complex content faster? 33 | 34 | For handling complex content, we recommend setting the `channel-type` option to the [`'shared-array-buffer'`](qwebr-communication-channels.qmd#sec-shared-array-buffer), which can significantly speed up its execution. This environment requires the proper configuration of HTTP headers for [Cross-Origin Embedder Policy (COEP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy) and [Cross-Origin Opener Policy (COOP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy). By setting these headers correctly, you can already achieve notable speed improvements when working with webR. 35 | 36 | However, for further enhancements and speed optimizations beyond what the COEP and COOP headers provide, we recommend keeping an eye on the [main webR project's documentation](https://docs.r-wasm.org/webr/latest/). The core webR project continuously works on improving performance and scalability, so any future advancements in handling complex content faster will likely originate from their developments. 37 | 38 | # webR Limitations 39 | 40 | > Q. I noticed that built in docs with ? don't work in webR. Are there any other known issues? How long to feature parity? 41 | 42 | Regarding feature parity with the main `webR` project, it's important to understand that `quarto-webr` inherits the same limitations and capabilities as the core `webR` technology. Efforts to address these limitations and bring feature parity will depend on the ongoing development of `webR` itself and the evolution of WebAssembly and web browser capabilities. While there may be progress in mitigating some of these limitations over time, achieving complete feature parity may be a complex and ongoing process. In the case of help documentation, we added support in `quarto-webr` v0.3.7. 43 | 44 | The known limitations at this time are: 45 | 46 | 1. **Package Installation**: Installing packages from source within `webR` is not currently supported. This limitation is unlikely to change in the near future as it would require a complete C and Fortran compiler toolchain to run within the browser. As a result, the only supported way to install R packages in `webR` is by providing pre-compiled WebAssembly binaries. 47 | 48 | 2. **Graphics Device**: The `webr::canvas()` graphics device relies on OffscreenCanvas support in the web browser or JavaScript engine running `webR`. This means that a modern and up-to-date browser is required for plotting with this device. Older browsers without OffscreenCanvas support can still create plots using the Cairo-based graphics devices, such as `png()`. 49 | 50 | 3. **Communication Channels**: `webR` relies on communication channels for interaction. Without cross-origin isolation, it falls back to the ServiceWorker communication channel, which may result in reduced performance or require additional setup. 51 | 52 | 4. **Interruption of Running Code**: Interruption of running R code and the use of nested R REPLs (such as `readline()`, `menu()`, `browser()`, etc.) are unsupported when using the PostMessage communication channel. 53 | 54 | 5. **System Command**: The `system()` command is not implemented in webR, which means that executing system-level commands from within R code or packages is not possible. 55 | 56 | # State of Accessibility 57 | 58 | > Q. You mentioned there has been some work on accessibility. I'm curious what the current state of accessibility is? What are the known issues? 59 | 60 | Accessibility is an important aspect of webR, and we are committed to ensuring that the tool is usable by individuals with disabilities. To address accessibility concerns, we have engaged the expertise of [JooYoung Seo](https://github.com/jooyoungseo), an Assistant Professor in the School of Information Sciences (iSchool) at the University of Illinois Urbana-Champaign. JooYoung specializes in accessibility within Data Science and has been instrumental in conducting periodic accessibility reviews of webR. 61 | 62 | One of the primary areas of focus has been making sure that screen readers can easily identify and interact with code cells on the page. This ensures that individuals with visual impairments can effectively use webR. While we've made significant strides in improving accessibility, we continue to work on addressing any known issues and enhancing the overall accessibility of the tool. We are committed to providing an inclusive and user-friendly experience for all users, and JooYoung's expertise has been invaluable in this regard. 63 | 64 | # Package Usage 65 | 66 | > Q. Does the use of R packages cause any issues for you when teaching content with webR and Quarto? 67 | 68 | When teaching content with `webR` and Quarto, the use of R packages is certainly supported. However, it's important to be aware of a few considerations that can help ensure a smooth teaching experience. 69 | 70 | In a typical R environment, packages are installed once and are available for subsequent sessions using `library()` or `require()`. In `webR`, packages are installed on each session. This means that each `webR` session starts with a clean slate, and packages need to be installed again for that specific session. 71 | 72 | To optimize this process and avoid unnecessary downloads, it's recommended to use the `webr::install()` function instead of the standard `install.packages()` function. `webr::install()` checks if a package is already installed and does not re-download it if it's already available. This can significantly speed up the package installation process when working with `webR` and Quarto. 73 | 74 | One way to simplify the teaching process and prevent students from working while packages are being installed is to use the built-in [`packages` option](qwebr-using-r-packages.qmd#install-r-packages-on-document-open) in the document's header. This option hides the installation process from students and ensures that the required packages are pre-installed when they access the document. 75 | 76 | Finally, it's worth noting that the R packages available to `webR` may not always be the latest versions that you can get from CRAN (the Comprehensive R Archive Network). Therefore, it's a good practice to check the package versions and ensure compatibility with your teaching materials. 77 | 78 | 79 | # Debugging 80 | 81 | > Q. How are error messages, etc. communicated in webr's interface? Would it be easy for a student to debug without the tools that are available in the RStudio? 82 | 83 | Error messages, warnings, and other diagnostic information are presented in the output of a `quarto-webr` interface, just like in a standard R environment. These messages appear directly below the code cell that generated them. While `quarto-webr` provides a user-friendly interface for working with R in a web browser, it does not offer advanced debugging tools like `debug()`, `debugonce()`, `debuggingState()`, or `setBreakpoint()`. Therefore, debugging in `quarto-webr` is primarily reliant on interpreting the error messages and warnings displayed in the output. For students familiar with RStudio's debugging tools, transitioning to `quarto-webr` may require an adjustment to debugging practices. However, the clear presentation of error messages in the output makes it relatively straightforward for students to identify and address issues in their code. 84 | 85 | 86 | # Styling 87 | 88 | > Q. Is it possible to style the UI elements the quarto-webr extension add to your document? Do they get affected by styling/theme changes so things look coherent? 89 | 90 | Certainly! You have the flexibility to style the UI elements added by the `quarto-webr` extension to your document. For more details, please see [Theming Elements](qwebr-theming.qmd). 91 | -------------------------------------------------------------------------------- /docs/qwebr-first-steps.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Making your first webR-powered Quarto document" 3 | author: "James Joseph Balamuta" 4 | date: "03-20-2023" 5 | date-modified: last-modified 6 | format: 7 | html: 8 | toc: true 9 | filters: 10 | - webr 11 | aliases: 12 | - webr-first-steps.html 13 | --- 14 | 15 | To get started, we highly recommend watching our walkthrough video. This video provides an in-depth breakdown of how to use a Quarto extension like `quarto-webr` within a Quarto document. Following that, delve into the subsequent sections that highlight crucial workflow changes for incorporating webR functionality into your Quarto HTML documents. We strongly encourage you to bookmark this page, as it serves as an invaluable reference for users of all expertise levels. 16 | 17 | ## Workflow Video 18 | 19 | {{< video https://youtu.be/DoRR2S5lLvk 20 | title="Creating your first webR-powered Quarto Document inside of RStudio" 21 | start="5" 22 | >}} 23 | 24 | ## Installation 25 | 26 | To use this extension in a Quarto project, install it from within the project's working directory by typing into **Terminal**: 27 | 28 | ```bash 29 | quarto add coatless/quarto-webr 30 | ``` 31 | 32 | ![Demonstration of using the Terminal tab to install the extension.](https://i.imgur.com/aVuBdyN.png) 33 | 34 | :::callout-note 35 | Quarto extensions are project-specific installations and are not stored in a global library, unlike R packages. This means that for every new Quarto project or directory where you create a Quarto Document, you'll need to install the extension again. 36 | ::: 37 | 38 | ## Usage 39 | 40 | Once the extension is successfully installed, you can begin utilizing it in your Quarto documents located within the same working directory as the `_extensions` folder. To activate the `webR` functionality in those documents, follow these steps: 41 | 42 | 1. **Add `webr` Filter**: In the header of your Quarto document, add the `webr` filter to the list of filters: 43 | 44 | ```yaml 45 | filters: 46 | - webr 47 | ``` 48 | 49 | 2. **Use `{webr-r}` Code Blocks**: Write your R code within code blocks marked with `{webr-r}`. Here's an example: 50 | 51 | ````markdown 52 | --- 53 | title: webR in Quarto HTML Documents 54 | format: html 55 | engine: knitr 56 | filters: 57 | - webr 58 | --- 59 | 60 | This is a webr-enabled code cell in a Quarto HTML document. 61 | 62 | ```{webr-r} 63 | fit = lm(mpg ~ am, data = mtcars) 64 | summary(fit) 65 | ``` 66 | ```` 67 | 68 | 3. **Render Your Document**: You can now render your Quarto document by clicking on ![](images/rstudio-render-button.png){width="25" height="20"} **Render** (or use the keyboard shortcut ⇧⌘K on macOS or Ctrl+Shift+K on Windows/Linux). The document will execute under `engine: knitr` by default, but you can specify a different engine if needed. 69 | 70 | :::callout-note 71 | If an engine is not specified, Quarto will attempt to use the `jupyter` compute engine by default. This may cause an error if `jupyter` is not installed on your computer. 72 | ::: 73 | 74 | # Fin 75 | 76 | In summary, this guide has provided an overview of how to incorporate the community `quarto-webr` extension into your Quarto HTML documents using RStudio. We began with a walkthrough video that offered an in-depth understanding of how this Quarto extension operates within the Quarto framework. Subsequently, we explored key workflow changes necessary for incorporating webR into your Quarto HTML documents, from installation to document rendering. 77 | 78 | For your next steps consider looking at different use cases for [interactive options](qwebr-code-cell-demos.qmd). 79 | 80 | If you're eager to delve even deeper, explore topics like [setting document-level customizations inside the document header](qwebr-meta-options.qmd), [using R packages inside webR](qwebr-using-r-packages.qmd), or [hiding and executing code](qwebr-internal-cell.qmd). These resources will further empower you to make the most of `quarto-webr` and `webR` to elevate your Quarto documents to new heights. -------------------------------------------------------------------------------- /docs/qwebr-loading-data.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Accessing and Using Data" 3 | subtitle: "Working with webR's Virtual File System and Data" 4 | author: "James Joseph Balamuta" 5 | date: "01-14-2024" 6 | date-modified: last-modified 7 | format: 8 | html: 9 | toc: true 10 | engine: knitr 11 | filters: 12 | - webr 13 | --- 14 | 15 | # Overview 16 | 17 | When working with webR in a web environment, there are some modifications and considerations required for using data. This documentation entry guides you through a few changes related to accessing data for the community Quarto extension. 18 | 19 | ## Background: Virtual File System 20 | 21 | Given the browser-based nature of webR, accessing local files is restricted. To overcome this limitation, webR establishes a [**virtual** file system](https://docs.r-wasm.org/webr/latest/communication.html#emscripten-virtual-filesystem) inside of your browser that is separate from your local file system. Consequently, webR does **not** have awareness of local file system and its paths. Thus, to use data we need to download it into the virtual file system either through: an R package, a URL using HTTPS, or a Web API. 22 | 23 | By default, the webR virtual file system's home directory and initial working directory is `/home/web_user`. This can be changed using a built-in extension [document-level option `home-dir`](https://quarto-webr.thecoatlessprofessor.com/qwebr-meta-options.html#home-dir). 24 | 25 | ### Aside 26 | 27 | While there are methods for mounting pre-built images using the webR's [Mounting Filesystem](https://docs.r-wasm.org/webr/latest/mounting.html#the-virtual-filesystem) mechanic, the community `quarto-webr` Extension does not support this option at the moment. 28 | 29 | ## Accessing Data through R Data Packages 30 | 31 | The quickest approach for accessing data is to store it inside of an [R data package](https://thecoatlessprofessor.com/programming/r/creating-an-r-data-package/). This kind of R package consists solely of data in an R ready format with the added benefit of help documentation. If the data package is available on CRAN, there's a good chance a version exists for webR on the [main webR package repository (warning not a mobile data friendly link)](https://repo.r-wasm.org/) and, thus, can be accessed using `install.packages("pkg")` or added to the documents `packages` key. 32 | 33 | If the R package is not available on CRAN, then it will need to be compiled for webR, deployed, and accessed through GitHub Pages or [r-universe.dev](https://ropensci.org/blog/2023/11/17/runiverse-wasm/) by following the advice on [creating a custom webR/R WASM package repository](qwebr-using-r-packages.qmd#custom-repositories). 34 | 35 | ## Retrieving Data from the Web 36 | 37 | ::: {.callout-important} 38 | Before proceeding, take note of the following considerations when working with remote data: 39 | 40 | 1. **Security Protocol:** webR necessitates data retrieval via the [HyperText Transfer Protocol Secure (HTTPS)](https://developer.mozilla.org/en-US/docs/Glossary/HTTPS) protocol to ensure secure connections and the [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) being enabled on the server where the data is being served. 41 | 2. **Package Compatibility:** In the absence of websockets within webR, packages reliant on `{curl}` methods may require adaptation or alternative solutions. 42 | ::: 43 | 44 | ### Hosting Data 45 | 46 | #### Standalone Repository 47 | 48 | We suggest creating a GitHub repository that uses GitHub Pages to host the data. By default, GitHub Pages serves data files using the CORS protocol and can quickly be setup to enforce HTTPS URLs [by checking a box](https://docs.github.com/en/pages/getting-started-with-github-pages/securing-your-github-pages-site-with-https#enforcing-https-for-your-github-pages-site). 49 | 50 | You can see an example raw data repository here: 51 | 52 | 53 | 54 | The corresponding site deployment of the `main` branch can be seen here: 55 | 56 | 57 | 58 | #### Alongside the document 59 | 60 | There may be times when it is not feasible to create a standalone repository to host the data. In cases like this, you may wish to host the data alongside of the document through Quarto's publishing system. In this case, please add the `resources` key to the top of the [HTML document](https://quarto.org/docs/reference/formats/html.html#includes) or inside the [project's `_quarto.yml`](https://quarto.org/docs/reference/projects/websites.html#project). 61 | 62 | For `my-document.qmd`, this would be: 63 | 64 | ```yaml 65 | --- 66 | title: "quarto-webr document with data" 67 | format: 68 | html: 69 | resources: 70 | - my-data.csv # Include just the CSV 71 | - my-data-directory/* # Include all files 72 | engine: knitr 73 | filters: 74 | - webr 75 | --- 76 | ``` 77 | 78 | For `_quarto.yml`, this would be: 79 | 80 | ```yaml 81 | --- 82 | project: 83 | type: website 84 | resources: 85 | - my-data.csv # Include just the CSV 86 | - my-data-directory/* # Include all files 87 | --- 88 | ``` 89 | 90 | Subsequently, reference the data using the URL to where the document is located. For example, if the document is at: 91 | 92 | ```default 93 | https://example.com/folder/my-document.html 94 | ``` 95 | 96 | Then, the data should be accessed using: 97 | 98 | ```default 99 | https://example.com/folder/my-data.csv 100 | ``` 101 | 102 | :::{.callout-note} 103 | You may need to publish the document before using the URL. Also, be mindful of data version mismatches, as the data will be fetched from the HTTPS URL instead of being available locally. 104 | ::: 105 | 106 | ### Obtain Data 107 | 108 | We can retrieve data at a URL with HTTPS through using the `download.file()` function and, subsequently, reading it into R using a relative path. The later can be done using either Base R or Tidyverse functions. 109 | 110 | For example, if we wanted to work with [flights.csv](https://coatless.github.io/raw-data/flights.csv) from the [`nycflights13`](https://cran.r-project.org/package=nycflights13) _R_ package ([Details](https://nycflights13.tidyverse.org/reference/flights.html)), we would specify: 111 | 112 | ```r 113 | url <- "https://coatless.github.io/raw-data/flights.csv" 114 | download.file(url, "flights.csv") 115 | ``` 116 | 117 | This action saves the file into webR's virtual file system to be read into R's analysis environment. Replace `"https://coatless.github.io/raw-data/flights.csv"` and `"flights.csv"` with the actual URL of your desired data source and desired local file name. 118 | 119 | ### Base R 120 | 121 | For optimized performance, leverage base R's `read.*()` functions, as they do not necessitate additional package dependencies. 122 | 123 | ```r 124 | data <- read.csv("flights.csv") 125 | ``` 126 | 127 | ### Tidyverse 128 | 129 | Alternatively, you can use `tidyverse`-based functions like `readr::read_*()`. 130 | 131 | :::{.callout-note} 132 | Note that employing `tidyverse` or `readr` functions entails additional package downloads at the session's outset or immediately preceeding the function usage. 133 | ::: 134 | 135 | ```r 136 | install.packages("readr") 137 | data <- readr::read_csv("data.csv") 138 | ``` 139 | 140 | ### Try it! 141 | 142 | We've setup the above example inside of an interactive cell for your to explore below. 143 | 144 | :::{.panel-tabset} 145 | 146 | ### {quarto-webr} 147 | 148 | ```{webr-r} 149 | #| autorun: true 150 | # See where we are in the file system: 151 | cat("We're currently at:\n") 152 | getwd() 153 | 154 | # View a list of files for the working directory. 155 | cat("We have the following files present:\n") 156 | list.files() 157 | 158 | # Specify the data URL using HTTPS 159 | url <- "https://coatless.github.io/raw-data/flights.csv" 160 | 161 | # Download the data file from the HTTPS URL and save it as 162 | # flights.csv 163 | cat("Download the data ...\n") 164 | download.file(url, "flights.csv") 165 | 166 | # Check for the data. 167 | cat("After downloading the data, we now have:\n") 168 | list.files() 169 | 170 | # Read the flights data into R 171 | flights_from_csv <- read.csv("flights.csv") 172 | 173 | # See the first few rows of the flights_from_csv data frame. 174 | cat("Let's view the first 6 observations of data:\n") 175 | head(flights_from_csv) 176 | ``` 177 | 178 | ### Code cell 179 | 180 | ```{{webr-r}} 181 | #| autorun: true 182 | # See where we are in the file system: 183 | cat("We're currently at:\n") 184 | getwd() 185 | 186 | # View a list of files for the working directory. 187 | cat("We have the following files present:\n") 188 | list.files() 189 | 190 | # Specify the data URL using HTTPS 191 | url <- "https://coatless.github.io/raw-data/flights.csv" 192 | 193 | # Download the data file from the HTTPS URL and save it as 194 | # flights.csv 195 | cat("Download the data ...\n") 196 | download.file(url, "flights.csv") 197 | 198 | # Check for the data. 199 | cat("After downloading the data, we now have:\n") 200 | list.files() 201 | 202 | # Read the flights data into R 203 | flights_from_csv <- read.csv("flights.csv") 204 | 205 | # See the first few rows of the flights_from_csv data frame. 206 | cat("Let's view the first 6 observations of data:\n") 207 | head(flights_from_csv) 208 | ``` 209 | 210 | ::: 211 | -------------------------------------------------------------------------------- /docs/qwebr-meta-options.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Customization Options" 3 | subtitle: "Fine-Tuning `quarto-webr` with Powerful Configuration Options" 4 | author: "James Joseph Balamuta" 5 | date: "09-14-2023" 6 | date-modified: last-modified 7 | format: 8 | html: 9 | toc: true 10 | engine: knitr 11 | aliases: 12 | - webr-meta-options.html 13 | --- 14 | 15 | The `quarto-webr` extension empowers you to tailor your webR environment to meet your unique requirements. By configuring various options in your document's YAML header or `_quarto.yml` file, you can structure the webR experience on a per-page or per-project basis. Below, we explore these customization options and how to implement them. 16 | 17 | # Customization Options 18 | 19 | Enhance your webR experience by customizing its behavior through the `webr` key. This key should be added before listing the `filter` statement. 20 | 21 | ## Document YAML 22 | 23 | To fine-tune webR to the specific needs of a document, place inside your document's YAML header the `webr` key. Specifying options this way allows webR to be setup with unique options confined to only that document. 24 | 25 | ```yaml 26 | --- 27 | title: webR in Quarto HTML Documents 28 | format: html 29 | engine: knitr 30 | webr: 31 | show-startup-message: false # Disable displaying status of webR initialization 32 | packages: ['ggplot2', 'dplyr'] # Install R packages on document open 33 | filters: 34 | - webr 35 | --- 36 | ``` 37 | 38 | ## Global Configuration 39 | 40 | If you have multiple pages that use webR, we suggest setting global options inside of the `_quarto.yml` file. This option is appropriate for Websites, Blogs, or Books. For instance, if you have a book project, the `_quarto.yml` should look like: 41 | 42 | ```yaml 43 | project: 44 | type: book 45 | 46 | book: 47 | title: "Sample quarto-webr Book Project" 48 | # ... more options 49 | 50 | # Set default options for every bookpage that may or may not include webR. 51 | webr: 52 | show-startup-message: false # Disable displaying status of webR initialization 53 | packages: ['ggplot2', 'dplyr'] # Install R packages on document open 54 | 55 | # Attach webR extension for the project 56 | filters: 57 | - webr 58 | ``` 59 | 60 | :::{.callout-note} 61 | If a webR code cell is not present on a website, blog, or book page, then the `quarto-webr` extension will not setup webR on the page. 62 | ::: 63 | 64 | You can see full examples of setting a global option under the [Deployment Templates](qwebr-deployment-templates.qmd) page. 65 | 66 | ## webR options 67 | 68 | By specifying various `WebROptions` options in the document YAML, you can create a personalized webR experience 69 | 70 | ### `home-dir` 71 | 72 | - **Description**: Set the WebAssembly user's home directory and initial working directory. 73 | - **Default Value**: `'/home/web_user'` 74 | - **Documentation**: [homeDir](https://docs.r-wasm.org/webr/latest/api/js/interfaces/WebR.WebROptions.html#homedir) 75 | 76 | ### `version` 77 | 78 | - **Description**: Define the version that should be used for the R WebAssembly binaries. 79 | - **Default Value**: `0.3.3` (version keyed by the extension) 80 | 81 | ### `base-url` 82 | 83 | - **Description**: Define the base URL for downloading R WebAssembly binaries. 84 | - **Default Value**: `'https://webr.r-wasm.org/v[version]/'` 85 | - **Documentation**: [baseUrl](https://docs.r-wasm.org/webr/latest/api/js/interfaces/WebR.WebROptions.html#baseurl) 86 | 87 | ### `channel-type` 88 | 89 | - **Description**: Specify the communication channel type to interact with webR. 90 | - **Default Value**: `"automatic"` (0) 91 | - **Possible Values**: `"automatic"` (0), `"shared-array-buffer"` (1), `"service-worker"` (2), `"post-message"` (3). 92 | - **Documentation**: [channelType](https://docs.r-wasm.org/webr/latest/api/js/interfaces/WebR.WebROptions.html#channeltype) 93 | 94 | :::callout-note 95 | We recommend using the `"post-message"` channel when [GitHub Pages](https://pages.github.com/) or [Quarto Pub](https://quartopub.com/) serve the webR-enabled document. Note that this option prevents the interruption of running R code and the use of nested R REPLs (`readline()`, `menu()`, `browser()`, etc.). 96 | For more details, please see [Communication Channels](qwebr-communication-channels.qmd#sec-post-message) 97 | ::: 98 | 99 | ### `service-worker-url` 100 | 101 | - **Description**: Set the base URL for loading JavaScript worker scripts when using the ServiceWorker communication channel mode. 102 | - **Default Value**: `''` 103 | - **Documentation**: [serviceWorkerUrl](https://docs.r-wasm.org/webr/latest/api/js/interfaces/WebR.WebROptions.html#serviceworkerurl) 104 | 105 | 106 | ## Native Extension Options 107 | 108 | The extension also provides native options that affect its behavior: 109 | 110 | ### `show-startup-message` 111 | 112 | - **Description**: Controls the display of the WebR initialization state in the document header. 113 | - **Default Value**: `true` 114 | - **Demo Document**: [Setting Options in Document Header](demos/qwebr-setting-options-in-document-yaml.qmd) 115 | 116 | ### `show-header-message` 117 | 118 | - **Description**: Determines whether COOP and COEP headers are in use for faster page loads. 119 | - **Default Value**: `false` 120 | - **Demo Document**: [Setting Options in Document Header](demos/qwebr-setting-options-in-document-yaml.qmd) 121 | 122 | ### `cell-options` 123 | 124 | - **Description**: Modifies default cell options for `{webr-r}` cells. 125 | - **Default Value**: Please see [Code Cell Options](qwebr-cell-options.qmd) for individual cell option defaults. 126 | - **Demo Document**: [Set Global Cell Options](demos/qwebr-global-cell-defaults.qmd) 127 | - **Example:** 128 | 129 | ```yaml 130 | webr: 131 | cell-options: 132 | autorun: true 133 | fig-height: 400 134 | fig-width: 300 135 | ``` 136 | 137 | This modifies the default cell options for `autorun`, `fig-width`, and `fig-height` for all cells in the document. 138 | 139 | ### `repos` 140 | 141 | - **Description**: Specify the repository locations to search for R packages when trying to install them in array form. Regardless of values specified, we will always conclude by checking to see if the package is present in the main webR repository: . 142 | - **Default Value**: `['https://repo.r-wasm.org/']` 143 | - **Demo Document**: [Custom R WASM Package Repository](demos/qwebr-custom-repository.qmd) 144 | - **Example**: `['https://username.r-universe.dev', 'https://username.github.io/reponame']` will cause webR to first look for the package on `r-universe.dev`, then move to looking at the package on GitHub Pages, before finally landing on the official repository. 145 | 146 | ### `packages` 147 | 148 | - **Description**: Specifies R packages to install automatically when the document opens. 149 | - **Default Value**: `[]` 150 | - **Demo Document**: [Setting Options in Document Header](demos/qwebr-setting-options-in-document-yaml.qmd) 151 | - **Example:** `['ggplot2', 'dplyr']` will cause `ggplot2` and `dplyr` to be installed. 152 | 153 | ### `autoload-packages` 154 | 155 | - **Description**: The `autoload-packages` option allows you to control whether R packages specified in the `packages` document option will be automatically loaded using `library()` calls when the document opens. By default, this option is set to `true`, meaning that packages listed in the `packages` option will be automatically loaded. If you set it to `false`, you will need to include a code cell with `library(package)` function calls for each package in `packages`. 156 | - **Default Value**: `true` 157 | - **Demo Document**: [Setting Options in Document Header](demos/qwebr-setting-options-in-document-yaml.qmd) 158 | 159 | -------------------------------------------------------------------------------- /docs/qwebr-theming.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Theming Elements" 3 | subtitle: "Customizing the Look and Feel of `quarto-webr` Elements" 4 | date: "11-01-2023" 5 | date-modified: last-modified 6 | author: James Balamuta 7 | engine: markdown 8 | format: 9 | html: 10 | toc: true 11 | filters: 12 | - webr 13 | --- 14 | 15 | :::{.callout-note} 16 | This section of the documentation is tailored to those with a deeper understanding of web design. If you're new to these concepts, don't worry; you can still create fantastic documents using the `quarto-webr` extension. This part is for those who want to take their styling to the next level and have knowledge of HTML and CSS. 17 | ::: 18 | 19 | On this page, we delve into the world of web design to enhance the visual aesthetics and styling of web-based documents created with the Quarto-WebR extension. While prior knowledge of these topics is not mandatory for using the extension, a good understanding can empower you to create documents that effectively convey valuable insights and captivate your audience with a visually appealing design tailored to your preferences. Whether you want to seamlessly integrate your document with your personal brand or align it with your organization's style guidelines, this page serves as your expert guide, leading you through the process of crafting a visually captivating and cohesive user experience. The focus here is on explaining the HTML structure and predefined CSS classes that will help you achieve the visual results you desire. 20 | 21 | ## CSS Class and ID Identifiers 22 | 23 | To effectively style web-based documents created with the extension, you'll need to understand the unique `id` and `class` attributes associated with different content areas. There are two key areas to every Quarto document that uses the `quarto-webr` extension: header and code cells. The header is where status and debug information can be found whereas the code cell portion is where R code is actively run using webR. 24 | 25 | Let's turn our attention to the document's header. By default, the webR initialization state is displayed in the header. This can be turned off by setting the [`show-startup-message: false` meta option.](qwebr-meta-options.qmd). 26 | 27 | - **Status Area**: This represents the area we dynamic add to the document using JavaScript and stores the **Status Title** and **Status Message** 28 | - `id`: `#qwebr-status-message-area` 29 | - **Status Title**: This element contains the header of the status text. 30 | - `id`: `#qwebr-status-message-title` 31 | - **Status Message**: This element is updated with the document status updates. 32 | - `id`: `#qwebr-status-message-body` 33 | 34 | With this in mind, we next focus on improving how content is being displayed through **code cells**. There are two primary context types where code content is displayed to users: 35 | 36 | - **Interactive Area**: This area encompasses the **Code Editor**, **Code Output**, and the **Graph Output Area** under the `interactive` context. 37 | - `id`: `#qwebr-interactive-area-{{ID}}` 38 | - `class`: `.qwebr-interactive-area` 39 | 40 | - **Non-Interactive Area**: This includes the **Code Output** and the **Graph Output Area** under the `output` context. 41 | - `id`: `#qwebr-noninteractive-area-{{ID}}` 42 | - `class`: `.qwebr-noninteractive-area` 43 | 44 | Within the interactive section, you'll find elements that are displayed when users request results: 45 | 46 | - **Run Button**: This button triggers the execution of your R code. 47 | - `id`: `#qwebr-button-run-{{ID}}` 48 | - `class`: `.qwebr-button-run` 49 | 50 | - **Console Area**: This area contains the **Code Editor** and **Code Output**. 51 | - `id`: `#qwebr-console-area-{{ID}}` 52 | - `class`: `.qwebr-console-area` 53 | 54 | - **Code Editor**: You use this area to input and edit your R code. 55 | - `id`: `#qwebr-editor-{{ID}}` 56 | - `class`: `.qwebr-editor` 57 | 58 | Across both contexts, you'll find shared output element classes and names: 59 | 60 | - **Code Output Area**: This is where the results and output of your R code are displayed. 61 | - `id`: `#qwebr-output-code-area-{{ID}}` 62 | - `class`: `.qwebr-output-code-area` 63 | 64 | - **Code Output Standard Output**: Results from standard output (`STDOUT`) are stored here. 65 | - `id`: `#qwebr-output-code-stdout-{{ID}}` 66 | - `class`: `.qwebr-output-code-stdout` 67 | 68 | - **Code Output Standard Error**: Each line of results from standard error (`STDERR`) when running your code is stored here. 69 | - `id`: `#qwebr-output-code-stderr-{{ID}}` 70 | - `class`: `.qwebr-output-code-stderr` 71 | 72 | - **Graph Output Area**: Any graphical output of your R code is displayed in this area. 73 | - `id`: `#qwebr-output-graph-area-{{ID}}` 74 | - `class`: `.qwebr-output-graph-area` 75 | 76 | - **Browse Output Area**: Any HTML widgets generated by your R code is displayed in this area. 77 | - `id`: `#qwebr-output-code-browse-{{ID}}` 78 | - `class`: `.qwebr-output-code-browse` 79 | 80 | 81 | The `{{ID}}` in these identifiers represents the instance of the element on the page, whether it's the first, second, or nth occurrence. You can customize their appearance by targeting the specific `id` or `class` attributes in your document's CSS, or you can include a separate CSS file to align with your design preferences. 82 | 83 | ## CSS & HTML Structure 84 | 85 | ### Interactive Area Structure 86 | 87 | ```{.html} 88 |
89 | 90 |
91 |
92 |
93 |
94 |
95 |

 96 |     
97 |
98 |
99 |
100 |
101 | ``` 102 | 103 | ### Non-interactive Area Structure 104 | 105 | ```{.html} 106 |
107 |
108 |

109 |    
110 |
111 |
112 |
113 | ``` 114 | 115 | ## Custom Embedded Styles 116 | 117 | For instance, you can insert new CSS elements by using the following method: 118 | 119 | ````markdown 120 | ```{=html} 121 | 125 | ``` 126 | ```` 127 | 128 | ## External Theme Support 129 | 130 | Furthermore, if you are using a Quarto theme, you can make use of [theme-specific styling options](https://quarto.org/docs/output-formats/html-themes.html#basic-options) to ensure that these UI elements align with the overall theme of your document. 131 | 132 | ```markdown 133 | --- 134 | title: My post 135 | format: 136 | html: 137 | theme: 138 | - cosmo 139 | - custom.scss 140 | --- 141 | ``` 142 | 143 | ## Light and Dark Mode 144 | 145 | The Monaco editor used by `{quarto-webr}` to power interactive code cells respects [Quarto's light and dark theme modes](https://quarto.org/docs/output-formats/html-themes.html#dark-mode). To apply light and dark themes on a Quarto website, specify the following settings in the `_quarto.yml` configuration file: 146 | 147 | ```yaml 148 | theme: 149 | light: cosmo 150 | dark: darkly 151 | ``` 152 | 153 | Once set, a clickable toggle will appear on the page that can switch between these modes. This toggle modifies CSS classes on the `body` HTML element, adding `.quarto-light` for light mode and `.quarto-dark` for dark mode. 154 | 155 | :::{.callout-note} 156 | The Monaco editor's theme automatically adjusts based on the document's theme. It uses a light theme (`vs`) in light mode and a dark theme (`vs-dark`) in dark mode. 157 | ::: 158 | 159 | ### RevealJS 160 | 161 | For RevealJS, please note you may only specify [a single RevealJS theme](https://quarto.org/docs/presentations/revealjs/themes.html#using-themes) at a time. We recommend specifying either `default` (for light mode) or `dark` (for dark mode). 162 | 163 | ```yaml 164 | format: 165 | revealjs: 166 | theme: default 167 | ``` 168 | -------------------------------------------------------------------------------- /docs/qwebr-troubleshooting.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Troubleshooting" 3 | subtitle: "Common Problems and Fixes in quarto-webR" 4 | date: "03-20-2023" 5 | date-modified: last-modified 6 | engine: knitr 7 | aliases: 8 | - webr-troubleshooting.html 9 | --- 10 | 11 | As this is an exciting new frontier, we're learning as we go. Or as my friend [Lawrence](https://cs.illinois.edu/about/people/faculty/angrave) says, ["I like to build airplanes in the air-"](https://www.youtube.com/watch?v=L2zqTYgcpfg). In the spirit of learning, let's address some common issues you may come across... 12 | 13 | # Unable to Render the Quarto File 14 | 15 | **Problem**: When I add the `webr` value to the `filter` section, my Quarto document fails to render and displays a lengthy error message. 16 | 17 | **Solution**: Quarto extensions are project-specific, which means you must install the extension for each new project you create. To resolve this issue, ensure that your project directory structure includes an `_extensions` directory with the appropriate extension files, as shown below: 18 | 19 | ```sh 20 | . 21 | ├── _extensions 22 | │ └── coatless 23 | │ └── webr 24 | │ ├── _extension.yml 25 | │ ├── ... 26 | │ └── webr.lua 27 | └── test-document.qmd 28 | ``` 29 | 30 | If your directory is missing the `_extensions/` folder, please install the `webr` extension by following the instructions in [Install the quarto-webr extension](qwebr-first-steps.qmd) video. 31 | 32 | Starting from Quarto v1.4, you will receive an improved error message that emphasizes the extension's absence from your current working directory. 33 | 34 | ```{sh} 35 | #| eval: false 36 | #| code-fold: true 37 | #| code-summary: "Missing extension error for Quarto v1.4 and later" 38 | 39 | FATAL (/Applications/quarto/share/filters/main.lua:129) An error occurred: 40 | Could not run /Users/jjb/github/demo-webr/webr as a JSON filter. 41 | Please make sure the file exists and is executable. 42 | 43 | Did you intend 'webr' as a Lua filter in an extension? 44 | If so, make sure you've spelled the name of the extension correctly. 45 | 46 | The original Pandoc error follows below. 47 | Error running filter /Users/jjb/github/demo-webr/webr: 48 | Could not find executable /Users/jjb/github/demo-webr/webr 49 | ``` 50 | 51 | In versions prior to Quarto v1.4, including v1.3 and earlier, the error message may differ, but it typically signals that the extension is either missing or not executable. 52 | 53 | ```{sh} 54 | #| eval: false 55 | #| code-fold: true 56 | #| code-summary: "Missing extension error for Quarto v1.3 and earlier" 57 | 58 | Error running filter /Applications/quarto/share/filters/main.lua: 59 | Error running filter /Users/jjb/github/demo-webr/webr: 60 | Could not find executable /Users/jjb/github/demo-webr/webr 61 | stack traceback: 62 | /Applications/quarto/share/filters/main.lua:4030: in function 63 | [C]: in ? 64 | [C]: in method 'walk' 65 | /Applications/quarto/share/filters/main.lua:171: in function 'run_emulated_filter' 66 | /Applications/quarto/share/filters/main.lua:449: in local 'callback' 67 | /Applications/quarto/share/filters/main.lua:454: in upvalue 'run_emulated_filter_chain' 68 | /Applications/quarto/share/filters/main.lua:495: in function 69 | stack traceback: 70 | /Applications/quarto/share/filters/main.lua:171: in function 'run_emulated_filter' 71 | /Applications/quarto/share/filters/main.lua:449: in local 'callback' 72 | /Applications/quarto/share/filters/main.lua:454: in upvalue 'run_emulated_filter_chain' 73 | /Applications/quarto/share/filters/main.lua:495: in function 74 | ``` 75 | 76 | 77 | # Directly Accessing Rendered HTML 78 | 79 | **Problem**: When I directly open the rendered HTML document in a web browser, webR components are not loaded due to security reasons. 80 | 81 | **Solution**: When you use `quarto preview` or `quarto render`, the rendered HTML document is served by mimicking a server running under `https://localhost/`. In this context, everything usually works fine if you follow the directory structure mentioned above. 82 | 83 | However, if you directly open the rendered HTML document (e.g., `demo-quarto-web.html`) in a web browser, you may encounter issues with WebR components not loading due to security restrictions. This behavior is explained further in this [StackOverflow answer](https://stackoverflow.com/questions/6811398/html5-web-workers-work-in-firefox-4-but-not-in-chrome-12-0-742-122/6823683#6823683). 84 | 85 | To address this problem and avoid the need for a local Quarto installation to open the rendered file directly, you have a few options: 86 | 87 | 1. **Use Chrome's `--allow-file-access-from-files` access**: You can modify your Chrome shortcut to include the [`--allow-file-access-from-files` flag](https://stackoverflow.com/questions/18586921/how-to-launch-html-using-chrome-at-allow-file-access-from-files-mode). This allows local files to access other local files, potentially resolving the issue. 88 | 89 | 2. **Use the WebServer for Chrome Extension**: Install the [WebServer for Chrome extension](https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=en) to serve your HTML files. This extension sets up a local web server that doesn't have the same security restrictions as directly opening files. 90 | 91 | 3. **Use NPM to Obtain `local-web-server`**: Install the [`local-web-server` package from npm](https://github.com/lwsjs/local-web-server), which is a lightweight, no-configuration-required HTTP server. You can use it to serve your HTML files without encountering security restrictions. 92 | 93 | # Speed Up webR 94 | 95 | **Problem**: WebR documents are not performing as efficiently as expected. 96 | 97 | **Solution**: To optimize the performance of webR documents, it's essential to set appropriate HTTP headers for [COOP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy) and [COEP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy). These headers help speed up the process and ensure a smoother user experience. 98 | 99 | Here are the recommended COOP and COEP headers to use: 100 | 101 | ```http 102 | Cross-Origin-Opener-Policy: same-origin 103 | Cross-Origin-Embedder-Policy: require-corp 104 | ``` 105 | 106 | By configuring these headers, you enforce a same-origin policy for cross-origin windows and ensure that cross-origin iframes are required to have a COEP policy that allows cross-origin embedding. For more detailed instructions on setting up these headers, please refer to the [`"shared-array-buffer"`](qwebr-communication-channels.qmd#sec-shared-array-buffer) channel type documentation. 107 | 108 | # Engine Registration 109 | 110 | **Problem**: When using the `knitr` engine instead of the `jupyter` engine and the original tag `{webr}` instead of `{webr-r}`, a warning message may appear in the render processing output: 111 | 112 | ```r 113 | Warning message: 114 | In get_engine(options$engine) : 115 | Unknown language engine 'webr' (must be registered via knit_engines$set()). 116 | ``` 117 | 118 | **Solution**: The warning message about the unknown language engine 'webr' is purely cosmetic and does not affect the functionality of the `webr` filter. It is merely an aesthetic issue and does not impact the execution of code cells. 119 | 120 | This warning occurs because the `knitr` engine is not initially aware of the `webr` engine. However, this lack of awareness does not cause any functional problems. The `webr` filter will operate as expected despite this warning. 121 | 122 | While the warning is not critical, it may be addressed in future updates for aesthetic reasons. Nevertheless, you can safely disregard this warning message as it does not interfere with the functionality of your webR documents. 123 | 124 | # Stuck at Loading webR... 125 | 126 | **Problem**: If you encounter the message `Loading webR...` above your code cell instead of `Run code`, it's likely due to missing worker files (`webr-worker.js` and `webr-serviceworker.js`) in the document's root or a relative directory. 127 | 128 | **Solution**: To resolve this issue, make sure that these worker files are located in the same directory as your Quarto document. Here's the recommended directory structure: 129 | 130 | ```sh 131 | . 132 | ├── demo-quarto-webr.qmd 133 | ├── webr-serviceworker.js 134 | └── webr-worker.js 135 | ``` 136 | 137 | If you still encounter the error after confirming the file placement, check the output of the preview command in either the **Terminal** or RStudio's **Background Jobs** tab. The output might resemble the following: 138 | 139 | ```sh 140 | quarto preview --no-browser --no-watch-inputs 141 | 142 | Watching files for changes 143 | GET: /website/posts/index.html 144 | /website/posts/webr-serviceworker.js (404: Not Found) 145 | /website/posts/webr-worker.js (404: Not Found) 146 | ``` 147 | 148 | This indicates that the `webr-serviceworker.js` and `webr-worker.js` files are missing during the rendering stage of your document. To fix this, add the [`resources` key](https://quarto.org/docs/reference/formats/html.html#includes) to your document header, explicitly specifying these two JavaScript files like so: 149 | 150 | ```markdown 151 | --- 152 | title: "My Post" 153 | resources: 154 | - webr-serviceworker.js 155 | - webr-worker.js 156 | filters: 157 | - webr 158 | --- 159 | ``` 160 | 161 | :::{.callout-note} 162 | We've informed the Quarto team about this issue regarding [automatic inclusion of extension registered dependencies](https://github.com/quarto-dev/quarto-cli/issues/6828). 163 | ::: 164 | 165 | If the problem persists, you can specify the location of the worker files using the [`service-worker-url` option](qwebr-meta-options.qmd) in the document's YAML header or set the [`channel-type` option to `"post-message"`](qwebr-communication-channels.qmd#sec-post-message). You can see an example of the later [here](qwebr-communication-channels.qmd#specifying-how-webr-communicates). 166 | -------------------------------------------------------------------------------- /docs/qwebr-using-r-packages.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Using R Packages" 3 | subtitle: "Seamlessly integrate R packages into your interactive Quarto HTML documents" 4 | author: "James Joseph Balamuta" 5 | date: "09-14-2023" 6 | date-modified: last-modified 7 | format: 8 | html: 9 | toc: true 10 | engine: knitr 11 | filters: 12 | - webr 13 | aliases: 14 | - webr-using-r-packages.html 15 | --- 16 | 17 | Whether you need specialized statistical analysis, advanced visualization, or any other R-based functionality, you can harness the rich ecosystem of R packages directly within your documents. By default, the community `quarto-webr` extension avoids loading additional packages. However, you have two ways to incorporate packages into your document: one where packages are installed when the document opens, and the other where packages are installed interactively within specific code cells. 18 | 19 | # Available R Packages 20 | 21 | Before you use any R package with webR, it's essential to check if it's available. You can explore the available packages by navigating to the [webR binary R repository](https://repo.r-wasm.org/) (link is not mobile friendly) for package listings. 22 | 23 | ::: {.callout-note} 24 | webR reports the number of packages available in two ways: 25 | 26 | - **Built R packages**: This indicates the number of R packages with WebAssembly binaries that can be used within webR, although they may have a decreased number of features available. 27 | 28 | - **Available R packages**: This number represents feature-complete R packages that have all their dependencies compiled and are fully functional within webR. 29 | 30 | To achieve parity with base R, the **Available R packages** metric serves as an indicator of whether R scripts may require further modification to function properly within webR. 31 | ::: 32 | 33 | Alternatively, you can run the following R code, either with webR or just R: 34 | 35 | ```{webr-r} 36 | # Determine the version of R being used 37 | major_minor_version <- paste( 38 | R.version$major, 39 | strsplit(R.version$minor, ".", fixed = TRUE)[[1L]][1L], 40 | sep = "." 41 | ) 42 | 43 | # Obtain a list of packages 44 | webr_info <- as.data.frame( 45 | available.packages( 46 | contriburl = paste0( 47 | "https://repo.r-wasm.org/bin/emscripten/contrib/", 48 | major_minor_version 49 | ) 50 | ) 51 | ) 52 | 53 | # Obtain the number of R packages built 54 | n_webr_pkgs <- nrow(webr_info) 55 | 56 | # Number of R packages available to webR 57 | cat("There are current", n_webr_pkgs, 58 | "available to use with webR!\n") 59 | 60 | # Only view the first 6, there's a lot available! 61 | head(webr_info[, c("Version", "License")]) 62 | ``` 63 | 64 | 65 | 66 | ## Custom Repositories 67 | 68 | If an R package is not available on the [main webR repository](https://repo.r-wasm.org) (link is not mobile friendly), fear not! You can compile your own R package to an R WASM Package binary and setup a custom repository to share it. 69 | 70 | The quickest way is to opt into using the **[r-universe.dev](https://ropensci.org/blog/2023/11/17/runiverse-wasm/) service**. This is a free service that allows you to host R packages and binaries not just for webR, but also macOS, Linux, and Windows variants of R. 71 | 72 | 73 | If you want tighter integration with your development repository, we have the following guides: 74 | 75 | - [Org-focused webR/WASM Package Repository without a `{pkgdown}` website](https://github.com/coatless-tutorials/webr-org-gh-action) 76 | - [Unified GitHub Action Deployment using artifacts of R WASM Package binaries and {pkgdown} website](https://github.com/coatless-tutorials/webr-unified-gh-workflow) 77 | - [Separate GitHub Action Deployment onto `gh-pages` branch of R WASM Package binaries and {pkgdown} website](https://github.com/coatless-tutorials/webr-github-action-wasm-binaries) 78 | 79 | 80 | Once done, please make sure to specify where the custom repository is by using the `repos` key under the `webr` option in the document header. For example, we can add two custom repositories -- one to a GitHub pages hosted repository and another to the [r-universe](https://r-universe.dev/search/), by using: 81 | 82 | ```yaml 83 | --- 84 | webr: 85 | repos: 86 | - https://username.github.io/reponame 87 | - https://username.r-universe.dev 88 | --- 89 | ``` 90 | 91 | :::{.callout-note} 92 | The community `{quarto-webr}` extension is setup to always check whether an R package is available at the main repository even without it being specified in the `repos` key. 93 | ::: 94 | 95 | # Install R Packages on Document Open 96 | 97 | To automatically install packages when the document opens, add the `packages` key under `webr` in the YAML header, listing the packages in an array: 98 | 99 | ```yaml 100 | --- 101 | webr: 102 | packages: ['ggplot2', 'dplyr'] 103 | --- 104 | ``` 105 | 106 | By using this approach, you ensure that necessary packages are available right from the start when readers access your document. Moreover, the webR code cells will not become active until the packages are installed and loaded. This can be especially helpful when working with packages in multiple cells. 107 | 108 | If you do not want the packages to be loaded by default, add the `autoload-packages: false` under `webr` in the YAML header. This will disable the calls to load each R package in the `packages` key, e.g. `library(package)`. 109 | 110 | ```yaml 111 | --- 112 | webr: 113 | packages: ['ggplot2', 'dplyr'] 114 | autoload-packages: false 115 | --- 116 | ``` 117 | 118 | # Installing an R Package Interactively 119 | 120 | If you need to install a package interactively within specific code cells, you can do so using either the `webr::install()` or `install.packages()` function. This method allows you to install packages on-the-fly when needed. 121 | 122 | :::callout-note 123 | Please note that not all R packages are immediately available for use with webR due to the presence of compiled code routines. The installation process might also take some time depending on the [communication channel](qwebr-communication-channels.qmd#sec-service-worker) being used. 124 | ::: 125 | 126 | Let's take ggplot2 as an example: 127 | 128 | ```{webr-r} 129 | webr::install("ggplot2") 130 | ``` 131 | 132 | Using this approach, you can install packages on a per-code cell basis, which can be more efficient when you only need specific packages for certain parts of your document. 133 | 134 | 135 | # Load R Packages Interactively 136 | 137 | Once an R package is installed, you can use it just like normal by calling either `library()` or `require()` to load the package. 138 | 139 | For instance, if you have installed `ggplot2` in the prior code cell, then the following will load the `ggplot2` and create a scatterplot. 140 | 141 | ```{webr-r} 142 | library("ggplot2") 143 | 144 | ggplot(mpg, aes(displ, hwy, colour = class)) + 145 | geom_point() 146 | ``` 147 | 148 | 149 | Not a fan of having a code cell dedicated to load packages? You can use the `packages` key option above to let the `quarto-webr` extension take care of loading the packages after installing. 150 | -------------------------------------------------------------------------------- /examples/blog/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | /_site/* 3 | -------------------------------------------------------------------------------- /examples/blog/_extensions: -------------------------------------------------------------------------------- 1 | ../../_extensions -------------------------------------------------------------------------------- /examples/blog/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: website 3 | 4 | website: 5 | title: "blog" 6 | navbar: 7 | right: 8 | - about.qmd 9 | - icon: github 10 | href: https://github.com/ 11 | - icon: twitter 12 | href: https://twitter.com 13 | format: 14 | html: 15 | theme: cosmo 16 | css: styles.css 17 | 18 | # Enable webR on all post pages 19 | webr: 20 | channel-type: 'automatic' 21 | filters: 22 | - webr 23 | -------------------------------------------------------------------------------- /examples/blog/about.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "About" 3 | image: profile.jpg 4 | about: 5 | template: jolla 6 | links: 7 | - icon: github 8 | text: GitHub 9 | href: https://github.com/coatless/quarto-webr 10 | --- 11 | 12 | This blog is a demo showing how to use the `quarto-webr` extension. 13 | -------------------------------------------------------------------------------- /examples/blog/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "blog" 3 | listing: 4 | contents: posts 5 | sort: "date desc" 6 | type: default 7 | categories: true 8 | sort-ui: false 9 | filter-ui: false 10 | page-layout: full 11 | title-block-banner: true 12 | --- 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/blog/posts/_metadata.yml: -------------------------------------------------------------------------------- 1 | # options specified here will apply to all posts in this folder 2 | 3 | # freeze computational output 4 | # (see https://quarto.org/docs/projects/code-execution.html#freeze) 5 | freeze: true 6 | 7 | # Enable banner style title blocks 8 | title-block-banner: true 9 | -------------------------------------------------------------------------------- /examples/blog/posts/embed-slides/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coatless/quarto-webr/8ad65f045e718ecfd45c0e5b2ec04998dd508c0f/examples/blog/posts/embed-slides/image.jpg -------------------------------------------------------------------------------- /examples/blog/posts/embed-slides/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Post Containing Slides with Interactive Code" 3 | author: "James Balamuta" 4 | date: "2023-11-13" 5 | categories: [news, code, analysis] 6 | image: "image.jpg" 7 | --- 8 | 9 | This is a post that contains slides with interactive code on a [Quarto Blog](https://quarto.org/docs/websites/website-blog.html) through the [`quarto-webr`](https://github.com/coatless/quarto-webr) extension. The configuration setup for the `quarto-webr` extension is taken care of in the `_quarto.yml` file to avoid needing to re-specify options multiple times. 10 | 11 | ## Presentation 12 | 13 | :::{.callout-important} 14 | For `quarto-webr` to work within RevealJS, you must use a [**pre-release** version of Quarto that is 1.4.502 or greater](https://quarto.org/docs/download/prerelease) that contains an updated copy of `pandoc`. For more details, please see [Issue #14](https://github.com/coatless/quarto-webr/issues/14). 15 | ::: 16 | 17 | 24 | 25 |
26 | ```{=html} 27 | 28 | ``` 29 |
30 | 31 | ## Embed Code 32 | 33 | Place the following code inside of the Quarto Document: 34 | 35 | ````html 36 | 43 | 44 |
45 | ```{=html} 46 | 47 | ``` 48 |
49 | ```` 50 | -------------------------------------------------------------------------------- /examples/blog/posts/post-with-code/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coatless/quarto-webr/8ad65f045e718ecfd45c0e5b2ec04998dd508c0f/examples/blog/posts/post-with-code/image.jpg -------------------------------------------------------------------------------- /examples/blog/posts/post-with-code/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Post With Interactive Code" 3 | author: "James Balamuta" 4 | date: "2023-11-12" 5 | categories: [news, code, analysis] 6 | image: "image.jpg" 7 | --- 8 | 9 | This is a post with interactive code on a [Quarto Blog](https://quarto.org/docs/websites/website-blog.html) through the [`quarto-webr`](https://github.com/coatless/quarto-webr) extension. The configuration setup for the `quarto-webr` extension is taken care of in the `_quarto.yml` file to avoid needing to re-specify options multiple times. 10 | 11 | ```{webr-r} 12 | print("Hello blog Quarto world!") 13 | ``` 14 | -------------------------------------------------------------------------------- /examples/blog/profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coatless/quarto-webr/8ad65f045e718ecfd45c0e5b2ec04998dd508c0f/examples/blog/profile.jpg -------------------------------------------------------------------------------- /examples/blog/styles.css: -------------------------------------------------------------------------------- 1 | /* css styles */ 2 | -------------------------------------------------------------------------------- /examples/book/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | -------------------------------------------------------------------------------- /examples/book/_extensions: -------------------------------------------------------------------------------- 1 | ../../_extensions/ -------------------------------------------------------------------------------- /examples/book/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: book 3 | 4 | book: 5 | title: "Sample quarto-webr Book Project" 6 | author: "JJB" 7 | date: today 8 | url: https://quarto-webr.thecoatlessprofessor.com/examples/book 9 | repo-url: https://github.com/coatless/quarto-webr/tree/main/examples/book 10 | repo-actions: edit 11 | search: true 12 | reader-mode: true 13 | sidebar: 14 | style: "docked" 15 | chapters: 16 | - index.qmd 17 | - part: "Exploring R" 18 | chapters: 19 | - example-page.qmd 20 | - slide-embed.qmd 21 | - href: ../../ 22 | text: Documentation Portal 23 | page-footer: 24 | left: "An example book with quarto-webr." 25 | right: 26 | - icon: github 27 | href: https://github.com/coatless/quarto-webr 28 | 29 | # Set the language that should be used for Quarto book 30 | # https://github.com/quarto-dev/quarto-cli/tree/main/src/resources/language 31 | # lang: en 32 | 33 | # Set default options for every webpage that may or may not include webR. 34 | webr: 35 | show-startup-message: false # Display status of webR initialization 36 | # show-header-message: false # Check to see if COOP&COEP headers are set for speed. 37 | # packages: ['ggplot2', 'dplyr'] # Pre-install dependencies 38 | # base-url: '' # Base URL used for specifying where R WebAssembly binaries should be located 39 | # home-dir: '/home/rstudio' # Customize where the working directory is 40 | # channel-type: 'post-message' # Specify communication channel 41 | # service-worker-url: '' # URL from where to load JavaScript worker scripts when loading webR with the ServiceWorker communication channel. 42 | 43 | # Attach webR to every page 44 | filters: 45 | - webr 46 | -------------------------------------------------------------------------------- /examples/book/example-page.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Example page" 3 | webr: 4 | show-startup-message: true # Display status of webR initialization 5 | packages: ['ggplot2', 'dplyr'] # Pre-install dependency 6 | --- 7 | 8 | On this page, we set two options directly in the Quarto document. The rest of the options are coming from the `_quarto.yml` project file. These options are considered "global". 9 | 10 | The local options that we enabled are to show the webR status bar and to pre-install the `ggplot2` and `dplyr` packages. We create a hypothetical document that compares and constrasts Base R code with Tidyverse code. 11 | 12 | 13 | # Sorting 14 | 15 | Consider the need to find the highest or lowest values. In this case, we're seeking to sort or modify the order of the data. 16 | 17 | ::: {.panel-tabset group="language"} 18 | 19 | ## Base R 20 | 21 | ```{webr-r} 22 | within(mtcars, { 23 | mtcars[order(cyl, disp), , drop = FALSE] 24 | }) 25 | ``` 26 | 27 | ## tidyverse 28 | 29 | ```{webr-r} 30 | library(dplyr) 31 | mtcars |> 32 | arrange(cyl, disp) 33 | ``` 34 | 35 | 36 | ::: 37 | 38 | # Summarize 39 | 40 | Next, let's take a look at how summarization differs between Base R and the Tidyverse 41 | 42 | ::: {.panel-tabset group="language"} 43 | 44 | ## Base R 45 | 46 | ```{webr-r} 47 | mtcars_by <- by(mtcars, mtcars$cyl, function(df) { 48 | with(df, data.frame(cyl = cyl[[1]], mean = mean(disp), n = nrow(df))) 49 | }) 50 | do.call(rbind, mtcars_by) 51 | ``` 52 | 53 | ## tidyverse 54 | 55 | ```{webr-r} 56 | library(dplyr) 57 | 58 | mtcars |> 59 | group_by(cyl) |> 60 | summarise(mean = mean(disp), n = n()) 61 | ``` 62 | 63 | 64 | ::: 65 | 66 | # Graphing 67 | 68 | Next, let's take a look at how summarization differs between Base R and the Tidyverse 69 | 70 | ::: {.panel-tabset group="language"} 71 | 72 | ## Base R 73 | 74 | ```{webr-r} 75 | plot(mtcars$wt, mtcars$mpg, 76 | main = "Scatterplot in Base R", 77 | xlab = "Car Weight", ylab = "MPG", 78 | col = "blue", lwd = 1) 79 | abline(lm(mtcars$mpg ~ mtcars$wt), col = "red") 80 | ``` 81 | 82 | ## tidyverse 83 | 84 | ```{webr-r} 85 | library(ggplot2) 86 | 87 | ggplot(mtcars, aes(x = wt, y = mpg)) + 88 | geom_point(size=2, color="blue", stroke=1) + 89 | geom_smooth(method=lm, color="red") + 90 | ggtitle("Scatterplot in ggplot2") + 91 | xlab("Car Weight") 92 | ``` 93 | 94 | 95 | ::: 96 | -------------------------------------------------------------------------------- /examples/book/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Quarto Webr Demo Book" 3 | --- 4 | 5 | # Welcome 6 | 7 | Welcome to a demo Book that uses the [`quarto-webr`](https://github.com/coatless/quarto-webr) extension to generate interactive code cells with [Quarto](https://quarto.org) and [webR](https://docs.r-wasm.org/webr/latest/). 8 | 9 | ```{webr-r} 10 | print("Hello there! Welcome to a quarto-webR powered book!") 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /examples/book/slide-embed.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Embed Slides" 3 | --- 4 | 5 | On this page, we show how we can embed a RevealJS Presentation inside of a Quarto Book. 6 | 7 | ## Presentation 8 | 9 | :::{.callout-important} 10 | For `quarto-webr` to work within RevealJS, you must use a [**pre-release** version of Quarto that is 1.4.502 or greater](https://quarto.org/docs/download/prerelease) that contains an updated copy of `pandoc`. For more details, please see [Issue #14](https://github.com/coatless/quarto-webr/issues/14). 11 | ::: 12 | 13 | 20 | 21 |
22 | ```{=html} 23 | 24 | 25 | ``` 26 |
27 |
28 | ```{=html} 29 | 30 | ``` 31 |
32 | 33 | ## Embed Code 34 | 35 | Place the following code inside of the Quarto Document: 36 | 37 | ````html 38 | 45 | 46 |
47 | ```{=html} 48 | 49 | ``` 50 |
51 | ```` -------------------------------------------------------------------------------- /examples/html-document/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | -------------------------------------------------------------------------------- /examples/html-document/_extensions: -------------------------------------------------------------------------------- 1 | ../../_extensions/ -------------------------------------------------------------------------------- /examples/html-document/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | title: "index" 3 | -------------------------------------------------------------------------------- /examples/html-document/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "quarto-webr Demo HTML Document" 3 | format: html 4 | webr: 5 | channel-type: "automatic" 6 | filters: 7 | - webr 8 | --- 9 | 10 | # Welcome 11 | 12 | Welcome to a demo HTML Document that uses the [`quarto-webr`](https://github.com/coatless/quarto-webr) extension to generate interactive code cells with [Quarto](https://quarto.org) and [webR](https://docs.r-wasm.org/webr/latest/). 13 | 14 | ```{webr-r} 15 | print("Hello there! Welcome to a quarto-webR powered HTML Document!") 16 | ``` 17 | 18 | Let's go back to the [documentation portal](../../) 19 | -------------------------------------------------------------------------------- /examples/readme/_extensions: -------------------------------------------------------------------------------- 1 | ../../_extensions -------------------------------------------------------------------------------- /examples/readme/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | title: "index" 3 | -------------------------------------------------------------------------------- /examples/readme/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: webR in Quarto HTML Documents 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | This is a webr-enabled code cell in a Quarto HTML document. 10 | 11 | ```{webr-r} 12 | fit = lm(mpg ~ am, data = mtcars) 13 | 14 | summary(fit) 15 | ``` 16 | 17 | 18 | Return to the [documentation website](https://quarto-webr.thecoatlessprofessor.com/) or [GitHub Repository](https://github.com/coatless/quarto-webr). -------------------------------------------------------------------------------- /examples/revealjs/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | -------------------------------------------------------------------------------- /examples/revealjs/_extensions: -------------------------------------------------------------------------------- 1 | ../../_extensions/ -------------------------------------------------------------------------------- /examples/revealjs/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | title: "index" 3 | -------------------------------------------------------------------------------- /examples/revealjs/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "quarto-webr Demo RevealJS Document" 3 | format: revealjs 4 | webr: 5 | packages: ['ggplot2', 'dplyr'] # Install R packages on document open 6 | # autoload-packages: false # Disable automatic loading of packages 7 | # show-startup-message: false # Disable displaying status of webR initialization 8 | filters: 9 | - webr 10 | --- 11 | 12 | ## Welcome 13 | 14 | Welcome to a demo RevealJS presentation that uses the [`quarto-webr`](https://github.com/coatless/quarto-webr) extension to generate interactive code cells with [Quarto](https://quarto.org) and [webR](https://docs.r-wasm.org/webr/latest/). 15 | 16 | :::{.callout-important} 17 | This template requires a [**pre-release** version of Quarto that is 1.4.502 or greater](https://quarto.org/docs/download/prerelease) that contains an updated copy of `pandoc`. For more details, please see [Issue #14](https://github.com/coatless/quarto-webr/issues/14). 18 | ::: 19 | 20 | Not the right template? Let's go back to the [documentation portal](../../) 21 | 22 | ## webR in RevealJS 23 | 24 | This is a webR-enabled code cell in a Quarto RevealJS document. 25 | 26 | ```{webr-r} 27 | fit = lm(mpg ~ wt, data = mtcars) 28 | 29 | summary(fit) 30 | ``` 31 | 32 | ## Base R Graphing with webR 33 | 34 | ```{webr-r} 35 | plot(pressure) 36 | ``` 37 | 38 | ## ggplot2 in webR 39 | 40 | ```{webr-r} 41 | ggplot(mpg, aes(displ, hwy, colour = class)) + 42 | geom_point() 43 | ``` 44 | 45 | ## Help Documentation 46 | 47 | ```{webr-r} 48 | ?mean 49 | ``` 50 | 51 | 52 | ## Prints, Warnings, and Errors 53 | 54 | ```{webr-r} 55 | cat("Hello there!\n") 56 | 57 | x = c(1, 2, 3) 58 | print(x) 59 | 60 | warning("Uh-oh, something is amiss") 61 | 62 | stop("I'm sorry Dave, I'm afraid I can't do that") 63 | ``` 64 | 65 | 66 | ## Keyboard Shortcuts 67 | 68 | - Run selected code using either: 69 | - macOS: + ↩/Return 70 | - Windows/Linux: Ctrl + ↩/Enter 71 | - Run the entire code by clicking the "Run code" button or pressing Shift+. 72 | 73 | ```{webr-r} 74 | print("Hello quarto-webr RevealJS world!") 75 | 76 | 3 + 5 77 | ``` 78 | 79 | ## Embedded Slides 80 | 81 | You can embed the slide deck inside of a Quarto Website or Book by using: 82 | 83 | ````html 84 | 91 | 92 |
93 | ```{=html} 94 | 95 | ``` 96 |
97 | ```` 98 | 99 | :::{.callout-note} 100 | Avoid using _within_ a RevealJS presentation. Only 1 instance of webR should be running. 101 | ::: 102 | 103 | ## Fin 104 | 105 | Thanks for checking out the demo! Let's head back to 106 | the [documentation portal](../../). -------------------------------------------------------------------------------- /examples/website/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | /_site/* 3 | -------------------------------------------------------------------------------- /examples/website/_extensions: -------------------------------------------------------------------------------- 1 | ../../_extensions/ -------------------------------------------------------------------------------- /examples/website/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: website 3 | 4 | website: 5 | title: "Demo Quarto Webr Website" 6 | search: true 7 | reader-mode: true 8 | navbar: 9 | left: 10 | - href: index.qmd 11 | text: Home 12 | - href: example-page.qmd 13 | text: Example page 14 | - href: slide-embed.qmd 15 | text: Embed Slides 16 | - href: ../../ 17 | text: Documentation Portal 18 | sidebar: 19 | style: "floating" 20 | contents: 21 | - section: "Content" 22 | contents: 23 | - index.qmd 24 | - example-page.qmd 25 | - slide-embed.qmd 26 | - href: ../../ 27 | text: Documentation Portal 28 | 29 | page-footer: 30 | left: "An example website with quarto-webr." 31 | right: 32 | - icon: github 33 | href: https://github.com/coatless/quarto-webr 34 | 35 | # Set the language that should be used for Quarto websites 36 | # https://github.com/quarto-dev/quarto-cli/tree/main/src/resources/language 37 | # lang: en 38 | 39 | # Set default options for every webpage that may or may not include webR. 40 | webr: 41 | show-startup-message: false # Display status of webR initialization 42 | # show-header-message: false # Check to see if COOP&COEP headers are set for speed. 43 | # packages: ['ggplot2', 'dplyr'] # Pre-install dependencies 44 | # base-url: '' # Base URL used for specifying where R WebAssembly binaries should be located 45 | # home-dir: '/home/rstudio' # Customize where the working directory is 46 | # channel-type: 'post-message' # Specify communication channel 47 | # service-worker-url: '' # URL from where to load JavaScript worker scripts when loading webR with the ServiceWorker communication channel. 48 | 49 | # Attach webR to every page 50 | filters: 51 | - webr 52 | -------------------------------------------------------------------------------- /examples/website/example-page.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Example page" 3 | webr: 4 | show-startup-message: true # Display status of webR initialization 5 | packages: ['ggplot2'] # Pre-install dependency 6 | --- 7 | 8 | On this page, we set two options directly in the Quarto document. The rest of the options are coming from the `_quarto.yml` project file. These options are considered "global". 9 | 10 | The local options that we enabled are to show the webR status bar and to pre-install the ggplot2 package. 11 | 12 | ```{webr-r} 13 | library(ggplot2) 14 | 15 | p <- ggplot(mpg, aes(cyl, hwy)) 16 | p + geom_jitter(aes(colour = class)) 17 | ``` 18 | 19 | :::callout-note 20 | If we did not specify the package dependency in the document header, then we would need to add to the code cell the installation command of `webr::install('ggplot2')` prior to using `library(ggplot2)`. 21 | ::: -------------------------------------------------------------------------------- /examples/website/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Quarto Webr Demo Website" 3 | --- 4 | 5 | # Welcome 6 | 7 | Welcome to a demo website that uses the [`quarto-webr`](https://github.com/coatless/quarto-webr) extension to generate interactive code cells with [Quarto](https://quarto.org) and [webR](https://docs.r-wasm.org/webr/latest/). 8 | 9 | ```{webr-r} 10 | print("Hello there! Welcome to a quarto-webR powered website!") 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /examples/website/slide-embed.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Embed Slides" 3 | --- 4 | 5 | On this page, we show how we can embed a RevealJS Presentation inside of a Quarto Website. 6 | 7 | ## Presentation 8 | 9 | :::{.callout-important} 10 | For `quarto-webr` to work within RevealJS, you must use a [**pre-release** version of Quarto that is 1.4.502 or greater](https://quarto.org/docs/download/prerelease) that contains an updated copy of `pandoc`. For more details, please see [Issue #14](https://github.com/coatless/quarto-webr/issues/14). 11 | ::: 12 | 13 | 20 | 21 |
22 | ```{=html} 23 | 24 | ``` 25 |
26 | 27 | ## Embed Code 28 | 29 | Place the following code inside of the Quarto Document: 30 | 31 | ````html 32 | 39 | 40 |
41 | ```{=html} 42 | 43 | ``` 44 |
45 | ```` 46 | -------------------------------------------------------------------------------- /quarto-webr.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": {} 8 | } -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | -------------------------------------------------------------------------------- /tests/_extensions: -------------------------------------------------------------------------------- 1 | ../_extensions -------------------------------------------------------------------------------- /tests/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: website 3 | 4 | website: 5 | title: "Test Suite for quarto-webr" 6 | search: true 7 | reader-mode: true 8 | sidebar: 9 | style: "floating" 10 | contents: 11 | - href: index.qmd 12 | text: Home 13 | - href: ../../ 14 | text: Main Website 15 | - section: "Tests" 16 | contents: 17 | - auto: "*test*.qmd" 18 | 19 | 20 | page-footer: 21 | left: "Test suite for quarto-webr." 22 | right: 23 | - icon: github 24 | href: https://github.com/coatless/quarto-webr 25 | 26 | # Allow quarto to switch between light and dark themes. 27 | theme: 28 | light: cosmo 29 | dark: darkly 30 | 31 | # Set the language that should be used for Quarto websites 32 | # https://github.com/quarto-dev/quarto-cli/tree/main/src/resources/language 33 | # lang: en 34 | 35 | # Set default options for every webpage that may or may not include webR. 36 | # webr: 37 | # show-startup-message: false # Display status of webR initialization 38 | # show-header-message: false # Check to see if COOP&COEP headers are set for speed. 39 | # packages: ['ggplot2', 'dplyr'] # Pre-install dependencies 40 | # base-url: '' # Base URL used for specifying where R WebAssembly binaries should be located 41 | # home-dir: '/home/rstudio' # Customize where the working directory is 42 | # channel-type: 'post-message' # Specify communication channel 43 | # service-worker-url: '' # URL from where to load JavaScript worker scripts when loading webR with the ServiceWorker communication channel. 44 | 45 | # Attach webR to every page 46 | filters: 47 | - webr 48 | -------------------------------------------------------------------------------- /tests/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "quarto-webr Test Website" 3 | subtitle: "Extension Test Suite" 4 | --- 5 | 6 | # Welcome 7 | 8 | Welcome to the test suite website for the [`quarto-webr`](https://github.com/coatless/quarto-webr). This website is meant to examine how different features of the extension are working or not working across different browsers. 9 | 10 | ```{webr-r} 11 | print("Welcome to behind the scenes of quarto-webr!") 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /tests/qwebr-test-editor-options.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Editor Options" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Check that the editor responses correctly to options being set. 10 | 11 | ## Adaptive Container Constraints 12 | 13 | ### Single line 14 | 15 | ```{webr-r} 16 | print("test") 17 | ``` 18 | 19 | ### Uncapped height 20 | 21 | ```{webr-r} 22 | print("test") 23 | 59120 24 | 1 + 1 25 | c(1, 3, 4) 26 | print("line 5") 27 | ``` 28 | 29 | ### Height cap 30 | 31 | ```{webr-r} 32 | #| editor-max-height: 80 33 | print("test") 34 | 59120 35 | 1 + 1 36 | c(1, 3, 4) 37 | print("line 5") 38 | ``` 39 | 40 | ## Autosuggetions 41 | 42 | Opt-in to auto suggestions. 43 | 44 | ```{webr-r} 45 | #| editor-quick-suggestions: true 46 | my_long_variable = 1 47 | 48 | prin 49 | ``` 50 | 51 | 52 | ## Highlight 53 | 54 | Opt-in to auto suggestions. 55 | 56 | ### Only 1 line 57 | ```{webr-r} 58 | #| editor-code-line-numbers:1 59 | my_long_variable = 1 60 | 61 | 1 + 1 62 | 63 | print("hello!") 64 | ``` 65 | 66 | ### Line 1 and 5 67 | ```{webr-r} 68 | #| editor-code-line-numbers:1,5 69 | my_long_variable = 1 70 | 71 | 1 + 1 72 | 73 | print("hello!") 74 | ``` 75 | 76 | ### Line 1-3 and 5 77 | 78 | ```{webr-r} 79 | #| editor-code-line-numbers:1-3,5 80 | my_long_variable = 1 81 | 82 | 1 + 1 83 | 84 | print("hello!") 85 | ``` 86 | 87 | 88 | ## Word wrap 89 | 90 | ### Enabled Wrap 91 | ```{webr-r} 92 | #| editor-word-wrap: true 93 | 94 | my_extra_extra_extra_extra_extra_long_variable = 1 95 | ``` 96 | 97 | ### Disabled Wrap 98 | ```{webr-r} 99 | #| editor-word-wrap: false 100 | 101 | my_extra_extra_extra_extra_extra_long_variable = 1 102 | ``` 103 | -------------------------------------------------------------------------------- /tests/qwebr-test-escape-html-output-characters.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Escape Output with HTML Entities" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Ensure HTML output is escaped or passed t hrough 10 | 11 | ## Interactive 12 | 13 | ### results: markup 14 | ```{webr-r} 15 | # This function converts a markdown link into HTML 16 | "[Posit](https://posit.co)" |> (\(.) { 17 | text <- sub("\\].*", "", sub(".*\\[", "", .)) 18 | url <- sub("\\).*", "", sub(".*\\(", "", .)) 19 | 20 | writeLines(noquote(paste0('', text, ''))) 21 | })() 22 | ``` 23 | 24 | ## Non-interactive 25 | 26 | ### results: markup 27 | 28 | ```{webr-r} 29 | #| context: output 30 | # This function converts a markdown link into HTML 31 | "[Posit](https://posit.co)" |> (\(.) { 32 | text <- sub("\\].*", "", sub(".*\\[", "", .)) 33 | url <- sub("\\).*", "", sub(".*\\(", "", .)) 34 | 35 | writeLines(noquote(paste0('', text, ''))) 36 | })() 37 | ``` 38 | 39 | ### results: asis 40 | 41 | ```{webr-r} 42 | #| context: output 43 | #| results: asis 44 | # This function converts a markdown link into HTML 45 | "[Posit](https://posit.co)" |> (\(.) { 46 | text <- sub("\\].*", "", sub(".*\\[", "", .)) 47 | url <- sub("\\).*", "", sub(".*\\(", "", .)) 48 | 49 | writeLines(noquote(paste0('', text, ''))) 50 | })() 51 | ``` 52 | 53 | 54 | ### output: asis 55 | 56 | ```{webr-r} 57 | #| context: output 58 | #| output: asis 59 | # This function converts a markdown link into HTML 60 | "[Posit](https://posit.co)" |> (\(.) { 61 | text <- sub("\\].*", "", sub(".*\\[", "", .)) 62 | url <- sub("\\).*", "", sub(".*\\(", "", .)) 63 | 64 | writeLines(noquote(paste0('', text, ''))) 65 | })() 66 | ``` 67 | 68 | -------------------------------------------------------------------------------- /tests/qwebr-test-global-cell-options.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Setting Global Cell Options" 3 | format: html 4 | engine: knitr 5 | webr: 6 | cell-options: 7 | comment: "## " 8 | autorun: true 9 | filters: 10 | - webr 11 | --- 12 | 13 | Check that the global options array is correctly parsed and that local values of the cell can still override a global option. 14 | 15 | ## Interactive 16 | 17 | ### Global 18 | ```{webr-r} 19 | print("test") 20 | ``` 21 | 22 | ### Local 23 | 24 | ```{webr-r} 25 | #| comment: "" 26 | print("test") 27 | ``` 28 | 29 | 30 | ## Non-interactive 31 | 32 | ### Global 33 | ```{webr-r} 34 | #| context: output 35 | print("test") 36 | ``` 37 | 38 | ### Local 39 | 40 | ```{webr-r} 41 | #| context: output 42 | #| comment: "" 43 | print("test") 44 | ``` 45 | -------------------------------------------------------------------------------- /tests/qwebr-test-help-documentation.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Help Documentation" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Test pager event support by verifying help documentation works in the interactive and non-interactive contexts. 10 | 11 | ## Interactive 12 | 13 | ```{webr-r} 14 | ?mean 15 | ``` 16 | 17 | ## Non-interactive 18 | 19 | ```{webr-r} 20 | #| context: output 21 | ?sd 22 | ``` 23 | -------------------------------------------------------------------------------- /tests/qwebr-test-interactive-with-keyboard-shortcut.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Keyboard Shortcuts in Code cell" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | This is a webr-enabled code cell in a Quarto HTML document. 10 | 11 | 12 | ```{webr-r} 13 | -3 + 5 14 | 15 | print("Hello quarto-webr World!") 16 | ``` 17 | 18 | 19 | - Run selected code using either: 20 | - macOS: + ↩/Return 21 | - Windows/Linux: Ctrl + ↩/Enter 22 | - Run the entire code by clicking the "Run code" button or pressing Shift+. 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/qwebr-test-internal-cell.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Cell Context Options" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Test page for verifying cell context options set explicitly with `context`. 10 | 11 | ## Interactive 12 | 13 | ### Static 14 | ```{webr-r} 15 | #| context: interactive 16 | 1 + 1 17 | ``` 18 | 19 | ### Autorun 20 | 21 | ```{webr-r} 22 | #| context: interactive 23 | #| autorun: true 24 | 1 + 1 25 | ``` 26 | 27 | ### Read-only 28 | 29 | ```{webr-r} 30 | #| context: interactive 31 | #| read-only: true 32 | #| autorun: true 33 | 1 + 1 34 | ``` 35 | 36 | 37 | ## Setup 38 | 39 | Hidden cell that sets `x` and `y` vector values. 40 | 41 | ```{webr-r} 42 | #| context: setup 43 | x = c(1, 5, 3, -2) 44 | y = c(-5, 8, 9, 4) 45 | ``` 46 | 47 | ## Output 48 | 49 | Hidden cell that retrieves previously set `x` and `y` vector values and displays the data. 50 | 51 | ```{webr-r} 52 | #| context: output 53 | cat("x: ") 54 | print(x) 55 | 56 | cat("y: ") 57 | print(y) 58 | 59 | plot(x, y) 60 | ``` 61 | -------------------------------------------------------------------------------- /tests/qwebr-test-multiple-cells.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Multiple webR cells" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Ensure each webR cell outputs in its own area. 10 | 11 | ## Interactive 12 | 13 | ```{webr-r} 14 | 1 + 1 15 | ``` 16 | 17 | Graph in separate code cell 18 | 19 | ```{webr-r} 20 | plot(pressure) 21 | ``` 22 | 23 | ## Non-interactive 24 | 25 | ```{webr-r} 26 | #| context: output 27 | 1 + 1 28 | ``` 29 | 30 | Graph in separate code cell 31 | 32 | ```{webr-r} 33 | #| context: output 34 | plot(pressure) 35 | ``` -------------------------------------------------------------------------------- /tests/qwebr-test-non-interactive-chained-cells.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Chained Non-interactive Areas" 3 | engine: knitr 4 | webr: 5 | packages: ['ggplot2', 'dplyr'] 6 | filters: 7 | - webr 8 | --- 9 | 10 | :::{.callout-important} 11 | We've slowed down each cell's execution time by about 1/4 of a second to show how the document is responding. 12 | ::: 13 | 14 | # Package dependencies 15 | 16 | The `quarto-webr` extension is set to automatically install and load the `ggplot2` and `dplyr` packages by specifying a `packages` key in the document's header. 17 | 18 | # Setup a hidden ggplot2 object 19 | 20 | From there, we're going to use the `context: setup` hidden cell to create a `ggplot2` object that uses the `mtcars` data set with the aesthetic mappings of `x = wt` and `y = mpg` called `g`. 21 | 22 | ```{webr-r} 23 | #| context: setup 24 | g <- ggplot(mtcars, aes(x = wt, y = mpg)) 25 | 26 | Sys.sleep(0.25) 27 | ``` 28 | 29 | # Generate a graph 30 | 31 | Let's move from setup to generating and displaying results by using `g` object created in `setup` within an `output` context: 32 | 33 | ```{webr-r} 34 | #| context: output 35 | g + geom_point() 36 | 37 | Sys.sleep(0.25) 38 | ``` 39 | 40 | # Re-use prior graph object 41 | 42 | Let's also re-use the base `g` but change the aesthetics so that colour is now present. 43 | 44 | ```{webr-r} 45 | #| context: output 46 | g + geom_point(aes(colour = factor(cyl))) 47 | Sys.sleep(0.25) 48 | ``` 49 | 50 | # Expose the setup object 51 | 52 | Finally, let's make sure we can do some interesting things with the interactive session. 53 | 54 | :::{.callout-note} 55 | Changes inside of interactive cells do not propagate backwards in the document. 56 | ::: 57 | 58 | ```{webr-r} 59 | g 60 | ``` 61 | -------------------------------------------------------------------------------- /tests/qwebr-test-non-interactive-context-with-packages.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Load and Use Packages used in Context" 3 | engine: knitr 4 | webr: 5 | packages: ['ggplot2'] 6 | show-startup-message: false 7 | autoload-packages: false 8 | filters: 9 | - webr 10 | --- 11 | 12 | This document disables autoloading of the packages and manually loads the package inside of the context output. 13 | 14 | ```{webr-r} 15 | #| context: output 16 | library("ggplot2") 17 | g <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point() 18 | g 19 | ``` 20 | 21 | Next, we should be able to retrieve the prior cells value 22 | ```{webr-r} 23 | #| context: interactive 24 | g + aes(color = factor(cyl)) 25 | ``` 26 | -------------------------------------------------------------------------------- /tests/qwebr-test-non-interactive-setup-with-packages-and-interactive.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Setup Cell with Packages for Interactive" 3 | engine: knitr 4 | webr: 5 | show-startup-message: true 6 | packages: ['tibble', 'dplyr', 'ggplot2'] 7 | autoload-packages: true 8 | filters: 9 | - webr 10 | --- 11 | 12 | The following hidden cell should setup a ggplot2 theme and set variables: 13 | 14 | ```{webr-r} 15 | #| context: setup 16 | s <- 1000 17 | theme_set(theme_minimal()) 18 | blue <- "#327291" 19 | ``` 20 | 21 | The next cell should handle graphing values with a theme being set: 22 | 23 | ```{webr-r} 24 | mean <- 5 25 | sd <- 2 26 | n <- 100 27 | 28 | data <- tibble(x = rnorm(n = n, mean = mean, sd = sd)) 29 | 30 | ggplot(data, aes(x = x)) + 31 | geom_histogram( 32 | color = "gray20", 33 | linewidth = 0.25, 34 | fill = blue, 35 | alpha = .85 36 | ) 37 | ``` -------------------------------------------------------------------------------- /tests/qwebr-test-non-interactive-setup-with-packages.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Packages used in Hidden Setup" 3 | engine: knitr 4 | webr: 5 | packages: ["dplyr", "tibble"] 6 | filters: 7 | - webr 8 | --- 9 | 10 | Perform data manipulations on `mtcars` in a non-interactive cell... 11 | 12 | ```{webr-r} 13 | #| label: spike-data 14 | #| context: setup 15 | 16 | new_mtcars <- mtcars |> 17 | tibble::rownames_to_column(var = "car") |> 18 | tibble::as_tibble() |> 19 | dplyr::select(car, cyl, disp, wt) |> 20 | dplyr::mutate(wt = dplyr::case_when( 21 | wt < 2 ~ -wt, 22 | TRUE ~ wt)) 23 | ``` 24 | 25 | Then we print it to see how it looks: 26 | 27 | ```{webr-r} 28 | #| label: spike-data 29 | new_mtcars 30 | ``` -------------------------------------------------------------------------------- /tests/qwebr-test-option-space-removal.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Space Removal after Options" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Check that the editor contents avoids retaining spaces after the options. 10 | 11 | 12 | ## Option with a Single Space 13 | 14 | ```{webr-r} 15 | #| autorun: true 16 | 17 | print("test") 18 | 1 + 1 19 | ``` 20 | 21 | ## Multiple Options with a Single Space 22 | 23 | ```{webr-r} 24 | #| read-only: true 25 | #| editor-code-line-numbers: 1,3-5,7 26 | 27 | # This is a comment 28 | 29 | 1 + 1 30 | 2 + 2 31 | 3 + 3 32 | 33 | # This is another comment 34 | ``` 35 | 36 | ## Multiple Spaces 37 | 38 | ```{webr-r} 39 | #| autorun: true 40 | 41 | 42 | 43 | 44 | print("test") 45 | 46 | 1 + 1 47 | 48 | ``` 49 | 50 | 51 | ## No Space 52 | 53 | ```{webr-r} 54 | #| autorun: true 55 | print("test") 56 | 57 | 1 + 1 58 | ``` 59 | 60 | 61 | ## No Options 62 | 63 | ```{webr-r} 64 | fit <- lm(mpg ~ vs, data = mtcars) 65 | 66 | summary(fit) 67 | ``` 68 | -------------------------------------------------------------------------------- /tests/qwebr-test-output-classes.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: CSS Output Classes" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Test output classes for standard output, standard error, and custom `classes` attributes. 10 | 11 | ## Interactive 12 | 13 | ```{webr-r} 14 | cat("Display letters: ") 15 | print(letters[1:5]) 16 | 17 | warning("This is a warning message!") 18 | 19 | stop("This is a hard error message!") 20 | ``` 21 | 22 | ## Non-interactive 23 | 24 | ### No Comment 25 | ```{webr-r} 26 | #| context: output 27 | cat("Display letters: ") 28 | print(letters[1:5]) 29 | 30 | warning("This is a warning message!") 31 | 32 | stop("This is a hard error message!") 33 | ``` 34 | 35 | ### With comment 36 | 37 | ```{webr-r} 38 | #| context: output 39 | #| comment: "## " 40 | cat("Display letters: ") 41 | print(letters[1:5]) 42 | 43 | warning("This is a warning message!") 44 | 45 | stop("This is a hard error message!") 46 | ``` 47 | 48 | ### With output class custom 49 | 50 | ```{=html} 51 | 60 | ``` 61 | 62 | ```{webr-r} 63 | #| context: output 64 | #| classes: toad green 65 | cat("Display letters: ") 66 | print(letters[1:5]) 67 | 68 | warning("This is a warning message!") 69 | 70 | stop("This is a hard error message!") 71 | ``` 72 | -------------------------------------------------------------------------------- /tests/qwebr-test-output-graph.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Graphics Output" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | This webpage tests the interactive and output contexts for showing a graph 10 | 11 | ## Interactive 12 | 13 | ### Default options 14 | ```{webr-r} 15 | #| context: interactive 16 | plot(pressure) 17 | ``` 18 | 19 | ### Reduced fig height & width 20 | 21 | ```{webr-r} 22 | #| context: interactive 23 | #| fig-height: 6 24 | #| fig-width: 4 25 | #| out-width: 600px 26 | plot(pressure) 27 | ``` 28 | 29 | 30 | ## Non-interactive 31 | 32 | ### Default options 33 | ```{webr-r} 34 | #| context: output 35 | #| fig-cap: Testing out figure captions 36 | plot(pressure) 37 | ``` 38 | 39 | ### Reduced fig height & width 40 | ```{webr-r} 41 | #| context: output 42 | #| fig-height: 5 43 | #| fig-width: 6 44 | #| out-width: 500px 45 | plot(pressure) 46 | ``` 47 | 48 | 49 | ### Reduced fig height & width 50 | ```{webr-r} 51 | #| context: output 52 | #| fig-height: 5 53 | #| fig-width: 6 54 | #| out-width: 500px 55 | #| out-height: 500px 56 | plot(pressure) 57 | ``` -------------------------------------------------------------------------------- /tests/qwebr-test-output-stderr-result-suppression.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: STDErr & Result Output Suppression" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Test options for disabling standard error (`warning: false` or `message: false`), `results: hide`, and `output: false`. 10 | 11 | ## Interactive 12 | 13 | ### Suppresion with hide 14 | 15 | ```{webr-r} 16 | #| context: interactive 17 | #| results: hide 18 | cat("Display letters: ") 19 | print(letters[1:5]) 20 | 21 | warning("This is a warning message!") 22 | 23 | stop("This is a hard error message!") 24 | ``` 25 | 26 | 27 | ### Suppression with warning 28 | 29 | ```{webr-r} 30 | #| context: interactive 31 | #| warning: false 32 | cat("Display letters: ") 33 | print(letters[1:5]) 34 | 35 | warning("This is a warning message!") 36 | 37 | stop("This is a hard error message!") 38 | ``` 39 | 40 | 41 | ### Suppression with message 42 | 43 | ```{webr-r} 44 | #| context: interactive 45 | #| message: false 46 | cat("Display letters: ") 47 | print(letters[1:5]) 48 | 49 | warning("This is a warning message!") 50 | 51 | stop("This is a hard error message!") 52 | ``` 53 | 54 | 55 | ## Non-interactive 56 | 57 | ### Suppresion with hide 58 | 59 | ```{webr-r} 60 | #| context: output 61 | #| results: hide 62 | cat("Display letters: ") 63 | print(letters[1:5]) 64 | 65 | warning("This is a warning message!") 66 | 67 | stop("This is a hard error message!") 68 | ``` 69 | 70 | ### Suppresion with output 71 | 72 | ```{webr-r} 73 | #| context: output 74 | #| output: false 75 | cat("Display letters: ") 76 | print(letters[1:5]) 77 | 78 | warning("This is a warning message!") 79 | 80 | stop("This is a hard error message!") 81 | ``` 82 | 83 | 84 | 85 | ### Suppression with warning 86 | 87 | ```{webr-r} 88 | #| context: output 89 | #| warning: false 90 | cat("Display letters: ") 91 | print(letters[1:5]) 92 | 93 | warning("This is a warning message!") 94 | 95 | stop("This is a hard error message!") 96 | ``` 97 | 98 | 99 | ### Suppression with message 100 | 101 | ```{webr-r} 102 | #| context: output 103 | #| message: false 104 | cat("Display letters: ") 105 | print(letters[1:5]) 106 | 107 | warning("This is a warning message!") 108 | 109 | stop("This is a hard error message!") 110 | ``` 111 | -------------------------------------------------------------------------------- /tests/qwebr-test-packages-autoload.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Autoload Package" 3 | format: html 4 | engine: knitr 5 | webr: 6 | packages: ['ggplot2'] 7 | autoload-packages: 'false' 8 | filters: 9 | - webr 10 | --- 11 | 12 | This webpage tests the `autoload-packages` key meta option by not loading the requested packages. 13 | 14 | ```{webr-r} 15 | # Must call the library statement 16 | library('ggplot2') 17 | ``` -------------------------------------------------------------------------------- /tests/qwebr-test-packages-multi.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Packages Key with Autoloading" 3 | format: html 4 | engine: knitr 5 | webr: 6 | packages: ['ggplot2', 'dplyr'] 7 | autoload-packages: true 8 | filters: 9 | - webr 10 | --- 11 | 12 | This webpage tests the `packages` key meta option with the default of `autoload-packages` removing the need for a `library()` call. 13 | 14 | ```{webr-r} 15 | ggplot() 16 | ``` -------------------------------------------------------------------------------- /tests/qwebr-test-repo-key.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Repos package key" 3 | format: html 4 | engine: knitr 5 | webr: 6 | packages: ['demorwasmbinary', 'visualize', 'fakepkg'] 7 | repos: 8 | - 'https://tutorials.thecoatlessprofessor.com/webr-unified-gh-workflow/' 9 | filters: 10 | - webr 11 | --- 12 | 13 | This document tests the `repos` key meta option by attempting to download a package `demorwasmbinary` from a custom repository at: 14 | 15 | 16 | 17 | And, then, falls back on the main webR repository for a second package `visualize`. 18 | 19 | ```{webr-r} 20 | #| context: output 21 | 22 | print(paste0("Check if we are in webR with non-CRAN package demorwasmbinary: ", demorwasmbinary::in_webr())) 23 | 24 | print("Creating a graph with a package on CRAN") 25 | visualize::visualize.norm() 26 | ``` -------------------------------------------------------------------------------- /tests/qwebr-test-revealjs.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: webR in RevealJS" 3 | subtitle: "Examining State" 4 | authors: "Presentation Lead" 5 | format: 6 | revealjs: 7 | theme: dark 8 | engine: knitr 9 | filters: 10 | - webr 11 | --- 12 | 13 | ## webR in RevealJS 14 | 15 | This is a webR-enabled code cell in a Quarto RevealJS document. 16 | 17 | ```{webr-r} 18 | fit = lm(mpg ~ wt, data = mtcars) 19 | 20 | summary(fit) 21 | ``` 22 | 23 | 24 | ## Keyboard Shortcuts 25 | 26 | - Run selected code using either: 27 | - macOS: + ↩/Return 28 | - Windows/Linux: Ctrl + ↩/Enter 29 | - Run the entire code by clicking the "Run code" button or pressing Shift+. 30 | 31 | ```{webr-r} 32 | print("Hello quarto-webr RevealJS world!") 33 | 34 | 3 + 5 35 | ``` 36 | 37 | ## Text Before and After Code Cell 38 | 39 | Sample text before 40 | 41 | ```{webr-r} 42 | message("Hello World!") 43 | ``` 44 | 45 | Sample text after 46 | 47 | ## Scrollable Class Enabled 48 | 49 | ```{webr-r} 50 | 2 + 3 51 | ``` 52 | 53 | The default webR block should not make the slide too wide 54 | (no scrollbar at the bottom). 55 | -------------------------------------------------------------------------------- /tests/qwebr-test-run-built-in.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Run built-in webR version" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Test to see if the `version` is respected under the built-in value: 10 | 11 | ```{webr-r} 12 | #| context: output 13 | utils::packageVersion("webr") 14 | ``` 15 | -------------------------------------------------------------------------------- /tests/qwebr-test-run-latest.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Run latest version" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | webr: 8 | version: 'latest' 9 | --- 10 | 11 | Test to see if the version key works under the latest version: 12 | 13 | ```{webr-r} 14 | #| context: output 15 | utils::packageVersion("webr") 16 | ``` 17 | -------------------------------------------------------------------------------- /tests/qwebr-test-self-contained.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: embed-resources" 3 | format: 4 | html: 5 | embed-resources: true 6 | engine: knitr 7 | filters: 8 | - webr 9 | --- 10 | 11 | Ensure `embed-resources` option correctly puts a copy of FontAwesome in the document. 12 | 13 | ## Interactive 14 | ```{webr-r} 15 | 1 + 1 16 | ``` 17 | 18 | ## Non-interactive 19 | 20 | ```{webr-r} 21 | #| context: output 22 | Sys.sleep(3) 23 | 24 | print("Sleep successful! Did you see the R logo?") 25 | ``` 26 | -------------------------------------------------------------------------------- /tests/qwebr-test-service-worker-version.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Service Worker with Version" 3 | format: 4 | html: 5 | resources: 6 | - webr-serviceworker.js 7 | - webr-worker.js 8 | engine: knitr 9 | webr: 10 | channel-type: "service-worker" 11 | version: "latest" 12 | filters: 13 | - webr 14 | --- 15 | 16 | This is a webr-enabled code cell in a Quarto HTML document that is set to use the service-worker option under the `latest` version of webR. 17 | 18 | ```{webr-r} 19 | #| autorun: true 20 | -3 + 5 21 | 22 | utils::packageVersion("webr") 23 | 24 | print("Hello service worker model!") 25 | ``` 26 | -------------------------------------------------------------------------------- /tests/qwebr-test-service-worker.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Service Worker" 3 | format: 4 | html: 5 | resources: 6 | - webr-serviceworker.js 7 | - webr-worker.js 8 | engine: knitr 9 | webr: 10 | channel-type: "service-worker" 11 | filters: 12 | - webr 13 | --- 14 | 15 | This is a webr-enabled code cell in a Quarto HTML document that is set to use the service-worker option. 16 | 17 | ```{webr-r} 18 | -3 + 5 19 | 20 | print("Hello service worker model!") 21 | ``` 22 | -------------------------------------------------------------------------------- /tests/qwebr-test-shim-install.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Install Packages Shim" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | ## Non-interactive 10 | 11 | ```{webr-r} 12 | #| context: output 13 | 14 | check_pkg_installed <- function(x) { 15 | x %in% installed.packages()[,"Package"] 16 | } 17 | 18 | print(paste0("(Pre-install) Is the package visualize installed? ", check_pkg_installed("visualize"))) 19 | 20 | install.packages("visualize") 21 | 22 | print(paste0("(Post-install) Is the package visualize installed? ", check_pkg_installed("visualize"))) 23 | ``` 24 | -------------------------------------------------------------------------------- /tests/qwebr-test-status-header-no-title.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | format: html 3 | engine: knitr 4 | filters: 5 | - webr 6 | --- 7 | 8 | Ensure that the webR code cell initializes a status even if a title is omitted. 9 | 10 | ```{webr-r} 11 | print("Hello hidden title world!") 12 | ``` 13 | -------------------------------------------------------------------------------- /tests/qwebr-test-status-header-suppressed-html copy.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: No Startup Status Present in HTML Documents" 3 | format: html 4 | engine: knitr 5 | webr: 6 | show-startup-message: false 7 | filters: 8 | - webr 9 | --- 10 | 11 | Ensure that the webR code cell initializes even if the webR status bar is disabled. 12 | 13 | ```{webr-r} 14 | print("Hello hidden title world!") 15 | ``` 16 | -------------------------------------------------------------------------------- /tests/qwebr-test-status-header-suppressed-revealjs.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: No Startup Status Present in RevealJS Presentations" 3 | subtitle: "Examining State" 4 | authors: "Presentation Lead" 5 | format: 6 | revealjs: 7 | theme: default 8 | engine: knitr 9 | webr: 10 | show-startup-message: false 11 | filters: 12 | - webr 13 | --- 14 | 15 | ## webR in RevealJS 16 | 17 | Ensure that the webR code cell initializes even if the webR status bar is disabled. 18 | 19 | ```{webr-r} 20 | print("Hello hidden title world!") 21 | ``` 22 | -------------------------------------------------------------------------------- /tests/qwebr-test-theme-switch.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test: Light and Dark Mode" 3 | format: html 4 | engine: knitr 5 | filters: 6 | - webr 7 | --- 8 | 9 | Test classes for Quarto's light and dark mode. 10 | 11 | Toggle the switch to see: editor change from `vs` to `vs-dark` and standard output. 12 | 13 | ## Interactive 14 | 15 | ```{webr-r} 16 | #| autorun: true 17 | cat("Display letters: ") 18 | print(letters[1:5]) 19 | 20 | plot(1:5) 21 | 22 | warning("This is a warning message!") 23 | 24 | stop("This is a hard error message!") 25 | ``` 26 | -------------------------------------------------------------------------------- /update-quarto-dev.sh: -------------------------------------------------------------------------------- 1 | QUARTO_VERSION="1.4.358" 2 | 3 | wget -O quarto-latest.deb https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-amd64.deb 4 | 5 | sudo dpkg -i ./quarto-latest.deb 6 | 7 | rm quarto-latest.deb 8 | 9 | --------------------------------------------------------------------------------