Navigating Task search view with keyboard #3620
Replies: 4 comments 6 replies
-
|
I could have sworn that I answered this already. Did you also ask on Discord? |
Beta Was this translation helpful? Give feedback.
-
|
@darylducharme I'm in the exact same boat. Code blocks (like
The Tasks API code looks like this (I'm using Codescript Toolkit for now, but you could also use DataviewJS or Templater). Code and changes to Tasks taken from #2459 (comment) This is a highly custom approach and may not work for everybody, but it allows me to use Vim gestures and mappings (e.g. I use |
Beta Was this translation helpful? Give feedback.
-
|
@darylducharme FYI I'mlooking into adding functionality to the Tasks Plugin that lets you navigate the rendered results by keyboard; this might take a long while to build, but I'm somewhat optimistic that it at least is possible |
Beta Was this translation helpful? Give feedback.
-
|
As a reference - here's a proof of concept of navigable divs (you can run it using the CodeScript Toolkit plugin (first click the code button, then navigate to the ```code-button
---
caption: NavigableDivsPlugin
isRaw: false
removeAfterExecution:
shouldKeepGap: false
when: never
shouldAutoOutput: true
shouldAutoRun: false
shouldShowSystemMessages: true
shouldWrapConsole: true
---
import { Plugin, MarkdownPostProcessorContext, Scope } from 'obsidian';
class NavigableDivsPlugin extends Plugin {
async onload() {
console.log('Loading Navigable Divs Plugin');
// Register code block processor for "navdivs" blocks
this.registerMarkdownCodeBlockProcessor('navdivs', (source, el, ctx) => {
this.createNavigableDivs(source, el, ctx);
});
}
createNavigableDivs(source: string, container: HTMLElement, ctx: MarkdownPostProcessorContext) {
// Parse the source to get individual div contents
const lines = source.split('\n').filter(line => line.trim());
if (lines.length === 0) {
container.createEl('p', { text: 'No items to display' });
return;
}
// Create container for divs
const divsContainer = container.createEl('div', {
cls: 'navigable-divs-container',
attr: { 'tabindex': '0' }
});
// Add some basic styling
divsContainer.style.border = '1px solid var(--background-modifier-border)';
divsContainer.style.borderRadius = '4px';
divsContainer.style.padding = '10px';
divsContainer.style.outline = 'none';
// Create individual divs
const divElements: HTMLElement[] = [];
lines.forEach((line, index) => {
const div = divsContainer.createEl('div', {
cls: 'navigable-div',
attr: {
'data-index': index.toString()
}
});
div.textContent = line;
div.style.padding = '8px';
div.style.margin = '4px 0';
div.style.border = '1px solid var(--background-modifier-border)';
div.style.borderRadius = '3px';
div.style.cursor = 'pointer';
div.style.transition = 'background-color 0.2s';
divElements.push(div);
});
// Create a Scope for keyboard navigation
const scope = new Scope();
// Track current selection
let currentIndex = 0;
this.highlightDiv(divElements[currentIndex], divElements);
// Register keyboard shortcuts using Scope
scope.register([], 'ArrowDown', (evt) => {
evt.preventDefault();
currentIndex = Math.min(currentIndex + 1, divElements.length - 1);
this.highlightDiv(divElements[currentIndex], divElements);
return false;
});
scope.register([], 'ArrowUp', (evt) => {
evt.preventDefault();
currentIndex = Math.max(currentIndex - 1, 0);
this.highlightDiv(divElements[currentIndex], divElements);
return false;
});
// Vim-style navigation
scope.register([], 'j', (evt) => {
evt.preventDefault();
currentIndex = Math.min(currentIndex + 1, divElements.length - 1);
this.highlightDiv(divElements[currentIndex], divElements);
return false;
});
scope.register([], 'k', (evt) => {
evt.preventDefault();
currentIndex = Math.max(currentIndex - 1, 0);
this.highlightDiv(divElements[currentIndex], divElements);
return false;
});
// Home/End keys
scope.register([], 'Home', (evt) => {
evt.preventDefault();
currentIndex = 0;
this.highlightDiv(divElements[currentIndex], divElements);
return false;
});
scope.register([], 'End', (evt) => {
evt.preventDefault();
currentIndex = divElements.length - 1;
this.highlightDiv(divElements[currentIndex], divElements);
return false;
});
// Enter or Space to select
scope.register([], 'Enter', (evt) => {
evt.preventDefault();
this.selectDiv(divElements[currentIndex], divElements);
return false;
});
scope.register([], 'Space', (evt) => {
evt.preventDefault();
this.selectDiv(divElements[currentIndex], divElements);
return false;
});
// Set up click handlers
divElements.forEach((div, index) => {
div.addEventListener('click', () => {
currentIndex = index;
this.selectDiv(div, divElements);
});
});
// Activate scope when container is focused
this.registerDomEvent(divsContainer, 'focusin', () => {
this.app.keymap.pushScope(scope);
});
// Deactivate scope when focus leaves container
this.registerDomEvent(divsContainer, 'focusout', (evt: FocusEvent) => {
// Check if focus is moving outside the container
if (!divsContainer.contains(evt.relatedTarget as Node)) {
this.app.keymap.popScope(scope);
}
});
// Make container focusable and focus it initially
divsContainer.focus();
}
selectDiv(selectedDiv: HTMLElement, allDivs: HTMLElement[]) {
// Remove selection from all divs
allDivs.forEach(div => {
div.style.backgroundColor = '';
div.style.color = '';
div.style.fontWeight = '';
});
// Highlight selected div
selectedDiv.style.backgroundColor = 'var(--interactive-accent)';
selectedDiv.style.color = 'var(--text-on-accent)';
selectedDiv.style.fontWeight = 'bold';
// Log selection (you can replace this with custom logic)
const index = selectedDiv.getAttribute('data-index');
const text = selectedDiv.textContent;
console.log(`Selected div ${index}: ${text}`);
}
highlightDiv(focusedDiv: HTMLElement, allDivs: HTMLElement[]) {
// Remove highlight from all divs
allDivs.forEach(div => {
if (div.style.backgroundColor !== 'var(--interactive-accent)') {
div.style.backgroundColor = '';
div.style.color = '';
}
});
// Add focus highlight if not selected
if (focusedDiv.style.backgroundColor !== 'var(--interactive-accent)') {
focusedDiv.style.backgroundColor = 'var(--background-modifier-hover)';
}
}
onunload() {
console.log('Unloading Navigable Divs Plugin');
}
}
codeButtonContext.registerTempPlugin(NavigableDivsPlugin);
```
```navdivs
- [ ] Item 1
- [ ] Item 2
- [ ] Item 3
```
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I use Vim mode and I use the Task plugin in a way that has tasks on many different pages collected in my main pages I work in. I would like a way to navigate those task views with a keyboard. This may not be possible as is, but perhaps there could be a way to open a special temporary view (or a sidebar) that allows navigation of the task views on a page?
Or, perhaps if you use the keyboard shortcut for editing (default Ctrl+K), it would open up a view for the section you are editing.
It's a big ask, but I use this plugin so much that grabbing the mouse for all the interactions is a bit annoying. Maybe there is something related to accessibility settings that would help?
Beta Was this translation helpful? Give feedback.
All reactions