Skip to content

Commit

Permalink
Switch to monaco for editing
Browse files Browse the repository at this point in the history
  • Loading branch information
hildjj committed Jun 7, 2024
1 parent 9441bbe commit 3b54dc1
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 66 deletions.
1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"start": "five-server",
"test": "playwright test"
},
"type": "module",
"author": "Joe Hildebrand <joe-github@cursive.net>",
"license": "MIT",
"devDependencies": {
Expand Down
Binary file added web/src/codicon.ttf
Binary file not shown.
33 changes: 20 additions & 13 deletions web/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@
<head>
<meta charset="utf-8" />
<title>cbor2 playground</title>
<style>
body {
display: none;
background-color:cornsilk;
}
</style>
<!-- <link href="https://cdn.jsdelivr.net/npm/vscode-codicons@0.0.17/dist/codicon.min.css" rel="stylesheet"> -->
</head>

<body>
<h2>CBOR converter</h2>

<div class="container">
<div class="input">
<div class="input col">
<h3>Input</h3>
<div class="cmd">
<select id="input-fmt">
Expand All @@ -22,9 +29,9 @@ <h3>Input</h3>
</select>
<span id="to">&rarr;&rarr;&rarr; to &rarr;&rarr;&rarr;</span>
</div>
<textarea id="input-text" rows="30" cols="50" autofocus></textarea>
<div id="input-text" class="monaco"></div>
</div>
<div class="output">
<div class="output col">
<h3>Output</h3>
<div class="cmd">
<select id="output-fmt">
Expand All @@ -38,17 +45,13 @@ <h3>Output</h3>
</select>
<button id="copy">Copy to input</button>
</div>
<textarea id="output-text" rows="30" cols="50" readonly></textarea>
<div class="power">
Powered by <a href="https://github.com/hildjj/cbor2/">cbor2</a>.
<a href="https://github.com/hildjj/cbor2/tree/main/web">Source</a>
</div>
<div id="output-text" class="monaco"></div>
</div>
<div class="options">
<div class="options col">
<h3>Options</h3>
<div class="cmd">&nbsp;</div>
<h4>Encoding</h4>
<ul id="encodeOpts">
<button class="accordion">Encoding</button>
<ul id="encodeOpts" class="panel">
<li>
<input type="checkbox" id="avoidIntsEncode">
<label for="avoidIntsEncode">avoidInts</label>
Expand Down Expand Up @@ -122,8 +125,8 @@ <h4>Encoding</h4>
</select>
</li>
</ul>
<h4>Decoding</h4>
<ul id="decodeOpts">
<button class="accordion">Decoding</button>
<ul id="decodeOpts" class="panel">
<li>
<input type="checkbox" id="boxed">
<label for="boxed">boxed</label>
Expand Down Expand Up @@ -201,6 +204,10 @@ <h4>Decoding</h4>
</select>
</li>
</ul>
<div class="power">
Powered by <a href="https://github.com/hildjj/cbor2/">cbor2</a>.
<a href="https://github.com/hildjj/cbor2/tree/main/web">Source</a>
</div>
</div>
</div>
</body>
Expand Down
121 changes: 92 additions & 29 deletions web/src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import './style.css';
// eslint-disable-next-line n/no-missing-import
import * as monaco from 'https://cdn.jsdelivr.net/npm/monaco-editor@0.49.0/+esm';

import {
Simple,
Tag,
Expand All @@ -24,13 +27,61 @@ import {
import {sortCoreDeterministic, sortLengthFirstDeterministic} from 'cbor2/sorts';
import {inspect} from 'node-inspect-extracted';

const ofmt = document.getElementById('output-fmt');
const otxt = document.getElementById('output-text');
const proxy = URL.createObjectURL(new Blob([`
self.MonacoEnvironment = {
baseUrl: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.49.0/min'
};
importScripts('https://cdn.jsdelivr.net/npm/monaco-editor@0.49.0/min/vs/base/worker/workerMain.js');
`], {type: 'text/javascript'}));
window.MonacoEnvironment = {
getWorkerUrl: () => proxy,
};

const itxt = document.getElementById('input-text');
const otxt = document.getElementById('output-text');
const ofmt = document.getElementById('output-fmt');
const ifmt = document.getElementById('input-fmt');
const copy = document.getElementById('copy');
const sortKeysEncode = document.querySelector('#sortKeysEncode');
const sortKeysDecode = document.querySelector('#sortKeysDecode');
const fontSize = 16;
const theme = 'vs-dark';

const inEditor = monaco.editor.create(itxt, {
detectIndentation: false,
fontSize,
language: 'js',
minimap: {enabled: false},
tabSize: 2,
theme,
});
const inModel = inEditor.getModel();

const outEditor = monaco.editor.create(otxt, {
detectIndentation: false,
fontSize,
minimap: {enabled: false},
readOnly: true,
theme,
});
const outModel = outEditor.getModel();

window.addEventListener('resize', () => {
// See https://stackoverflow.com/a/70120566/8388
inEditor.layout({width: 0, height: 0});
outEditor.layout({width: 0, height: 0});
window.requestAnimationFrame(() => {
const iRect = itxt.getBoundingClientRect();
inEditor.layout({width: iRect.width, height: iRect.height});
const oRect = otxt.getBoundingClientRect();
outEditor.layout({width: oRect.width, height: oRect.height});
});
});

window._cbor2testing = {
inModel,
outModel,
};

let state = {
inp: 'JSON',
Expand Down Expand Up @@ -76,9 +127,9 @@ const notDcborDecodeOptions = Object.fromEntries(
Object.entries(dcborDecodeOptions).map(([k, v]) => [k, !v])
);

function error(e) {
export function error(e) {
copy.disabled = true;
otxt.value = e.toString();
outModel.setValue(e.toString());
}

function showEncodeOpts() {
Expand Down Expand Up @@ -131,40 +182,42 @@ function input() {
// Convert a buffer to the desired output format
function output(buf, typ) {
try {
const outp = ofmt.selectedOptions[0].label;
const outp = ofmt.value;
switch (outp) {
case 'hex':
copy.disabled = false;
otxt.value = u8toHex(buf);
outModel.setValue(u8toHex(buf));
break;
case 'base64':
copy.disabled = false;
otxt.value = bytesToBase64(buf);
outModel.setValue(bytesToBase64(buf));
break;
case 'base64url':
copy.disabled = false;
otxt.value = bytesToBase64url(buf);
outModel.setValue(bytesToBase64url(buf));
break;
case 'commented':
copy.disabled = false;
otxt.value = comment(buf, state.decodeOpts);
outModel.setValue(comment(buf, state.decodeOpts));
break;
case 'diagnostic':
copy.disabled = true;
otxt.value = diagnose(buf, state.decodeOpts);
outModel.setValue(diagnose(buf, state.decodeOpts));
break;
case 'js':
copy.disabled = false;
otxt.value = inspect(decode(buf, state.decodeOpts), {
outModel.setValue(inspect(decode(buf, state.decodeOpts), {
depth: Infinity,
compact: 1,
maxArrayLength: Infinity,
breakLength: otxt.cols - 1,
});
breakLength: 30,
}));
break;
case 'JSON':
copy.disabled = false;
otxt.value = JSON.stringify(decode(buf, state.decodeOpts), null, 2);
outModel.setValue(
JSON.stringify(decode(buf, state.decodeOpts), null, 2)
);
break;
default:
throw new Error(`Unknown output: "${outp}"`);
Expand Down Expand Up @@ -297,34 +350,44 @@ ifmt.oninput = () => {
};
copy.onclick = () => {
// Copy output to input, and guess the new input format
let txt = otxt.value;
let sel = ofmt.selectedOptions[0].label;
let txt = outModel.getValue();
let sel = ofmt.value;

if (ofmt.selectedOptions[0].label === 'commented') {
if (sel === 'commented') {
const m = txt.match(/^0x[0-9a-f]+/i);
txt = m ? m[0] : '';
sel = 'hex';
}

itxt.value = txt;
for (const o of ifmt.options) {
if (o.label === sel) {
ifmt.selectedIndex = o.index;
break;
}
}
ifmt.value = sel;
state.inp = sel;
inModel.setValue(txt);
};

// Debounce
let timeout = null;
itxt.oninput = () => {
state.txt = itxt.value;
inModel.onDidChangeContent(() => {
state.txt = inModel.getValue();
clearTimeout(timeout);
timeout = setTimeout(() => {
clearTimeout(timeout);
timeout = null;
return convert();
}, 300);
};
});

const acc = document.getElementsByClassName('accordion');
for (let i = 0; i < acc.length; i++) {
const a = acc[i];
a.addEventListener('click', () => {
a.classList.toggle('active');
const panel = a.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = `${panel.scrollHeight}px`;
}
});
}

(async() => {
const u = new URL(window.location.href);
Expand All @@ -334,9 +397,9 @@ itxt.oninput = () => {
state.decodeOpts.sortKeys = sortFuncs.get(state.decodeOpts.sortKeys);
state.encodeOpts.sortKeys = sortFuncs.get(state.encodeOpts.sortKeys);
}
itxt.value = state.txt;
ofmt.value = state.outp;
ifmt.value = state.inp;
inModel.setValue(state.txt);

showEncodeOpts();
for (const inp of document.querySelectorAll('#encodeOpts input')) {
Expand Down
63 changes: 55 additions & 8 deletions web/src/style.css
Original file line number Diff line number Diff line change
@@ -1,44 +1,91 @@
body {
font-family: Arial, Helvetica, sans-serif;
background-color:cornsilk;
display: block;
}

.container {
display: flex;
flex-flow: row wrap;
align-items: flex-start;
align-items: stretch;
gap: 1em;
width: 100%;
}

.cmd {
margin: 0 10px 5px 10px;
margin: 0 10px 5px 0;
}

#to {
float: right;
}

h3 {
margin: 0 10px 5px 10px;
margin: 0 10px 5px 0;
}

h4 {
margin: 0 10px 5px 10px;
margin: 0 10px 5px 0;
}

li {
display: flex;
flex-wrap: wrap;
align-items: center;
/* margin-left: -20px; */
}

li * {
margin: 3px;
}

textarea {
margin: 0 10px 0 10px;
.power {
margin-top: 10px;
}

.power {
margin: 10px;
.monaco {
min-width: 300px;
min-height: 30em;
max-width: 99%;
}

.col {
flex: 1;
}

.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
width: 90%;
text-align: left;
border: none;
outline: none;
transition: 0.4s;
font-weight: bold;
font-size: 1.1em;
}

.active, .accordion:hover {
background-color: #ccc;
}

.accordion:after {
content: '\02795'; /* Unicode character for "plus" sign (+) */
/* font-size: 13px; */
color: #777;
float: right;
margin-left: 5px;
}

.active:after {
content: "\2796"; /* Unicode character for "minus" sign (-) */
}

.panel {
padding: 0;
margin: 5px 5px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
Loading

0 comments on commit 3b54dc1

Please sign in to comment.