<div id="intro">
Welcome to Code Scrubber!<br/>
The code lower is freely editable, feel free to paste (Ctrl+Shift+F) from wherever <br/>
Pressing ANALYZE will detect numbers and make them scrubbable. This also happens 3s after last entry, but unfortunately resets cursor position, needs fixing :)<br/>
Pressing MODE will switch between HTML (direct copy) and JS Eval (JavaScript expression evaluation modes), which you can use to eg. evaluate math expressions (try 1 + 1)<br/><br/>
<strong>Pressing Ctrl+Shift toggles the scrubbing option</strong><br/>
Go to <a target="_blank" href="https://codepen.io/domjancik/pen/VwamOyJ">this pen</a> for a hold to edit version
</div>
<div>
<button id="button">ANALYZE</button>
<button id="button-mode">MODE</button>
<div class="inline" id="mode">HTML</div>
</div>
<pre id="code" contenteditable="true">42 + 100</pre>
<div id="progress"></div>
<div id="equals"> = </div>
<div class="inline" id="result">RESULT</div>
<div id="footer"><a href="https://domj.net" target="_blank">domj<br/>2020</a></div>
body {
font-family: sans-serif;
background: brown;
}
#intro {
font-size: 0.75rem;
color: lightyellow;
margin-bottom: 1rem;
}
#code {
background: lightyellow;
padding: 1rem;
border-radius: 5px;
margin-bottom: 0;
}
#mode {
color: white;
}
#equals {
text-align: center;
color: white;
font-size: 2rem;
}
button, button:focus {
border: none;
border-radius: 5px;
background: lightyellow;
padding: 10px;
box-shadow: 0 2px black;
outline-style: none;
transition: all 100ms;
font-weight: bold;
}
button:active {
box-shadow: 0 1px black;
transform: translateY(1px);
outline-style: none;
}
#result {
border: solid lightgray 1px;
border-radius: 5px;
background: white;
}
.inline {
display: inline-block;
}
.number {
transition: all 500ms;
color: white;
background: black;
padding: 1px;
border-radius: 5px;
cursor: e-resize;
border: 1px solid transparent;
}
.disabled .number {
background: transparent;
color: inherit;
cursor: inherit;
border: 1px solid rgba(0,0,0,0.1);
}
#footer {
position: fixed;
bottom: 20px;
right: 20px;
color: white;
}
#progress {
margin-top: 5px;
width: 10%;
height: 1px;
background: lightyellow;
}
#footer a {
color: white;
}
const code = $('#code')
const button = $("#button")
const result = $("#result")
let mouseDown = false
let lastX = 0
let curElement = null
let numberElements = null
let mode = false
let scrubbingEnabled = true
const evaluateEval = () => result.text(eval(code.text()))
const evaluateHtml = () => {
console.log(code.text())
result.html(code.text())
}
const evaluate = () => {
mode ? evaluateEval() : evaluateHtml()
}
const analyze = () => {
let text = code.text()
text = text.replace(/</g, "<")
text = text.replace(/(\d+)/g, (a, b) => `<span class="number">${a}</span>`)
//numbers = text
console.log(text)
code.html(text)
numberElements = $(".number")
numberElements.each(function(index) {
const el = $(this)
console.log("num")
console.log(el.text())
el.mousedown(e => {
if (!scrubbingEnabled) return e
lastX = e.clientX
mouseDown = true
curElement = el
})
})
evaluate()
}
// const numberElement = $(numberElements.get(0))
// const pos = numberElement.position()
// pos.top += numberElement.height()
const scrub = (e) => {
if (!mouseDown) return
// console.log(e)
console.log("scrubbing")
let num = +curElement.text()
curElement.text(num + e.clientX - lastX)
lastX = e.clientX
evaluate()
}
$(document)
.mouseup(() => {
mouseDown = false
})
.mousemove(e => scrub(e))
button.click(analyze)
$("#button-mode").click(() => {
mode = !mode
$("#mode").text(mode ? "JS eval()" : "HTML")
})
code.text(`<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>`)
// Keyboard interaction
$(document).keydown(e => {
if (e.code.indexOf('Shift') !== -1 && e.ctrlKey) {
scrubbingEnabled = !scrubbingEnabled
code.toggleClass('disabled', !scrubbingEnabled)
}
})
// Auto Analyze
const progressBar = $("#progress")
let progress = 0;
let lastChange = new Date()
const ANALYZE_DELAY = 3000
code.on('input', _.debounce(analyze, ANALYZE_DELAY))
code.on('input', () => {lastChange = new Date()})
const progressUpdate = () => {
const elapsed = new Date() - lastChange
const percent = Math.min(elapsed / ANALYZE_DELAY * 100, 100)
progressBar.css('width', `${percent}%`)
window.requestAnimationFrame(progressUpdate)
}
window.requestAnimationFrame(progressUpdate)
// Init
analyze()
This Pen doesn't use any external CSS resources.