From b924ba7b7029af2936e92994685bc5c7dc187503 Mon Sep 17 00:00:00 2001 From: Danielo Rodriguez Date: Thu, 19 Oct 2023 12:12:37 +0200 Subject: [PATCH 1/4] WIP: remove input-text-suggester from suggest folder --- src/suggesters/suggestFolder.ts | 63 ++++++++++++++++----------------- src/views/FormBuilder.svelte | 13 ++++--- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/suggesters/suggestFolder.ts b/src/suggesters/suggestFolder.ts index b93aa1e6..cf438f82 100644 --- a/src/suggesters/suggestFolder.ts +++ b/src/suggesters/suggestFolder.ts @@ -1,40 +1,39 @@ // Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes -import { App, TAbstractFile, TFolder } from "obsidian"; -import { TextInputSuggest } from "./suggest"; +import { AbstractInputSuggest, App, TAbstractFile, TFolder } from "obsidian"; -export class FolderSuggest extends TextInputSuggest { +export class FolderSuggest extends AbstractInputSuggest { - constructor( - public inputEl: HTMLInputElement, - protected app: App, - ) { - super(app, inputEl); - console.log('FolderSuggest constructor'); - } - getSuggestions(inputStr: string): TFolder[] { - const abstractFiles = this.app.vault.getAllLoadedFiles(); - const lowerCaseInputStr = inputStr.toLowerCase(); + constructor( + public inputEl: HTMLInputElement, + public app: App, + ) { + super(app, inputEl); + console.log('FolderSuggest constructor'); + } + getSuggestions(inputStr: string): TFolder[] { + const abstractFiles = this.app.vault.getAllLoadedFiles(); + const lowerCaseInputStr = inputStr.toLowerCase(); - const folders: TFolder[] = abstractFiles.reduce((acc, folder: TAbstractFile) => { - if ( - folder instanceof TFolder && - folder.path.toLowerCase().contains(lowerCaseInputStr) - ) { - acc.push(folder) - } - return acc - }, [] as TFolder[]); + const folders: TFolder[] = abstractFiles.reduce((acc, folder: TAbstractFile) => { + if ( + folder instanceof TFolder && + folder.path.toLowerCase().contains(lowerCaseInputStr) + ) { + acc.push(folder) + } + return acc + }, [] as TFolder[]); - return folders; - } + return folders; + } - renderSuggestion(file: TFolder, el: HTMLElement): void { - el.setText(file.path); - } + renderSuggestion(file: TFolder, el: HTMLElement): void { + el.setText(file.path); + } - selectSuggestion(file: TFolder): void { - this.inputEl.value = file.path; - this.inputEl.trigger("input"); - this.close(); - } + selectSuggestion(file: TFolder): void { + this.inputEl.value = file.path; + this.inputEl.trigger("input"); + this.close(); + } } diff --git a/src/views/FormBuilder.svelte b/src/views/FormBuilder.svelte index 4786265e..0372f633 100644 --- a/src/views/FormBuilder.svelte +++ b/src/views/FormBuilder.svelte @@ -10,6 +10,7 @@ import FormRow from "./components/FormRow.svelte"; import InputBuilderDataview from "./components/inputBuilderDataview.svelte"; import InputBuilderSelect from "./components/InputBuilderSelect.svelte"; + import InputFolder from "./components/InputFolder.svelte"; export let definition: EditableFormDefinition = { title: "", @@ -279,13 +280,11 @@ {/each} {:else if field.input.source === "notes"} - -
- -
+ {/if} {:else if field.input.type === "slider"} {@const min_id = `min_${index}`} From 68cace2135ac38d66027d1f620f34eda700e82df Mon Sep 17 00:00:00 2001 From: Danielo Rodriguez Date: Thu, 19 Oct 2023 12:32:25 +0200 Subject: [PATCH 2/4] fix: remove all trace of text input suggest --- src/suggesters/suggest.ts | 217 -------------------------- src/suggesters/suggestArray.ts | 9 +- src/suggesters/suggestFile.ts | 9 +- src/suggesters/suggestFromDataview.ts | 71 +++++---- 4 files changed, 42 insertions(+), 264 deletions(-) delete mode 100644 src/suggesters/suggest.ts diff --git a/src/suggesters/suggest.ts b/src/suggesters/suggest.ts deleted file mode 100644 index 13902997..00000000 --- a/src/suggesters/suggest.ts +++ /dev/null @@ -1,217 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -// @ts-ignore: no-unsafe-call -// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes - -import { Scope } from "obsidian"; -import type { ISuggestOwner, App } from "obsidian"; -import { createPopper } from "@popperjs/core"; -import type { Instance as PopperInstance } from "@popperjs/core"; - -const wrapAround = (value: number, size: number): number => { - return ((value % size) + size) % size; -}; - -class Suggest { - private owner: ISuggestOwner; - // @ts-ignore - private values: T[]; - // @ts-ignore - private suggestions: HTMLDivElement[]; - // @ts-ignore - private selectedItem: number; - private containerEl: HTMLElement; - - constructor( - owner: ISuggestOwner, - containerEl: HTMLElement, - scope: Scope - ) { - this.owner = owner; - this.containerEl = containerEl; - - containerEl.on( - "click", - ".suggestion-item", - // @ts-ignore - this.onSuggestionClick.bind(this) - ); - containerEl.on( - "mousemove", - ".suggestion-item", - // @ts-ignore - this.onSuggestionMouseover.bind(this) - ); - - scope.register([], "ArrowUp", (event) => { - if (!event.isComposing) { - this.setSelectedItem(this.selectedItem - 1, true); - return false; - } - }); - - scope.register([], "ArrowDown", (event) => { - if (!event.isComposing) { - this.setSelectedItem(this.selectedItem + 1, true); - return false; - } - }); - - scope.register([], "Enter", (event) => { - if (!event.isComposing) { - this.useSelectedItem(event); - return false; - } - }); - } - - onSuggestionClick(event: MouseEvent, el: HTMLDivElement): void { - event.preventDefault(); - - const item = this.suggestions.indexOf(el); - this.setSelectedItem(item, false); - this.useSelectedItem(event); - } - - onSuggestionMouseover(_event: MouseEvent, el: HTMLDivElement): void { - const item = this.suggestions.indexOf(el); - this.setSelectedItem(item, false); - } - - setSuggestions(values: T[]) { - this.containerEl.empty(); - const suggestionEls: HTMLDivElement[] = []; - - values.forEach((value) => { - const suggestionEl = this.containerEl.createDiv("suggestion-item"); - this.owner.renderSuggestion(value, suggestionEl); - suggestionEls.push(suggestionEl); - }); - - this.values = values; - this.suggestions = suggestionEls; - this.setSelectedItem(0, false); - } - - useSelectedItem(event: MouseEvent | KeyboardEvent) { - const currentValue = this.values[this.selectedItem]; - if (currentValue) { - this.owner.selectSuggestion(currentValue, event); - } - } - - setSelectedItem(selectedIndex: number, scrollIntoView: boolean) { - const normalizedIndex = wrapAround( - selectedIndex, - this.suggestions.length - ); - const prevSelectedSuggestion = this.suggestions[this.selectedItem]; - const selectedSuggestion = this.suggestions[normalizedIndex]; - - prevSelectedSuggestion?.removeClass("is-selected"); - selectedSuggestion?.addClass("is-selected"); - - this.selectedItem = normalizedIndex; - - if (scrollIntoView) { - selectedSuggestion?.scrollIntoView(false); - } - } -} - -export abstract class TextInputSuggest implements ISuggestOwner { - protected app: App; - protected inputEl: HTMLInputElement | HTMLTextAreaElement; - - // @ts-ignore - private popper: PopperInstance; - private scope: Scope; - private suggestEl: HTMLElement; - private suggest: Suggest; - - constructor(app: App, inputEl: HTMLInputElement | HTMLTextAreaElement) { - this.app = app; - this.inputEl = inputEl; - this.scope = new Scope(); - - this.suggestEl = createDiv("suggestion-container"); - const suggestion = this.suggestEl.createDiv("suggestion"); - this.suggest = new Suggest(this, suggestion, this.scope); - - this.scope.register([], "Escape", this.close.bind(this)); - - this.inputEl.addEventListener("input", this.onInputChanged.bind(this)); - this.inputEl.addEventListener("focus", this.onInputChanged.bind(this)); - this.inputEl.addEventListener("blur", this.close.bind(this)); - this.suggestEl.on( - "mousedown", - ".suggestion-container", - (event: MouseEvent) => { - event.preventDefault(); - } - ); - } - - onInputChanged(): void { - const inputStr = this.inputEl.value; - const suggestions = this.getSuggestions(inputStr); - - if (!suggestions) { - this.close(); - return; - } - - if (suggestions.length > 0) { - this.suggest.setSuggestions(suggestions); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - this.open((this.app).dom.appContainerEl, this.inputEl); - } else { - this.close(); - } - } - - open(container: HTMLElement, inputEl: HTMLElement): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this.app).keymap.pushScope(this.scope); - - container.appendChild(this.suggestEl); - this.popper = createPopper(inputEl, this.suggestEl, { - placement: "bottom-start", - modifiers: [ - { - name: "sameWidth", - enabled: true, - fn: ({ state, instance }) => { - // Note: positioning needs to be calculated twice - - // first pass - positioning it according to the width of the popper - // second pass - position it with the width bound to the reference element - // we need to early exit to avoid an infinite loop - const targetWidth = `${state.rects.reference.width}px`; - if (state.styles.popper?.width === targetWidth) { - return; - } - //@ts-ignore - state.styles.popper.width = targetWidth; - void instance.update(); - }, - phase: "beforeWrite", - requires: ["computeStyles"], - }, - ], - }); - } - - close(): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this.app).keymap.popScope(this.scope); - - this.suggest.setSuggestions([]); - if (this.popper) this.popper.destroy(); - this.suggestEl.detach(); - } - - abstract getSuggestions(inputStr: string): T[]; - abstract renderSuggestion(item: T, el: HTMLElement): void; - abstract selectSuggestion(item: T): void; -} diff --git a/src/suggesters/suggestArray.ts b/src/suggesters/suggestArray.ts index b103dfa0..ecf2024b 100644 --- a/src/suggesters/suggestArray.ts +++ b/src/suggesters/suggestArray.ts @@ -1,11 +1,10 @@ -import { App } from "obsidian"; -import { TextInputSuggest } from "./suggest"; +import { AbstractInputSuggest, App } from "obsidian"; -export class ArraySuggest extends TextInputSuggest { +export class ArraySuggest extends AbstractInputSuggest { content: Set; - constructor(app: App, input: HTMLInputElement, content: Set) { - super(app, input); + constructor(app: App, private inputEl: HTMLInputElement, content: Set) { + super(app, inputEl); this.content = content; } diff --git a/src/suggesters/suggestFile.ts b/src/suggesters/suggestFile.ts index 04197ef2..36cfc498 100644 --- a/src/suggesters/suggestFile.ts +++ b/src/suggesters/suggestFile.ts @@ -1,7 +1,4 @@ -// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes - -import { App, TAbstractFile, TFile } from "obsidian"; -import { TextInputSuggest } from "./suggest"; +import { AbstractInputSuggest, App, TAbstractFile, TFile } from "obsidian"; import { get_tfiles_from_folder } from "../utils/files"; import { tryCatch } from "../utils/Error"; @@ -13,9 +10,9 @@ export interface FileStrategy { selectSuggestion(file: TFile): string; } -export class FileSuggest extends TextInputSuggest { +export class FileSuggest extends AbstractInputSuggest { constructor( - protected app: App, + public app: App, public inputEl: HTMLInputElement, private strategy: FileStrategy, private folder: string, diff --git a/src/suggesters/suggestFromDataview.ts b/src/suggesters/suggestFromDataview.ts index 8521bfbb..1267cd77 100644 --- a/src/suggesters/suggestFromDataview.ts +++ b/src/suggesters/suggestFromDataview.ts @@ -1,6 +1,5 @@ // Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes -import { App, TAbstractFile, TFolder } from "obsidian"; -import { TextInputSuggest } from "./suggest"; +import { AbstractInputSuggest, App } from "obsidian"; import { ModalFormError, tryCatch } from "src/utils/Error"; import { log_error } from "src/utils/Log"; @@ -9,42 +8,42 @@ import { log_error } from "src/utils/Log"; * It requires the dataview plugin to be installed and enabled. * For now, we are not very strict with the checks and just throw errors */ -export class DataviewSuggest extends TextInputSuggest { - sandboxedQuery: (dv: any, pages: any) => string[] +export class DataviewSuggest extends AbstractInputSuggest { + sandboxedQuery: (dv: any, pages: any) => string[] - constructor( - public inputEl: HTMLInputElement, - dvQuery: string, - protected app: App, - ) { - super(app, inputEl); - this.sandboxedQuery = tryCatch( - () => eval(`(function sandboxedQuery(dv, pages) { return ${dvQuery} })`), - "Invalid dataview query" - ) - } + constructor( + public inputEl: HTMLInputElement, + dvQuery: string, + public app: App, + ) { + super(app, inputEl); + this.sandboxedQuery = tryCatch( + () => eval(`(function sandboxedQuery(dv, pages) { return ${dvQuery} })`), + "Invalid dataview query" + ) + } - getSuggestions(inputStr: string): string[] { - const dv = this.app.plugins.plugins.dataview?.api - if (!dv) { - log_error(new ModalFormError("Dataview plugin is not enabled")) - return []; - } - const result = this.sandboxedQuery(dv, dv.pages) - if (!Array.isArray(result)) { - log_error(new ModalFormError("The dataview query did not return an array")) - return []; - } - return result.filter(r => r.toLowerCase().includes(inputStr.toLowerCase())) - } + getSuggestions(inputStr: string): string[] { + const dv = this.app.plugins.plugins.dataview?.api + if (!dv) { + log_error(new ModalFormError("Dataview plugin is not enabled")) + return []; + } + const result = this.sandboxedQuery(dv, dv.pages) + if (!Array.isArray(result)) { + log_error(new ModalFormError("The dataview query did not return an array")) + return []; + } + return result.filter(r => r.toLowerCase().includes(inputStr.toLowerCase())) + } - renderSuggestion(option: string, el: HTMLElement): void { - el.setText(option); - } + renderSuggestion(option: string, el: HTMLElement): void { + el.setText(option); + } - selectSuggestion(option: string): void { - this.inputEl.value = option; - this.inputEl.trigger("input"); - this.close(); - } + selectSuggestion(option: string): void { + this.inputEl.value = option; + this.inputEl.trigger("input"); + this.close(); + } } From 43ad5fba8b6a44369b0aa721b9839a6448ae221e Mon Sep 17 00:00:00 2001 From: Danielo Rodriguez Date: Thu, 19 Oct 2023 12:34:18 +0200 Subject: [PATCH 3/4] chore: cleanup --- src/suggesters/suggestFolder.ts | 1 - src/suggesters/suggestFromDataview.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/suggesters/suggestFolder.ts b/src/suggesters/suggestFolder.ts index cf438f82..db12e45c 100644 --- a/src/suggesters/suggestFolder.ts +++ b/src/suggesters/suggestFolder.ts @@ -8,7 +8,6 @@ export class FolderSuggest extends AbstractInputSuggest { public app: App, ) { super(app, inputEl); - console.log('FolderSuggest constructor'); } getSuggestions(inputStr: string): TFolder[] { const abstractFiles = this.app.vault.getAllLoadedFiles(); diff --git a/src/suggesters/suggestFromDataview.ts b/src/suggesters/suggestFromDataview.ts index 1267cd77..a60e809a 100644 --- a/src/suggesters/suggestFromDataview.ts +++ b/src/suggesters/suggestFromDataview.ts @@ -1,4 +1,3 @@ -// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes import { AbstractInputSuggest, App } from "obsidian"; import { ModalFormError, tryCatch } from "src/utils/Error"; import { log_error } from "src/utils/Log"; From 16cc4aff0a1db9a9f59588eb205e4b01d2ab988d Mon Sep 17 00:00:00 2001 From: Danielo Rodriguez Date: Thu, 19 Oct 2023 12:36:26 +0200 Subject: [PATCH 4/4] chore: remove popper --- package-lock.json | 14 ++------------ package.json | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 37125204..94d6178b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,14 @@ { "name": "obsidian-modal-form", - "version": "1.16.4", + "version": "1.16.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "obsidian-modal-form", - "version": "1.16.4", + "version": "1.16.5", "license": "MIT", "dependencies": { - "@popperjs/core": "^2.11.8", "fuse.js": "^6.6.2" }, "devDependencies": { @@ -598,15 +597,6 @@ "node": ">= 8" } }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, "node_modules/@tsconfig/svelte": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.2.tgz", diff --git a/package.json b/package.json index 18c5c0e0..85c0d717 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "typescript": "^5.2.2" }, "dependencies": { - "@popperjs/core": "^2.11.8", "fuse.js": "^6.6.2" } }