Skip to content

Commit

Permalink
Add editor controls for running code on mobile
Browse files Browse the repository at this point in the history
  • Loading branch information
marijnh committed Feb 29, 2024
1 parent 1346df0 commit 1562661
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 10 deletions.
23 changes: 21 additions & 2 deletions html/css/ejs.css
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,16 @@ nav button.help {

div.popup {
position: fixed;
left: 0; right: 0; top: 50px;
left: 0; right: 0; top: 0; bottom: 0;
border-radius: 3px;
max-width: min(35rem, 90%);
height: fit-content;
box-sizing: content-box;
margin: auto;
border: 1px solid #4ab;
padding: 0 1.5em 1em;
background: white;
max-height: 80%;
max-height: 90%;
overflow-y: auto;
overflow-x: hidden;
outline: 1000px solid #ffffffbb;
Expand Down Expand Up @@ -241,6 +244,22 @@ blockquote footer:before {
border-bottom: 1px solid #4ab;
}

.editor-controls {
position: absolute;
display: flex;
flex-direction: column;
top: -3px;
right: -15px;
}

.editor-controls button {
color: #888;
font-size: 16px;
background: transparent;
padding: 0;
border: none;
}

.sandbox-output {
border-top: 1px solid #4ab;
padding: 4px 0 4px 10px;
Expand Down
58 changes: 50 additions & 8 deletions src/client/ejs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ function chapterInteraction() {
}
})

let modName = /Mac/.test(navigator.platform) ? "Cmd-" : "Ctrl-"

function showHelp() {
let popup = document.body.appendChild(document.createElement("div"))
popup.className = "popup"
popup.appendChild(document.createElement("h2")).textContent = "Instructions"
popup.appendChild(document.createElement("p")).textContent = `Code on this page can be edited and run by clicking it or moving focus to it and pressing Enter. Code executed this way shares its environment with other code ran on the page, and some pre-defined code for the chapter. When inside the code editor, the following keyboard shortcuts are available.`
let mod = /Mac/.test(navigator.platform) ? "Cmd-" : "Ctrl-"
for (let [key, desc] of [
[mod + "Enter", "Run code"],
[mod + "j", "Revert code"],
[mod + "↓", "Deactivate editor"],
[mod + "Escape", "Reset environment"],
[modName + "Enter", "Run code"],
[modName + "j", "Revert code"],
[modName + "↓", "Deactivate editor"],
[modName + "Escape", "Reset environment"],
]) {
let b = popup.appendChild(document.createElement("div"))
b.appendChild(document.createElement("kbd")).textContent = key
Expand Down Expand Up @@ -70,8 +71,10 @@ function chapterInteraction() {
let node = document.createElement(type)
if (attrs && typeof attrs == "object" && attrs.nodeType == null) {
for (let attr in attrs) if (attrs.hasOwnProperty(attr)) {
if (attr == "css") node.style.cssText = attrs[attr]
else node.setAttribute(attr, attrs[attr])
let value = attrs[attr]
if (attr == "css") node.style.cssText = value
else if (typeof value !== "string") node[attr] = value
else node.setAttribute(attr, value)
}
firstChild = 2
}
Expand Down Expand Up @@ -158,9 +161,15 @@ function chapterInteraction() {
let editorState = createState(code, lang, [
extraKeys,
EditorView.domEventHandlers({
focus: () => {
focus: (e, view) => {
clearTimeout(pollingScroll)
pollingScroll = setTimeout(pollScroll, 500)
showEditorControls(view)
},
blur: (e, view) => {
setTimeout(() => {
if (!view.hasFocus) hideEditorControls(view)
}, 100)
}
}),
EditorView.updateListener.of(debounce(update => {
Expand Down Expand Up @@ -237,6 +246,39 @@ function chapterInteraction() {
})
}

function showEditorControls(editor) {
if (editor.dom.parentNode.querySelector(".editor-controls")) return
editor.dom.parentNode.appendChild(elt("div", {
class: "editor-controls"
}, elt("button", {
onmousedown: e => {
runCode(editor)
e.preventDefault()
},
title: `Run code (${modName}Enter)`,
"aria-label": "Run code"
}, "▸"), elt("button", {
onmousedown: e => {
revertCode(editor)
e.preventDefault()
},
title: `Revert code (${modName}j)`,
"aria-label": "Revert code"
}, "▫"), elt("button", {
onmousedown: e => {
resetSandbox(editor.state.facet(contextFacet).sandbox)
e.preventDefault()
},
title: `Reset sandbox (${modName}Escape)`,
"aria-label": "Reset sandbox"
}, "ø")))
}

function hideEditorControls(editor) {
let controls = editor.dom.parentNode.querySelector(".editor-controls")
if (controls) controls.remove()
}

let sandboxSnippets = {}
{
let snippets = document.getElementsByClassName("snippet")
Expand Down

0 comments on commit 1562661

Please sign in to comment.