Skip to content

Commit 1f049e5

Browse files
committed
feat: Add character key shortcuts bookmarklet (#4)
1 parent e5b0617 commit 1f049e5

File tree

7 files changed

+204
-1
lines changed

7 files changed

+204
-1
lines changed

html/charkey.html

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<meta name="robots" content="noindex">
4+
5+
<link rel="stylesheet" href="style/app.css">
6+
7+
<title>Character key shortcuts</title>
8+
9+
<h1>Character key shortcuts</h1>
10+
11+
<p>A bookmarklet to ... </p>
12+
13+
<p> Feedback and suggestions welcome!</p>
14+
15+
<p><my-bookmarklet name="Trigger char key shortcuts"></my-bookmarklet></p>
16+
17+
<my-dev-warning></my-dev-warning>
18+
19+
20+
<script type="importmap">
21+
{
22+
"imports": {
23+
"charKeyBookmarklet": "../lib/characterKeyShortcuts.esm.marklet.js",
24+
"ndf-bookmarklets": "../index.js",
25+
"my-elements": "https://nfreear.github.io/elements/i.js"
26+
},
27+
"myElements": {
28+
"use": [ "my-bookmarklet", "my-dev-warning" ]
29+
}
30+
}
31+
</script>
32+
33+
<script type="module">
34+
import 'my-elements';
35+
import { characterKeyShortcutsBookmarklet } from 'charKeyBookmarklet';
36+
37+
const bookmarkletLinkElem = document.querySelector('my-bookmarklet');
38+
39+
bookmarkletLinkElem.fromFunction(characterKeyShortcutsBookmarklet);
40+
</script>
41+
42+
</html>

index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11

2+
export { YoutrackHtmlListParser } from './lib/YoutrackHtmlListParser.js';
23
export { youtrackRecheckListBookmarklet } from './lib/youtrackRecheckList.marklet.js';
34
export { youtrackRecheckList } from './lib/youtrackRecheckList.js';
45
export { youtrackRecheckListBookmarkletLegacy } from './lib/youtrackRecheckList.legacy.js';
56
export { youtrackRecheckListBookmarkletPSpeller } from './lib/youtrackRecheckList.PS.js';
7+
export { makeAsyncCharCodeIterator } from './lib/util/charCodeIterator.js';
8+
export { characterKeyShortcutsBookmarklet } from './lib/characterKeyShortcuts.esm.marklet.js';
9+
export { characterKeyShortcuts, fireKBEvent } from './lib/characterKeyShortcuts.esm.js';

lib/characterKeyShortcuts.esm.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
*/
3+
import makeAsyncCharCodeIterator from './util/charCodeIterator.js';
4+
5+
const { KeyboardEvent } = window;
6+
7+
export async function characterKeyShortcuts () {
8+
const IT = makeAsyncCharCodeIterator();
9+
let RES = await IT.next();
10+
11+
while (!RES.done) {
12+
console.log(`> ${RES.value}: ${String.fromCharCode(RES.value)}`);
13+
fireKBEvent('keydown', RES.value);
14+
fireKBEvent('keypress', RES.value);
15+
fireKBEvent('keyup', RES.value);
16+
RES = await IT.next();
17+
}
18+
}
19+
20+
export function fireKBEvent (evName, num) {
21+
const ev = new KeyboardEvent(evName, {
22+
key: String.fromCharCode(num),
23+
which: num,
24+
keyCode: num,
25+
charCode: num,
26+
bubbles: true,
27+
cancelable: false
28+
});
29+
document.body.dispatchEvent(ev);
30+
return ev;
31+
}
32+
33+
function checkAndRun () {
34+
const SCRIPT = document.querySelector('script[src *= "characterKeyShortcuts.js"]');
35+
if (SCRIPT && SCRIPT.dataset.runBm) {
36+
characterKeyShortcuts();
37+
}
38+
}
39+
40+
checkAndRun();
41+
42+
export default characterKeyShortcuts;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
*
3+
* 2.1.4 Character Key Shortcuts Level A.
4+
* @see https://www.w3.org/WAI/WCAG22/quickref/#character-key-shortcuts
5+
* @see http://3needs.org/en/testing/code/kb-shortcuts.html
6+
*/
7+
8+
/** The bookmarklet JavaScript, enclosed in an Immediately Invoked Function Expression (IIFE).
9+
* @see https://developer.mozilla.org/en-US/docs/Glossary/IIFE
10+
*/
11+
export function characterKeyShortcutsBookmarklet () {
12+
(async () => {
13+
const MOD = await import('{__ORIGIN__}/lib/characterKeyShortcuts.js');
14+
const { characterKeyShortcuts } = MOD;
15+
console.debug('Character Key Shortcuts:', MOD);
16+
await characterKeyShortcuts();
17+
})();
18+
}
19+
20+
export default characterKeyShortcutsBookmarklet;

lib/util/charCodeIterator.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
*
3+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_generators
4+
* @see https://codepen.io/nfreear/pen/myyNyzy
5+
*/
6+
export const DEFAULTS = {
7+
start: 32,
8+
end: 8365,
9+
step: 1,
10+
timeout: 20 // Milliseconds.
11+
};
12+
13+
export function makeAsyncCharCodeIterator (start = 32, end = 8365, step = 1, timeoutMs = 20) {
14+
let nextIndex = start;
15+
let iterationCount = 0;
16+
17+
const myAsyncIterator = {
18+
async next () {
19+
let result;
20+
return new Promise((resolve, reject) => {
21+
setTimeout(() => {
22+
if (nextIndex < end) {
23+
if (nextIndex === 127) { nextIndex = 161; }
24+
if (nextIndex === 192) { nextIndex = 8364; }
25+
26+
result = { value: nextIndex, done: false };
27+
nextIndex += step;
28+
iterationCount++;
29+
return resolve(result);
30+
}
31+
return resolve({ value: iterationCount, done: true });
32+
},
33+
timeoutMs);
34+
});
35+
}
36+
};
37+
return myAsyncIterator;
38+
}
39+
40+
export function makeCharCodeIterator (start = 32, end = 8365, step = 1) {
41+
let nextIndex = start;
42+
let iterationCount = 0;
43+
44+
const myIterator = {
45+
async next () {
46+
let result;
47+
48+
if (nextIndex < end) {
49+
if (nextIndex === 127) { nextIndex = 161; }
50+
if (nextIndex === 192) { nextIndex = 8364; }
51+
52+
result = { value: nextIndex, done: false };
53+
nextIndex += step;
54+
iterationCount++;
55+
return result;
56+
}
57+
return { value: iterationCount, done: true };
58+
}
59+
/* [Symbol.iterator]() {
60+
return this;
61+
}, */
62+
};
63+
return myIterator;
64+
}
65+
66+
export default makeAsyncCharCodeIterator;

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
},
1313
"scripts": {
1414
"lint": "semistandard --fix",
15-
"start": "live-server --port=9001",
15+
"start": "node script/httpServer.js",
16+
"start:x": "live-server --port=9001",
1617
"test": "npm run lint"
1718
},
1819
"semistandard": {

script/httpServer.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* HTTP server, with middleware to set CORS header.
3+
*/
4+
5+
const liveServer = require('live-server');
6+
const PATH = require('path');
7+
8+
const root = PATH.resolve(__dirname, '..');
9+
10+
const PARAMS = {
11+
port: 9001, // Set the server port. Defaults to 8080.
12+
host: '0.0.0.0', // Set the address to bind to. Defaults to 0.0.0.0 or process.env.IP.
13+
root, // Set root directory that's being served. Defaults to cwd.
14+
open: false, // When false, it won't load your browser by default.
15+
ignore: 'scss,my/templates', // comma-separated string for paths to ignore
16+
file: 'index.html', // When set, serve this file (server root relative) for every 404 (useful for single-page applications)
17+
wait: 1000, // Waits for all changes, before reloading. Defaults to 0 sec.
18+
// mount: [['/components', './node_modules']], // Mount a directory to a route.
19+
logLevel: 2, // 0 = errors only, 1 = some, 2 = lots
20+
middleware: [
21+
function setCorsHttpHeader (req, res, next) {
22+
res.setHeader('Access-Control-Allow-Origin', '*');
23+
next();
24+
}
25+
] // Takes an array of Connect-compatible middleware that are injected into the server middleware stack
26+
};
27+
28+
liveServer.start(PARAMS);

0 commit comments

Comments
 (0)