From a0fc339cf4b326ffcb6ec7de5f4001833b71087b Mon Sep 17 00:00:00 2001 From: Florrie Date: Wed, 12 Sep 2018 14:10:49 -0300 Subject: ctrl-F, '/': jump to an item by entering its name --- ui.js | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) (limited to 'ui.js') diff --git a/ui.js b/ui.js index 3da7f5c..1d8d2da 100644 --- a/ui.js +++ b/ui.js @@ -708,6 +708,16 @@ class GrouplikeListingElement extends Form { } }) + this.jumpElement = new ListingJumpElement() + this.addInput(this.jumpElement) + this.jumpElement.visible = false + + this.jumpElement.on('cancel', () => { + this.hideJumpElement() + }) + + this.jumpElement.on('value', value => this.handleJumpValue(value)) + this.pathElement = new PathElement() this.addInput(this.pathElement) @@ -727,9 +737,15 @@ class GrouplikeListingElement extends Form { this.form.y = this.commentLabel.bottom this.form.h -= this.commentLabel.h this.form.h -= 1 // For the path element + if (this.jumpElement.visible) this.form.h -= 1 + + this.form.fixLayout() // Respond to being resized this.pathElement.y = this.contentH - 1 this.pathElement.w = this.contentW + + this.jumpElement.y = this.pathElement.y - 1 + this.jumpElement.w = this.contentW } selected() { @@ -744,6 +760,8 @@ class GrouplikeListingElement extends Form { keyPressed(keyBuf) { if (telc.isBackspace(keyBuf)) { this.loadParentGrouplike() + } else if (telc.isCharacter(keyBuf, '/') || keyBuf[0] === 6) { // '/', ctrl-F + this.showJumpElement() } else { return super.keyPressed(keyBuf) } @@ -837,6 +855,40 @@ class GrouplikeListingElement extends Form { this.form.selectAndShow(item) } + handleJumpValue(value) { + // Don't perform the search if the user didn't enter anything. + if (value.length) { + const lower = value.toLowerCase() + const getName = inp => (inp.item && inp.item.name) ? inp.item.name.toLowerCase().trim() : '' + // TODO: Search past the current index, for repeated searches? + const startsIndex = this.form.inputs.findIndex(inp => getName(inp).startsWith(lower)) + const includesIndex = this.form.inputs.findIndex(inp => getName(inp).includes(lower)) + const matchedIndex = startsIndex >= 0 ? startsIndex : includesIndex + + if (matchedIndex >= 0) { + this.form.curIndex = matchedIndex + this.form.scrollSelectedElementIntoView() + } else { + // TODO: Feedback that the search failed.. right now we just close the + // jump-to menu, which might not be right. + } + } + + this.hideJumpElement() + } + + showJumpElement() { + this.jumpElement.visible = true + this.root.select(this.jumpElement) + this.fixLayout() + } + + hideJumpElement() { + this.jumpElement.visible = false + this.root.select(this) + this.fixLayout() + } + get tabberLabel() { if (this.grouplike) { return this.grouplike.name || 'Unnamed group' @@ -872,7 +924,6 @@ class GrouplikeListingForm extends ListScrollForm { } selectAndShow(item) { - // TODO: Make sure this is still working. const index = this.inputs.findIndex(inp => inp.item === item) if (index >= 0) { this.curIndex = index @@ -998,6 +1049,37 @@ class GrouplikeItemElement extends Button { } } +class ListingJumpElement extends Form { + constructor() { + super() + + this.label = new Label('Jump to: ') + this.addChild(this.label) + + this.input = new TextInput() + this.addInput(this.input) + + this.input.on('value', value => { + this.emit('value', value) + }) + + this.input.on('cancel', () => { + this.emit('cancel') + }) + } + + selected() { + this.input.value = '' + this.input.keepCursorInRange() + this.root.select(this.input) + } + + fixLayout() { + this.input.x = this.label.right + this.input.w = this.contentW - this.input.x + } +} + class PathElement extends ListScrollForm { constructor() { super('horizontal') -- cgit 1.3.0-6-gf8a5