obsidian#SearchComponent TypeScript Examples

The following examples show how to use obsidian#SearchComponent. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: choiceBuilder.ts    From quickadd with MIT License 6 votes vote down vote up
protected addFileSearchInputToSetting(setting: Setting, value: string, onChangeCallback: (value: string) => void): SearchComponent {
        let component: SearchComponent;

        setting.addSearch(searchComponent => {
            component = searchComponent;
           searchComponent.setValue(value);
           searchComponent.setPlaceholder("File path");

           const markdownFiles: string[] = this.app.vault.getMarkdownFiles().map(f => f.path);
           new GenericTextSuggester(this.app, searchComponent.inputEl, markdownFiles);

           searchComponent.onChange(onChangeCallback);
        });

        return component;
    }
Example #2
Source File: TagModal.ts    From obsidian-rss with GNU General Public License v3.0 5 votes vote down vote up
display(): void {
        const {contentEl} = this;
        contentEl.empty();

        contentEl.createEl("h1", {text: t("edit_tags")});

        const tagDiv = contentEl.createDiv("tags");

        for (const tag in this.tags) {
            new Setting(tagDiv)
                .addSearch(async (search: SearchComponent) => {
                    new ArraySuggest(this.app, search.inputEl, get(tagsStore));
                    search
                        .setValue(this.tags[tag])
                        .onChange(async (value: string) => {
                            this.removeValidationError(search);
                            if (!value.match(TAG_REGEX) || value.match(NUMBER_REGEX) || value.contains(" ") || value.contains('#')) {
                                this.setValidationError(search, t("invalid_tag"));
                                return;
                            }
                            this.tags = this.tags.filter(e => e !== this.tags[tag]);
                            this.tags.push(value);
                        });
                })
                .addExtraButton((button) => {
                    button
                        .setTooltip(t("delete"))
                        .setIcon("trash")
                        .onClick(() => {
                            this.tags = this.tags.filter(e => e !== this.tags[tag]);
                            this.display();
                        });

                });
        }

        let tagValue = "";
        let tagComponent: SearchComponent;
        const newTag = new Setting(tagDiv)
            .addSearch(async (search: SearchComponent) => {
                tagComponent = search;
                new ArraySuggest(this.app, search.inputEl, get(tagsStore));
                search
                    .onChange(async (value: string) => {
                        if (!value.match(TAG_REGEX) || value.match(NUMBER_REGEX) || value.contains(" ") || value.contains('#')) {
                            this.setValidationError(search, t("invalid_tag"));
                            return;
                        }
                        tagValue = value;
                    });
            }).addExtraButton(button => {
                button
                    .setTooltip(t("add"))
                    .setIcon("plus")
                    .onClick(() => {
                        if (!tagValue.match(TAG_REGEX) || tagValue.match(NUMBER_REGEX) || tagValue.contains(" ") || tagValue.contains('#')) {
                            this.setValidationError(tagComponent, t("invalid_tag"));
                            return;
                        }
                        this.tags.push(tagValue);
                        this.display();
                    });
            });
        newTag.controlEl.addClass("rss-setting-input");

        const buttonEl = contentEl.createSpan("actionButtons");

        new Setting(buttonEl).addExtraButton((btn) =>
            btn
                .setTooltip(t("save"))
                .setIcon("checkmark")
                .onClick(async () => {
                    this.close();
                }));
    }
Example #3
Source File: SettingsTab.ts    From obsidian-rss with GNU General Public License v3.0 5 votes vote down vote up
display(): void {
        const {containerEl} = this;

        containerEl.empty();

        containerEl.createEl('h2', {text: t("RSS_Reader") + " " + t("settings")});

        containerEl.createEl('h3', {text: t("file_creation")});

        const templateDesc = new DocumentFragment();
        templateDesc.createDiv().innerHTML = t("template_new_help") + "<br>" + t("available_variables") + `<br>` +
            `<strong>{{title}}</strong> → ${t("article_title")}<br>` +
            `<strong>{{link}}</strong> → ${t("article_link")}<br>` +
            `<strong>{{author}}</strong> → ${t("article_author")}<br>` +
            `<strong>{{published}}</strong> → ${t("article_published")}<br>` +
            `<strong>{{created}}</strong> → ${t("note_created")}<br>` +
            `<strong>{{description}}</strong> → ${t("article_description")}<br>` +
            `<strong>{{content}}</strong> → ${t("article_content")}<br>` +
            `<strong>{{folder}}</strong> → ${t("feed_folder")}<br>` +
            `<strong>{{feed}}</strong> → ${t("feed_title")}<br>` +
            `<strong>{{filename}}</strong> → ${t("filename")}<br>` +
            `<strong>{{tags}}</strong> → ${t("article_tags")}<br>` +
            `<strong>{{media}}</strong> → ${t("article_media")}<br>` +
            `<strong>{{highlights}}</strong> → ${t("highlights")}`;

        new Setting(containerEl)
            .setName(t("template_new"))
            .setDesc(templateDesc)
            .addTextArea((textArea: TextAreaComponent) => {
                textArea
                    .setValue(this.plugin.settings.template)
                    .setPlaceholder(DEFAULT_SETTINGS.template)
                    .onChange(async (value) => {
                        await this.plugin.writeSettings(() => ({
                            template: value
                        }));
                    });
                textArea.inputEl.setAttr("rows", 15);
                textArea.inputEl.setAttr("cols", 50);
            });

        const pasteTemplateDesc = new DocumentFragment();
        pasteTemplateDesc.createDiv().innerHTML = t("template_new_help") + "<br>" + t("available_variables") + `<br>` +
            `<strong>{{title}}</strong> → ${t("article_title")}<br>` +
            `<strong>{{link}}</strong> → ${t("article_link")}<br>` +
            `<strong>{{author}}</strong> → ${t("article_author")}<br>` +
            `<strong>{{published}}</strong> → ${t("article_published")}<br>` +
            `<strong>{{created}}</strong> → ${t("note_created")}<br>` +
            `<strong>{{description}}</strong> → ${t("article_description")}<br>` +
            `<strong>{{content}}</strong> → ${t("article_content")}<br>` +
            `<strong>{{folder}}</strong> → ${t("feed_folder")}<br>` +
            `<strong>{{feed}}</strong> → ${t("feed_title")}<br>` +
            `<strong>{{tags}}</strong> → ${t("article_tags")}<br>` +
            `<strong>{{media}}</strong> → ${t("article_media")}<br>` +
            `<strong>{{highlights}}</strong> → ${t("highlights")}`;

        new Setting(containerEl)
            .setName(t("template_paste"))
            .setDesc(pasteTemplateDesc)
            .addTextArea((textArea: TextAreaComponent) => {
                textArea
                    .setValue(this.plugin.settings.pasteTemplate)
                    .setPlaceholder(DEFAULT_SETTINGS.pasteTemplate)
                    .onChange(async (value) => {
                        await this.plugin.writeSettings(() => ({
                            pasteTemplate: value
                        }));
                    });
                textArea.inputEl.setAttr("rows", 15);
                textArea.inputEl.setAttr("cols", 50);
            });

        new Setting(containerEl)
            .setName(t("file_location"))
            .setDesc(t("file_location_help"))
            .addDropdown(async (dropdown: DropdownComponent) => {
                dropdown
                    .addOption("default", t("file_location_default"))
                    .addOption("custom", t("file_location_custom"))
                    .setValue(this.plugin.settings.saveLocation)
                    .onChange(async (value: string) => {
                        await this.plugin.writeSettings(() => (
                            {saveLocation: value}
                        ));
                        this.display();
                    });
            });

        if (this.plugin.settings.saveLocation == "custom") {
            new Setting(containerEl)
                .setName(t("file_location_folder"))
                .setDesc(t("file_location_folder_help"))
                .addSearch(async (search: SearchComponent) => {
                    new FolderSuggest(this.app, search.inputEl);
                    search
                        .setValue(this.plugin.settings.saveLocationFolder)
                        .setPlaceholder(DEFAULT_SETTINGS.saveLocationFolder)
                        .onChange(async (value: string) => {
                            await this.plugin.writeSettings(() => (
                                {saveLocationFolder: value}
                            ));
                        });
                });
        }

        let dateFormatSampleEl: MomentFormatComponent;
        const dateFormat = new Setting(containerEl)
            .setName(t("date_format"))
            .addMomentFormat((format: MomentFormatComponent) => {
                dateFormatSampleEl = format
                    .setDefaultFormat(DEFAULT_SETTINGS.dateFormat)
                    .setPlaceholder(DEFAULT_SETTINGS.dateFormat)
                    .setValue(this.plugin.settings.dateFormat)
                    .onChange(async (value) => {
                        await this.plugin.writeSettings(() => (
                            {dateFormat: value}
                        ));
                    });
            });
        const referenceLink = dateFormat.descEl.createEl("a");
        referenceLink.setAttr("href", "https://momentjs.com/docs/#/displaying/format/");
        referenceLink.setText(t("syntax_reference"));
        const text = dateFormat.descEl.createDiv("text");
        text.setText(t("syntax_looks"));
        const sampleEl = text.createSpan("sample");
        dateFormatSampleEl.setSampleEl(sampleEl);
        dateFormat.addExtraButton((button) => {
            button
                .setIcon('reset')
                .setTooltip(t("reset"))
                .onClick(async () => {
                    await this.plugin.writeSettings(() => ({
                        dateFormat: DEFAULT_SETTINGS.dateFormat
                    }));
                    this.display();
                });
        });

        new Setting(containerEl)
            .setName(t("ask_filename"))
            .setDesc(t("ask_filename_help"))
            .addToggle((toggle: ToggleComponent) => {
                toggle
                    .setValue(this.plugin.settings.askForFilename)
                    .onChange(async (value) => {
                        await this.plugin.writeSettings(() => ({
                            askForFilename: value
                        }));
                    });
            });

        new Setting(containerEl)
            .setName(t("default_filename"))
            .setDesc(t("default_filename_help"))
            .addText((text) => {
                text
                    .setPlaceholder(DEFAULT_SETTINGS.defaultFilename)
                    .setValue(this.plugin.settings.defaultFilename)
                    .onChange(async (value) => {
                        if (value.length > 0) {
                            await this.plugin.writeSettings(() => ({
                                defaultFilename: value
                            }));
                        } else {
                            new Notice(t("fix_errors"));
                        }
                    });
            });

        containerEl.createEl("hr", {attr: {style: "border-top: 5px solid var(--background-modifier-border);"}});
        containerEl.createEl("h3", {text: "Misc"});

        const refresh = new Setting(containerEl)
            .setName(t("refresh_time"))
            .setDesc(t("refresh_time_help"))
            .addText((text: TextComponent) => {
                text
                    .setPlaceholder(String(DEFAULT_SETTINGS.updateTime))
                    .setValue(String(this.plugin.settings.updateTime))
                    .onChange(async (value) => {
                        if (value.length === 0) {
                            new Notice(t("specify_positive_number"));
                            return;
                        }
                        if (Number(value) < 0) {
                            new Notice(t("specify_positive_number"));
                            return;
                        }

                        await this.plugin.writeSettings(() => (
                            {updateTime: Number(value)}
                        ));
                    });
                text.inputEl.setAttr("type", "number");
                text.inputEl.setAttr("min", "1");
                //we don't want decimal numbers.
                text.inputEl.setAttr("onkeypress", "return event.charCode >= 48 && event.charCode <= 57");
            });
        refresh.addExtraButton((button) => {
            button
                .setIcon('reset')
                .setTooltip('restore default')
                .onClick(async () => {
                    await this.plugin.writeSettings(() => ({
                        updateTime: DEFAULT_SETTINGS.updateTime
                    }));
                    this.display();
                });
        });

        new Setting(containerEl)
            .setName(t("multi_device_usage"))
            .setDesc(t("multi_device_usage_help"))
            .addToggle((toggle: ToggleComponent) => {
                return toggle
                    .setValue(this.plugin.settings.autoSync)
                    .onChange(async (value) => {
                        await this.plugin.writeSettings(() => ({
                            autoSync: value
                        }));
                    });
            });

        new Setting(containerEl)
            .setName(t("display_style"))
            .addDropdown(dropdown => {
                return dropdown
                    .addOption("list", t("list"))
                    .addOption("cards", t("cards"))
                    .setValue(this.plugin.settings.displayStyle)
                    .onChange(async (value) => {
                        await this.plugin.writeSettings(() => ({
                            displayStyle: value
                        }));
                    });
            });

        containerEl.createEl("h2", {text: t("content")});

        const filterContainer = containerEl.createDiv("filter-container");
        displayFilterSettings(this.plugin, filterContainer);

        const feedsContainer = containerEl.createDiv(
            "feed-container"
        );
        displayFeedSettings(this.plugin, feedsContainer);

        containerEl.createEl("hr", {attr: {style: "border-top: 5px solid var(--background-modifier-border);"}});

        const hotkeyContainer = containerEl.createDiv("hotkey-container");
        displayHotkeys(this.plugin, hotkeyContainer);

        containerEl.createEl("hr", {attr: {style: "border-top: 5px solid var(--background-modifier-border);"}});

        const details = containerEl.createEl("details");
        const summary = details.createEl("summary");
        summary.setText(t("advanced"));
        const advanced = details.createDiv("advanced");

        advanced.createEl("h3", {text: t("customize_terms")});
        advanced.createSpan({text: "Change a few selected terms here. You can help translating the plugin "});
        advanced.createEl("a", {text: "here", href: "https://github.com/joethei/obsidian-rss/tree/master/src/l10n"});

        new Setting(advanced)
            .setName(t("folders"))
            .addText(text => {
                text
                    .setPlaceholder(t("folders"))
                    .setValue(this.plugin.settings.renamedText.folders)
                    .onChange(async value => {
                        await this.plugin.writeSettings(() => ({
                            renamedText: {
                                ...this.plugin.settings.renamedText,
                                folders: value
                            }
                        }));
                    });
            });

        new Setting(advanced)
            .setName(t("filtered_folders"))
            .addText(text => {
                text
                    .setPlaceholder(t("filtered_folders"))
                    .setValue(this.plugin.settings.renamedText.filtered_folders)
                    .onChange(async value => {
                        await this.plugin.writeSettings(() => ({
                            renamedText: {
                                ...this.plugin.settings.renamedText,
                                filtered_folders: value
                            }
                        }));
                    });
            });

        new Setting(advanced)
            .setName(t("no_folder"))
            .addText(text => {
                text
                    .setPlaceholder(t("no_folder"))
                    .setValue(this.plugin.settings.renamedText.no_folder)
                    .onChange(async value => {
                        await this.plugin.writeSettings(() => ({
                            renamedText: {
                                ...this.plugin.settings.renamedText,
                                no_folder: value
                            }
                        }));
                    });
            });

        advanced.createEl("hr", {attr: {style: "border-top: 5px solid var(--background-modifier-border);"}});

        new Setting(advanced)
            .setName(t("display_media"))
            .addToggle(toggle => {
               toggle
                   .setValue(this.plugin.settings.displayMedia)
                   .onChange(async value => {
                       await this.plugin.writeSettings(() => ({
                           displayMedia: value
                       }));
                   });
            });
    }
Example #4
Source File: FeedModal.ts    From obsidian-rss with GNU General Public License v3.0 4 votes vote down vote up
async display() : Promise<void> {
        const { contentEl } = this;

        contentEl.empty();

        let nameText: TextComponent;
        const name = new Setting(contentEl)
            .setName(t("name"))
            .setDesc(t("name_help"))
            .addText((text) => {
                nameText = text;
                text.setValue(this.name)
                    .onChange((value) => {
                        this.removeValidationError(text);
                       this.name = value;
                    });
            });
        name.controlEl.addClass("rss-setting-input");

        let urlText: TextComponent;
        const url = new Setting(contentEl)
            .setName("URL")
            .setDesc(t("url_help"))
            .addText((text) => {
                urlText = text;
                text.setValue(this.url)
                    .onChange(async(value) => {
                        this.removeValidationError(text);
                        this.url = value;

                    });
            });
        url.controlEl.addClass("rss-setting-input");

        new Setting(contentEl)
            .setName(t("folder"))
            .setDesc(t("folder_help"))
            .addSearch(async (search: SearchComponent) => {
                new FeedFolderSuggest(this.app, search.inputEl);
                search
                    .setValue(this.folder)
                    .setPlaceholder(t("no_folder"))
                    .onChange(async (value: string) => {
                        this.folder = value;
                    });
            });

        const footerEl = contentEl.createDiv();
        const footerButtons = new Setting(footerEl);
        footerButtons.addButton((b) => {
            b.setTooltip(t("save"))
                .setIcon("checkmark")
                .onClick(async () => {
                    let error = false;
                    if(!nameText.getValue().length) {
                        this.setValidationError(nameText, t("invalid_name"));
                        error = true;
                    }

                    if(!urlText.getValue().length) {
                        this.setValidationError(urlText, t("invalid_url"));
                        error = true;
                    }
                    if(!isValidHttpUrl(urlText.getValue())) {
                        this.setValidationError(urlText, t("invalid_url"));
                        error = true;
                    }else {
                        const items = await getFeedItems({name: "test", url: urlText.getValue(), folder: ""});
                        if(items.items.length == 0) {
                            this.setValidationError(urlText, t("invalid_feed"));
                            error = true;
                        }
                    }

                    if(error) {
                        new Notice(t("fix_errors"));
                        return;
                    }
                    this.saved = true;
                    this.close();
                });
            return b;
        });
        footerButtons.addExtraButton((b) => {
            b.setIcon("cross")
                .setTooltip(t("cancel"))
                .onClick(() => {
                    this.saved = false;
                    this.close();
                });
            return b;
        });
    }
Example #5
Source File: FilteredFolderModal.ts    From obsidian-rss with GNU General Public License v3.0 4 votes vote down vote up
async display() : Promise<void> {
        const { contentEl } = this;

        contentEl.empty();

        let nameText: TextComponent;
        const name = new Setting(contentEl)
            .setName(t("name"))
            .setDesc(t("filter_name_help"))
            .addText((text) => {
                nameText = text;
                text.setValue(this.name)
                    .onChange((value) => {
                        this.removeValidationError(text);
                        this.name = value;
                    });
            });
        name.controlEl.addClass("rss-setting-input");

        new Setting(contentEl)
            .setName(t("only_favorites"))
            .addToggle(toggle => {
                toggle
                    .setValue(this.favorites)
                    .onChange(value => {
                        this.favorites = value;
                    });
            });

        new Setting(contentEl)
            .setName(t("show_read"))
            .addToggle(toggle => {
                toggle
                    .setValue(this.read)
                    .onChange(value => {
                        this.read = value;
                    });
            });

        new Setting(contentEl)
            .setName(t("show_unread"))
            .addToggle(toggle => {
                toggle
                    .setValue(this.unread)
                    .onChange(value => {
                        this.unread = value;
                    });
            });

        const sorting = new Setting(contentEl)
            .setName(t("sort"))
            .addDropdown((dropdown: DropdownComponent) => {
                for(const order in SortOrder) {
                    if(order.length > 1) {
                        // @ts-ignore
                        dropdown.addOption(order, t("sort_" + order.toLowerCase()));
                    }
                }

                dropdown
                    .setValue(this.sortOrder)
                    .onChange(async (value: string) => {
                        this.sortOrder = value;
                    });
            });
        sorting.controlEl.addClass("rss-setting-input");

        //folders
        const foldersDiv = contentEl.createDiv("folders");
        foldersDiv.createEl("h2", {text: t("folders")});
        foldersDiv.createEl("p", {text: t("filter_folder_help")});

        for (const folder in this.filterFolders) {
            new Setting(foldersDiv)
                .addSearch(async (search: SearchComponent) => {
                    new ArraySuggest(this.app, search.inputEl, get(folderStore));
                    search
                        .setValue(this.filterFolders[folder])
                        .onChange(async (value: string) => {
                            this.removeValidationError(search);
                            this.filterFolders = this.filterFolders.filter(e => e !== this.filterFolders[folder]);
                            this.filterFolders.push(value);
                        });
                })
                .addExtraButton((button) => {
                    button
                        .setTooltip(t("delete"))
                        .setIcon("feather-trash")
                        .onClick(() => {
                            this.filterFolders = this.filterFolders.filter(e => e !== this.filterFolders[folder]);
                            this.display();
                        });

                });
        }

        let folderValue = "";
        const newFolder = new Setting(foldersDiv)
            .addSearch(async (search: SearchComponent) => {
                new ArraySuggest(this.app, search.inputEl, get(folderStore));
                search
                    .onChange(async (value: string) => {
                        folderValue = value;
                    });
            }).addExtraButton(button => {
                button
                    .setTooltip(t("add"))
                    .setIcon("plus")
                    .onClick(() => {
                        this.filterFolders.push(folderValue);
                        this.display();
                    });
            });
        newFolder.controlEl.addClass("rss-setting-input");

        foldersDiv.createEl("p", {text: t("filter_folder_ignore_help")});

        //ignore folders
        for (const folder in this.ignoreFolders) {
            new Setting(foldersDiv)
                .addSearch(async (search: SearchComponent) => {
                    new ArraySuggest(this.app, search.inputEl, get(folderStore));
                    search
                        .setValue(this.ignoreFolders[folder])
                        .onChange(async (value: string) => {
                            this.removeValidationError(search);
                            this.ignoreFolders = this.ignoreFolders.filter(e => e !== this.ignoreFolders[folder]);
                            this.ignoreFolders.push(value);
                        });
                })
                .addExtraButton((button) => {
                    button
                        .setTooltip(t("delete"))
                        .setIcon("trash")
                        .onClick(() => {
                            this.ignoreFolders = this.ignoreFolders.filter(e => e !== this.ignoreFolders[folder]);
                            this.display();
                        });

                });
        }

        let folderIgnoreValue = "";
        const newIgnoreFolder = new Setting(foldersDiv)
            .addSearch(async (search: SearchComponent) => {
                new ArraySuggest(this.app, search.inputEl, get(folderStore));
                search
                    .onChange(async (value: string) => {
                        folderIgnoreValue = value;
                    });
            }).addExtraButton(button => {
                button
                    .setTooltip(t("add"))
                    .setIcon("plus")
                    .onClick(() => {
                        this.ignoreFolders.push(folderIgnoreValue);
                        this.display();
                    });
            });
        newIgnoreFolder.controlEl.addClass("rss-setting-input");


        //feeds
        const feedsDiv = contentEl.createDiv("feeds");
        feedsDiv.createEl("h2", {text: t("feeds")});
        feedsDiv.createEl("p", {text: t("filter_feed_help")});

        const feeds = this.plugin.settings.feeds.filter(feed => {
            if(this.filterFolders.length === 0)
                return true;
            return this.filterFolders.contains(feed.folder);
        }).map((feed) => feed.name);

        for (const feed in this.filterFeeds) {
            new Setting(feedsDiv)
                .addSearch(async (search: SearchComponent) => {
                    new ArraySuggest(this.app, search.inputEl, new Set(feeds));
                    search
                        .setValue(this.filterFeeds[feed])
                        .onChange(async (value: string) => {
                            this.removeValidationError(search);
                            this.filterFeeds = this.filterFeeds.filter(e => e !== this.filterFeeds[feed]);
                            this.filterFeeds.push(value);
                        });
                })
                .addExtraButton((button) => {
                    button
                        .setTooltip(t("delete"))
                        .setIcon("trash")
                        .onClick(() => {
                            this.filterFeeds = this.filterFeeds.filter(e => e !== this.filterFeeds[feed]);
                            this.display();
                        });

                });
        }

        let feedValue = "";
        const newFeed = new Setting(feedsDiv)
            .addSearch(async (search: SearchComponent) => {
                new ArraySuggest(this.app, search.inputEl, new Set(feeds));
                search
                    .onChange(async (value: string) => {
                        feedValue = value;
                    });
            }).addExtraButton(button => {
                button
                    .setTooltip(t("add"))
                    .setIcon("plus")
                    .onClick(() => {
                        this.filterFeeds.push(feedValue);
                        this.display();
                    });
            });
        newFeed.controlEl.addClass("rss-setting-input");

        feedsDiv.createEl("p", {text: t("filter_feed_ignore_help")});

        //ignore feeds
        for (const folder in this.ignoreFeeds) {
            new Setting(feedsDiv)
                .addSearch(async (search: SearchComponent) => {
                    new ArraySuggest(this.app, search.inputEl, new Set(feeds));
                    search
                        .setValue(this.ignoreFeeds[folder])
                        .onChange(async (value: string) => {
                            this.removeValidationError(search);
                            this.ignoreFeeds = this.ignoreFeeds.filter(e => e !== this.ignoreFeeds[folder]);
                            this.ignoreFeeds.push(value);
                        });
                })
                .addExtraButton((button) => {
                    button
                        .setTooltip(t("delete"))
                        .setIcon("trash")
                        .onClick(() => {
                            this.ignoreFeeds = this.ignoreFeeds.filter(e => e !== this.ignoreFeeds[folder]);
                            this.display();
                        });

                });
        }

        let feedIgnoreValue = "";
        const newIgnoreFeed = new Setting(feedsDiv)
            .addSearch(async (search: SearchComponent) => {
                new ArraySuggest(this.app, search.inputEl, new Set(feeds));
                search
                    .onChange(async (value: string) => {
                        feedIgnoreValue = value;
                    });
            }).addExtraButton(button => {
                button
                    .setTooltip(t("add"))
                    .setIcon("plus")
                    .onClick(() => {
                        this.ignoreFeeds.push(feedIgnoreValue);
                        this.display();
                    });
            });
        newIgnoreFeed.controlEl.addClass("rss-setting-input");

        //tags
        const tagDiv = contentEl.createDiv("tags");
        tagDiv.createEl("h2", {text: t("tags")});
        tagDiv.createEl("p", {text: t("filter_tags_help")});

        for (const tag in this.filterTags) {
            new Setting(tagDiv)
                .addSearch(async (search: SearchComponent) => {
                    new ArraySuggest(this.app, search.inputEl, get(tagsStore));
                    search
                        .setValue(this.filterTags[tag])
                        .onChange(async (value: string) => {
                            this.removeValidationError(search);
                            if (!value.match(TAG_REGEX) || value.match(NUMBER_REGEX) || value.contains(" ") || value.contains('#')) {
                                this.setValidationError(search, t("invalid_tag"));
                                return;
                            }
                            this.filterTags = this.filterTags.filter(e => e !== this.filterTags[tag]);
                            this.filterTags.push(value);
                        });
                })
                .addExtraButton((button) => {
                    button
                        .setTooltip(t("delete"))
                        .setIcon("trash")
                        .onClick(() => {
                            this.filterTags = this.filterTags.filter(e => e !== this.filterTags[tag]);
                            this.display();
                        });

                });
        }

        let tagValue = "";
        let tagComponent: SearchComponent;
        const newTag = new Setting(tagDiv)
            .addSearch(async (search: SearchComponent) => {
                tagComponent = search;
                new ArraySuggest(this.app, search.inputEl, get(tagsStore));
                search
                    .onChange(async (value: string) => {
                        if (!value.match(TAG_REGEX) || value.match(NUMBER_REGEX) || value.contains(" ") || value.contains('#')) {
                            this.setValidationError(search, t("invalid_tag"));
                            return;
                        }
                        tagValue = value;
                    });
            }).addExtraButton(button => {
                button
                    .setTooltip(t("add"))
                    .setIcon("plus")
                    .onClick(() => {
                        if (!tagValue.match(TAG_REGEX) || tagValue.match(NUMBER_REGEX) || tagValue.contains(" ") || tagValue.contains('#')) {
                            this.setValidationError(tagComponent, t("invalid_tag"));
                            return;
                        }
                        this.filterTags.push(tagValue);
                        this.display();
                    });
            });
        newTag.controlEl.addClass("rss-setting-input");

        tagDiv.createEl("p", {text: t("filter_tags_ignore_help")});

        for (const tag in this.ignoreTags) {
            new Setting(tagDiv)
                .addSearch(async (search: SearchComponent) => {
                    new ArraySuggest(this.app, search.inputEl, get(tagsStore));
                    search
                        .setValue(this.ignoreTags[tag])
                        .onChange(async (value: string) => {
                            this.removeValidationError(search);
                            if (!value.match(TAG_REGEX) || value.match(NUMBER_REGEX) || value.contains(" ") || value.contains('#')) {
                                this.setValidationError(search, t("invalid_tag"));
                                return;
                            }
                            this.ignoreTags = this.ignoreTags.filter(e => e !== this.ignoreTags[tag]);
                            this.ignoreTags.push(value);
                        });
                })
                .addExtraButton((button) => {
                    button
                        .setTooltip(t("delete"))
                        .setIcon("trash")
                        .onClick(() => {
                            this.ignoreTags = this.ignoreTags.filter(e => e !== this.ignoreTags[tag]);
                            this.display();
                        });

                });
        }

        let ignoreTagValue = "";
        let ignoreTagComponent: SearchComponent;
        const newTagIgnore = new Setting(tagDiv)
            .addSearch(async (search: SearchComponent) => {
                ignoreTagComponent = search;
                new ArraySuggest(this.app, search.inputEl, get(tagsStore));
                search
                    .onChange(async (value: string) => {
                        if (!value.match(TAG_REGEX) || value.match(NUMBER_REGEX) || value.contains(" ") || value.contains('#')) {
                            this.setValidationError(search, t("invalid_tag"));
                            return;
                        }
                        ignoreTagValue = value;
                    });
            }).addExtraButton(button => {
                button
                    .setTooltip(t("add"))
                    .setIcon("plus")
                    .onClick(() => {
                        if (!ignoreTagValue.match(TAG_REGEX) || ignoreTagValue.match(NUMBER_REGEX) || ignoreTagValue.contains(" ") || ignoreTagValue.contains('#')) {
                            this.setValidationError(ignoreTagComponent, t("invalid_tag"));
                            return;
                        }
                        this.ignoreTags.push(ignoreTagValue);
                        this.display();
                    });
            });
        newTagIgnore.controlEl.addClass("rss-setting-input");


        //save & cancel

        const footerEl = contentEl.createDiv();
        const footerButtons = new Setting(footerEl);
        footerButtons.addButton((b) => {
            b.setTooltip(t("save"))
                .setIcon("checkmark")
                .onClick(async () => {
                    let error = false;
                    if(!nameText.getValue().length) {
                        this.setValidationError(nameText, t("invalid_name"));
                        error = true;
                    }

                    if(error) {
                        new Notice(t("fix_errors"));
                        return;
                    }
                    this.saved = true;
                    this.close();
                });
            return b;
        });
        footerButtons.addExtraButton((b) => {
            b.setIcon("cross")
                .setTooltip(t("cancel"))
                .onClick(() => {
                    this.saved = false;
                    this.close();
                });
            return b;
        });
    }