feat(web): h/l move between the content and the side panel (#49)
- commit
- 55a688e4d192f040fba9fc6c0a70a78b0d4922e4
- author
- brice · · 2026-10-17 22:40 UTC
- committer
- bnema · · 2026-10-17 22:40 UTC
- parent
- 126ed2b
- signature
- SSH Unverified
SHA256:VOCA5lYARHcbKDZ7GhTV45VmcjWnJ6ZQIBazj17LivAThe key is unknown - refs
- tag: v0.19.0
37 files · +426 -15
A internal/adapters/web/jstest/rail.test.mjs +64 -0
| @@ -0,0 +1,64 @@ | |||
| 1 | + | // Tests of the side panel keys of static/js/ermite.js (ermite.rail, and j / k | |
| 2 | + | // inside the panel) on a tiny hand-rolled DOM. Run with | |
| 3 | + | // node --test 'internal/adapters/web/jstest/*.test.mjs' | |
| 4 | + | import assert from 'node:assert/strict'; | |
| 5 | + | import { readFileSync } from 'node:fs'; | |
| 6 | + | import { test } from 'node:test'; | |
| 7 | + | import { el, installDom } from './dom.mjs'; | |
| 8 | + | ||
| 9 | + | // A page: <main>, and a rail with a hidden input, a closed-details command | |
| 10 | + | // (not laid out), then the controls a key can reach. | |
| 11 | + | const doc = installDom(); | |
| 12 | + | const main = el('main', { id: 'main' }); | |
| 13 | + | const hidden = el('input', { attrs: { type: 'hidden' } }); | |
| 14 | + | const folded = el('a', { href: '/x', attrs: { href: '/x' } }); | |
| 15 | + | folded.getClientRects = () => []; // inside a closed <details> | |
| 16 | + | const markRead = el('button', { cls: 'btn' }); | |
| 17 | + | const ready = el('button', { cls: 'btn primary' }); | |
| 18 | + | const close = el('button', { cls: 'btn danger' }); | |
| 19 | + | const rail = el('aside', { cls: 'rail' }, hidden, folded, markRead, ready, close); | |
| 20 | + | document.body.append(main, rail); | |
| 21 | + | let active = document.body; | |
| 22 | + | Object.defineProperty(doc, 'activeElement', { get: () => active }); | |
| 23 | + | for (const e of [main, markRead, ready, close, folded]) e.focus = () => { active = e; }; | |
| 24 | + | rail.contains = (e) => { for (let n = e; n; n = n.parent) if (n === rail) return true; return false; }; | |
| 25 | + | ||
| 26 | + | // Only the ermiteRail block of the file is evaluated: the rest needs a page. | |
| 27 | + | const src = readFileSync(new URL('../static/js/ermite.js', import.meta.url), 'utf8'); | |
| 28 | + | const start = src.indexOf(' window.ermiteRail = '); | |
| 29 | + | const end = src.indexOf(' })();', start) + ' })();'.length; | |
| 30 | + | new Function(src.slice(start, end))(); | |
| 31 | + | const R = window.ermiteRail; | |
| 32 | + | const E = { rail: (into) => (into ? R.enter() : R.leave()), move: (d) => R.step(d) }; | |
| 33 | + | ||
| 34 | + | test('l focuses the main action of the panel, j / k walk its shown controls, h goes back', () => { | |
| 35 | + | active = main; | |
| 36 | + | E.rail(true); | |
| 37 | + | assert.equal(active, ready, 'the primary button first'); | |
| 38 | + | E.move(1); | |
| 39 | + | assert.equal(active, close); | |
| 40 | + | E.move(1); | |
| 41 | + | assert.equal(active, close, 'stops at the last control'); | |
| 42 | + | E.move(-1); | |
| 43 | + | E.move(-1); | |
| 44 | + | assert.equal(active, markRead, 'the folded link is skipped'); | |
| 45 | + | E.move(-1); | |
| 46 | + | assert.equal(active, markRead, 'stops at the first shown control'); | |
| 47 | + | E.rail(false); | |
| 48 | + | assert.equal(active, main); | |
| 49 | + | }); | |
| 50 | + | ||
| 51 | + | test('without a primary action, l takes the first shown control', () => { | |
| 52 | + | ready.className = 'btn'; | |
| 53 | + | active = main; | |
| 54 | + | E.rail(true); | |
| 55 | + | assert.equal(active, markRead); | |
| 56 | + | ready.className = 'btn primary'; | |
| 57 | + | }); | |
| 58 | + | ||
| 59 | + | test('h outside the panel leaves the focus alone; j / k outside it are not taken', () => { | |
| 60 | + | active = main; | |
| 61 | + | E.rail(false); | |
| 62 | + | assert.equal(active, main); | |
| 63 | + | assert.equal(R.step(1), false, 'the row cursor keeps j / k'); | |
| 64 | + | }); | |
| @@ -0,0 +1,64 @@ | |||||
| 1 | + | // Tests of the side panel keys of static/js/ermite.js (ermite.rail, and j / k | |||
| 2 | + | // inside the panel) on a tiny hand-rolled DOM. Run with | |||
| 3 | + | // node --test 'internal/adapters/web/jstest/*.test.mjs' | |||
| 4 | + | import assert from 'node:assert/strict'; | |||
| 5 | + | import { readFileSync } from 'node:fs'; | |||
| 6 | + | import { test } from 'node:test'; | |||
| 7 | + | import { el, installDom } from './dom.mjs'; | |||
| 8 | + | ||||
| 9 | + | // A page: <main>, and a rail with a hidden input, a closed-details command | |||
| 10 | + | // (not laid out), then the controls a key can reach. | |||
| 11 | + | const doc = installDom(); | |||
| 12 | + | const main = el('main', { id: 'main' }); | |||
| 13 | + | const hidden = el('input', { attrs: { type: 'hidden' } }); | |||
| 14 | + | const folded = el('a', { href: '/x', attrs: { href: '/x' } }); | |||
| 15 | + | folded.getClientRects = () => []; // inside a closed <details> | |||
| 16 | + | const markRead = el('button', { cls: 'btn' }); | |||
| 17 | + | const ready = el('button', { cls: 'btn primary' }); | |||
| 18 | + | const close = el('button', { cls: 'btn danger' }); | |||
| 19 | + | const rail = el('aside', { cls: 'rail' }, hidden, folded, markRead, ready, close); | |||
| 20 | + | document.body.append(main, rail); | |||
| 21 | + | let active = document.body; | |||
| 22 | + | Object.defineProperty(doc, 'activeElement', { get: () => active }); | |||
| 23 | + | for (const e of [main, markRead, ready, close, folded]) e.focus = () => { active = e; }; | |||
| 24 | + | rail.contains = (e) => { for (let n = e; n; n = n.parent) if (n === rail) return true; return false; }; | |||
| 25 | + | ||||
| 26 | + | // Only the ermiteRail block of the file is evaluated: the rest needs a page. | |||
| 27 | + | const src = readFileSync(new URL('../static/js/ermite.js', import.meta.url), 'utf8'); | |||
| 28 | + | const start = src.indexOf(' window.ermiteRail = '); | |||
| 29 | + | const end = src.indexOf(' })();', start) + ' })();'.length; | |||
| 30 | + | new Function(src.slice(start, end))(); | |||
| 31 | + | const R = window.ermiteRail; | |||
| 32 | + | const E = { rail: (into) => (into ? R.enter() : R.leave()), move: (d) => R.step(d) }; | |||
| 33 | + | ||||
| 34 | + | test('l focuses the main action of the panel, j / k walk its shown controls, h goes back', () => { | |||
| 35 | + | active = main; | |||
| 36 | + | E.rail(true); | |||
| 37 | + | assert.equal(active, ready, 'the primary button first'); | |||
| 38 | + | E.move(1); | |||
| 39 | + | assert.equal(active, close); | |||
| 40 | + | E.move(1); | |||
| 41 | + | assert.equal(active, close, 'stops at the last control'); | |||
| 42 | + | E.move(-1); | |||
| 43 | + | E.move(-1); | |||
| 44 | + | assert.equal(active, markRead, 'the folded link is skipped'); | |||
| 45 | + | E.move(-1); | |||
| 46 | + | assert.equal(active, markRead, 'stops at the first shown control'); | |||
| 47 | + | E.rail(false); | |||
| 48 | + | assert.equal(active, main); | |||
| 49 | + | }); | |||
| 50 | + | ||||
| 51 | + | test('without a primary action, l takes the first shown control', () => { | |||
| 52 | + | ready.className = 'btn'; | |||
| 53 | + | active = main; | |||
| 54 | + | E.rail(true); | |||
| 55 | + | assert.equal(active, markRead); | |||
| 56 | + | ready.className = 'btn primary'; | |||
| 57 | + | }); | |||
| 58 | + | ||||
| 59 | + | test('h outside the panel leaves the focus alone; j / k outside it are not taken', () => { | |||
| 60 | + | active = main; | |||
| 61 | + | E.rail(false); | |||
| 62 | + | assert.equal(active, main); | |||
| 63 | + | assert.equal(R.step(1), false, 'the row cursor keeps j / k'); | |||
| 64 | + | }); | |||
M internal/adapters/web/keys.templ +2 -0
| @@ -14,6 +14,8 @@ templ Keys() { | |||
| 14 | 14 | k-top from:body -> ermite.edge(false); | |
| 15 | 15 | k-bottom from:body -> ermite.edge(true); | |
| 16 | 16 | k-open from:body -> ermite.open(); | |
| 17 | + | k-right from:body -> ermite.rail(true); | |
| 18 | + | k-left from:body -> ermite.rail(false); | |
| 17 | 19 | k-esc from:body -> ermite.closeDialogs(); | |
| 18 | 20 | k-help from:body -> ermite.dialog('panel-help'); | |
| 19 | 21 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -14,6 +14,8 @@ templ Keys() { | |||||
| 14 | k-top from:body -> ermite.edge(false); | 14 | k-top from:body -> ermite.edge(false); | ||
| 15 | k-bottom from:body -> ermite.edge(true); | 15 | k-bottom from:body -> ermite.edge(true); | ||
| 16 | k-open from:body -> ermite.open(); | 16 | k-open from:body -> ermite.open(); | ||
| 17 | + | k-right from:body -> ermite.rail(true); | |||
| 18 | + | k-left from:body -> ermite.rail(false); | |||
| 17 | k-esc from:body -> ermite.closeDialogs(); | 19 | k-esc from:body -> ermite.closeDialogs(); | ||
| 18 | k-help from:body -> ermite.dialog('panel-help'); | 20 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 19 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 21 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/adapters/web/keys_templ.go +1 -1
| @@ -34,7 +34,7 @@ func Keys() templ.Component { | |||
| 34 | 34 | templ_7745c5c3_Var1 = templ.NopComponent | |
| 35 | 35 | } | |
| 36 | 36 | ctx = templ.ClearChildren(ctx) | |
| 37 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div id=\"keys\" hidden hx-on=\"k-j from:body -> ermite.move(1);\n k-k from:body -> ermite.move(-1);\n k-top from:body -> ermite.edge(false);\n k-bottom from:body -> ermite.edge(true);\n k-open from:body -> ermite.open();\n k-esc from:body -> ermite.closeDialogs();\n k-help from:body -> ermite.dialog('panel-help');\n k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter');\n k-cmd from:body -> ermite.dialog('panel-cmd', 'cmd-q'); ermiteFinder.load();\n k-filter from:body -> ermite.focusFilter();\n k-gh from:body -> ermite.go('.brand');\n k-s from:body -> ermite.tab('s');\n k-t from:body -> ermite.tab('t');\n k-c from:body -> ermite.tab('c');\n k-r from:body -> ermite.tab('r');\n k-m from:body -> ermite.tab('m');\n k-next from:body -> ermite.nextNote();\n k-split from:body -> ermite.layout('split');\n k-unified from:body -> ermite.layout('unified');\n k-collapse from:body -> ermite.collapse();\n k-permalink from:body -> ermite.permalink();\n k-merge from:body -> window.ermiteMR?.openMerge();\n k-read from:body -> window.ermiteMR?.markRead();\n k-gf from:body -> window.ermiteMR?.focusFiles()\"></div>") | |
| 37 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div id=\"keys\" hidden hx-on=\"k-j from:body -> ermite.move(1);\n k-k from:body -> ermite.move(-1);\n k-top from:body -> ermite.edge(false);\n k-bottom from:body -> ermite.edge(true);\n k-open from:body -> ermite.open();\n k-right from:body -> ermite.rail(true);\n k-left from:body -> ermite.rail(false);\n k-esc from:body -> ermite.closeDialogs();\n k-help from:body -> ermite.dialog('panel-help');\n k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter');\n k-cmd from:body -> ermite.dialog('panel-cmd', 'cmd-q'); ermiteFinder.load();\n k-filter from:body -> ermite.focusFilter();\n k-gh from:body -> ermite.go('.brand');\n k-s from:body -> ermite.tab('s');\n k-t from:body -> ermite.tab('t');\n k-c from:body -> ermite.tab('c');\n k-r from:body -> ermite.tab('r');\n k-m from:body -> ermite.tab('m');\n k-next from:body -> ermite.nextNote();\n k-split from:body -> ermite.layout('split');\n k-unified from:body -> ermite.layout('unified');\n k-collapse from:body -> ermite.collapse();\n k-permalink from:body -> ermite.permalink();\n k-merge from:body -> window.ermiteMR?.openMerge();\n k-read from:body -> window.ermiteMR?.markRead();\n k-gf from:body -> window.ermiteMR?.focusFiles()\"></div>") | |
| 38 | 38 | if templ_7745c5c3_Err != nil { | |
| 39 | 39 | return templ_7745c5c3_Err | |
| 40 | 40 | } | |
| @@ -34,7 +34,7 @@ func Keys() templ.Component { | |||||
| 34 | templ_7745c5c3_Var1 = templ.NopComponent | 34 | templ_7745c5c3_Var1 = templ.NopComponent | ||
| 35 | } | 35 | } | ||
| 36 | ctx = templ.ClearChildren(ctx) | 36 | ctx = templ.ClearChildren(ctx) | ||
| 37 | - | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div id=\"keys\" hidden hx-on=\"k-j from:body -> ermite.move(1);\n k-k from:body -> ermite.move(-1);\n k-top from:body -> ermite.edge(false);\n k-bottom from:body -> ermite.edge(true);\n k-open from:body -> ermite.open();\n k-esc from:body -> ermite.closeDialogs();\n k-help from:body -> ermite.dialog('panel-help');\n k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter');\n k-cmd from:body -> ermite.dialog('panel-cmd', 'cmd-q'); ermiteFinder.load();\n k-filter from:body -> ermite.focusFilter();\n k-gh from:body -> ermite.go('.brand');\n k-s from:body -> ermite.tab('s');\n k-t from:body -> ermite.tab('t');\n k-c from:body -> ermite.tab('c');\n k-r from:body -> ermite.tab('r');\n k-m from:body -> ermite.tab('m');\n k-next from:body -> ermite.nextNote();\n k-split from:body -> ermite.layout('split');\n k-unified from:body -> ermite.layout('unified');\n k-collapse from:body -> ermite.collapse();\n k-permalink from:body -> ermite.permalink();\n k-merge from:body -> window.ermiteMR?.openMerge();\n k-read from:body -> window.ermiteMR?.markRead();\n k-gf from:body -> window.ermiteMR?.focusFiles()\"></div>") | 37 | + | templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div id=\"keys\" hidden hx-on=\"k-j from:body -> ermite.move(1);\n k-k from:body -> ermite.move(-1);\n k-top from:body -> ermite.edge(false);\n k-bottom from:body -> ermite.edge(true);\n k-open from:body -> ermite.open();\n k-right from:body -> ermite.rail(true);\n k-left from:body -> ermite.rail(false);\n k-esc from:body -> ermite.closeDialogs();\n k-help from:body -> ermite.dialog('panel-help');\n k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter');\n k-cmd from:body -> ermite.dialog('panel-cmd', 'cmd-q'); ermiteFinder.load();\n k-filter from:body -> ermite.focusFilter();\n k-gh from:body -> ermite.go('.brand');\n k-s from:body -> ermite.tab('s');\n k-t from:body -> ermite.tab('t');\n k-c from:body -> ermite.tab('c');\n k-r from:body -> ermite.tab('r');\n k-m from:body -> ermite.tab('m');\n k-next from:body -> ermite.nextNote();\n k-split from:body -> ermite.layout('split');\n k-unified from:body -> ermite.layout('unified');\n k-collapse from:body -> ermite.collapse();\n k-permalink from:body -> ermite.permalink();\n k-merge from:body -> window.ermiteMR?.openMerge();\n k-read from:body -> window.ermiteMR?.markRead();\n k-gf from:body -> window.ermiteMR?.focusFiles()\"></div>") |
| 38 | if templ_7745c5c3_Err != nil { | 38 | if templ_7745c5c3_Err != nil { | ||
| 39 | return templ_7745c5c3_Err | 39 | return templ_7745c5c3_Err | ||
| 40 | } | 40 | } | ||
M internal/adapters/web/overlays.templ +1 -0
| @@ -14,6 +14,7 @@ templ OverlayHelp(mr bool) { | |||
| 14 | 14 | <div><dt><kbd>?</kbd></dt><dd>this list</dd></div> | |
| 15 | 15 | <div><dt><kbd>j</kbd> <kbd>k</kbd></dt><dd>move the row cursor down / up</dd></div> | |
| 16 | 16 | <div><dt><kbd>enter</kbd></dt><dd>open the row under the cursor</dd></div> | |
| 17 | + | <div><dt><kbd>l</kbd> <kbd>h</kbd></dt><dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd></div> | |
| 17 | 18 | <div><dt><kbd>g g</kbd> <kbd>G</kbd></dt><dd>first / last row</dd></div> | |
| 18 | 19 | <div><dt><kbd>/</kbd></dt><dd>filter the list; on Files, find a file in the repository</dd></div> | |
| 19 | 20 | <div><dt><kbd>b</kbd></dt><dd>{ "switch" } branch or tag</dd></div> | |
| @@ -14,6 +14,7 @@ templ OverlayHelp(mr bool) { | |||||
| 14 | <div><dt><kbd>?</kbd></dt><dd>this list</dd></div> | 14 | <div><dt><kbd>?</kbd></dt><dd>this list</dd></div> | ||
| 15 | <div><dt><kbd>j</kbd> <kbd>k</kbd></dt><dd>move the row cursor down / up</dd></div> | 15 | <div><dt><kbd>j</kbd> <kbd>k</kbd></dt><dd>move the row cursor down / up</dd></div> | ||
| 16 | <div><dt><kbd>enter</kbd></dt><dd>open the row under the cursor</dd></div> | 16 | <div><dt><kbd>enter</kbd></dt><dd>open the row under the cursor</dd></div> | ||
| 17 | + | <div><dt><kbd>l</kbd> <kbd>h</kbd></dt><dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd></div> | |||
| 17 | <div><dt><kbd>g g</kbd> <kbd>G</kbd></dt><dd>first / last row</dd></div> | 18 | <div><dt><kbd>g g</kbd> <kbd>G</kbd></dt><dd>first / last row</dd></div> | ||
| 18 | <div><dt><kbd>/</kbd></dt><dd>filter the list; on Files, find a file in the repository</dd></div> | 19 | <div><dt><kbd>/</kbd></dt><dd>filter the list; on Files, find a file in the repository</dd></div> | ||
| 19 | <div><dt><kbd>b</kbd></dt><dd>{ "switch" } branch or tag</dd></div> | 20 | <div><dt><kbd>b</kbd></dt><dd>{ "switch" } branch or tag</dd></div> | ||
M internal/adapters/web/overlays_templ.go +10 -10 generated file: collapsed
M internal/adapters/web/static/js/ermite.js +69 -4
| @@ -46,10 +46,11 @@ | |||
| 46 | 46 | body().dispatchEvent(new CustomEvent('k-' + name, { bubbles: false })); | |
| 47 | 47 | }, | |
| 48 | 48 | ||
| 49 | - | // Row cursor: j / k. | |
| 49 | + | // Row cursor: j / k. In the side panel they move the focus between its | |
| 50 | + | // controls instead. | |
| 50 | 51 | move(d) { | |
| 51 | 52 | if ($('dialog[open]')) return; | |
| 52 | - | if (window.ermiteMR?.stepFiles(d)) return; | |
| 53 | + | if (window.ermiteMR?.stepFiles(d) || window.ermiteRail.step(d)) return; | |
| 53 | 54 | const rows = visibleRows(); | |
| 54 | 55 | if (!rows.length) { | |
| 55 | 56 | scrollBy(0, d * 180); | |
| @@ -75,6 +76,16 @@ | |||
| 75 | 76 | open() { | |
| 76 | 77 | if (!$('dialog[open]')) $('[data-cursor] a')?.click(); | |
| 77 | 78 | }, | |
| 79 | + | // l / h: into the side panel (the current file of a merge request, else | |
| 80 | + | // its main action, else its first control) and back to the content. | |
| 81 | + | // Enter then activates the control. | |
| 82 | + | rail(into) { | |
| 83 | + | if ($('dialog[open]')) return; | |
| 84 | + | if (into && window.ermiteMR?.focusFiles()) return flash('files · j k move · enter open · h back'); | |
| 85 | + | if (!into && window.ermiteMR?.leaveFiles()) return; | |
| 86 | + | const msg = into ? window.ermiteRail.enter() : window.ermiteRail.leave(); | |
| 87 | + | if (msg) flash(msg); | |
| 88 | + | }, | |
| 78 | 89 | // openFile opens a file of the diff the table of contents links to. | |
| 79 | 90 | openFile(id) { | |
| 80 | 91 | const f = document.getElementById(id); | |
| @@ -215,9 +226,63 @@ | |||
| 215 | 226 | }; | |
| 216 | 227 | window.ermite = ermite; | |
| 217 | 228 | ||
| 229 | + | // The side panel (aside.rail) by keyboard: l enters it on its main action | |
| 230 | + | // (the primary button) or its first control, j / k step between its shown | |
| 231 | + | // controls (not hidden, not in a closed <details>), h leaves it for <main>. | |
| 232 | + | // Each returns the hint to flash, if any. Self-contained: jstest/rail.test.mjs | |
| 233 | + | // evaluates this block alone. | |
| 234 | + | window.ermiteRail = (() => { | |
| 235 | + | const CONTROLS = ['a', 'button', 'select', 'summary', 'input', 'textarea']; | |
| 236 | + | const reachable = (e) => { | |
| 237 | + | if (e.disabled || e.closest('[hidden]')) return false; | |
| 238 | + | if (e.tagName === 'A' && !e.hasAttribute('href')) return false; | |
| 239 | + | if (e.tagName === 'INPUT' && e.getAttribute('type') === 'hidden') return false; | |
| 240 | + | return !e.getClientRects || e.getClientRects().length > 0; | |
| 241 | + | }; | |
| 242 | + | const rail = () => document.querySelector('.rail'); | |
| 243 | + | // items walks the panel in document order. | |
| 244 | + | const items = (r) => { | |
| 245 | + | const out = []; | |
| 246 | + | const walk = (e) => { | |
| 247 | + | for (const c of e.children) { | |
| 248 | + | if (CONTROLS.includes(c.tagName.toLowerCase())) { if (reachable(c)) out.push(c); } | |
| 249 | + | else walk(c); | |
| 250 | + | } | |
| 251 | + | }; | |
| 252 | + | walk(r); | |
| 253 | + | return out; | |
| 254 | + | }; | |
| 255 | + | const inside = (r) => r && r.contains(document.activeElement); | |
| 256 | + | const go = (e) => { e.focus(); e.scrollIntoView({ block: 'nearest' }); }; | |
| 257 | + | return { | |
| 258 | + | enter() { | |
| 259 | + | const r = rail(); | |
| 260 | + | if (!r) return 'no side panel on this page'; | |
| 261 | + | const list = items(r); | |
| 262 | + | const target = list.find((e) => e.matches('.btn.primary')) || list[0]; | |
| 263 | + | if (!target) return 'nothing to act on in the side panel'; | |
| 264 | + | go(target); | |
| 265 | + | return 'side panel · j k move · enter act · h back'; | |
| 266 | + | }, | |
| 267 | + | leave() { | |
| 268 | + | if (inside(rail())) document.getElementById('main')?.focus({ preventScroll: true }); | |
| 269 | + | }, | |
| 270 | + | // step moves d controls within the panel; false when the focus is not in it. | |
| 271 | + | step(d) { | |
| 272 | + | const r = rail(); | |
| 273 | + | if (!inside(r)) return false; | |
| 274 | + | const list = items(r); | |
| 275 | + | const i = list.indexOf(document.activeElement); | |
| 276 | + | const next = list[Math.max(0, Math.min(list.length - 1, i + d))]; | |
| 277 | + | if (next) go(next); | |
| 278 | + | return true; | |
| 279 | + | }, | |
| 280 | + | }; | |
| 281 | + | })(); | |
| 282 | + | ||
| 218 | 283 | // 1. Keys. | |
| 219 | 284 | const single = { j: 'j', k: 'k', G: 'bottom', '/': 'filter', '?': 'help', b: 'refs', f: 'cmd', ':': 'cmd', y: 'permalink', | |
| 220 | - | s: 's', t: 't', c: 'c', r: 'r', m: 'm', n: 'next', d: 'split', u: 'unified', x: 'collapse', Enter: 'open', Escape: 'esc', | |
| 285 | + | s: 's', t: 't', c: 'c', r: 'r', m: 'm', n: 'next', h: 'left', l: 'right', d: 'split', u: 'unified', x: 'collapse', Enter: 'open', Escape: 'esc', | |
| 221 | 286 | // the merge request page (mr.js): the merge menu, mark read | |
| 222 | 287 | M: 'merge', R: 'read' }; | |
| 223 | 288 | // "g t" is the key "t": the tabs have one event each. | |
| @@ -225,7 +290,7 @@ | |||
| 225 | 290 | let pending = 0; | |
| 226 | 291 | let pendingTimer = 0; | |
| 227 | 292 | addEventListener('keydown', (e) => { | |
| 228 | - | const typing = e.target.closest('input, textarea, select, [contenteditable]'); | |
| 293 | + | const typing = e.target.closest('input:not([type=checkbox], [type=radio], [type=submit], [type=button]), textarea, select, [contenteditable]'); | |
| 229 | 294 | // ctrl k / cmd k opens the palette; in a field only cmd k, so that the | |
| 230 | 295 | // field keeps ctrl k (kill to end of line on macOS). | |
| 231 | 296 | if ((e.metaKey || (e.ctrlKey && !typing)) && !e.altKey && !e.shiftKey && e.key.toLowerCase() === 'k') { e.preventDefault(); pending = 0; return ermite.fire('cmd'); } | |
| @@ -46,10 +46,11 @@ | |||||
| 46 | body().dispatchEvent(new CustomEvent('k-' + name, { bubbles: false })); | 46 | body().dispatchEvent(new CustomEvent('k-' + name, { bubbles: false })); | ||
| 47 | }, | 47 | }, | ||
| 48 | 48 | ||||
| 49 | - | // Row cursor: j / k. | 49 | + | // Row cursor: j / k. In the side panel they move the focus between its |
| 50 | + | // controls instead. | |||
| 50 | move(d) { | 51 | move(d) { | ||
| 51 | if ($('dialog[open]')) return; | 52 | if ($('dialog[open]')) return; | ||
| 52 | - | if (window.ermiteMR?.stepFiles(d)) return; | 53 | + | if (window.ermiteMR?.stepFiles(d) || window.ermiteRail.step(d)) return; |
| 53 | const rows = visibleRows(); | 54 | const rows = visibleRows(); | ||
| 54 | if (!rows.length) { | 55 | if (!rows.length) { | ||
| 55 | scrollBy(0, d * 180); | 56 | scrollBy(0, d * 180); | ||
| @@ -75,6 +76,16 @@ | |||||
| 75 | open() { | 76 | open() { | ||
| 76 | if (!$('dialog[open]')) $('[data-cursor] a')?.click(); | 77 | if (!$('dialog[open]')) $('[data-cursor] a')?.click(); | ||
| 77 | }, | 78 | }, | ||
| 79 | + | // l / h: into the side panel (the current file of a merge request, else | |||
| 80 | + | // its main action, else its first control) and back to the content. | |||
| 81 | + | // Enter then activates the control. | |||
| 82 | + | rail(into) { | |||
| 83 | + | if ($('dialog[open]')) return; | |||
| 84 | + | if (into && window.ermiteMR?.focusFiles()) return flash('files · j k move · enter open · h back'); | |||
| 85 | + | if (!into && window.ermiteMR?.leaveFiles()) return; | |||
| 86 | + | const msg = into ? window.ermiteRail.enter() : window.ermiteRail.leave(); | |||
| 87 | + | if (msg) flash(msg); | |||
| 88 | + | }, | |||
| 78 | // openFile opens a file of the diff the table of contents links to. | 89 | // openFile opens a file of the diff the table of contents links to. | ||
| 79 | openFile(id) { | 90 | openFile(id) { | ||
| 80 | const f = document.getElementById(id); | 91 | const f = document.getElementById(id); | ||
| @@ -215,9 +226,63 @@ | |||||
| 215 | }; | 226 | }; | ||
| 216 | window.ermite = ermite; | 227 | window.ermite = ermite; | ||
| 217 | 228 | ||||
| 229 | + | // The side panel (aside.rail) by keyboard: l enters it on its main action | |||
| 230 | + | // (the primary button) or its first control, j / k step between its shown | |||
| 231 | + | // controls (not hidden, not in a closed <details>), h leaves it for <main>. | |||
| 232 | + | // Each returns the hint to flash, if any. Self-contained: jstest/rail.test.mjs | |||
| 233 | + | // evaluates this block alone. | |||
| 234 | + | window.ermiteRail = (() => { | |||
| 235 | + | const CONTROLS = ['a', 'button', 'select', 'summary', 'input', 'textarea']; | |||
| 236 | + | const reachable = (e) => { | |||
| 237 | + | if (e.disabled || e.closest('[hidden]')) return false; | |||
| 238 | + | if (e.tagName === 'A' && !e.hasAttribute('href')) return false; | |||
| 239 | + | if (e.tagName === 'INPUT' && e.getAttribute('type') === 'hidden') return false; | |||
| 240 | + | return !e.getClientRects || e.getClientRects().length > 0; | |||
| 241 | + | }; | |||
| 242 | + | const rail = () => document.querySelector('.rail'); | |||
| 243 | + | // items walks the panel in document order. | |||
| 244 | + | const items = (r) => { | |||
| 245 | + | const out = []; | |||
| 246 | + | const walk = (e) => { | |||
| 247 | + | for (const c of e.children) { | |||
| 248 | + | if (CONTROLS.includes(c.tagName.toLowerCase())) { if (reachable(c)) out.push(c); } | |||
| 249 | + | else walk(c); | |||
| 250 | + | } | |||
| 251 | + | }; | |||
| 252 | + | walk(r); | |||
| 253 | + | return out; | |||
| 254 | + | }; | |||
| 255 | + | const inside = (r) => r && r.contains(document.activeElement); | |||
| 256 | + | const go = (e) => { e.focus(); e.scrollIntoView({ block: 'nearest' }); }; | |||
| 257 | + | return { | |||
| 258 | + | enter() { | |||
| 259 | + | const r = rail(); | |||
| 260 | + | if (!r) return 'no side panel on this page'; | |||
| 261 | + | const list = items(r); | |||
| 262 | + | const target = list.find((e) => e.matches('.btn.primary')) || list[0]; | |||
| 263 | + | if (!target) return 'nothing to act on in the side panel'; | |||
| 264 | + | go(target); | |||
| 265 | + | return 'side panel · j k move · enter act · h back'; | |||
| 266 | + | }, | |||
| 267 | + | leave() { | |||
| 268 | + | if (inside(rail())) document.getElementById('main')?.focus({ preventScroll: true }); | |||
| 269 | + | }, | |||
| 270 | + | // step moves d controls within the panel; false when the focus is not in it. | |||
| 271 | + | step(d) { | |||
| 272 | + | const r = rail(); | |||
| 273 | + | if (!inside(r)) return false; | |||
| 274 | + | const list = items(r); | |||
| 275 | + | const i = list.indexOf(document.activeElement); | |||
| 276 | + | const next = list[Math.max(0, Math.min(list.length - 1, i + d))]; | |||
| 277 | + | if (next) go(next); | |||
| 278 | + | return true; | |||
| 279 | + | }, | |||
| 280 | + | }; | |||
| 281 | + | })(); | |||
| 282 | + | ||||
| 218 | // 1. Keys. | 283 | // 1. Keys. | ||
| 219 | const single = { j: 'j', k: 'k', G: 'bottom', '/': 'filter', '?': 'help', b: 'refs', f: 'cmd', ':': 'cmd', y: 'permalink', | 284 | const single = { j: 'j', k: 'k', G: 'bottom', '/': 'filter', '?': 'help', b: 'refs', f: 'cmd', ':': 'cmd', y: 'permalink', | ||
| 220 | - | s: 's', t: 't', c: 'c', r: 'r', m: 'm', n: 'next', d: 'split', u: 'unified', x: 'collapse', Enter: 'open', Escape: 'esc', | 285 | + | s: 's', t: 't', c: 'c', r: 'r', m: 'm', n: 'next', h: 'left', l: 'right', d: 'split', u: 'unified', x: 'collapse', Enter: 'open', Escape: 'esc', |
| 221 | // the merge request page (mr.js): the merge menu, mark read | 286 | // the merge request page (mr.js): the merge menu, mark read | ||
| 222 | M: 'merge', R: 'read' }; | 287 | M: 'merge', R: 'read' }; | ||
| 223 | // "g t" is the key "t": the tabs have one event each. | 288 | // "g t" is the key "t": the tabs have one event each. | ||
| @@ -225,7 +290,7 @@ | |||||
| 225 | let pending = 0; | 290 | let pending = 0; | ||
| 226 | let pendingTimer = 0; | 291 | let pendingTimer = 0; | ||
| 227 | addEventListener('keydown', (e) => { | 292 | addEventListener('keydown', (e) => { | ||
| 228 | - | const typing = e.target.closest('input, textarea, select, [contenteditable]'); | 293 | + | const typing = e.target.closest('input:not([type=checkbox], [type=radio], [type=submit], [type=button]), textarea, select, [contenteditable]'); |
| 229 | // ctrl k / cmd k opens the palette; in a field only cmd k, so that the | 294 | // ctrl k / cmd k opens the palette; in a field only cmd k, so that the | ||
| 230 | // field keeps ctrl k (kill to end of line on macOS). | 295 | // field keeps ctrl k (kill to end of line on macOS). | ||
| 231 | if ((e.metaKey || (e.ctrlKey && !typing)) && !e.altKey && !e.shiftKey && e.key.toLowerCase() === 'k') { e.preventDefault(); pending = 0; return ermite.fire('cmd'); } | 296 | if ((e.metaKey || (e.ctrlKey && !typing)) && !e.altKey && !e.shiftKey && e.key.toLowerCase() === 'k') { e.preventDefault(); pending = 0; return ermite.fire('cmd'); } | ||
M internal/app/testdata/web/blob-binary.html +9 -0
| @@ -178,6 +178,13 @@ | |||
| 178 | 178 | </div> | |
| 179 | 179 | <div> | |
| 180 | 180 | <dt> | |
| 181 | + | <kbd>l</kbd> | |
| 182 | + | <kbd>h</kbd> | |
| 183 | + | </dt> | |
| 184 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 185 | + | </div> | |
| 186 | + | <div> | |
| 187 | + | <dt> | |
| 181 | 188 | <kbd>g g</kbd> | |
| 182 | 189 | <kbd>G</kbd> | |
| 183 | 190 | </dt> | |
| @@ -359,6 +366,8 @@ | |||
| 359 | 366 | k-top from:body -> ermite.edge(false); | |
| 360 | 367 | k-bottom from:body -> ermite.edge(true); | |
| 361 | 368 | k-open from:body -> ermite.open(); | |
| 369 | + | k-right from:body -> ermite.rail(true); | |
| 370 | + | k-left from:body -> ermite.rail(false); | |
| 362 | 371 | k-esc from:body -> ermite.closeDialogs(); | |
| 363 | 372 | k-help from:body -> ermite.dialog('panel-help'); | |
| 364 | 373 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -178,6 +178,13 @@ | |||||
| 178 | </div> | 178 | </div> | ||
| 179 | <div> | 179 | <div> | ||
| 180 | <dt> | 180 | <dt> | ||
| 181 | + | <kbd>l</kbd> | |||
| 182 | + | <kbd>h</kbd> | |||
| 183 | + | </dt> | |||
| 184 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 185 | + | </div> | |||
| 186 | + | <div> | |||
| 187 | + | <dt> | |||
| 181 | <kbd>g g</kbd> | 188 | <kbd>g g</kbd> | ||
| 182 | <kbd>G</kbd> | 189 | <kbd>G</kbd> | ||
| 183 | </dt> | 190 | </dt> | ||
| @@ -359,6 +366,8 @@ | |||||
| 359 | k-top from:body -> ermite.edge(false); | 366 | k-top from:body -> ermite.edge(false); | ||
| 360 | k-bottom from:body -> ermite.edge(true); | 367 | k-bottom from:body -> ermite.edge(true); | ||
| 361 | k-open from:body -> ermite.open(); | 368 | k-open from:body -> ermite.open(); | ||
| 369 | + | k-right from:body -> ermite.rail(true); | |||
| 370 | + | k-left from:body -> ermite.rail(false); | |||
| 362 | k-esc from:body -> ermite.closeDialogs(); | 371 | k-esc from:body -> ermite.closeDialogs(); | ||
| 363 | k-help from:body -> ermite.dialog('panel-help'); | 372 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 364 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 373 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/blob-code.html +9 -0
| @@ -248,6 +248,13 @@ | |||
| 248 | 248 | </div> | |
| 249 | 249 | <div> | |
| 250 | 250 | <dt> | |
| 251 | + | <kbd>l</kbd> | |
| 252 | + | <kbd>h</kbd> | |
| 253 | + | </dt> | |
| 254 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 255 | + | </div> | |
| 256 | + | <div> | |
| 257 | + | <dt> | |
| 251 | 258 | <kbd>g g</kbd> | |
| 252 | 259 | <kbd>G</kbd> | |
| 253 | 260 | </dt> | |
| @@ -429,6 +436,8 @@ | |||
| 429 | 436 | k-top from:body -> ermite.edge(false); | |
| 430 | 437 | k-bottom from:body -> ermite.edge(true); | |
| 431 | 438 | k-open from:body -> ermite.open(); | |
| 439 | + | k-right from:body -> ermite.rail(true); | |
| 440 | + | k-left from:body -> ermite.rail(false); | |
| 432 | 441 | k-esc from:body -> ermite.closeDialogs(); | |
| 433 | 442 | k-help from:body -> ermite.dialog('panel-help'); | |
| 434 | 443 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -248,6 +248,13 @@ | |||||
| 248 | </div> | 248 | </div> | ||
| 249 | <div> | 249 | <div> | ||
| 250 | <dt> | 250 | <dt> | ||
| 251 | + | <kbd>l</kbd> | |||
| 252 | + | <kbd>h</kbd> | |||
| 253 | + | </dt> | |||
| 254 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 255 | + | </div> | |||
| 256 | + | <div> | |||
| 257 | + | <dt> | |||
| 251 | <kbd>g g</kbd> | 258 | <kbd>g g</kbd> | ||
| 252 | <kbd>G</kbd> | 259 | <kbd>G</kbd> | ||
| 253 | </dt> | 260 | </dt> | ||
| @@ -429,6 +436,8 @@ | |||||
| 429 | k-top from:body -> ermite.edge(false); | 436 | k-top from:body -> ermite.edge(false); | ||
| 430 | k-bottom from:body -> ermite.edge(true); | 437 | k-bottom from:body -> ermite.edge(true); | ||
| 431 | k-open from:body -> ermite.open(); | 438 | k-open from:body -> ermite.open(); | ||
| 439 | + | k-right from:body -> ermite.rail(true); | |||
| 440 | + | k-left from:body -> ermite.rail(false); | |||
| 432 | k-esc from:body -> ermite.closeDialogs(); | 441 | k-esc from:body -> ermite.closeDialogs(); | ||
| 433 | k-help from:body -> ermite.dialog('panel-help'); | 442 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 434 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 443 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/blob-empty.html +9 -0
| @@ -178,6 +178,13 @@ | |||
| 178 | 178 | </div> | |
| 179 | 179 | <div> | |
| 180 | 180 | <dt> | |
| 181 | + | <kbd>l</kbd> | |
| 182 | + | <kbd>h</kbd> | |
| 183 | + | </dt> | |
| 184 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 185 | + | </div> | |
| 186 | + | <div> | |
| 187 | + | <dt> | |
| 181 | 188 | <kbd>g g</kbd> | |
| 182 | 189 | <kbd>G</kbd> | |
| 183 | 190 | </dt> | |
| @@ -359,6 +366,8 @@ | |||
| 359 | 366 | k-top from:body -> ermite.edge(false); | |
| 360 | 367 | k-bottom from:body -> ermite.edge(true); | |
| 361 | 368 | k-open from:body -> ermite.open(); | |
| 369 | + | k-right from:body -> ermite.rail(true); | |
| 370 | + | k-left from:body -> ermite.rail(false); | |
| 362 | 371 | k-esc from:body -> ermite.closeDialogs(); | |
| 363 | 372 | k-help from:body -> ermite.dialog('panel-help'); | |
| 364 | 373 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -178,6 +178,13 @@ | |||||
| 178 | </div> | 178 | </div> | ||
| 179 | <div> | 179 | <div> | ||
| 180 | <dt> | 180 | <dt> | ||
| 181 | + | <kbd>l</kbd> | |||
| 182 | + | <kbd>h</kbd> | |||
| 183 | + | </dt> | |||
| 184 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 185 | + | </div> | |||
| 186 | + | <div> | |||
| 187 | + | <dt> | |||
| 181 | <kbd>g g</kbd> | 188 | <kbd>g g</kbd> | ||
| 182 | <kbd>G</kbd> | 189 | <kbd>G</kbd> | ||
| 183 | </dt> | 190 | </dt> | ||
| @@ -359,6 +366,8 @@ | |||||
| 359 | k-top from:body -> ermite.edge(false); | 366 | k-top from:body -> ermite.edge(false); | ||
| 360 | k-bottom from:body -> ermite.edge(true); | 367 | k-bottom from:body -> ermite.edge(true); | ||
| 361 | k-open from:body -> ermite.open(); | 368 | k-open from:body -> ermite.open(); | ||
| 369 | + | k-right from:body -> ermite.rail(true); | |||
| 370 | + | k-left from:body -> ermite.rail(false); | |||
| 362 | k-esc from:body -> ermite.closeDialogs(); | 371 | k-esc from:body -> ermite.closeDialogs(); | ||
| 363 | k-help from:body -> ermite.dialog('panel-help'); | 372 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 364 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 373 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/blob-image.html +9 -0
| @@ -180,6 +180,13 @@ | |||
| 180 | 180 | </div> | |
| 181 | 181 | <div> | |
| 182 | 182 | <dt> | |
| 183 | + | <kbd>l</kbd> | |
| 184 | + | <kbd>h</kbd> | |
| 185 | + | </dt> | |
| 186 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 187 | + | </div> | |
| 188 | + | <div> | |
| 189 | + | <dt> | |
| 183 | 190 | <kbd>g g</kbd> | |
| 184 | 191 | <kbd>G</kbd> | |
| 185 | 192 | </dt> | |
| @@ -361,6 +368,8 @@ | |||
| 361 | 368 | k-top from:body -> ermite.edge(false); | |
| 362 | 369 | k-bottom from:body -> ermite.edge(true); | |
| 363 | 370 | k-open from:body -> ermite.open(); | |
| 371 | + | k-right from:body -> ermite.rail(true); | |
| 372 | + | k-left from:body -> ermite.rail(false); | |
| 364 | 373 | k-esc from:body -> ermite.closeDialogs(); | |
| 365 | 374 | k-help from:body -> ermite.dialog('panel-help'); | |
| 366 | 375 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -180,6 +180,13 @@ | |||||
| 180 | </div> | 180 | </div> | ||
| 181 | <div> | 181 | <div> | ||
| 182 | <dt> | 182 | <dt> | ||
| 183 | + | <kbd>l</kbd> | |||
| 184 | + | <kbd>h</kbd> | |||
| 185 | + | </dt> | |||
| 186 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 187 | + | </div> | |||
| 188 | + | <div> | |||
| 189 | + | <dt> | |||
| 183 | <kbd>g g</kbd> | 190 | <kbd>g g</kbd> | ||
| 184 | <kbd>G</kbd> | 191 | <kbd>G</kbd> | ||
| 185 | </dt> | 192 | </dt> | ||
| @@ -361,6 +368,8 @@ | |||||
| 361 | k-top from:body -> ermite.edge(false); | 368 | k-top from:body -> ermite.edge(false); | ||
| 362 | k-bottom from:body -> ermite.edge(true); | 369 | k-bottom from:body -> ermite.edge(true); | ||
| 363 | k-open from:body -> ermite.open(); | 370 | k-open from:body -> ermite.open(); | ||
| 371 | + | k-right from:body -> ermite.rail(true); | |||
| 372 | + | k-left from:body -> ermite.rail(false); | |||
| 364 | k-esc from:body -> ermite.closeDialogs(); | 373 | k-esc from:body -> ermite.closeDialogs(); | ||
| 365 | k-help from:body -> ermite.dialog('panel-help'); | 374 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 366 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 375 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/blob-markdown.html +9 -0
| @@ -245,6 +245,13 @@ | |||
| 245 | 245 | </div> | |
| 246 | 246 | <div> | |
| 247 | 247 | <dt> | |
| 248 | + | <kbd>l</kbd> | |
| 249 | + | <kbd>h</kbd> | |
| 250 | + | </dt> | |
| 251 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 252 | + | </div> | |
| 253 | + | <div> | |
| 254 | + | <dt> | |
| 248 | 255 | <kbd>g g</kbd> | |
| 249 | 256 | <kbd>G</kbd> | |
| 250 | 257 | </dt> | |
| @@ -426,6 +433,8 @@ | |||
| 426 | 433 | k-top from:body -> ermite.edge(false); | |
| 427 | 434 | k-bottom from:body -> ermite.edge(true); | |
| 428 | 435 | k-open from:body -> ermite.open(); | |
| 436 | + | k-right from:body -> ermite.rail(true); | |
| 437 | + | k-left from:body -> ermite.rail(false); | |
| 429 | 438 | k-esc from:body -> ermite.closeDialogs(); | |
| 430 | 439 | k-help from:body -> ermite.dialog('panel-help'); | |
| 431 | 440 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -245,6 +245,13 @@ | |||||
| 245 | </div> | 245 | </div> | ||
| 246 | <div> | 246 | <div> | ||
| 247 | <dt> | 247 | <dt> | ||
| 248 | + | <kbd>l</kbd> | |||
| 249 | + | <kbd>h</kbd> | |||
| 250 | + | </dt> | |||
| 251 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 252 | + | </div> | |||
| 253 | + | <div> | |||
| 254 | + | <dt> | |||
| 248 | <kbd>g g</kbd> | 255 | <kbd>g g</kbd> | ||
| 249 | <kbd>G</kbd> | 256 | <kbd>G</kbd> | ||
| 250 | </dt> | 257 | </dt> | ||
| @@ -426,6 +433,8 @@ | |||||
| 426 | k-top from:body -> ermite.edge(false); | 433 | k-top from:body -> ermite.edge(false); | ||
| 427 | k-bottom from:body -> ermite.edge(true); | 434 | k-bottom from:body -> ermite.edge(true); | ||
| 428 | k-open from:body -> ermite.open(); | 435 | k-open from:body -> ermite.open(); | ||
| 436 | + | k-right from:body -> ermite.rail(true); | |||
| 437 | + | k-left from:body -> ermite.rail(false); | |||
| 429 | k-esc from:body -> ermite.closeDialogs(); | 438 | k-esc from:body -> ermite.closeDialogs(); | ||
| 430 | k-help from:body -> ermite.dialog('panel-help'); | 439 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 431 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 440 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/blob-svg.html +9 -0
| @@ -203,6 +203,13 @@ | |||
| 203 | 203 | </div> | |
| 204 | 204 | <div> | |
| 205 | 205 | <dt> | |
| 206 | + | <kbd>l</kbd> | |
| 207 | + | <kbd>h</kbd> | |
| 208 | + | </dt> | |
| 209 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 210 | + | </div> | |
| 211 | + | <div> | |
| 212 | + | <dt> | |
| 206 | 213 | <kbd>g g</kbd> | |
| 207 | 214 | <kbd>G</kbd> | |
| 208 | 215 | </dt> | |
| @@ -384,6 +391,8 @@ | |||
| 384 | 391 | k-top from:body -> ermite.edge(false); | |
| 385 | 392 | k-bottom from:body -> ermite.edge(true); | |
| 386 | 393 | k-open from:body -> ermite.open(); | |
| 394 | + | k-right from:body -> ermite.rail(true); | |
| 395 | + | k-left from:body -> ermite.rail(false); | |
| 387 | 396 | k-esc from:body -> ermite.closeDialogs(); | |
| 388 | 397 | k-help from:body -> ermite.dialog('panel-help'); | |
| 389 | 398 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -203,6 +203,13 @@ | |||||
| 203 | </div> | 203 | </div> | ||
| 204 | <div> | 204 | <div> | ||
| 205 | <dt> | 205 | <dt> | ||
| 206 | + | <kbd>l</kbd> | |||
| 207 | + | <kbd>h</kbd> | |||
| 208 | + | </dt> | |||
| 209 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 210 | + | </div> | |||
| 211 | + | <div> | |||
| 212 | + | <dt> | |||
| 206 | <kbd>g g</kbd> | 213 | <kbd>g g</kbd> | ||
| 207 | <kbd>G</kbd> | 214 | <kbd>G</kbd> | ||
| 208 | </dt> | 215 | </dt> | ||
| @@ -384,6 +391,8 @@ | |||||
| 384 | k-top from:body -> ermite.edge(false); | 391 | k-top from:body -> ermite.edge(false); | ||
| 385 | k-bottom from:body -> ermite.edge(true); | 392 | k-bottom from:body -> ermite.edge(true); | ||
| 386 | k-open from:body -> ermite.open(); | 393 | k-open from:body -> ermite.open(); | ||
| 394 | + | k-right from:body -> ermite.rail(true); | |||
| 395 | + | k-left from:body -> ermite.rail(false); | |||
| 387 | k-esc from:body -> ermite.closeDialogs(); | 396 | k-esc from:body -> ermite.closeDialogs(); | ||
| 388 | k-help from:body -> ermite.dialog('panel-help'); | 397 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 389 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 398 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/blob-text.html +9 -0
| @@ -198,6 +198,13 @@ | |||
| 198 | 198 | </div> | |
| 199 | 199 | <div> | |
| 200 | 200 | <dt> | |
| 201 | + | <kbd>l</kbd> | |
| 202 | + | <kbd>h</kbd> | |
| 203 | + | </dt> | |
| 204 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 205 | + | </div> | |
| 206 | + | <div> | |
| 207 | + | <dt> | |
| 201 | 208 | <kbd>g g</kbd> | |
| 202 | 209 | <kbd>G</kbd> | |
| 203 | 210 | </dt> | |
| @@ -379,6 +386,8 @@ | |||
| 379 | 386 | k-top from:body -> ermite.edge(false); | |
| 380 | 387 | k-bottom from:body -> ermite.edge(true); | |
| 381 | 388 | k-open from:body -> ermite.open(); | |
| 389 | + | k-right from:body -> ermite.rail(true); | |
| 390 | + | k-left from:body -> ermite.rail(false); | |
| 382 | 391 | k-esc from:body -> ermite.closeDialogs(); | |
| 383 | 392 | k-help from:body -> ermite.dialog('panel-help'); | |
| 384 | 393 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -198,6 +198,13 @@ | |||||
| 198 | </div> | 198 | </div> | ||
| 199 | <div> | 199 | <div> | ||
| 200 | <dt> | 200 | <dt> | ||
| 201 | + | <kbd>l</kbd> | |||
| 202 | + | <kbd>h</kbd> | |||
| 203 | + | </dt> | |||
| 204 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 205 | + | </div> | |||
| 206 | + | <div> | |||
| 207 | + | <dt> | |||
| 201 | <kbd>g g</kbd> | 208 | <kbd>g g</kbd> | ||
| 202 | <kbd>G</kbd> | 209 | <kbd>G</kbd> | ||
| 203 | </dt> | 210 | </dt> | ||
| @@ -379,6 +386,8 @@ | |||||
| 379 | k-top from:body -> ermite.edge(false); | 386 | k-top from:body -> ermite.edge(false); | ||
| 380 | k-bottom from:body -> ermite.edge(true); | 387 | k-bottom from:body -> ermite.edge(true); | ||
| 381 | k-open from:body -> ermite.open(); | 388 | k-open from:body -> ermite.open(); | ||
| 389 | + | k-right from:body -> ermite.rail(true); | |||
| 390 | + | k-left from:body -> ermite.rail(false); | |||
| 382 | k-esc from:body -> ermite.closeDialogs(); | 391 | k-esc from:body -> ermite.closeDialogs(); | ||
| 383 | k-help from:body -> ermite.dialog('panel-help'); | 392 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 384 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 393 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/blob-too-large.html +9 -0
| @@ -178,6 +178,13 @@ | |||
| 178 | 178 | </div> | |
| 179 | 179 | <div> | |
| 180 | 180 | <dt> | |
| 181 | + | <kbd>l</kbd> | |
| 182 | + | <kbd>h</kbd> | |
| 183 | + | </dt> | |
| 184 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 185 | + | </div> | |
| 186 | + | <div> | |
| 187 | + | <dt> | |
| 181 | 188 | <kbd>g g</kbd> | |
| 182 | 189 | <kbd>G</kbd> | |
| 183 | 190 | </dt> | |
| @@ -359,6 +366,8 @@ | |||
| 359 | 366 | k-top from:body -> ermite.edge(false); | |
| 360 | 367 | k-bottom from:body -> ermite.edge(true); | |
| 361 | 368 | k-open from:body -> ermite.open(); | |
| 369 | + | k-right from:body -> ermite.rail(true); | |
| 370 | + | k-left from:body -> ermite.rail(false); | |
| 362 | 371 | k-esc from:body -> ermite.closeDialogs(); | |
| 363 | 372 | k-help from:body -> ermite.dialog('panel-help'); | |
| 364 | 373 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -178,6 +178,13 @@ | |||||
| 178 | </div> | 178 | </div> | ||
| 179 | <div> | 179 | <div> | ||
| 180 | <dt> | 180 | <dt> | ||
| 181 | + | <kbd>l</kbd> | |||
| 182 | + | <kbd>h</kbd> | |||
| 183 | + | </dt> | |||
| 184 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 185 | + | </div> | |||
| 186 | + | <div> | |||
| 187 | + | <dt> | |||
| 181 | <kbd>g g</kbd> | 188 | <kbd>g g</kbd> | ||
| 182 | <kbd>G</kbd> | 189 | <kbd>G</kbd> | ||
| 183 | </dt> | 190 | </dt> | ||
| @@ -359,6 +366,8 @@ | |||||
| 359 | k-top from:body -> ermite.edge(false); | 366 | k-top from:body -> ermite.edge(false); | ||
| 360 | k-bottom from:body -> ermite.edge(true); | 367 | k-bottom from:body -> ermite.edge(true); | ||
| 361 | k-open from:body -> ermite.open(); | 368 | k-open from:body -> ermite.open(); | ||
| 369 | + | k-right from:body -> ermite.rail(true); | |||
| 370 | + | k-left from:body -> ermite.rail(false); | |||
| 362 | k-esc from:body -> ermite.closeDialogs(); | 371 | k-esc from:body -> ermite.closeDialogs(); | ||
| 363 | k-help from:body -> ermite.dialog('panel-help'); | 372 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 364 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 373 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/blob-trojan.html +9 -0
| @@ -245,6 +245,13 @@ | |||
| 245 | 245 | </div> | |
| 246 | 246 | <div> | |
| 247 | 247 | <dt> | |
| 248 | + | <kbd>l</kbd> | |
| 249 | + | <kbd>h</kbd> | |
| 250 | + | </dt> | |
| 251 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 252 | + | </div> | |
| 253 | + | <div> | |
| 254 | + | <dt> | |
| 248 | 255 | <kbd>g g</kbd> | |
| 249 | 256 | <kbd>G</kbd> | |
| 250 | 257 | </dt> | |
| @@ -426,6 +433,8 @@ | |||
| 426 | 433 | k-top from:body -> ermite.edge(false); | |
| 427 | 434 | k-bottom from:body -> ermite.edge(true); | |
| 428 | 435 | k-open from:body -> ermite.open(); | |
| 436 | + | k-right from:body -> ermite.rail(true); | |
| 437 | + | k-left from:body -> ermite.rail(false); | |
| 429 | 438 | k-esc from:body -> ermite.closeDialogs(); | |
| 430 | 439 | k-help from:body -> ermite.dialog('panel-help'); | |
| 431 | 440 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -245,6 +245,13 @@ | |||||
| 245 | </div> | 245 | </div> | ||
| 246 | <div> | 246 | <div> | ||
| 247 | <dt> | 247 | <dt> | ||
| 248 | + | <kbd>l</kbd> | |||
| 249 | + | <kbd>h</kbd> | |||
| 250 | + | </dt> | |||
| 251 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 252 | + | </div> | |||
| 253 | + | <div> | |||
| 254 | + | <dt> | |||
| 248 | <kbd>g g</kbd> | 255 | <kbd>g g</kbd> | ||
| 249 | <kbd>G</kbd> | 256 | <kbd>G</kbd> | ||
| 250 | </dt> | 257 | </dt> | ||
| @@ -426,6 +433,8 @@ | |||||
| 426 | k-top from:body -> ermite.edge(false); | 433 | k-top from:body -> ermite.edge(false); | ||
| 427 | k-bottom from:body -> ermite.edge(true); | 434 | k-bottom from:body -> ermite.edge(true); | ||
| 428 | k-open from:body -> ermite.open(); | 435 | k-open from:body -> ermite.open(); | ||
| 436 | + | k-right from:body -> ermite.rail(true); | |||
| 437 | + | k-left from:body -> ermite.rail(false); | |||
| 429 | k-esc from:body -> ermite.closeDialogs(); | 438 | k-esc from:body -> ermite.closeDialogs(); | ||
| 430 | k-help from:body -> ermite.dialog('panel-help'); | 439 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 431 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 440 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commit-big.html +9 -0
| @@ -216,6 +216,13 @@ | |||
| 216 | 216 | </div> | |
| 217 | 217 | <div> | |
| 218 | 218 | <dt> | |
| 219 | + | <kbd>l</kbd> | |
| 220 | + | <kbd>h</kbd> | |
| 221 | + | </dt> | |
| 222 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 223 | + | </div> | |
| 224 | + | <div> | |
| 225 | + | <dt> | |
| 219 | 226 | <kbd>g g</kbd> | |
| 220 | 227 | <kbd>G</kbd> | |
| 221 | 228 | </dt> | |
| @@ -397,6 +404,8 @@ | |||
| 397 | 404 | k-top from:body -> ermite.edge(false); | |
| 398 | 405 | k-bottom from:body -> ermite.edge(true); | |
| 399 | 406 | k-open from:body -> ermite.open(); | |
| 407 | + | k-right from:body -> ermite.rail(true); | |
| 408 | + | k-left from:body -> ermite.rail(false); | |
| 400 | 409 | k-esc from:body -> ermite.closeDialogs(); | |
| 401 | 410 | k-help from:body -> ermite.dialog('panel-help'); | |
| 402 | 411 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -216,6 +216,13 @@ | |||||
| 216 | </div> | 216 | </div> | ||
| 217 | <div> | 217 | <div> | ||
| 218 | <dt> | 218 | <dt> | ||
| 219 | + | <kbd>l</kbd> | |||
| 220 | + | <kbd>h</kbd> | |||
| 221 | + | </dt> | |||
| 222 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 223 | + | </div> | |||
| 224 | + | <div> | |||
| 225 | + | <dt> | |||
| 219 | <kbd>g g</kbd> | 226 | <kbd>g g</kbd> | ||
| 220 | <kbd>G</kbd> | 227 | <kbd>G</kbd> | ||
| 221 | </dt> | 228 | </dt> | ||
| @@ -397,6 +404,8 @@ | |||||
| 397 | k-top from:body -> ermite.edge(false); | 404 | k-top from:body -> ermite.edge(false); | ||
| 398 | k-bottom from:body -> ermite.edge(true); | 405 | k-bottom from:body -> ermite.edge(true); | ||
| 399 | k-open from:body -> ermite.open(); | 406 | k-open from:body -> ermite.open(); | ||
| 407 | + | k-right from:body -> ermite.rail(true); | |||
| 408 | + | k-left from:body -> ermite.rail(false); | |||
| 400 | k-esc from:body -> ermite.closeDialogs(); | 409 | k-esc from:body -> ermite.closeDialogs(); | ||
| 401 | k-help from:body -> ermite.dialog('panel-help'); | 410 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 402 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 411 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commit-binary.html +9 -0
| @@ -208,6 +208,13 @@ | |||
| 208 | 208 | </div> | |
| 209 | 209 | <div> | |
| 210 | 210 | <dt> | |
| 211 | + | <kbd>l</kbd> | |
| 212 | + | <kbd>h</kbd> | |
| 213 | + | </dt> | |
| 214 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 215 | + | </div> | |
| 216 | + | <div> | |
| 217 | + | <dt> | |
| 211 | 218 | <kbd>g g</kbd> | |
| 212 | 219 | <kbd>G</kbd> | |
| 213 | 220 | </dt> | |
| @@ -389,6 +396,8 @@ | |||
| 389 | 396 | k-top from:body -> ermite.edge(false); | |
| 390 | 397 | k-bottom from:body -> ermite.edge(true); | |
| 391 | 398 | k-open from:body -> ermite.open(); | |
| 399 | + | k-right from:body -> ermite.rail(true); | |
| 400 | + | k-left from:body -> ermite.rail(false); | |
| 392 | 401 | k-esc from:body -> ermite.closeDialogs(); | |
| 393 | 402 | k-help from:body -> ermite.dialog('panel-help'); | |
| 394 | 403 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -208,6 +208,13 @@ | |||||
| 208 | </div> | 208 | </div> | ||
| 209 | <div> | 209 | <div> | ||
| 210 | <dt> | 210 | <dt> | ||
| 211 | + | <kbd>l</kbd> | |||
| 212 | + | <kbd>h</kbd> | |||
| 213 | + | </dt> | |||
| 214 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 215 | + | </div> | |||
| 216 | + | <div> | |||
| 217 | + | <dt> | |||
| 211 | <kbd>g g</kbd> | 218 | <kbd>g g</kbd> | ||
| 212 | <kbd>G</kbd> | 219 | <kbd>G</kbd> | ||
| 213 | </dt> | 220 | </dt> | ||
| @@ -389,6 +396,8 @@ | |||||
| 389 | k-top from:body -> ermite.edge(false); | 396 | k-top from:body -> ermite.edge(false); | ||
| 390 | k-bottom from:body -> ermite.edge(true); | 397 | k-bottom from:body -> ermite.edge(true); | ||
| 391 | k-open from:body -> ermite.open(); | 398 | k-open from:body -> ermite.open(); | ||
| 399 | + | k-right from:body -> ermite.rail(true); | |||
| 400 | + | k-left from:body -> ermite.rail(false); | |||
| 392 | k-esc from:body -> ermite.closeDialogs(); | 401 | k-esc from:body -> ermite.closeDialogs(); | ||
| 393 | k-help from:body -> ermite.dialog('panel-help'); | 402 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 394 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 403 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commit-merge.html +9 -0
| @@ -250,6 +250,13 @@ | |||
| 250 | 250 | </div> | |
| 251 | 251 | <div> | |
| 252 | 252 | <dt> | |
| 253 | + | <kbd>l</kbd> | |
| 254 | + | <kbd>h</kbd> | |
| 255 | + | </dt> | |
| 256 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 257 | + | </div> | |
| 258 | + | <div> | |
| 259 | + | <dt> | |
| 253 | 260 | <kbd>g g</kbd> | |
| 254 | 261 | <kbd>G</kbd> | |
| 255 | 262 | </dt> | |
| @@ -431,6 +438,8 @@ | |||
| 431 | 438 | k-top from:body -> ermite.edge(false); | |
| 432 | 439 | k-bottom from:body -> ermite.edge(true); | |
| 433 | 440 | k-open from:body -> ermite.open(); | |
| 441 | + | k-right from:body -> ermite.rail(true); | |
| 442 | + | k-left from:body -> ermite.rail(false); | |
| 434 | 443 | k-esc from:body -> ermite.closeDialogs(); | |
| 435 | 444 | k-help from:body -> ermite.dialog('panel-help'); | |
| 436 | 445 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -250,6 +250,13 @@ | |||||
| 250 | </div> | 250 | </div> | ||
| 251 | <div> | 251 | <div> | ||
| 252 | <dt> | 252 | <dt> | ||
| 253 | + | <kbd>l</kbd> | |||
| 254 | + | <kbd>h</kbd> | |||
| 255 | + | </dt> | |||
| 256 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 257 | + | </div> | |||
| 258 | + | <div> | |||
| 259 | + | <dt> | |||
| 253 | <kbd>g g</kbd> | 260 | <kbd>g g</kbd> | ||
| 254 | <kbd>G</kbd> | 261 | <kbd>G</kbd> | ||
| 255 | </dt> | 262 | </dt> | ||
| @@ -431,6 +438,8 @@ | |||||
| 431 | k-top from:body -> ermite.edge(false); | 438 | k-top from:body -> ermite.edge(false); | ||
| 432 | k-bottom from:body -> ermite.edge(true); | 439 | k-bottom from:body -> ermite.edge(true); | ||
| 433 | k-open from:body -> ermite.open(); | 440 | k-open from:body -> ermite.open(); | ||
| 441 | + | k-right from:body -> ermite.rail(true); | |||
| 442 | + | k-left from:body -> ermite.rail(false); | |||
| 434 | k-esc from:body -> ermite.closeDialogs(); | 443 | k-esc from:body -> ermite.closeDialogs(); | ||
| 435 | k-help from:body -> ermite.dialog('panel-help'); | 444 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 436 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 445 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commit-modify-split.html +9 -0
| @@ -373,6 +373,13 @@ And <b>html</b> & "quotes".</pre> | |||
| 373 | 373 | </div> | |
| 374 | 374 | <div> | |
| 375 | 375 | <dt> | |
| 376 | + | <kbd>l</kbd> | |
| 377 | + | <kbd>h</kbd> | |
| 378 | + | </dt> | |
| 379 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 380 | + | </div> | |
| 381 | + | <div> | |
| 382 | + | <dt> | |
| 376 | 383 | <kbd>g g</kbd> | |
| 377 | 384 | <kbd>G</kbd> | |
| 378 | 385 | </dt> | |
| @@ -554,6 +561,8 @@ And <b>html</b> & "quotes".</pre> | |||
| 554 | 561 | k-top from:body -> ermite.edge(false); | |
| 555 | 562 | k-bottom from:body -> ermite.edge(true); | |
| 556 | 563 | k-open from:body -> ermite.open(); | |
| 564 | + | k-right from:body -> ermite.rail(true); | |
| 565 | + | k-left from:body -> ermite.rail(false); | |
| 557 | 566 | k-esc from:body -> ermite.closeDialogs(); | |
| 558 | 567 | k-help from:body -> ermite.dialog('panel-help'); | |
| 559 | 568 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -373,6 +373,13 @@ And <b>html</b> & "quotes".</pre> | |||||
| 373 | </div> | 373 | </div> | ||
| 374 | <div> | 374 | <div> | ||
| 375 | <dt> | 375 | <dt> | ||
| 376 | + | <kbd>l</kbd> | |||
| 377 | + | <kbd>h</kbd> | |||
| 378 | + | </dt> | |||
| 379 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 380 | + | </div> | |||
| 381 | + | <div> | |||
| 382 | + | <dt> | |||
| 376 | <kbd>g g</kbd> | 383 | <kbd>g g</kbd> | ||
| 377 | <kbd>G</kbd> | 384 | <kbd>G</kbd> | ||
| 378 | </dt> | 385 | </dt> | ||
| @@ -554,6 +561,8 @@ And <b>html</b> & "quotes".</pre> | |||||
| 554 | k-top from:body -> ermite.edge(false); | 561 | k-top from:body -> ermite.edge(false); | ||
| 555 | k-bottom from:body -> ermite.edge(true); | 562 | k-bottom from:body -> ermite.edge(true); | ||
| 556 | k-open from:body -> ermite.open(); | 563 | k-open from:body -> ermite.open(); | ||
| 564 | + | k-right from:body -> ermite.rail(true); | |||
| 565 | + | k-left from:body -> ermite.rail(false); | |||
| 557 | k-esc from:body -> ermite.closeDialogs(); | 566 | k-esc from:body -> ermite.closeDialogs(); | ||
| 558 | k-help from:body -> ermite.dialog('panel-help'); | 567 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 559 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 568 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commit-modify.html +9 -0
| @@ -373,6 +373,13 @@ And <b>html</b> & "quotes".</pre> | |||
| 373 | 373 | </div> | |
| 374 | 374 | <div> | |
| 375 | 375 | <dt> | |
| 376 | + | <kbd>l</kbd> | |
| 377 | + | <kbd>h</kbd> | |
| 378 | + | </dt> | |
| 379 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 380 | + | </div> | |
| 381 | + | <div> | |
| 382 | + | <dt> | |
| 376 | 383 | <kbd>g g</kbd> | |
| 377 | 384 | <kbd>G</kbd> | |
| 378 | 385 | </dt> | |
| @@ -554,6 +561,8 @@ And <b>html</b> & "quotes".</pre> | |||
| 554 | 561 | k-top from:body -> ermite.edge(false); | |
| 555 | 562 | k-bottom from:body -> ermite.edge(true); | |
| 556 | 563 | k-open from:body -> ermite.open(); | |
| 564 | + | k-right from:body -> ermite.rail(true); | |
| 565 | + | k-left from:body -> ermite.rail(false); | |
| 557 | 566 | k-esc from:body -> ermite.closeDialogs(); | |
| 558 | 567 | k-help from:body -> ermite.dialog('panel-help'); | |
| 559 | 568 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -373,6 +373,13 @@ And <b>html</b> & "quotes".</pre> | |||||
| 373 | </div> | 373 | </div> | ||
| 374 | <div> | 374 | <div> | ||
| 375 | <dt> | 375 | <dt> | ||
| 376 | + | <kbd>l</kbd> | |||
| 377 | + | <kbd>h</kbd> | |||
| 378 | + | </dt> | |||
| 379 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 380 | + | </div> | |||
| 381 | + | <div> | |||
| 382 | + | <dt> | |||
| 376 | <kbd>g g</kbd> | 383 | <kbd>g g</kbd> | ||
| 377 | <kbd>G</kbd> | 384 | <kbd>G</kbd> | ||
| 378 | </dt> | 385 | </dt> | ||
| @@ -554,6 +561,8 @@ And <b>html</b> & "quotes".</pre> | |||||
| 554 | k-top from:body -> ermite.edge(false); | 561 | k-top from:body -> ermite.edge(false); | ||
| 555 | k-bottom from:body -> ermite.edge(true); | 562 | k-bottom from:body -> ermite.edge(true); | ||
| 556 | k-open from:body -> ermite.open(); | 563 | k-open from:body -> ermite.open(); | ||
| 564 | + | k-right from:body -> ermite.rail(true); | |||
| 565 | + | k-left from:body -> ermite.rail(false); | |||
| 557 | k-esc from:body -> ermite.closeDialogs(); | 566 | k-esc from:body -> ermite.closeDialogs(); | ||
| 558 | k-help from:body -> ermite.dialog('panel-help'); | 567 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 559 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 568 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commit-rename.html +9 -0
| @@ -277,6 +277,13 @@ | |||
| 277 | 277 | </div> | |
| 278 | 278 | <div> | |
| 279 | 279 | <dt> | |
| 280 | + | <kbd>l</kbd> | |
| 281 | + | <kbd>h</kbd> | |
| 282 | + | </dt> | |
| 283 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 284 | + | </div> | |
| 285 | + | <div> | |
| 286 | + | <dt> | |
| 280 | 287 | <kbd>g g</kbd> | |
| 281 | 288 | <kbd>G</kbd> | |
| 282 | 289 | </dt> | |
| @@ -458,6 +465,8 @@ | |||
| 458 | 465 | k-top from:body -> ermite.edge(false); | |
| 459 | 466 | k-bottom from:body -> ermite.edge(true); | |
| 460 | 467 | k-open from:body -> ermite.open(); | |
| 468 | + | k-right from:body -> ermite.rail(true); | |
| 469 | + | k-left from:body -> ermite.rail(false); | |
| 461 | 470 | k-esc from:body -> ermite.closeDialogs(); | |
| 462 | 471 | k-help from:body -> ermite.dialog('panel-help'); | |
| 463 | 472 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -277,6 +277,13 @@ | |||||
| 277 | </div> | 277 | </div> | ||
| 278 | <div> | 278 | <div> | ||
| 279 | <dt> | 279 | <dt> | ||
| 280 | + | <kbd>l</kbd> | |||
| 281 | + | <kbd>h</kbd> | |||
| 282 | + | </dt> | |||
| 283 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 284 | + | </div> | |||
| 285 | + | <div> | |||
| 286 | + | <dt> | |||
| 280 | <kbd>g g</kbd> | 287 | <kbd>g g</kbd> | ||
| 281 | <kbd>G</kbd> | 288 | <kbd>G</kbd> | ||
| 282 | </dt> | 289 | </dt> | ||
| @@ -458,6 +465,8 @@ | |||||
| 458 | k-top from:body -> ermite.edge(false); | 465 | k-top from:body -> ermite.edge(false); | ||
| 459 | k-bottom from:body -> ermite.edge(true); | 466 | k-bottom from:body -> ermite.edge(true); | ||
| 460 | k-open from:body -> ermite.open(); | 467 | k-open from:body -> ermite.open(); | ||
| 468 | + | k-right from:body -> ermite.rail(true); | |||
| 469 | + | k-left from:body -> ermite.rail(false); | |||
| 461 | k-esc from:body -> ermite.closeDialogs(); | 470 | k-esc from:body -> ermite.closeDialogs(); | ||
| 462 | k-help from:body -> ermite.dialog('panel-help'); | 471 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 463 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 472 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commit-root.html +9 -0
| @@ -596,6 +596,13 @@ | |||
| 596 | 596 | </div> | |
| 597 | 597 | <div> | |
| 598 | 598 | <dt> | |
| 599 | + | <kbd>l</kbd> | |
| 600 | + | <kbd>h</kbd> | |
| 601 | + | </dt> | |
| 602 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 603 | + | </div> | |
| 604 | + | <div> | |
| 605 | + | <dt> | |
| 599 | 606 | <kbd>g g</kbd> | |
| 600 | 607 | <kbd>G</kbd> | |
| 601 | 608 | </dt> | |
| @@ -777,6 +784,8 @@ | |||
| 777 | 784 | k-top from:body -> ermite.edge(false); | |
| 778 | 785 | k-bottom from:body -> ermite.edge(true); | |
| 779 | 786 | k-open from:body -> ermite.open(); | |
| 787 | + | k-right from:body -> ermite.rail(true); | |
| 788 | + | k-left from:body -> ermite.rail(false); | |
| 780 | 789 | k-esc from:body -> ermite.closeDialogs(); | |
| 781 | 790 | k-help from:body -> ermite.dialog('panel-help'); | |
| 782 | 791 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -596,6 +596,13 @@ | |||||
| 596 | </div> | 596 | </div> | ||
| 597 | <div> | 597 | <div> | ||
| 598 | <dt> | 598 | <dt> | ||
| 599 | + | <kbd>l</kbd> | |||
| 600 | + | <kbd>h</kbd> | |||
| 601 | + | </dt> | |||
| 602 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 603 | + | </div> | |||
| 604 | + | <div> | |||
| 605 | + | <dt> | |||
| 599 | <kbd>g g</kbd> | 606 | <kbd>g g</kbd> | ||
| 600 | <kbd>G</kbd> | 607 | <kbd>G</kbd> | ||
| 601 | </dt> | 608 | </dt> | ||
| @@ -777,6 +784,8 @@ | |||||
| 777 | k-top from:body -> ermite.edge(false); | 784 | k-top from:body -> ermite.edge(false); | ||
| 778 | k-bottom from:body -> ermite.edge(true); | 785 | k-bottom from:body -> ermite.edge(true); | ||
| 779 | k-open from:body -> ermite.open(); | 786 | k-open from:body -> ermite.open(); | ||
| 787 | + | k-right from:body -> ermite.rail(true); | |||
| 788 | + | k-left from:body -> ermite.rail(false); | |||
| 780 | k-esc from:body -> ermite.closeDialogs(); | 789 | k-esc from:body -> ermite.closeDialogs(); | ||
| 781 | k-help from:body -> ermite.dialog('panel-help'); | 790 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 782 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 791 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commit-trojan.html +9 -0
| @@ -385,6 +385,13 @@ | |||
| 385 | 385 | </div> | |
| 386 | 386 | <div> | |
| 387 | 387 | <dt> | |
| 388 | + | <kbd>l</kbd> | |
| 389 | + | <kbd>h</kbd> | |
| 390 | + | </dt> | |
| 391 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 392 | + | </div> | |
| 393 | + | <div> | |
| 394 | + | <dt> | |
| 388 | 395 | <kbd>g g</kbd> | |
| 389 | 396 | <kbd>G</kbd> | |
| 390 | 397 | </dt> | |
| @@ -566,6 +573,8 @@ | |||
| 566 | 573 | k-top from:body -> ermite.edge(false); | |
| 567 | 574 | k-bottom from:body -> ermite.edge(true); | |
| 568 | 575 | k-open from:body -> ermite.open(); | |
| 576 | + | k-right from:body -> ermite.rail(true); | |
| 577 | + | k-left from:body -> ermite.rail(false); | |
| 569 | 578 | k-esc from:body -> ermite.closeDialogs(); | |
| 570 | 579 | k-help from:body -> ermite.dialog('panel-help'); | |
| 571 | 580 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -385,6 +385,13 @@ | |||||
| 385 | </div> | 385 | </div> | ||
| 386 | <div> | 386 | <div> | ||
| 387 | <dt> | 387 | <dt> | ||
| 388 | + | <kbd>l</kbd> | |||
| 389 | + | <kbd>h</kbd> | |||
| 390 | + | </dt> | |||
| 391 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 392 | + | </div> | |||
| 393 | + | <div> | |||
| 394 | + | <dt> | |||
| 388 | <kbd>g g</kbd> | 395 | <kbd>g g</kbd> | ||
| 389 | <kbd>G</kbd> | 396 | <kbd>G</kbd> | ||
| 390 | </dt> | 397 | </dt> | ||
| @@ -566,6 +573,8 @@ | |||||
| 566 | k-top from:body -> ermite.edge(false); | 573 | k-top from:body -> ermite.edge(false); | ||
| 567 | k-bottom from:body -> ermite.edge(true); | 574 | k-bottom from:body -> ermite.edge(true); | ||
| 568 | k-open from:body -> ermite.open(); | 575 | k-open from:body -> ermite.open(); | ||
| 576 | + | k-right from:body -> ermite.rail(true); | |||
| 577 | + | k-left from:body -> ermite.rail(false); | |||
| 569 | k-esc from:body -> ermite.closeDialogs(); | 578 | k-esc from:body -> ermite.closeDialogs(); | ||
| 570 | k-help from:body -> ermite.dialog('panel-help'); | 579 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 571 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 580 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commits-page2.html +9 -0
| @@ -209,6 +209,13 @@ | |||
| 209 | 209 | </div> | |
| 210 | 210 | <div> | |
| 211 | 211 | <dt> | |
| 212 | + | <kbd>l</kbd> | |
| 213 | + | <kbd>h</kbd> | |
| 214 | + | </dt> | |
| 215 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 216 | + | </div> | |
| 217 | + | <div> | |
| 218 | + | <dt> | |
| 212 | 219 | <kbd>g g</kbd> | |
| 213 | 220 | <kbd>G</kbd> | |
| 214 | 221 | </dt> | |
| @@ -376,6 +383,8 @@ | |||
| 376 | 383 | k-top from:body -> ermite.edge(false); | |
| 377 | 384 | k-bottom from:body -> ermite.edge(true); | |
| 378 | 385 | k-open from:body -> ermite.open(); | |
| 386 | + | k-right from:body -> ermite.rail(true); | |
| 387 | + | k-left from:body -> ermite.rail(false); | |
| 379 | 388 | k-esc from:body -> ermite.closeDialogs(); | |
| 380 | 389 | k-help from:body -> ermite.dialog('panel-help'); | |
| 381 | 390 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -209,6 +209,13 @@ | |||||
| 209 | </div> | 209 | </div> | ||
| 210 | <div> | 210 | <div> | ||
| 211 | <dt> | 211 | <dt> | ||
| 212 | + | <kbd>l</kbd> | |||
| 213 | + | <kbd>h</kbd> | |||
| 214 | + | </dt> | |||
| 215 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 216 | + | </div> | |||
| 217 | + | <div> | |||
| 218 | + | <dt> | |||
| 212 | <kbd>g g</kbd> | 219 | <kbd>g g</kbd> | ||
| 213 | <kbd>G</kbd> | 220 | <kbd>G</kbd> | ||
| 214 | </dt> | 221 | </dt> | ||
| @@ -376,6 +383,8 @@ | |||||
| 376 | k-top from:body -> ermite.edge(false); | 383 | k-top from:body -> ermite.edge(false); | ||
| 377 | k-bottom from:body -> ermite.edge(true); | 384 | k-bottom from:body -> ermite.edge(true); | ||
| 378 | k-open from:body -> ermite.open(); | 385 | k-open from:body -> ermite.open(); | ||
| 386 | + | k-right from:body -> ermite.rail(true); | |||
| 387 | + | k-left from:body -> ermite.rail(false); | |||
| 379 | k-esc from:body -> ermite.closeDialogs(); | 388 | k-esc from:body -> ermite.closeDialogs(); | ||
| 380 | k-help from:body -> ermite.dialog('panel-help'); | 389 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 381 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 390 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commits-path.html +9 -0
| @@ -224,6 +224,13 @@ | |||
| 224 | 224 | </div> | |
| 225 | 225 | <div> | |
| 226 | 226 | <dt> | |
| 227 | + | <kbd>l</kbd> | |
| 228 | + | <kbd>h</kbd> | |
| 229 | + | </dt> | |
| 230 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 231 | + | </div> | |
| 232 | + | <div> | |
| 233 | + | <dt> | |
| 227 | 234 | <kbd>g g</kbd> | |
| 228 | 235 | <kbd>G</kbd> | |
| 229 | 236 | </dt> | |
| @@ -391,6 +398,8 @@ | |||
| 391 | 398 | k-top from:body -> ermite.edge(false); | |
| 392 | 399 | k-bottom from:body -> ermite.edge(true); | |
| 393 | 400 | k-open from:body -> ermite.open(); | |
| 401 | + | k-right from:body -> ermite.rail(true); | |
| 402 | + | k-left from:body -> ermite.rail(false); | |
| 394 | 403 | k-esc from:body -> ermite.closeDialogs(); | |
| 395 | 404 | k-help from:body -> ermite.dialog('panel-help'); | |
| 396 | 405 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -224,6 +224,13 @@ | |||||
| 224 | </div> | 224 | </div> | ||
| 225 | <div> | 225 | <div> | ||
| 226 | <dt> | 226 | <dt> | ||
| 227 | + | <kbd>l</kbd> | |||
| 228 | + | <kbd>h</kbd> | |||
| 229 | + | </dt> | |||
| 230 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 231 | + | </div> | |||
| 232 | + | <div> | |||
| 233 | + | <dt> | |||
| 227 | <kbd>g g</kbd> | 234 | <kbd>g g</kbd> | ||
| 228 | <kbd>G</kbd> | 235 | <kbd>G</kbd> | ||
| 229 | </dt> | 236 | </dt> | ||
| @@ -391,6 +398,8 @@ | |||||
| 391 | k-top from:body -> ermite.edge(false); | 398 | k-top from:body -> ermite.edge(false); | ||
| 392 | k-bottom from:body -> ermite.edge(true); | 399 | k-bottom from:body -> ermite.edge(true); | ||
| 393 | k-open from:body -> ermite.open(); | 400 | k-open from:body -> ermite.open(); | ||
| 401 | + | k-right from:body -> ermite.rail(true); | |||
| 402 | + | k-left from:body -> ermite.rail(false); | |||
| 394 | k-esc from:body -> ermite.closeDialogs(); | 403 | k-esc from:body -> ermite.closeDialogs(); | ||
| 395 | k-help from:body -> ermite.dialog('panel-help'); | 404 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 396 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 405 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commits-root.html +9 -0
| @@ -1109,6 +1109,13 @@ | |||
| 1109 | 1109 | </div> | |
| 1110 | 1110 | <div> | |
| 1111 | 1111 | <dt> | |
| 1112 | + | <kbd>l</kbd> | |
| 1113 | + | <kbd>h</kbd> | |
| 1114 | + | </dt> | |
| 1115 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 1116 | + | </div> | |
| 1117 | + | <div> | |
| 1118 | + | <dt> | |
| 1112 | 1119 | <kbd>g g</kbd> | |
| 1113 | 1120 | <kbd>G</kbd> | |
| 1114 | 1121 | </dt> | |
| @@ -1276,6 +1283,8 @@ | |||
| 1276 | 1283 | k-top from:body -> ermite.edge(false); | |
| 1277 | 1284 | k-bottom from:body -> ermite.edge(true); | |
| 1278 | 1285 | k-open from:body -> ermite.open(); | |
| 1286 | + | k-right from:body -> ermite.rail(true); | |
| 1287 | + | k-left from:body -> ermite.rail(false); | |
| 1279 | 1288 | k-esc from:body -> ermite.closeDialogs(); | |
| 1280 | 1289 | k-help from:body -> ermite.dialog('panel-help'); | |
| 1281 | 1290 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -1109,6 +1109,13 @@ | |||||
| 1109 | </div> | 1109 | </div> | ||
| 1110 | <div> | 1110 | <div> | ||
| 1111 | <dt> | 1111 | <dt> | ||
| 1112 | + | <kbd>l</kbd> | |||
| 1113 | + | <kbd>h</kbd> | |||
| 1114 | + | </dt> | |||
| 1115 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 1116 | + | </div> | |||
| 1117 | + | <div> | |||
| 1118 | + | <dt> | |||
| 1112 | <kbd>g g</kbd> | 1119 | <kbd>g g</kbd> | ||
| 1113 | <kbd>G</kbd> | 1120 | <kbd>G</kbd> | ||
| 1114 | </dt> | 1121 | </dt> | ||
| @@ -1276,6 +1283,8 @@ | |||||
| 1276 | k-top from:body -> ermite.edge(false); | 1283 | k-top from:body -> ermite.edge(false); | ||
| 1277 | k-bottom from:body -> ermite.edge(true); | 1284 | k-bottom from:body -> ermite.edge(true); | ||
| 1278 | k-open from:body -> ermite.open(); | 1285 | k-open from:body -> ermite.open(); | ||
| 1286 | + | k-right from:body -> ermite.rail(true); | |||
| 1287 | + | k-left from:body -> ermite.rail(false); | |||
| 1279 | k-esc from:body -> ermite.closeDialogs(); | 1288 | k-esc from:body -> ermite.closeDialogs(); | ||
| 1280 | k-help from:body -> ermite.dialog('panel-help'); | 1289 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 1281 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 1290 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/commits-small.html +9 -0
| @@ -370,6 +370,13 @@ | |||
| 370 | 370 | </div> | |
| 371 | 371 | <div> | |
| 372 | 372 | <dt> | |
| 373 | + | <kbd>l</kbd> | |
| 374 | + | <kbd>h</kbd> | |
| 375 | + | </dt> | |
| 376 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 377 | + | </div> | |
| 378 | + | <div> | |
| 379 | + | <dt> | |
| 373 | 380 | <kbd>g g</kbd> | |
| 374 | 381 | <kbd>G</kbd> | |
| 375 | 382 | </dt> | |
| @@ -557,6 +564,8 @@ | |||
| 557 | 564 | k-top from:body -> ermite.edge(false); | |
| 558 | 565 | k-bottom from:body -> ermite.edge(true); | |
| 559 | 566 | k-open from:body -> ermite.open(); | |
| 567 | + | k-right from:body -> ermite.rail(true); | |
| 568 | + | k-left from:body -> ermite.rail(false); | |
| 560 | 569 | k-esc from:body -> ermite.closeDialogs(); | |
| 561 | 570 | k-help from:body -> ermite.dialog('panel-help'); | |
| 562 | 571 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -370,6 +370,13 @@ | |||||
| 370 | </div> | 370 | </div> | ||
| 371 | <div> | 371 | <div> | ||
| 372 | <dt> | 372 | <dt> | ||
| 373 | + | <kbd>l</kbd> | |||
| 374 | + | <kbd>h</kbd> | |||
| 375 | + | </dt> | |||
| 376 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 377 | + | </div> | |||
| 378 | + | <div> | |||
| 379 | + | <dt> | |||
| 373 | <kbd>g g</kbd> | 380 | <kbd>g g</kbd> | ||
| 374 | <kbd>G</kbd> | 381 | <kbd>G</kbd> | ||
| 375 | </dt> | 382 | </dt> | ||
| @@ -557,6 +564,8 @@ | |||||
| 557 | k-top from:body -> ermite.edge(false); | 564 | k-top from:body -> ermite.edge(false); | ||
| 558 | k-bottom from:body -> ermite.edge(true); | 565 | k-bottom from:body -> ermite.edge(true); | ||
| 559 | k-open from:body -> ermite.open(); | 566 | k-open from:body -> ermite.open(); | ||
| 567 | + | k-right from:body -> ermite.rail(true); | |||
| 568 | + | k-left from:body -> ermite.rail(false); | |||
| 560 | k-esc from:body -> ermite.closeDialogs(); | 569 | k-esc from:body -> ermite.closeDialogs(); | ||
| 561 | k-help from:body -> ermite.dialog('panel-help'); | 570 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 562 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 571 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/empty.html +9 -0
| @@ -127,6 +127,13 @@ | |||
| 127 | 127 | </div> | |
| 128 | 128 | <div> | |
| 129 | 129 | <dt> | |
| 130 | + | <kbd>l</kbd> | |
| 131 | + | <kbd>h</kbd> | |
| 132 | + | </dt> | |
| 133 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 134 | + | </div> | |
| 135 | + | <div> | |
| 136 | + | <dt> | |
| 130 | 137 | <kbd>g g</kbd> | |
| 131 | 138 | <kbd>G</kbd> | |
| 132 | 139 | </dt> | |
| @@ -225,6 +232,8 @@ | |||
| 225 | 232 | k-top from:body -> ermite.edge(false); | |
| 226 | 233 | k-bottom from:body -> ermite.edge(true); | |
| 227 | 234 | k-open from:body -> ermite.open(); | |
| 235 | + | k-right from:body -> ermite.rail(true); | |
| 236 | + | k-left from:body -> ermite.rail(false); | |
| 228 | 237 | k-esc from:body -> ermite.closeDialogs(); | |
| 229 | 238 | k-help from:body -> ermite.dialog('panel-help'); | |
| 230 | 239 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -127,6 +127,13 @@ | |||||
| 127 | </div> | 127 | </div> | ||
| 128 | <div> | 128 | <div> | ||
| 129 | <dt> | 129 | <dt> | ||
| 130 | + | <kbd>l</kbd> | |||
| 131 | + | <kbd>h</kbd> | |||
| 132 | + | </dt> | |||
| 133 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 134 | + | </div> | |||
| 135 | + | <div> | |||
| 136 | + | <dt> | |||
| 130 | <kbd>g g</kbd> | 137 | <kbd>g g</kbd> | ||
| 131 | <kbd>G</kbd> | 138 | <kbd>G</kbd> | ||
| 132 | </dt> | 139 | </dt> | ||
| @@ -225,6 +232,8 @@ | |||||
| 225 | k-top from:body -> ermite.edge(false); | 232 | k-top from:body -> ermite.edge(false); | ||
| 226 | k-bottom from:body -> ermite.edge(true); | 233 | k-bottom from:body -> ermite.edge(true); | ||
| 227 | k-open from:body -> ermite.open(); | 234 | k-open from:body -> ermite.open(); | ||
| 235 | + | k-right from:body -> ermite.rail(true); | |||
| 236 | + | k-left from:body -> ermite.rail(false); | |||
| 228 | k-esc from:body -> ermite.closeDialogs(); | 237 | k-esc from:body -> ermite.closeDialogs(); | ||
| 229 | k-help from:body -> ermite.dialog('panel-help'); | 238 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 230 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 239 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/home.html +9 -0
| @@ -159,6 +159,13 @@ | |||
| 159 | 159 | </div> | |
| 160 | 160 | <div> | |
| 161 | 161 | <dt> | |
| 162 | + | <kbd>l</kbd> | |
| 163 | + | <kbd>h</kbd> | |
| 164 | + | </dt> | |
| 165 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 166 | + | </div> | |
| 167 | + | <div> | |
| 168 | + | <dt> | |
| 162 | 169 | <kbd>g g</kbd> | |
| 163 | 170 | <kbd>G</kbd> | |
| 164 | 171 | </dt> | |
| @@ -263,6 +270,8 @@ | |||
| 263 | 270 | k-top from:body -> ermite.edge(false); | |
| 264 | 271 | k-bottom from:body -> ermite.edge(true); | |
| 265 | 272 | k-open from:body -> ermite.open(); | |
| 273 | + | k-right from:body -> ermite.rail(true); | |
| 274 | + | k-left from:body -> ermite.rail(false); | |
| 266 | 275 | k-esc from:body -> ermite.closeDialogs(); | |
| 267 | 276 | k-help from:body -> ermite.dialog('panel-help'); | |
| 268 | 277 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -159,6 +159,13 @@ | |||||
| 159 | </div> | 159 | </div> | ||
| 160 | <div> | 160 | <div> | ||
| 161 | <dt> | 161 | <dt> | ||
| 162 | + | <kbd>l</kbd> | |||
| 163 | + | <kbd>h</kbd> | |||
| 164 | + | </dt> | |||
| 165 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 166 | + | </div> | |||
| 167 | + | <div> | |||
| 168 | + | <dt> | |||
| 162 | <kbd>g g</kbd> | 169 | <kbd>g g</kbd> | ||
| 163 | <kbd>G</kbd> | 170 | <kbd>G</kbd> | ||
| 164 | </dt> | 171 | </dt> | ||
| @@ -263,6 +270,8 @@ | |||||
| 263 | k-top from:body -> ermite.edge(false); | 270 | k-top from:body -> ermite.edge(false); | ||
| 264 | k-bottom from:body -> ermite.edge(true); | 271 | k-bottom from:body -> ermite.edge(true); | ||
| 265 | k-open from:body -> ermite.open(); | 272 | k-open from:body -> ermite.open(); | ||
| 273 | + | k-right from:body -> ermite.rail(true); | |||
| 274 | + | k-left from:body -> ermite.rail(false); | |||
| 266 | k-esc from:body -> ermite.closeDialogs(); | 275 | k-esc from:body -> ermite.closeDialogs(); | ||
| 267 | k-help from:body -> ermite.dialog('panel-help'); | 276 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 268 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 277 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/not-found-page.html +9 -0
| @@ -116,6 +116,13 @@ | |||
| 116 | 116 | </div> | |
| 117 | 117 | <div> | |
| 118 | 118 | <dt> | |
| 119 | + | <kbd>l</kbd> | |
| 120 | + | <kbd>h</kbd> | |
| 121 | + | </dt> | |
| 122 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 123 | + | </div> | |
| 124 | + | <div> | |
| 125 | + | <dt> | |
| 119 | 126 | <kbd>g g</kbd> | |
| 120 | 127 | <kbd>G</kbd> | |
| 121 | 128 | </dt> | |
| @@ -208,6 +215,8 @@ | |||
| 208 | 215 | k-top from:body -> ermite.edge(false); | |
| 209 | 216 | k-bottom from:body -> ermite.edge(true); | |
| 210 | 217 | k-open from:body -> ermite.open(); | |
| 218 | + | k-right from:body -> ermite.rail(true); | |
| 219 | + | k-left from:body -> ermite.rail(false); | |
| 211 | 220 | k-esc from:body -> ermite.closeDialogs(); | |
| 212 | 221 | k-help from:body -> ermite.dialog('panel-help'); | |
| 213 | 222 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -116,6 +116,13 @@ | |||||
| 116 | </div> | 116 | </div> | ||
| 117 | <div> | 117 | <div> | ||
| 118 | <dt> | 118 | <dt> | ||
| 119 | + | <kbd>l</kbd> | |||
| 120 | + | <kbd>h</kbd> | |||
| 121 | + | </dt> | |||
| 122 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 123 | + | </div> | |||
| 124 | + | <div> | |||
| 125 | + | <dt> | |||
| 119 | <kbd>g g</kbd> | 126 | <kbd>g g</kbd> | ||
| 120 | <kbd>G</kbd> | 127 | <kbd>G</kbd> | ||
| 121 | </dt> | 128 | </dt> | ||
| @@ -208,6 +215,8 @@ | |||||
| 208 | k-top from:body -> ermite.edge(false); | 215 | k-top from:body -> ermite.edge(false); | ||
| 209 | k-bottom from:body -> ermite.edge(true); | 216 | k-bottom from:body -> ermite.edge(true); | ||
| 210 | k-open from:body -> ermite.open(); | 217 | k-open from:body -> ermite.open(); | ||
| 218 | + | k-right from:body -> ermite.rail(true); | |||
| 219 | + | k-left from:body -> ermite.rail(false); | |||
| 211 | k-esc from:body -> ermite.closeDialogs(); | 220 | k-esc from:body -> ermite.closeDialogs(); | ||
| 212 | k-help from:body -> ermite.dialog('panel-help'); | 221 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 213 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 222 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/not-found.html +9 -0
| @@ -116,6 +116,13 @@ | |||
| 116 | 116 | </div> | |
| 117 | 117 | <div> | |
| 118 | 118 | <dt> | |
| 119 | + | <kbd>l</kbd> | |
| 120 | + | <kbd>h</kbd> | |
| 121 | + | </dt> | |
| 122 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 123 | + | </div> | |
| 124 | + | <div> | |
| 125 | + | <dt> | |
| 119 | 126 | <kbd>g g</kbd> | |
| 120 | 127 | <kbd>G</kbd> | |
| 121 | 128 | </dt> | |
| @@ -208,6 +215,8 @@ | |||
| 208 | 215 | k-top from:body -> ermite.edge(false); | |
| 209 | 216 | k-bottom from:body -> ermite.edge(true); | |
| 210 | 217 | k-open from:body -> ermite.open(); | |
| 218 | + | k-right from:body -> ermite.rail(true); | |
| 219 | + | k-left from:body -> ermite.rail(false); | |
| 211 | 220 | k-esc from:body -> ermite.closeDialogs(); | |
| 212 | 221 | k-help from:body -> ermite.dialog('panel-help'); | |
| 213 | 222 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -116,6 +116,13 @@ | |||||
| 116 | </div> | 116 | </div> | ||
| 117 | <div> | 117 | <div> | ||
| 118 | <dt> | 118 | <dt> | ||
| 119 | + | <kbd>l</kbd> | |||
| 120 | + | <kbd>h</kbd> | |||
| 121 | + | </dt> | |||
| 122 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 123 | + | </div> | |||
| 124 | + | <div> | |||
| 125 | + | <dt> | |||
| 119 | <kbd>g g</kbd> | 126 | <kbd>g g</kbd> | ||
| 120 | <kbd>G</kbd> | 127 | <kbd>G</kbd> | ||
| 121 | </dt> | 128 | </dt> | ||
| @@ -208,6 +215,8 @@ | |||||
| 208 | k-top from:body -> ermite.edge(false); | 215 | k-top from:body -> ermite.edge(false); | ||
| 209 | k-bottom from:body -> ermite.edge(true); | 216 | k-bottom from:body -> ermite.edge(true); | ||
| 210 | k-open from:body -> ermite.open(); | 217 | k-open from:body -> ermite.open(); | ||
| 218 | + | k-right from:body -> ermite.rail(true); | |||
| 219 | + | k-left from:body -> ermite.rail(false); | |||
| 211 | k-esc from:body -> ermite.closeDialogs(); | 220 | k-esc from:body -> ermite.closeDialogs(); | ||
| 212 | k-help from:body -> ermite.dialog('panel-help'); | 221 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 213 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 222 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/refs.html +9 -0
| @@ -246,6 +246,13 @@ | |||
| 246 | 246 | </div> | |
| 247 | 247 | <div> | |
| 248 | 248 | <dt> | |
| 249 | + | <kbd>l</kbd> | |
| 250 | + | <kbd>h</kbd> | |
| 251 | + | </dt> | |
| 252 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 253 | + | </div> | |
| 254 | + | <div> | |
| 255 | + | <dt> | |
| 249 | 256 | <kbd>g g</kbd> | |
| 250 | 257 | <kbd>G</kbd> | |
| 251 | 258 | </dt> | |
| @@ -443,6 +450,8 @@ | |||
| 443 | 450 | k-top from:body -> ermite.edge(false); | |
| 444 | 451 | k-bottom from:body -> ermite.edge(true); | |
| 445 | 452 | k-open from:body -> ermite.open(); | |
| 453 | + | k-right from:body -> ermite.rail(true); | |
| 454 | + | k-left from:body -> ermite.rail(false); | |
| 446 | 455 | k-esc from:body -> ermite.closeDialogs(); | |
| 447 | 456 | k-help from:body -> ermite.dialog('panel-help'); | |
| 448 | 457 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -246,6 +246,13 @@ | |||||
| 246 | </div> | 246 | </div> | ||
| 247 | <div> | 247 | <div> | ||
| 248 | <dt> | 248 | <dt> | ||
| 249 | + | <kbd>l</kbd> | |||
| 250 | + | <kbd>h</kbd> | |||
| 251 | + | </dt> | |||
| 252 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 253 | + | </div> | |||
| 254 | + | <div> | |||
| 255 | + | <dt> | |||
| 249 | <kbd>g g</kbd> | 256 | <kbd>g g</kbd> | ||
| 250 | <kbd>G</kbd> | 257 | <kbd>G</kbd> | ||
| 251 | </dt> | 258 | </dt> | ||
| @@ -443,6 +450,8 @@ | |||||
| 443 | k-top from:body -> ermite.edge(false); | 450 | k-top from:body -> ermite.edge(false); | ||
| 444 | k-bottom from:body -> ermite.edge(true); | 451 | k-bottom from:body -> ermite.edge(true); | ||
| 445 | k-open from:body -> ermite.open(); | 452 | k-open from:body -> ermite.open(); | ||
| 453 | + | k-right from:body -> ermite.rail(true); | |||
| 454 | + | k-left from:body -> ermite.rail(false); | |||
| 446 | k-esc from:body -> ermite.closeDialogs(); | 455 | k-esc from:body -> ermite.closeDialogs(); | ||
| 447 | k-help from:body -> ermite.dialog('panel-help'); | 456 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 448 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 457 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/summary.html +9 -0
| @@ -275,6 +275,13 @@ | |||
| 275 | 275 | </div> | |
| 276 | 276 | <div> | |
| 277 | 277 | <dt> | |
| 278 | + | <kbd>l</kbd> | |
| 279 | + | <kbd>h</kbd> | |
| 280 | + | </dt> | |
| 281 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 282 | + | </div> | |
| 283 | + | <div> | |
| 284 | + | <dt> | |
| 278 | 285 | <kbd>g g</kbd> | |
| 279 | 286 | <kbd>G</kbd> | |
| 280 | 287 | </dt> | |
| @@ -472,6 +479,8 @@ | |||
| 472 | 479 | k-top from:body -> ermite.edge(false); | |
| 473 | 480 | k-bottom from:body -> ermite.edge(true); | |
| 474 | 481 | k-open from:body -> ermite.open(); | |
| 482 | + | k-right from:body -> ermite.rail(true); | |
| 483 | + | k-left from:body -> ermite.rail(false); | |
| 475 | 484 | k-esc from:body -> ermite.closeDialogs(); | |
| 476 | 485 | k-help from:body -> ermite.dialog('panel-help'); | |
| 477 | 486 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -275,6 +275,13 @@ | |||||
| 275 | </div> | 275 | </div> | ||
| 276 | <div> | 276 | <div> | ||
| 277 | <dt> | 277 | <dt> | ||
| 278 | + | <kbd>l</kbd> | |||
| 279 | + | <kbd>h</kbd> | |||
| 280 | + | </dt> | |||
| 281 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 282 | + | </div> | |||
| 283 | + | <div> | |||
| 284 | + | <dt> | |||
| 278 | <kbd>g g</kbd> | 285 | <kbd>g g</kbd> | ||
| 279 | <kbd>G</kbd> | 286 | <kbd>G</kbd> | ||
| 280 | </dt> | 287 | </dt> | ||
| @@ -472,6 +479,8 @@ | |||||
| 472 | k-top from:body -> ermite.edge(false); | 479 | k-top from:body -> ermite.edge(false); | ||
| 473 | k-bottom from:body -> ermite.edge(true); | 480 | k-bottom from:body -> ermite.edge(true); | ||
| 474 | k-open from:body -> ermite.open(); | 481 | k-open from:body -> ermite.open(); | ||
| 482 | + | k-right from:body -> ermite.rail(true); | |||
| 483 | + | k-left from:body -> ermite.rail(false); | |||
| 475 | k-esc from:body -> ermite.closeDialogs(); | 484 | k-esc from:body -> ermite.closeDialogs(); | ||
| 476 | k-help from:body -> ermite.dialog('panel-help'); | 485 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 477 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 486 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/tree-nested.html +9 -0
| @@ -198,6 +198,13 @@ | |||
| 198 | 198 | </div> | |
| 199 | 199 | <div> | |
| 200 | 200 | <dt> | |
| 201 | + | <kbd>l</kbd> | |
| 202 | + | <kbd>h</kbd> | |
| 203 | + | </dt> | |
| 204 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 205 | + | </div> | |
| 206 | + | <div> | |
| 207 | + | <dt> | |
| 201 | 208 | <kbd>g g</kbd> | |
| 202 | 209 | <kbd>G</kbd> | |
| 203 | 210 | </dt> | |
| @@ -379,6 +386,8 @@ | |||
| 379 | 386 | k-top from:body -> ermite.edge(false); | |
| 380 | 387 | k-bottom from:body -> ermite.edge(true); | |
| 381 | 388 | k-open from:body -> ermite.open(); | |
| 389 | + | k-right from:body -> ermite.rail(true); | |
| 390 | + | k-left from:body -> ermite.rail(false); | |
| 382 | 391 | k-esc from:body -> ermite.closeDialogs(); | |
| 383 | 392 | k-help from:body -> ermite.dialog('panel-help'); | |
| 384 | 393 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -198,6 +198,13 @@ | |||||
| 198 | </div> | 198 | </div> | ||
| 199 | <div> | 199 | <div> | ||
| 200 | <dt> | 200 | <dt> | ||
| 201 | + | <kbd>l</kbd> | |||
| 202 | + | <kbd>h</kbd> | |||
| 203 | + | </dt> | |||
| 204 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 205 | + | </div> | |||
| 206 | + | <div> | |||
| 207 | + | <dt> | |||
| 201 | <kbd>g g</kbd> | 208 | <kbd>g g</kbd> | ||
| 202 | <kbd>G</kbd> | 209 | <kbd>G</kbd> | ||
| 203 | </dt> | 210 | </dt> | ||
| @@ -379,6 +386,8 @@ | |||||
| 379 | k-top from:body -> ermite.edge(false); | 386 | k-top from:body -> ermite.edge(false); | ||
| 380 | k-bottom from:body -> ermite.edge(true); | 387 | k-bottom from:body -> ermite.edge(true); | ||
| 381 | k-open from:body -> ermite.open(); | 388 | k-open from:body -> ermite.open(); | ||
| 389 | + | k-right from:body -> ermite.rail(true); | |||
| 390 | + | k-left from:body -> ermite.rail(false); | |||
| 382 | k-esc from:body -> ermite.closeDialogs(); | 391 | k-esc from:body -> ermite.closeDialogs(); | ||
| 383 | k-help from:body -> ermite.dialog('panel-help'); | 392 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 384 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 393 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/tree-root.html +9 -0
| @@ -425,6 +425,13 @@ | |||
| 425 | 425 | </div> | |
| 426 | 426 | <div> | |
| 427 | 427 | <dt> | |
| 428 | + | <kbd>l</kbd> | |
| 429 | + | <kbd>h</kbd> | |
| 430 | + | </dt> | |
| 431 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 432 | + | </div> | |
| 433 | + | <div> | |
| 434 | + | <dt> | |
| 428 | 435 | <kbd>g g</kbd> | |
| 429 | 436 | <kbd>G</kbd> | |
| 430 | 437 | </dt> | |
| @@ -606,6 +613,8 @@ | |||
| 606 | 613 | k-top from:body -> ermite.edge(false); | |
| 607 | 614 | k-bottom from:body -> ermite.edge(true); | |
| 608 | 615 | k-open from:body -> ermite.open(); | |
| 616 | + | k-right from:body -> ermite.rail(true); | |
| 617 | + | k-left from:body -> ermite.rail(false); | |
| 609 | 618 | k-esc from:body -> ermite.closeDialogs(); | |
| 610 | 619 | k-help from:body -> ermite.dialog('panel-help'); | |
| 611 | 620 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -425,6 +425,13 @@ | |||||
| 425 | </div> | 425 | </div> | ||
| 426 | <div> | 426 | <div> | ||
| 427 | <dt> | 427 | <dt> | ||
| 428 | + | <kbd>l</kbd> | |||
| 429 | + | <kbd>h</kbd> | |||
| 430 | + | </dt> | |||
| 431 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 432 | + | </div> | |||
| 433 | + | <div> | |||
| 434 | + | <dt> | |||
| 428 | <kbd>g g</kbd> | 435 | <kbd>g g</kbd> | ||
| 429 | <kbd>G</kbd> | 436 | <kbd>G</kbd> | ||
| 430 | </dt> | 437 | </dt> | ||
| @@ -606,6 +613,8 @@ | |||||
| 606 | k-top from:body -> ermite.edge(false); | 613 | k-top from:body -> ermite.edge(false); | ||
| 607 | k-bottom from:body -> ermite.edge(true); | 614 | k-bottom from:body -> ermite.edge(true); | ||
| 608 | k-open from:body -> ermite.open(); | 615 | k-open from:body -> ermite.open(); | ||
| 616 | + | k-right from:body -> ermite.rail(true); | |||
| 617 | + | k-left from:body -> ermite.rail(false); | |||
| 609 | k-esc from:body -> ermite.closeDialogs(); | 618 | k-esc from:body -> ermite.closeDialogs(); | ||
| 610 | k-help from:body -> ermite.dialog('panel-help'); | 619 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 611 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 620 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/tree-slash-ref.html +9 -0
| @@ -195,6 +195,13 @@ | |||
| 195 | 195 | </div> | |
| 196 | 196 | <div> | |
| 197 | 197 | <dt> | |
| 198 | + | <kbd>l</kbd> | |
| 199 | + | <kbd>h</kbd> | |
| 200 | + | </dt> | |
| 201 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 202 | + | </div> | |
| 203 | + | <div> | |
| 204 | + | <dt> | |
| 198 | 205 | <kbd>g g</kbd> | |
| 199 | 206 | <kbd>G</kbd> | |
| 200 | 207 | </dt> | |
| @@ -376,6 +383,8 @@ | |||
| 376 | 383 | k-top from:body -> ermite.edge(false); | |
| 377 | 384 | k-bottom from:body -> ermite.edge(true); | |
| 378 | 385 | k-open from:body -> ermite.open(); | |
| 386 | + | k-right from:body -> ermite.rail(true); | |
| 387 | + | k-left from:body -> ermite.rail(false); | |
| 379 | 388 | k-esc from:body -> ermite.closeDialogs(); | |
| 380 | 389 | k-help from:body -> ermite.dialog('panel-help'); | |
| 381 | 390 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -195,6 +195,13 @@ | |||||
| 195 | </div> | 195 | </div> | ||
| 196 | <div> | 196 | <div> | ||
| 197 | <dt> | 197 | <dt> | ||
| 198 | + | <kbd>l</kbd> | |||
| 199 | + | <kbd>h</kbd> | |||
| 200 | + | </dt> | |||
| 201 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 202 | + | </div> | |||
| 203 | + | <div> | |||
| 204 | + | <dt> | |||
| 198 | <kbd>g g</kbd> | 205 | <kbd>g g</kbd> | ||
| 199 | <kbd>G</kbd> | 206 | <kbd>G</kbd> | ||
| 200 | </dt> | 207 | </dt> | ||
| @@ -376,6 +383,8 @@ | |||||
| 376 | k-top from:body -> ermite.edge(false); | 383 | k-top from:body -> ermite.edge(false); | ||
| 377 | k-bottom from:body -> ermite.edge(true); | 384 | k-bottom from:body -> ermite.edge(true); | ||
| 378 | k-open from:body -> ermite.open(); | 385 | k-open from:body -> ermite.open(); | ||
| 386 | + | k-right from:body -> ermite.rail(true); | |||
| 387 | + | k-left from:body -> ermite.rail(false); | |||
| 379 | k-esc from:body -> ermite.closeDialogs(); | 388 | k-esc from:body -> ermite.closeDialogs(); | ||
| 380 | k-help from:body -> ermite.dialog('panel-help'); | 389 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 381 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 390 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||
M internal/app/testdata/web/tree-subdir.html +9 -0
| @@ -220,6 +220,13 @@ | |||
| 220 | 220 | </div> | |
| 221 | 221 | <div> | |
| 222 | 222 | <dt> | |
| 223 | + | <kbd>l</kbd> | |
| 224 | + | <kbd>h</kbd> | |
| 225 | + | </dt> | |
| 226 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |
| 227 | + | </div> | |
| 228 | + | <div> | |
| 229 | + | <dt> | |
| 223 | 230 | <kbd>g g</kbd> | |
| 224 | 231 | <kbd>G</kbd> | |
| 225 | 232 | </dt> | |
| @@ -401,6 +408,8 @@ | |||
| 401 | 408 | k-top from:body -> ermite.edge(false); | |
| 402 | 409 | k-bottom from:body -> ermite.edge(true); | |
| 403 | 410 | k-open from:body -> ermite.open(); | |
| 411 | + | k-right from:body -> ermite.rail(true); | |
| 412 | + | k-left from:body -> ermite.rail(false); | |
| 404 | 413 | k-esc from:body -> ermite.closeDialogs(); | |
| 405 | 414 | k-help from:body -> ermite.dialog('panel-help'); | |
| 406 | 415 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | |
| @@ -220,6 +220,13 @@ | |||||
| 220 | </div> | 220 | </div> | ||
| 221 | <div> | 221 | <div> | ||
| 222 | <dt> | 222 | <dt> | ||
| 223 | + | <kbd>l</kbd> | |||
| 224 | + | <kbd>h</kbd> | |||
| 225 | + | </dt> | |||
| 226 | + | <dd>into the side panel (on a merge request, its files) / back to the content; there j k move between its controls</dd> | |||
| 227 | + | </div> | |||
| 228 | + | <div> | |||
| 229 | + | <dt> | |||
| 223 | <kbd>g g</kbd> | 230 | <kbd>g g</kbd> | ||
| 224 | <kbd>G</kbd> | 231 | <kbd>G</kbd> | ||
| 225 | </dt> | 232 | </dt> | ||
| @@ -401,6 +408,8 @@ | |||||
| 401 | k-top from:body -> ermite.edge(false); | 408 | k-top from:body -> ermite.edge(false); | ||
| 402 | k-bottom from:body -> ermite.edge(true); | 409 | k-bottom from:body -> ermite.edge(true); | ||
| 403 | k-open from:body -> ermite.open(); | 410 | k-open from:body -> ermite.open(); | ||
| 411 | + | k-right from:body -> ermite.rail(true); | |||
| 412 | + | k-left from:body -> ermite.rail(false); | |||
| 404 | k-esc from:body -> ermite.closeDialogs(); | 413 | k-esc from:body -> ermite.closeDialogs(); | ||
| 405 | k-help from:body -> ermite.dialog('panel-help'); | 414 | k-help from:body -> ermite.dialog('panel-help'); | ||
| 406 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | 415 | k-refs from:body -> ermite.dialog('panel-refs', 'refs-filter'); | ||