diff --git a/kalamine/server.py b/kalamine/server.py index 6a4258a..a72c00f 100644 --- a/kalamine/server.py +++ b/kalamine/server.py @@ -1,6 +1,7 @@ import threading import webbrowser from http.server import HTTPServer, SimpleHTTPRequestHandler +from importlib import metadata from pathlib import Path from xml.etree import ElementTree as ET @@ -40,6 +41,10 @@ def main_page(layout: KeyboardLayout, angle_mod: bool = False) -> str: +

+ kalamine + v{metadata.version('kalamine')}
\U0001f986 +

Name
{layout_ref}
@@ -77,6 +82,7 @@ def main_page(layout: KeyboardLayout, angle_mod: bool = False) -> str: + @@ -153,11 +159,10 @@ def __init__(self, *args, **kwargs) -> None: # type: ignore super().__init__(*args, **kwargs) def do_GET(self) -> None: - self.send_response(200) - def send( page: str, content: str = "text/plain", charset: str = "utf-8" ) -> None: + self.send_response(200) self.send_header("Content-type", f"{content}; charset={charset}") # no cash as one is likely working live on it self.send_header("Cache-Control", "no-cache, no-store, must-revalidate") @@ -170,9 +175,7 @@ def send( # XXX always reloads the layout on the root page, never in sub pages nonlocal kb_layout nonlocal angle_mod - if self.path == "/favicon.ico": - pass - elif self.path == "/json": + if self.path == "/json": send(web.pretty_json(kb_layout), content="application/json") elif self.path == "/keylayout": # send(keylayout.keylayout(kb_layout), content='application/xml') @@ -196,7 +199,7 @@ def send( kb_layout = KeyboardLayout(load_layout(file_path), angle_mod) # refresh send(main_page(kb_layout, angle_mod), content="text/html") else: - return SimpleHTTPRequestHandler.do_GET(self) + SimpleHTTPRequestHandler.do_GET(self) webserver = HTTPServer((host_name, webserver_port), LayoutHandler) thread = threading.Thread(None, webserver.serve_forever) diff --git a/kalamine/www/corpus/LICENSE b/kalamine/www/corpus/LICENSE index 27bf1b1..9c3458f 100644 --- a/kalamine/www/corpus/LICENSE +++ b/kalamine/www/corpus/LICENSE @@ -34,15 +34,14 @@ electronic works. Nearly all the individual works in the collection are in the public domain in the United States. If an individual work is unprotected by copyright law in the United States and you are located in the United States, we do not claim a right to prevent you from copying, distributing, performing, - displaying or creating derivative works based on the work as long as all - references to Project Gutenberg are removed. Of course, we hope that you - will support the Project Gutenberg-tm mission of promoting free access - to electronic works by freely sharing Project Gutenberg-tm works in - compliance with the terms of this agreement for keeping the Project - Gutenberg-tm name associated with the work. You can easily comply with - the terms of this agreement by keeping this work in the same format with - its attached full Project Gutenberg-tm License when you share it without - charge with others. +displaying or creating derivative works based on the work as long as all +references to Project Gutenberg are removed. Of course, we hope that you will +support the Project Gutenberg-tm mission of promoting free access to electronic +works by freely sharing Project Gutenberg-tm works in compliance with the terms +of this agreement for keeping the Project Gutenberg-tm name associated with the +work. You can easily comply with the terms of this agreement by keeping this +work in the same format with its attached full Project Gutenberg-tm License when +you share it without charge with others. [*] This particular work is one of the few individual works protected by copyright law in the United States and most of the remainder of the world, diff --git a/kalamine/www/corpus/fra_mixed-typical_2012_1M-sentences.json b/kalamine/www/corpus/fra_mixed-typical_2012_1M-sentences.json index bc29eef..8687fcf 100644 --- a/kalamine/www/corpus/fra_mixed-typical_2012_1M-sentences.json +++ b/kalamine/www/corpus/fra_mixed-typical_2012_1M-sentences.json @@ -86,7 +86,7 @@ "ä": 0.001, "=": 0.001 }, - "digrams": { + "bigrams": { "es": 2.5852, "le": 2.053, "on": 1.8595, @@ -793,9 +793,7 @@ "ln": 0.0014, "xy": 0.0014, "x?": 0.0013, - "â€": 0.0013, "ml": 0.0013, - "€™": 0.0013, "dû": 0.0013, "»,": 0.0013, "tn": 0.0013, @@ -873,7 +871,6 @@ "i ": 0.0009, "ït": 0.0009, "r:": 0.0009, - "œu": 0.0009, "kk": 0.0009, "-q": 0.0009, "k,": 0.0009, @@ -939,7 +936,6 @@ "ïc": 0.0006, "fp": 0.0006, "€.": 0.0006, - "™e": 0.0006, "à ": 0.0006, "cg": 0.0006, "fm": 0.0006, @@ -1064,7 +1060,6 @@ "©t": 0.0004, "td": 0.0004, "jd": 0.0004, - "™a": 0.0004, "œi": 0.0004, "x:": 0.0004, "dê": 0.0004, @@ -1118,7 +1113,6 @@ ".m": 0.0003, ".t": 0.0003, "m´": 0.0003, - "cœ": 0.0003, "y:": 0.0003, "nœ": 0.0003, "k!": 0.0003, @@ -1163,7 +1157,6 @@ "lj": 0.0003, "h!": 0.0003, "\"v": 0.0003, - "€.": 0.0003, "y!": 0.0003, "/k": 0.0003, "ür": 0.0003, @@ -1327,7 +1320,6 @@ "ón": 0.0001, "b:": 0.0001, "nî": 0.0001, - "'œ": 0.0001, "jr": 0.0001, "zs": 0.0001, "'ã": 0.0001, @@ -1434,7 +1426,6 @@ ",p": 0.0001, "k'": 0.0001, "xq": 0.0001, - "nœ": 0.0001, "gã": 0.0001, "&p": 0.0001, "rď": 0.0001, @@ -1488,7 +1479,6 @@ "ªm": 0.0001, "ïw": 0.0001, "wf": 0.0001, - "™ã": 0.0001, "\"?": 0.0001, "½t": 0.0001, "nï": 0.0001, @@ -1556,7 +1546,6 @@ "­s": 0.0001, "«t": 0.0001, "zw": 0.0001, - "™i": 0.0001, "äi": 0.0001, "sx": 0.0001, "lö": 0.0001, @@ -1618,7 +1607,6 @@ "vô": 0.0001, ",f": 0.0001, "är": 0.0001, - "™h": 0.0001, "é": 0.0001, "bœ": 0.0001, "§a": 0.0001, @@ -1638,7 +1626,6 @@ "ló": 0.0001, "qm": 0.0001, "éï": 0.0001, - "œi": 0.0001, ":m": 0.0001, "hg": 0.0001, "üc": 0.0001, @@ -1692,7 +1679,6 @@ "t(": 0.0001, "r­": 0.0001, "âi": 0.0001, - "™o": 0.0001, "´t": 0.0001, ">s": 0.0001, "“c": 0.0001, @@ -1718,7 +1704,6 @@ ":d": 0.0001, "lď": 0.0001, "m’": 0.0001, - "sœ": 0.0001, "l¹": 0.0001, ":b": 0.0001, "`u": 0.0001, @@ -4864,7 +4849,6 @@ "gyp": 0.001, "ww.": 0.001, "âgé": 0.001, - "’": 0.001, "oyo": 0.001, "arp": 0.001, "thl": 0.001, @@ -5828,7 +5812,6 @@ "d&r": 0.001, "iég": 0.001, "thy": 0.001, - "€™e": 0.001, "-hu": 0.001, "lch": 0.001, "mst": 0.001, diff --git a/kalamine/www/demo.js b/kalamine/www/demo.js index 2353cae..c13f9b7 100644 --- a/kalamine/www/demo.js +++ b/kalamine/www/demo.js @@ -3,7 +3,7 @@ window.addEventListener('DOMContentLoaded', () => { const keyboard = document.querySelector('x-keyboard'); const input = document.querySelector('input'); - const geometry = document.querySelector('select'); + const geometry = document.querySelector('#geometry'); if (!keyboard.layout) { console.warn('web components are not supported'); diff --git a/kalamine/www/favicon.ico b/kalamine/www/favicon.ico new file mode 100644 index 0000000..fecac3f Binary files /dev/null and b/kalamine/www/favicon.ico differ diff --git a/kalamine/www/mjs/layout-analyzer.js b/kalamine/www/mjs/layout-analyzer.js index 12a7231..aa264fa 100644 --- a/kalamine/www/mjs/layout-analyzer.js +++ b/kalamine/www/mjs/layout-analyzer.js @@ -1,6 +1,6 @@ const substituteChars = { - '\u00a0': ' ', // ( ) no-break space - '\u202f': ' ', // ( ) narrow no-break space + '\u00a0': ' ', // no-break space + '\u202f': ' ', // narrow no-break space '\u00ab': '"', // («) left-pointing double angle quotation mark '\u00bb': '"', // (») right-pointing double angle quotation mark @@ -268,8 +268,8 @@ export function analyzeKeyboardLayout( }; const isScissor = (kc1, kc2, finger1, finger2) => { - var finger1Height = getKeyRow(kc1); - var finger2Height = getKeyRow(kc2); + let finger1Height = getKeyRow(kc1); + let finger2Height = getKeyRow(kc2); switch (finger1.at(1) + finger2.at(1)) { case '45': diff --git a/kalamine/www/mjs/stats-canvas.js b/kalamine/www/mjs/stats-canvas.js index b65ad7e..07d94d6 100644 --- a/kalamine/www/mjs/stats-canvas.js +++ b/kalamine/www/mjs/stats-canvas.js @@ -71,7 +71,7 @@ class StatsCanvas extends HTMLElement { const scale = canvas.height / maxValue; - const renderBarPart = (groupIndex, columnIndex, column, flipVerically) => { + const renderBarPart = (groupIndex, columnIndex, column) => { let renderedBarHeight = 0; const colors = Object.entries(this.colors); diff --git a/kalamine/www/mjs/stats-table.js b/kalamine/www/mjs/stats-table.js index c4aacf3..9218972 100644 --- a/kalamine/www/mjs/stats-table.js +++ b/kalamine/www/mjs/stats-table.js @@ -9,12 +9,12 @@ class StatsTable extends HTMLElement { super(); const shadow = this.attachShadow({ mode: 'open' }); - // Stupid hack to get the height of a 'tr' element + // Stupid hack to get the height of a 'tr' element (XXX not working) const tableRowElement = document.createElement('tr'); tableRowElement.innerHTML = 'random placeholder text'; shadow.appendChild(tableRowElement); this.maxHeightCollapsed = - this.maxLinesCollapsed * tableRowElement.offsetHeight; + Math.max(180, this.maxLinesCollapsed * tableRowElement.offsetHeight); // Actually build the content of the element (+ remove the stupid tr) shadow.innerHTML = ` @@ -48,13 +48,11 @@ class StatsTable extends HTMLElement { cursor: pointer; clip-path: polygon(50% 100%, 0% 0%, 100% 0%); } - button.showLess { + .showLess + button { clip-path: polygon(50% 0%, 0% 100%, 100% 100%); } -
`; @@ -64,17 +62,11 @@ class StatsTable extends HTMLElement { this.innerHTML = ''; // Remove original content // Setting up the `see more` button - // Using 'function' to set 'this' to the button (self is the web component) - const self = this; - shadow.querySelector('button').addEventListener('click', function () { - const wrapper = shadow.getElementById('wrapper'); - if (wrapper.style.maxHeight == `${self.maxHeightCollapsed}px`) { - wrapper.style.maxHeight = `${wrapper.children[0].offsetHeight}px`; - this.className = 'showLess'; - } else { - wrapper.style.maxHeight = `${self.maxHeightCollapsed}px`; - this.className = ''; - } + shadow.querySelector('button').addEventListener('click', () => { + wrapper.style.maxHeight = wrapper.className === '' + ? `${wrapper.children[0].offsetHeight}px` + : `${this.maxHeightCollapsed}px`; + wrapper.classList.toggle('showLess'); }); } @@ -84,7 +76,7 @@ class StatsTable extends HTMLElement { table.innerHTML = `${table.title}` + Object.entries(values) - .filter(([digram, freq]) => freq >= 10 ** -precision) + .filter(([_, freq]) => freq >= 10 ** -precision) .sort(([_, freq1], [__, freq2]) => freq2 - freq1) .map( ([digram, freq]) => diff --git a/kalamine/www/mjs/stats.js b/kalamine/www/mjs/stats.js index 884e4b8..8378bbe 100644 --- a/kalamine/www/mjs/stats.js +++ b/kalamine/www/mjs/stats.js @@ -1,14 +1,8 @@ -import { getSupportedChars, analyzeKeyboardLayout } from './layout-analyzer.js'; +import { analyzeKeyboardLayout } from './layout-analyzer.js'; window.addEventListener('DOMContentLoaded', () => { - const inputField = document.querySelector('input'); - const keyboard = document.querySelector('x-keyboard'); - - const headingColor = 'rgb(127, 127, 127)'; // getComputedStyle(document.querySelector('h3')).color; - + const keyboard = document.querySelector('x-keyboard'); let corpus = {}; - let keyChars = {}; - let impreciseData = false; // display a percentage value const fmtPercent = (num, p) => `${Math.round(10 ** p * num) / 10 ** p}%`; @@ -57,10 +51,7 @@ window.addEventListener('DOMContentLoaded', () => { }; const showReport = () => { - keyChars = getSupportedChars(keyboard.layout.keyMap, keyboard.layout.deadKeys); - const report = analyzeKeyboardLayout(keyboard, corpus, keyChars, headingColor); - console.log(corpus); - console.log(report); + const report = analyzeKeyboardLayout(keyboard, corpus); document.querySelector('#sfu stats-canvas').renderData({ values: report.totalSfuSkuPerFinger, @@ -82,7 +73,7 @@ window.addEventListener('DOMContentLoaded', () => { showPercentAll('#load small', report.loadGroups.map(sumUpBarGroup), 1); showPercent('#unsupported-all', report.totalUnsupportedChars, 3); - document.querySelector('#imprecise-data').hidden = !impreciseData; + document.querySelector('#imprecise-data').hidden = !report.impreciseData; document .querySelector('#bottlenecks stats-table') @@ -94,11 +85,16 @@ window.addEventListener('DOMContentLoaded', () => { document .getElementById('corpus') .addEventListener('change', event => { - fetch(`corpus/${event.target.value}.json`) + const corpusName = event.target.value; + const noCorpus = (corpusName === '-'); + document.getElementById('analyzer').hidden = noCorpus; + if (noCorpus) { + return; + } + fetch(`corpus/${corpusName}.json`) .then(response => response.json()) .then(data => { corpus = data; - document.getElementById('analyzer').hidden = false; showReport(); }); }); diff --git a/kalamine/www/style.css b/kalamine/www/style.css index fb596c9..8da2bd7 100644 --- a/kalamine/www/style.css +++ b/kalamine/www/style.css @@ -52,6 +52,10 @@ select { text-wrap: balance; } +#analyzer { + padding-bottom: 2em; +} + h2 { border-bottom: 1px dotted currentcolor; }