Skip to content

Commit 115728f

Browse files
committed
Key binds for #26
1 parent 68654d9 commit 115728f

File tree

4 files changed

+100
-6
lines changed

4 files changed

+100
-6
lines changed

src/modals/SelectModal.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {App, Modal, Setting} from 'obsidian';
22
import {SelectModalElement} from './SelectModalElement';
3+
import {mod} from '../utils/Utils';
34

45
export abstract class SelectModal<T> extends Modal {
56
allowMultiSelect: boolean;
@@ -22,6 +23,17 @@ export abstract class SelectModal<T> extends Modal {
2223

2324
this.elements = elements;
2425
this.selectModalElements = [];
26+
27+
this.scope.register([], 'ArrowUp', () => {
28+
this.highlightUp();
29+
});
30+
this.scope.register([], 'ArrowDown', () => {
31+
this.highlightDown();
32+
});
33+
this.scope.register([], 'ArrowRight', () => {
34+
this.activateHighlighted();
35+
});
36+
this.scope.register([], 'Enter', () => this.submit());
2537
}
2638

2739
abstract renderElement(value: T, el: HTMLElement): any;
@@ -38,6 +50,14 @@ export abstract class SelectModal<T> extends Modal {
3850
}
3951
}
4052

53+
deHighlightAllOtherElements(elementId: number) {
54+
for (const selectModalElement of this.selectModalElements) {
55+
if (selectModalElement.id !== elementId) {
56+
selectModalElement.setHighlighted(false);
57+
}
58+
}
59+
}
60+
4161
async onOpen() {
4262
const {contentEl} = this;
4363

@@ -72,4 +92,54 @@ export abstract class SelectModal<T> extends Modal {
7292
}
7393
bottomSetting.addButton(btn => btn.setButtonText('Ok').setCta().onClick(() => this.submit()));
7494
}
95+
96+
activateHighlighted() {
97+
for (const selectModalElement of this.selectModalElements) {
98+
if (selectModalElement.isHighlighted()) {
99+
selectModalElement.setActive(!selectModalElement.isActive());
100+
if (!this.allowMultiSelect) {
101+
this.disableAllOtherElements(selectModalElement.id);
102+
}
103+
}
104+
}
105+
}
106+
107+
highlightUp() {
108+
for (const selectModalElement of this.selectModalElements) {
109+
if (selectModalElement.isHighlighted()) {
110+
this.getPreviousSelectModalElement(selectModalElement).setHighlighted(true);
111+
return;
112+
}
113+
}
114+
115+
// nothing is highlighted
116+
this.selectModalElements.last().setHighlighted(true);
117+
}
118+
119+
highlightDown() {
120+
for (const selectModalElement of this.selectModalElements) {
121+
if (selectModalElement.isHighlighted()) {
122+
this.getNextSelectModalElement(selectModalElement).setHighlighted(true);
123+
return;
124+
}
125+
}
126+
127+
// nothing is highlighted
128+
this.selectModalElements.first().setHighlighted(true);
129+
}
130+
131+
private getNextSelectModalElement(selectModalElement: SelectModalElement<T>): SelectModalElement<T> {
132+
let nextId = selectModalElement.id + 1;
133+
nextId = mod(nextId, this.selectModalElements.length);
134+
135+
return this.selectModalElements.filter(x => x.id === nextId).first();
136+
}
137+
138+
private getPreviousSelectModalElement(selectModalElement: SelectModalElement<T>): SelectModalElement<T> {
139+
let nextId = selectModalElement.id - 1;
140+
nextId = mod(nextId, this.selectModalElements.length);
141+
142+
return this.selectModalElements.filter(x => x.id === nextId).first();
143+
}
144+
75145
}

src/modals/SelectModalElement.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export class SelectModalElement<T> {
99
activeClass: string;
1010
hoverClass: string;
1111
private active: boolean;
12+
private highlighted: boolean;
1213

1314
constructor(value: T, parentElement: HTMLElement, id: number, selectModal: SelectModal<T>, active: boolean = false) {
1415
this.value = value;
@@ -29,21 +30,35 @@ export class SelectModalElement<T> {
2930
}
3031
});
3132
this.element.on('mouseenter', '#' + this.getHTMLId(), () => {
32-
this.addClass(this.hoverClass);
33+
this.setHighlighted(true);
3334
});
3435
this.element.on('mouseleave', '#' + this.getHTMLId(), () => {
35-
this.removeClass(this.hoverClass);
36+
this.setHighlighted(false);
3637
});
3738
}
3839

39-
isActive(): boolean {
40-
return this.active;
41-
}
42-
4340
getHTMLId(): string {
4441
return `media-db-plugin-select-element-${this.id}`;
4542
}
4643

44+
isHighlighted(): boolean {
45+
return this.highlighted;
46+
}
47+
48+
setHighlighted(value: boolean) {
49+
this.highlighted = value;
50+
if (this.highlighted) {
51+
this.addClass(this.hoverClass);
52+
this.selectModal.deHighlightAllOtherElements(this.id);
53+
} else {
54+
this.removeClass(this.hoverClass);
55+
}
56+
}
57+
58+
isActive(): boolean {
59+
return this.active;
60+
}
61+
4762
setActive(active: boolean): void {
4863
this.active = active;
4964
this.update();

src/utils/Utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,8 @@ export class UserSkipError extends Error {
164164
}
165165
}
166166

167+
// js can't even implement modulo correctly...
168+
export function mod(n: number, m: number): number {
169+
return ((n % m) + m) % m;
170+
}
171+

src/utils/YAMLConverter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ export class YAMLConverter {
1010
}
1111

1212
private static toYamlString(value: any, indentation: number): string {
13+
if (value == null) {
14+
return 'null';
15+
}
16+
1317
if (typeof value === 'boolean') {
1418
return value ? 'true' : 'false';
1519
} else if (typeof value === 'number') {

0 commit comments

Comments
 (0)