Skip to content

Commit

Permalink
Update quarto-webr extension version
Browse files Browse the repository at this point in the history
  • Loading branch information
coatless committed Jun 25, 2024
1 parent b6cf3be commit 184f636
Show file tree
Hide file tree
Showing 8 changed files with 595 additions and 38 deletions.
4 changes: 2 additions & 2 deletions _extensions/coatless/webr/_extension.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: webr
title: Embedded webr code cells
author: James Joseph Balamuta
version: 0.4.2-dev.5
quarto-required: ">=1.2.198"
version: 0.4.2
quarto-required: ">=1.4.554"
contributes:
filters:
- webr.lua
4 changes: 4 additions & 0 deletions _extensions/coatless/webr/qwebr-cell-initialization.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ qwebrInstance.then(
break;
case 'setup':
const activeDiv = document.getElementById(`qwebr-noninteractive-setup-area-${qwebrCounter}`);

// Store code in history
qwebrLogCodeToHistory(cellCode, entry.options);

// Run the code in a non-interactive state with all output thrown away
await mainWebR.evalRVoid(`${cellCode}`);
break;
Expand Down
45 changes: 42 additions & 3 deletions _extensions/coatless/webr/qwebr-compute-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,34 @@ globalThis.qwebrPrefixComment = function(x, comment) {
return `${comment}${x}`;
};

// Function to store the code in the history
globalThis.qwebrLogCodeToHistory = function(codeToRun, options) {
qwebrRCommandHistory.push(
`# Ran code in ${options.label} at ${new Date().toLocaleString()} ----\n${codeToRun}`
);
}

// Function to attach a download button onto the canvas
// allowing the user to download the image.
function qwebrImageCanvasDownloadButton(canvas, canvasContainer) {

// Create the download button
const downloadButton = document.createElement('button');
downloadButton.className = 'qwebr-canvas-image-download-btn';
downloadButton.textContent = 'Download Image';
canvasContainer.appendChild(downloadButton);

// Trigger a download of the image when the button is clicked
downloadButton.addEventListener('click', function() {
const image = canvas.toDataURL('image/png');
const link = document.createElement('a');
link.href = image;
link.download = 'qwebr-canvas-image.png';
link.click();
});
}


// Function to parse the pager results
globalThis.qwebrParseTypePager = async function (msg) {

Expand Down Expand Up @@ -113,6 +141,9 @@ globalThis.qwebrComputeEngine = async function(
captureOutputOptions.captureGraphics = false;
}

// Store the code to run in history
qwebrLogCodeToHistory(codeToRun, options);

// Setup a webR canvas by making a namespace call into the {webr} package
// Evaluate the R code
// Remove the active canvas silently
Expand Down Expand Up @@ -188,14 +219,20 @@ globalThis.qwebrComputeEngine = async function(

// Determine if we have graphs to display
if (result.images.length > 0) {

// Create figure element
const figureElement = document.createElement('figure');
const figureElement = document.createElement("figure");
figureElement.className = "qwebr-canvas-image";

// Place each rendered graphic onto a canvas element
result.images.forEach((img) => {

// Construct canvas for object
const canvas = document.createElement("canvas");

// Add an image download button
qwebrImageCanvasDownloadButton(canvas, figureElement);

// Set canvas size to image
canvas.width = img.width;
canvas.height = img.height;
Expand All @@ -216,17 +253,19 @@ globalThis.qwebrComputeEngine = async function(

// Append canvas to figure output area
figureElement.appendChild(canvas);
});

});

if (options['fig-cap']) {
// Create figcaption element
const figcaptionElement = document.createElement('figcaption');
figcaptionElement.innerText = options['fig-cap'];
// Append figcaption to figure
figureElement.appendChild(figcaptionElement);
}

elements.outputGraphDiv.appendChild(figureElement);

}

// Display the pager data
Expand Down
110 changes: 110 additions & 0 deletions _extensions/coatless/webr/qwebr-document-history.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Define a global storage and retrieval solution ----

// Store commands executed in R
globalThis.qwebrRCommandHistory = [];

// Function to retrieve the command history
globalThis.qwebrFormatRHistory = function() {
return qwebrRCommandHistory.join("\n\n");
}

// Retrieve HTML Elements ----

// Get the command modal
const command_history_modal = document.getElementById("qwebr-history-modal");

// Get the button that opens the command modal
const command_history_btn = document.getElementById("qwebrRHistoryButton");

// Get the <span> element that closes the command modal
const command_history_close_span = document.getElementById("qwebr-command-history-close-btn");

// Get the download button for r history information
const command_history_download_btn = document.getElementById("qwebr-download-history-btn");

// Plug in command history into modal/download button ----

// Function to populate the modal with command history
function populateCommandHistoryModal() {
document.getElementById("qwebr-command-history-contents").innerHTML = qwebrFormatRHistory() || "No commands have been executed yet.";
}

// Function to format the current date and time to
// a string with the format YYYY-MM-DD-HH-MM-SS
function formatDateTime() {
const now = new Date();

const year = now.getFullYear();
const day = String(now.getDate()).padStart(2, '0');
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are zero-based
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');

return `${year}-${month}-${day}-${hours}-${minutes}-${seconds}`;
}


// Function to convert document title with datetime to a safe filename
function safeFileName() {
// Get the current page title
let pageTitle = document.title;

// Combine the current page title with the current date and time
let pageNameWithDateTime = `Rhistory-${pageTitle}-${formatDateTime()}`;

// Replace unsafe characters with safe alternatives
let safeFilename = pageNameWithDateTime.replace(/[\\/:\*\?! "<>\|]/g, '-');

return safeFilename;
}


// Function to download list contents as text file
function downloadRHistory() {
// Get the current page title + datetime and use it as the filename
const filename = `${safeFileName()}.R`;

// Get the text contents of the R History list
const text = qwebrFormatRHistory();

// Create a new Blob object with the text contents
const blob = new Blob([text], { type: 'text/plain' });

// Create a new anchor element for the download
const a = document.createElement('a');
a.style.display = 'none';
a.href = URL.createObjectURL(blob);
a.download = filename;

// Append the anchor to the body, click it, and remove it
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}

// Register event handlers ----

// When the user clicks the View R History button, open the command modal
command_history_btn.onclick = function() {
populateCommandHistoryModal();
command_history_modal.style.display = "block";
}

// When the user clicks on <span> (x), close the command modal
command_history_close_span.onclick = function() {
command_history_modal.style.display = "none";
}

// When the user clicks anywhere outside of the command modal, close it
window.onclick = function(event) {
if (event.target == command_history_modal) {
command_history_modal.style.display = "none";
}
}

// Add an onclick event listener to the download button so that
// the user can download the R history as a text file
command_history_download_btn.onclick = function() {
downloadRHistory();
};
Loading

0 comments on commit 184f636

Please sign in to comment.