Skip to content

Commit

Permalink
feat(input): you can define a parent folder on the folder input
Browse files Browse the repository at this point in the history
fixes [Feature request] Designate "Parent Folder" for narrowing folder search options with Folder Type Fields  #305
  • Loading branch information
danielo515 committed Dec 12, 2024
1 parent 4599587 commit d208648
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 28 deletions.
17 changes: 7 additions & 10 deletions EXAMPLE_VAULT/.obsidian/plugins/modal-form/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -343,31 +343,28 @@
{
"title": "Frontmatter example",
"name": "frontmatter",
"version": "1",
"fields": [
{
"name": "title",
"label": "",
"description": "",
"isRequired": false,
"input": {
"type": "text",
"allowUnknownValues": false,
"hidden": false
},
"isRequired": false
}
},
{
"name": "tags",
"label": "",
"description": "",
"isRequired": false,
"input": {
"type": "tag",
"allowUnknownValues": false,
"hidden": false
},
"isRequired": false
"type": "tag"
}
}
]
],
"version": "1"
}
]
}
1 change: 1 addition & 0 deletions src/core/input/InputDefinitionSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const InputNoteFromFolderSchema = object({
});
export const InputFolderSchema = object({
type: literal("folder"),
parentFolder: optional(string([toTrimmed()])),
// TODO: allow exclude option
});
export const InputDataviewSourceSchema = object({
Expand Down
19 changes: 12 additions & 7 deletions src/suggesters/suggestFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,30 @@
import { AbstractInputSuggest, App, TAbstractFile, TFolder } from "obsidian";

export class FolderSuggest extends AbstractInputSuggest<TFolder> {

constructor(
public inputEl: HTMLInputElement,
public app: App,
private parentFolder?: string,
) {
super(app, inputEl);
}

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)
if (!(folder instanceof TFolder)) return acc;

const folderPath = folder.path.toLowerCase();
const matchesInput = folderPath.contains(lowerCaseInputStr);
const matchesParent =
!this.parentFolder || folderPath.startsWith(this.parentFolder.toLowerCase());

if (matchesInput && matchesParent) {
acc.push(folder);
}
return acc
return acc;
}, [] as TFolder[]);

return folders;
Expand Down
8 changes: 7 additions & 1 deletion src/views/FormBuilder.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
import FormRow from "./components/FormRow.svelte";
import InputBuilderDataview from "./components/inputBuilderDataview.svelte";
import InputBuilderDocumentBlock from "./components/InputBuilderDocumentBlock.svelte";
import InputBuilderFile from "./components/InputBuilderFile.svelte";
import InputFolder from "./components/InputBuilderFolder.svelte";
import InputBuilderImage from "./components/InputBuilderImage.svelte";
import InputBuilderFile from "./components/InputBuilderFile.svelte";
import InputBuilderSelect from "./components/InputBuilderSelect.svelte";
import Tabs from "./components/Tabs.svelte";
import TemplateEditor from "./components/TemplateEditor.svelte";
Expand Down Expand Up @@ -349,6 +349,12 @@
bind:folder={field.input.folder}
notifyChange={onChange}
/>
{:else if field.input.type === "folder"}
<InputFolder
{index}
bind:folder={field.input.parentFolder}
notifyChange={onChange}
/>
{:else if field.input.type === "dataview"}
<InputBuilderDataview
{index}
Expand Down
11 changes: 9 additions & 2 deletions src/views/components/Form/InputFolder.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@
import { useSetting } from "./useObsidianSetting";
export let field: FieldDefinition;
export let value: Writable<FieldValue>;
export let parentFolder: string | undefined;
export let app: App;
let search_: SearchComponent | undefined;
function customizer(setting: Setting) {
setting.addSearch((component) => {
new FolderSuggest(component.inputEl, app);
new FolderSuggest(component.inputEl, app, parentFolder);
search_ = component;
component.onChange((v) => {
$value = v;
$value = v.trim();
});
});
setting.infoEl.appendChild(
createSpan({
cls: "setting-item-description",
text: parentFolder ? `Searching in: ${parentFolder}` : "",
}),
);
}
$: if (search_) {
search_.setValue($value as string);
Expand Down
7 changes: 6 additions & 1 deletion src/views/components/Form/RenderField.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@
{:else if definition.input.type === "toggle"}
<ObsidianToggle field={definition} {value} />
{:else if definition.input.type === "folder"}
<InputFolder field={definition} {value} {app} />
<InputFolder
field={definition}
parentFolder={definition.input.parentFolder}
{value}
{app}
/>
{:else if definition.input.type === "dataview"}
<InputDataview field={definition} input={definition.input} {value} {errors} {app} />
{:else if definition.input.type === "note"}
Expand Down
11 changes: 4 additions & 7 deletions src/views/components/InputBuilderFolder.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
* This component is just to select a folder, not notes inside the folder
*/
export let index: number;
export let folder: string = "";
export let folder: string | undefined;
// This is just used to notify the parent component that the value has changed
// it is useful for example to persis the intermediary state of the form
export let notifyChange: () => void;
function searchFolder(element: HTMLElement) {
new Setting(element).addSearch((search) => {
search.setPlaceholder("Select a folder");
search.setValue(folder);
search.setValue(folder || "");
new FolderSuggest(search.inputEl, app);
search.onChange((value) => {
folder = value;
folder = value.trim() || undefined;
notifyChange();
});
});
Expand All @@ -24,10 +24,7 @@
</script>

<!-- The autocomplete input will be inside the first div, so we remove some styles with the utility classes -->
<div
class="modal-form flex column gap1 remove-padding remove-border fix-suggest"
use:searchFolder
>
<div class="modal-form flex column gap1 remove-padding remove-border fix-suggest" use:searchFolder>
<label for={id}>Source Folder</label>
</div>

Expand Down

0 comments on commit d208648

Please sign in to comment.