feat: Type-Ahead-Folge tippen (A-M-Y springt zu Amy Spring)
Buchstaben akkumulieren sich jetzt statt neu zu starten: 'A'+'M'+'Y' findet 'Amy Spring'. Präfix-Treffer haben Vorrang, danach Teiltreffer. Doppelter Buchstabe (AA) springt zum nächsten a-Eintrag wie Explorer. Folge wird verworfen, wenn sie keinen Treffer mehr hat, und nach >1s Pause neu gestartet. Build auf 2026.09.12.r002.
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ set -eu
|
|||||||
export COPYFILE_DISABLE=1
|
export COPYFILE_DISABLE=1
|
||||||
|
|
||||||
PLUGIN="u-navigator"
|
PLUGIN="u-navigator"
|
||||||
VERSION="2026.09.12.r001"
|
VERSION="2026.09.12.r002"
|
||||||
PKG_DIR="packages"
|
PKG_DIR="packages"
|
||||||
WORK_DIR=".plugin-build"
|
WORK_DIR=".plugin-build"
|
||||||
PKG_NAME="${PLUGIN}-${VERSION}.tgz"
|
PKG_NAME="${PLUGIN}-${VERSION}.tgz"
|
||||||
|
|||||||
Binary file not shown.
+30
-9
@@ -32,6 +32,7 @@ const state = {
|
|||||||
settingsPanelVisible: false,
|
settingsPanelVisible: false,
|
||||||
typeAhead: {
|
typeAhead: {
|
||||||
key: '',
|
key: '',
|
||||||
|
sequence: '',
|
||||||
windowId: null,
|
windowId: null,
|
||||||
at: 0
|
at: 0
|
||||||
},
|
},
|
||||||
@@ -2360,15 +2361,27 @@ function handleTypeAheadKey(event) {
|
|||||||
if (!win || !win.data.entries?.length) return;
|
if (!win || !win.data.entries?.length) return;
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const repeated = state.typeAhead.windowId === win.id && state.typeAhead.key === key && now - state.typeAhead.at < 1000;
|
const sameWindow = state.typeAhead.windowId === win.id;
|
||||||
|
const withinWindow = now - state.typeAhead.at < 1000;
|
||||||
|
const sequence = sameWindow && withinWindow ? (state.typeAhead.sequence || '') : '';
|
||||||
|
// Gleicher Buchstabe kurz nach einander = nächstes Vorkommen dieses Buchstabens
|
||||||
|
// (z. B. "AA" springt zum zweiten A-Eintrag), statt die Folge zu verdoppeln.
|
||||||
|
const repeated = sameWindow && withinWindow && state.typeAhead.key === key && sequence.length <= 1;
|
||||||
|
let next = repeated ? key : sequence + key;
|
||||||
|
if (!repeated && next.length > 16) next = key;
|
||||||
|
|
||||||
const entries = win.data.entries;
|
const entries = win.data.entries;
|
||||||
const selectedIndex = entries.findIndex((entry) => entry.path === win.data.selectedPath);
|
const selectedIndex = entries.findIndex((entry) => entry.path === win.data.selectedPath);
|
||||||
const startIndex = repeated ? selectedIndex + 1 : Math.max(0, selectedIndex + 1);
|
const startIndex = Math.max(0, selectedIndex + 1);
|
||||||
const match = findTypeAheadMatch(entries, key, startIndex);
|
const match = findTypeAheadMatch(entries, next, startIndex, repeated);
|
||||||
if (!match) return;
|
if (!match) {
|
||||||
|
// Unvollständiger Pfad ohne Treffer: Auswahl bleibt, Folge wird verworfen
|
||||||
|
if (sequence) state.typeAhead = { key, sequence: '', windowId: win.id, at: now };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
state.typeAhead = { key, windowId: win.id, at: now };
|
state.typeAhead = { key, sequence: next, windowId: win.id, at: now };
|
||||||
win.data.selectedPath = match.path;
|
win.data.selectedPath = match.path;
|
||||||
win.data.selectedPaths = [match.path];
|
win.data.selectedPaths = [match.path];
|
||||||
win.data.selectionAnchorPath = match.path;
|
win.data.selectionAnchorPath = match.path;
|
||||||
@@ -2377,15 +2390,23 @@ function handleTypeAheadKey(event) {
|
|||||||
updateSelectedRows();
|
updateSelectedRows();
|
||||||
updatePropertiesWindows();
|
updatePropertiesWindows();
|
||||||
scrollEntryIntoView(win, match.path);
|
scrollEntryIntoView(win, match.path);
|
||||||
recordDebug('typeahead.match', { key, path: match.path });
|
recordDebug('typeahead.match', { sequence: next, path: match.path });
|
||||||
}
|
}
|
||||||
|
|
||||||
function findTypeAheadMatch(entries, key, startIndex) {
|
function findTypeAheadMatch(entries, sequence, startIndex, preferNextOccurrence = false) {
|
||||||
|
// Erst: Präfix-Treffer ab der aktuellen Position (mit Wraparound).
|
||||||
|
// Zweit: Teiltreffer (z. B. "amy" findet "Amy Spring"), damit Tippfolgen auch bei
|
||||||
|
// Präfix-Konkurrenz zum richtigen Eintrag springen.
|
||||||
|
for (let pass = 0; pass < 2; pass += 1) {
|
||||||
for (let offset = 0; offset < entries.length; offset += 1) {
|
for (let offset = 0; offset < entries.length; offset += 1) {
|
||||||
const index = (startIndex + offset) % entries.length;
|
const index = (startIndex + offset) % entries.length;
|
||||||
const entry = entries[index];
|
const entry = entries[index];
|
||||||
if (entry.name?.toLocaleLowerCase().startsWith(key)) {
|
const name = entry.name?.toLocaleLowerCase();
|
||||||
return entry;
|
if (!name) continue;
|
||||||
|
const isMatch = pass === 0
|
||||||
|
? name.startsWith(sequence)
|
||||||
|
: name.includes(sequence) && !(preferNextOccurrence && sequence.length <= 1);
|
||||||
|
if (isMatch) return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE PLUGIN [
|
<!DOCTYPE PLUGIN [
|
||||||
<!ENTITY name "u-navigator">
|
<!ENTITY name "u-navigator">
|
||||||
<!ENTITY author "Michael Roll">
|
<!ENTITY author "Michael Roll">
|
||||||
<!ENTITY version "2026.09.12.r001">
|
<!ENTITY version "2026.09.12.r002">
|
||||||
<!ENTITY package "&name;-&version;.tgz">
|
<!ENTITY package "&name;-&version;.tgz">
|
||||||
<!ENTITY pluginURL "https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg">
|
<!ENTITY pluginURL "https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg">
|
||||||
<!ENTITY support "https://git.casaderoll.de/michael/Unraid-Navigator">
|
<!ENTITY support "https://git.casaderoll.de/michael/Unraid-Navigator">
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
<FILE Name="/boot/config/plugins/&name;/&package;">
|
<FILE Name="/boot/config/plugins/&name;/&package;">
|
||||||
<URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL>
|
<URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL>
|
||||||
<MD5>9cee8533bb7f227236fb9ff4963e2d73</MD5>
|
<MD5>97ee8d18a7eee6b3b1da1fa7451d5553</MD5>
|
||||||
</FILE>
|
</FILE>
|
||||||
|
|
||||||
<FILE Run="/bin/bash">
|
<FILE Run="/bin/bash">
|
||||||
|
|||||||
Reference in New Issue
Block a user