first commit
This commit is contained in:
BIN
tools/qalc/flaviut/favicon.png
Normal file
BIN
tools/qalc/flaviut/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
55
tools/qalc/flaviut/gnuplot-worker.js
Normal file
55
tools/qalc/flaviut/gnuplot-worker.js
Normal file
@@ -0,0 +1,55 @@
|
||||
let pendingRequests = [];
|
||||
|
||||
self.addEventListener('message', ({ data }) => {
|
||||
if (pendingRequests) {
|
||||
// gnuplot not loaded yet
|
||||
pendingRequests.push(data);
|
||||
} else {
|
||||
doPlot(data);
|
||||
}
|
||||
});
|
||||
|
||||
var Module = {
|
||||
noInitialRun: true,
|
||||
postRun: () => {
|
||||
shouldRunNow = true;
|
||||
pendingRequests.forEach(doPlot);
|
||||
pendingRequests = null;
|
||||
},
|
||||
print: (s) => {
|
||||
console.log('GNUPLOT LOG: ' + s);
|
||||
},
|
||||
printErr: (s) => {
|
||||
console.warn('GNUPLOT ERR: ' + s);
|
||||
},
|
||||
};
|
||||
|
||||
function doPlot({
|
||||
fix_cmd = true,
|
||||
data_files = {},
|
||||
commands,
|
||||
id,
|
||||
// TODO: do something with these...?
|
||||
extra_commandline,
|
||||
persist,
|
||||
}) {
|
||||
const files = Object.keys(data_files);
|
||||
for (const [file, data] of Object.entries(data_files)) {
|
||||
FS.writeFile(file, data);
|
||||
}
|
||||
const cmd = fix_cmd
|
||||
? commands.replace(
|
||||
'set terminal pop',
|
||||
"set terminal svg; set output '/output'"
|
||||
)
|
||||
: commands;
|
||||
FS.writeFile('/commands', cmd);
|
||||
callMain(['/commands']);
|
||||
const output = FS.readFile('/output', { encoding: 'utf8' });
|
||||
for (const file of ['/commands', '/output', ...files]) {
|
||||
FS.unlink(file);
|
||||
}
|
||||
self.postMessage({ id, output });
|
||||
}
|
||||
|
||||
importScripts('gnuplot.js');
|
4696
tools/qalc/flaviut/gnuplot.js
Normal file
4696
tools/qalc/flaviut/gnuplot.js
Normal file
File diff suppressed because it is too large
Load Diff
BIN
tools/qalc/flaviut/gnuplot.wasm
Executable file
BIN
tools/qalc/flaviut/gnuplot.wasm
Executable file
Binary file not shown.
53
tools/qalc/flaviut/index.html
Normal file
53
tools/qalc/flaviut/index.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us" style="margin: 2em;">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<link rel='icon' type='image/png' href='favicon.png'>
|
||||
<title>Qalculate Web</title>
|
||||
<link rel="preload" href="qalc.js" as="script">
|
||||
<link rel="preload" href="qalc.wasm" as="fetch">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<h1>Qalculate!</h1>
|
||||
|
||||
<p>This page is designed to test running Qalculate in the browser using
|
||||
WASM. At the moment, currencies are not supported, as they require
|
||||
external resources.</p>
|
||||
|
||||
<p>Plotting works, try <code>plot(3x^2; -10; 10)</code></p>
|
||||
|
||||
<p>The source code for this tool <a
|
||||
href="https://github.com/flaviut/qalculate-wasm">can be found on
|
||||
GitHub</a></p>
|
||||
|
||||
<div id="status">Downloading...</div>
|
||||
|
||||
<div class="hide" id="cell-template">
|
||||
<div class="cell">
|
||||
<input type="text" class="cell-input" placeholder="2x + 5 = 9">
|
||||
<div class="cell-result"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hide" id="plot-template">
|
||||
<div class="plot-err">
|
||||
<h2>Unable to plot</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="cells">
|
||||
|
||||
</div>
|
||||
|
||||
<script type='text/javascript' src='main.js'></script>
|
||||
<script async type="text/javascript" src="qalc.js"></script>
|
||||
<script data-goatcounter="https://j88og8.goatcounter.com/count"
|
||||
async src="//gc.zgo.at/count.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
185
tools/qalc/flaviut/main.js
Normal file
185
tools/qalc/flaviut/main.js
Normal file
@@ -0,0 +1,185 @@
|
||||
const statusElement = document.getElementById('status');
|
||||
const cellTmpl = document.querySelector('#cell-template .cell');
|
||||
const plotErrTmpl = document.querySelector('#plot-template .plot-err');
|
||||
const cells = document.getElementById('cells');
|
||||
|
||||
/** @typedef {node: HTMLElement, input: HTMLInputElement, result: HTMLElement} Cell */
|
||||
|
||||
/** @type {Cell} */
|
||||
let curCell;
|
||||
|
||||
/** @returns {Cell} */
|
||||
const getCell = (cellNode) => ({
|
||||
node: cellNode,
|
||||
input: cellNode.querySelector('.cell-input'),
|
||||
result: cellNode.querySelector('.cell-result'),
|
||||
});
|
||||
|
||||
let cellNum = 0;
|
||||
|
||||
function newCell() {
|
||||
if (curCell) {
|
||||
curCell.input.readOnly = true;
|
||||
}
|
||||
|
||||
curCell = getCell(cellTmpl.cloneNode(true));
|
||||
cellNum += 1;
|
||||
curCell.node.id = 'cell_' + cellNum;
|
||||
curCell.input.addEventListener('keydown', onKey);
|
||||
cells.append(curCell.node);
|
||||
focusCell(curCell);
|
||||
}
|
||||
|
||||
/** @param {Cell} cell */
|
||||
function focusCell(cell) {
|
||||
cell.input.focus({ preventScroll: true });
|
||||
if (cell.input.readOnly) {
|
||||
cell.input.select();
|
||||
}
|
||||
cell.node.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
|
||||
/** @param {KeyboardEvent} ev */
|
||||
function onKey(ev) {
|
||||
/** @type {HTMLInputElement} */
|
||||
const inp = ev.target;
|
||||
if (ev.key === 'Enter') {
|
||||
const text = inp.value;
|
||||
if (inp === curCell.input) {
|
||||
if (text.trim() !== '') {
|
||||
curCell.result.textContent = calc.calculateAndPrint(text, 1000);
|
||||
}
|
||||
newCell();
|
||||
} else {
|
||||
if (text.trim() !== '') {
|
||||
curCell.input.value = text;
|
||||
}
|
||||
focusCell(curCell);
|
||||
}
|
||||
} else if (ev.key === 'ArrowUp' || ev.key === 'ArrowDown') {
|
||||
const cellNode = inp.parentElement;
|
||||
const adjacent =
|
||||
ev.key === 'ArrowUp'
|
||||
? 'previousElementSibling'
|
||||
: 'nextElementSibling';
|
||||
let adjacentCellNode = cellNode;
|
||||
do {
|
||||
// this would be null if e.g. we're at the top and try to go up
|
||||
adjacentCellNode = adjacentCellNode[adjacent];
|
||||
} while (
|
||||
adjacentCellNode != null &&
|
||||
!adjacentCellNode.classList.contains('cell')
|
||||
);
|
||||
if (adjacentCellNode) {
|
||||
focusCell(getCell(adjacentCellNode));
|
||||
}
|
||||
ev.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
const emptySvg = `<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<svg
|
||||
width="600" height="480"
|
||||
viewBox="0 0 600 480"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
/>`;
|
||||
|
||||
let emptySvgUrl;
|
||||
let plot_id = 0;
|
||||
let gnuplotWorker;
|
||||
|
||||
const makeSvgUrl = (data) =>
|
||||
URL.createObjectURL(new Blob([data], { type: 'image/svg+xml' }));
|
||||
function runGnuplot(data_files, commands, extra_commandline, persist) {
|
||||
if (!gnuplotWorker) {
|
||||
gnuplotWorker = new Worker('gnuplot-worker.js');
|
||||
gnuplotWorker.addEventListener('message', (ev) => {
|
||||
const { id, output } = ev.data;
|
||||
const plot = document.getElementById('plot_' + id);
|
||||
if (output) {
|
||||
plot.src = makeSvgUrl(output);
|
||||
setTimeout(() => {
|
||||
focusCell(curCell);
|
||||
}, 10);
|
||||
} else {
|
||||
plot.replaceWith(plotErrTmpl.cloneNode(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!emptySvgUrl) {
|
||||
emptySvgUrl = makeSvgUrl(emptySvg);
|
||||
}
|
||||
|
||||
const img = new Image();
|
||||
img.classList.add('plot');
|
||||
img.src = emptySvgUrl;
|
||||
const id = plot_id++;
|
||||
img.id = 'plot_' + id;
|
||||
curCell.node.insertAdjacentElement('afterend', img);
|
||||
|
||||
gnuplotWorker.postMessage({
|
||||
data_files,
|
||||
commands,
|
||||
extra_commandline,
|
||||
persist,
|
||||
id,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
var Module = {
|
||||
postRun: () => {
|
||||
console.time('new');
|
||||
window.calc = new Module.Calculator();
|
||||
calc.loadGlobalDefinitions();
|
||||
console.timeEnd('new');
|
||||
|
||||
newCell();
|
||||
},
|
||||
print: function (text) {
|
||||
if (arguments.length > 1)
|
||||
text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.log(text);
|
||||
},
|
||||
printErr: function (text) {
|
||||
if (arguments.length > 1)
|
||||
text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.error(text);
|
||||
},
|
||||
setStatus: function (text) {
|
||||
if (!Module.setStatus.last)
|
||||
Module.setStatus.last = { time: Date.now(), text: '' };
|
||||
if (text === Module.setStatus.last.text) return;
|
||||
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
|
||||
var now = Date.now();
|
||||
if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon
|
||||
Module.setStatus.last.time = now;
|
||||
Module.setStatus.last.text = text;
|
||||
if (m) {
|
||||
text = m[1];
|
||||
}
|
||||
statusElement.innerHTML = text;
|
||||
},
|
||||
totalDependencies: 0,
|
||||
monitorRunDependencies: function (left) {
|
||||
this.totalDependencies = Math.max(this.totalDependencies, left);
|
||||
Module.setStatus(
|
||||
left
|
||||
? 'Preparing... (' +
|
||||
(this.totalDependencies - left) +
|
||||
'/' +
|
||||
this.totalDependencies +
|
||||
')'
|
||||
: 'All downloads complete.'
|
||||
);
|
||||
},
|
||||
};
|
||||
Module.setStatus('Downloading...');
|
||||
window.onerror = function (event) {
|
||||
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
|
||||
Module.setStatus('Exception thrown, see JavaScript console');
|
||||
Module.setStatus = function (text) {
|
||||
if (text) Module.printErr('[post-exception status] ' + text);
|
||||
};
|
||||
};
|
3955
tools/qalc/flaviut/qalc.js
Normal file
3955
tools/qalc/flaviut/qalc.js
Normal file
File diff suppressed because it is too large
Load Diff
BIN
tools/qalc/flaviut/qalc.wasm
Executable file
BIN
tools/qalc/flaviut/qalc.wasm
Executable file
Binary file not shown.
81
tools/qalc/flaviut/style.css
Normal file
81
tools/qalc/flaviut/style.css
Normal file
@@ -0,0 +1,81 @@
|
||||
@import url("/styles/common.css");
|
||||
|
||||
body {
|
||||
max-width: 1300px;
|
||||
min-width: 300px;
|
||||
|
||||
background: var(--background);
|
||||
font-family: var(--mono-font);
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: var(--text);
|
||||
caret-color: var(--primary);
|
||||
}
|
||||
|
||||
*, *::before, *::after {
|
||||
transition: all .3s ease-out;
|
||||
}
|
||||
|
||||
.cell-result {
|
||||
background: var(--background-lighter) !important;
|
||||
}
|
||||
|
||||
img {
|
||||
background: var(--background-lighter);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
img:hover {
|
||||
filter: brightness(1.5);
|
||||
}
|
||||
|
||||
input {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* original (except padding) */
|
||||
|
||||
.cell {
|
||||
margin: 1em 0;
|
||||
border-radius: 0.5em;
|
||||
border: 1px solid black;
|
||||
padding: 1em;
|
||||
}
|
||||
.cell-input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 1em;
|
||||
padding: 0.6em;
|
||||
}
|
||||
.cell-result {
|
||||
border-radius: 0.75em;
|
||||
background: #eee;
|
||||
padding: 0.75em;
|
||||
}
|
||||
.cell-input,
|
||||
.cell-result {
|
||||
font-family: sans-serif;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
body {
|
||||
max-width: 600px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.plot {
|
||||
display: block;
|
||||
}
|
||||
.plot-err {
|
||||
color: red;
|
||||
width: 600px;
|
||||
height: 480px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.plot-err h2 {
|
||||
text-align: center;
|
||||
}
|
24
tools/qalc/index.html
Normal file
24
tools/qalc/index.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Javalsai's Website - Tools::Qalc</title>
|
||||
<link rel="stylesheet" href="/styles/bundles/complete.css">
|
||||
</head>
|
||||
|
||||
<body class="flex column">
|
||||
<!--# include virtual="/components/header.html" -->
|
||||
<main>
|
||||
<h1><a class="reference" id="qalc" href="#qalc">Qalc</a></h1>
|
||||
<p>Popular libqalculate tool compiled for the web, I wanna wrap the library for with own style, but I'll also
|
||||
leave the default example from <a
|
||||
href="https://github.com/flaviut/qalculate-wasm">flaviut/qalculate-wasm</a> as it supports graphs too,
|
||||
I'll just inject some CSS for dark mode:
|
||||
<a href="flaviut">live example</a>
|
||||
</p>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
Reference in New Issue
Block a user