obsidian#TextAreaComponent TypeScript Examples

The following examples show how to use obsidian#TextAreaComponent. 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: settings.ts    From folder-note-core with MIT License 6 votes vote down vote up
constructor(public plugin: FNCore) {
    super(plugin.app);

    // Dropdowns
    this.fromOptsEl = new DropdownComponent(
      this.titleEl.createDiv({ text: "From:  " }),
    ).addOptions(LocDescMap);
    this.toOptsEl = new DropdownComponent(
      this.titleEl.createDiv({ text: "To:  " }),
    ).addOptions(LocDescMap);

    // Console output
    this.outputEl = new TextAreaComponent(this.contentEl)
      .setValue("Hello world")
      .setDisabled(true)
      .then((cb) => {
        cb.inputEl.style.width = "100%";
        cb.inputEl.rows = 10;
      });

    // Buttons
    this.buttonContainerEl = this.modalEl.createDiv({
      cls: "modal-button-container",
    });
    this.addButton((cb) =>
      cb.setButtonText("Check Conflicts").onClick(() => this.Convert(true)),
    );
    this.addButton((cb) =>
      cb
        .setButtonText("Convert")
        .setWarning()
        .onClick(() => this.Convert()),
    );
    this.addButton((cb) =>
      cb.setButtonText("Cancel").onClick(this.close.bind(this)),
    );
  }
Example #2
Source File: captureChoiceBuilder.ts    From quickadd with MIT License 6 votes vote down vote up
private addFormatSetting() {
        let textField: TextAreaComponent;
        const enableSetting = new Setting(this.contentEl);
        enableSetting.setName("Capture format")
            .setDesc("Set the format of the capture.")
            .addToggle(toggleComponent => {
                toggleComponent.setValue(this.choice.format.enabled)
                    .onChange(value => {
                        this.choice.format.enabled = value;
                        textField.setDisabled(!value);
                    })
            });

        const formatInput = new TextAreaComponent(this.contentEl);
        formatInput.setPlaceholder("Format");
        textField = formatInput;
        formatInput.inputEl.style.width = "100%";
        formatInput.inputEl.style.marginBottom = "8px";
        formatInput.inputEl.style.height = "10rem";
        formatInput.setValue(this.choice.format.format)
            .setDisabled(!this.choice.format.enabled)
            .onChange(async value => {
                this.choice.format.format = value;
                formatDisplay.innerText = await displayFormatter.format(value);
            });

        new FormatSyntaxSuggester(this.app, textField.inputEl, this.plugin);

        const formatDisplay: HTMLSpanElement = this.contentEl.createEl('span');
        const displayFormatter: FormatDisplayFormatter = new FormatDisplayFormatter(this.app, this.plugin);
        (async () => formatDisplay.innerText = await displayFormatter.format(this.choice.format.format))();
    }
Example #3
Source File: GenericWideInputPrompt.ts    From quickadd with MIT License 6 votes vote down vote up
protected createInputField(container: HTMLElement, placeholder?: string, value?: string) {
        const textComponent = new TextAreaComponent(container);

        textComponent.inputEl.classList.add('wideInputPromptInputEl');
        textComponent.setPlaceholder(placeholder ?? "")
            .setValue(value ?? "")
            .onChange(value => this.input = value)
            .inputEl.addEventListener('keydown', this.submitEnterCallback);

        return textComponent;
    }
Example #4
Source File: MathModal.ts    From quickadd with MIT License 6 votes vote down vote up
private display() {
        this.containerEl.addClass('quickAddModal', 'qaMathModal')
        this.contentEl.empty();

        const mathDiv = this.contentEl.createDiv();
        mathDiv.className = "math math-block is-loaded";

        const tc = new TextAreaComponent(this.contentEl);
        tc.inputEl.style.width = "100%";
        tc.inputEl.style.height = "10rem";

        this.inputEl = tc.inputEl;

        tc.onChange(debounce(async value => await this.mathjaxLoop(mathDiv, value), 50));

        tc.inputEl.addEventListener('keydown', this.keybindListener);

        this.createButtonBar(this.contentEl.createDiv());
    }
Example #5
Source File: sectionContentModal.ts    From obsidian_supercharged_links with MIT License 6 votes vote down vote up
onOpen(){
        this.titleEl.setText('Select the line before the field to add')
        const contentDiv = this.contentEl.createDiv()
        const inputDiv = contentDiv.createDiv()
        const inputEl = new TextAreaComponent(inputDiv)
        inputEl.inputEl.setAttr("cols", "50")
        inputEl.inputEl.setAttr("rows", "5")
        const footerDiv = contentDiv.createDiv({
            cls: "frontmatter-textarea-buttons"
        })
        const positionSelectorContainer = footerDiv.createDiv({
            cls: "position-selector-container"
        })
        const positionDropdown = new DropdownComponent(positionSelectorContainer)
        positionDropdown.addOption("1", "begining")
        positionDropdown.addOption("2", "end")
        positionDropdown.setValue("2")
        const saveButton = new ButtonComponent(footerDiv)
        saveButton
        .setIcon("checkmark")
        .onClick(() => {
            this.app.vault.read(this.file).then(result => {
                let newContent: string[] = []
                result.split("\n").forEach((line, lineNumber) =>{
                    newContent.push(line)
                    if(lineNumber == this.startLine && positionDropdown.getValue() == "1"){
                        newContent.push(inputEl.getValue())
                    }
                    if(lineNumber == this.startLine && positionDropdown.getValue() == "1"){
                        newContent.push(inputEl.getValue())
                    }
                })
            })
        })
        const cancelButton = new ExtraButtonComponent(footerDiv)
        cancelButton
        .setIcon("cross")
        .onClick(() => this.close())
    }
Example #6
Source File: settings.ts    From folder-note-core with MIT License 5 votes vote down vote up
outputEl: TextAreaComponent;
Example #7
Source File: GenericWideInputPrompt.ts    From quickadd with MIT License 5 votes vote down vote up
private inputComponent: TextAreaComponent;
Example #8
Source File: mockSetting.ts    From obsidian-switcher-plus with GNU General Public License v3.0 5 votes vote down vote up
addTextArea(cb: (component: TextAreaComponent) => any): this {
    cb(new MockTextAreaComponent(this.containerEl));
    return this;
  }
Example #9
Source File: mockSetting.ts    From obsidian-switcher-plus with GNU General Public License v3.0 5 votes vote down vote up
export class MockTextAreaComponent implements TextAreaComponent {
  inputEl: HTMLTextAreaElement;
  onChangeCB: (value: string) => any;

  constructor(public containerEl: HTMLElement) {
    this.inputEl = mock<HTMLTextAreaElement>();
  }

  getValue(): string {
    return this.inputEl.value;
  }

  setValue(value: string): this {
    this.inputEl.value = value;

    if (this.onChangeCB) {
      this.onChangeCB(value);
    }

    return this;
  }

  setPlaceholder(_placeholder: string): this {
    return this;
  }

  onChange(callback: (value: string) => any): this {
    this.onChangeCB = callback;
    return this;
  }

  setDisabled(_disabled: boolean): this {
    throw new Error('Method not implemented.');
  }
  onChanged(): void {
    throw new Error('Method not implemented.');
  }
  registerOptionListener(
    _listeners: Record<string, (value?: string) => string>,
    _key: string,
  ): this {
    throw new Error('Method not implemented.');
  }
  disabled: boolean;
  then(_cb: (component: this) => any): this {
    throw new Error('Method not implemented.');
  }
}
Example #10
Source File: event.ts    From obsidian-fantasy-calendar with MIT License 5 votes vote down vote up
buildInfo() {
        this.infoEl.empty();
        new Setting(this.infoEl)
            .setName("Note")
            .setDesc("Link the event to a note.")
            .addText((text) => {
                let files = this.app.vault.getFiles();
                text.setPlaceholder("Path");
                if (this.event.note) {
                    const [path, subpath] = this.event.note.split(/[#^]/);
                    const note = this.app.metadataCache.getFirstLinkpathDest(
                        path,
                        ""
                    );
                    if (note && note instanceof TFile) {
                        text.setValue(
                            `${note.basename}${subpath ? "#" : ""}${
                                subpath ? subpath : ""
                            }`
                        );
                    }
                }

                const modal = new PathSuggestionModal(this.app, text, [
                    ...files
                ]);

                modal.onClose = async () => {
                    text.inputEl.blur();

                    this.event.note = modal.link;

                    this.tryParse(modal.file);
                };
            });

        new Setting(this.infoEl).setName("Event Name").addText((t) =>
            t
                .setPlaceholder("Event Name")
                .setValue(this.event.name)
                .onChange((v) => {
                    this.event.name = v;
                })
        );

        const descriptionEl = this.infoEl.createDiv("event-description");
        descriptionEl.createEl("label", { text: "Event Description" });
        new TextAreaComponent(descriptionEl)
            .setPlaceholder("Event Description")
            .setValue(this.event.description)
            .onChange((v) => {
                this.event.description = v;
            });

        new Setting(this.infoEl).setName("Event Category").addDropdown((d) => {
            const options = Object.fromEntries(
                this.calendar.categories.map((category) => {
                    return [category.id, category.name];
                })
            );

            d.addOptions(options)
                .setValue(this.event.category)
                .onChange((v) => (this.event.category = v));
        });
    }
Example #11
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 #12
Source File: settingsTabSection.test.ts    From obsidian-switcher-plus with GNU General Public License v3.0 4 votes vote down vote up
describe('settingsTabSection', () => {
  let mockApp: MockProxy<App>;
  let mockPluginSettingTab: MockProxy<PluginSettingTab>;
  let mockConfig: MockProxy<SwitcherPlusSettings>;
  let mockContainerEl: MockProxy<HTMLElement>;
  let sut: SUT;

  beforeAll(() => {
    mockApp = mock<App>();
    mockContainerEl = mock<HTMLElement>();
    mockPluginSettingTab = mock<PluginSettingTab>({ containerEl: mockContainerEl });
    mockConfig = mock<SwitcherPlusSettings>();

    sut = sut = new SUT(mockApp, mockPluginSettingTab, mockConfig);
  });

  describe('createSetting', () => {
    it('should create a Setting with name and description', () => {
      const setNameSpy = jest.spyOn(Setting.prototype, 'setName');
      const setDescSpy = jest.spyOn(Setting.prototype, 'setDesc');
      const name = chance.word();
      const desc = chance.word();

      const setting = sut.createSetting(mock<HTMLElement>(), name, desc);

      expect(setting).not.toBeFalsy();
      expect(setNameSpy).toHaveBeenCalledWith(name);
      expect(setDescSpy).toHaveBeenCalledWith(desc);

      setNameSpy.mockRestore();
      setDescSpy.mockRestore();
    });
  });

  describe('addSectionTitle', () => {
    it('should display a header and divider for the section', () => {
      const title = chance.sentence();
      const desc = chance.sentence();
      const mockSetting = mock<Setting>();
      const createSettingSpy = jest.spyOn(SettingsTabSection.prototype, 'createSetting');
      createSettingSpy.mockReturnValue(mockSetting);

      sut.addSectionTitle(mockContainerEl, title, desc);

      expect(createSettingSpy).toHaveBeenCalledWith(mockContainerEl, title, desc);
      expect(mockSetting.setHeading).toHaveBeenCalled();

      createSettingSpy.mockRestore();
    });
  });

  describe('addTextSetting', () => {
    let mockSetting: MockProxy<Setting>;
    let mockTextComp: MockProxy<TextComponent>;
    let createSettingSpy: jest.SpyInstance;

    beforeAll(() => {
      mockSetting = mock<Setting>();
      mockTextComp = mock<TextComponent>();

      mockSetting.addText.mockImplementation((cb) => {
        cb(mockTextComp);
        return mockSetting;
      });

      createSettingSpy = jest.spyOn(SettingsTabSection.prototype, 'createSetting');
      createSettingSpy.mockReturnValue(mockSetting);
    });

    afterAll(() => {
      createSettingSpy.mockRestore();
    });

    it('should show the setting with the initial value', () => {
      const name = chance.sentence();
      const desc = chance.sentence();
      const initValue = 'init value';
      const placeholderValue = 'placeholder text';

      const result = sut.addTextSetting(
        mockContainerEl,
        name,
        desc,
        initValue,
        'editorListCommand',
        placeholderValue,
      );

      expect(result).not.toBeNull();
      expect(createSettingSpy).toHaveBeenCalledWith(mockContainerEl, name, desc);
      expect(mockTextComp.setValue).toHaveBeenCalledWith(initValue);
      expect(mockTextComp.setPlaceholder).toHaveBeenCalledWith(placeholderValue);
    });

    it('should save the modified setting', () => {
      mockConfig.editorListCommand = 'editor command';
      const finalValue = 'final value';

      let onChangeFn: (v: string) => void;
      mockTextComp.onChange.mockImplementationOnce((cb) => {
        onChangeFn = cb;
        return mockTextComp;
      });

      sut.addTextSetting(
        mockContainerEl,
        chance.word(),
        chance.sentence(),
        mockConfig.editorListCommand,
        'editorListCommand',
      );

      // trigger the value change here
      onChangeFn(finalValue);

      expect(mockTextComp.onChange).toHaveBeenCalled();
      expect(mockConfig.save).toHaveBeenCalled();
      expect(mockConfig.editorListCommand).toBe(finalValue);

      mockReset(mockConfig);
    });

    it('should fallback to the initial value when an empty string is set for the value', () => {
      const initValue = 'editor command';
      mockConfig.editorListCommand = initValue;

      let onChangeFn: (v: string) => void;
      mockTextComp.onChange.mockImplementationOnce((cb) => {
        onChangeFn = cb;
        return mockTextComp;
      });

      sut.addTextSetting(
        mockContainerEl,
        chance.word(),
        chance.sentence(),
        mockConfig.editorListCommand,
        'editorListCommand',
      );

      // trigger the value change here
      onChangeFn('');

      expect(mockTextComp.onChange).toHaveBeenCalled();
      expect(mockConfig.save).toHaveBeenCalled();
      expect(mockConfig.editorListCommand).toBe(initValue);

      mockReset(mockConfig);
    });
  });

  describe('addToggleSetting', () => {
    let mockSetting: MockProxy<Setting>;
    let mockToggleComp: MockProxy<ToggleComponent>;
    let createSettingSpy: jest.SpyInstance;

    beforeAll(() => {
      mockSetting = mock<Setting>();
      mockToggleComp = mock<ToggleComponent>();

      mockSetting.addToggle.mockImplementation((cb) => {
        cb(mockToggleComp);
        return mockSetting;
      });

      createSettingSpy = jest.spyOn(SettingsTabSection.prototype, 'createSetting');
      createSettingSpy.mockReturnValue(mockSetting);
    });

    afterAll(() => {
      createSettingSpy.mockRestore();
    });

    it('should show the setting with the initial value', () => {
      const name = chance.sentence();
      const desc = chance.sentence();
      const initValue = true;

      const result = sut.addToggleSetting(
        mockContainerEl,
        name,
        desc,
        initValue,
        'alwaysNewPaneForSymbols',
      );

      expect(result).not.toBeNull();
      expect(createSettingSpy).toHaveBeenCalledWith(mockContainerEl, name, desc);
      expect(mockToggleComp.setValue).toHaveBeenCalledWith(initValue);
    });

    it('should save the modified setting', () => {
      mockConfig.alwaysNewPaneForSymbols = false;
      const finalValue = true;

      let onChangeFn: (v: boolean) => void;
      mockToggleComp.onChange.mockImplementationOnce((cb) => {
        onChangeFn = cb;
        return mockToggleComp;
      });

      sut.addToggleSetting(
        mockContainerEl,
        chance.word(),
        chance.sentence(),
        mockConfig.alwaysNewPaneForSymbols,
        'alwaysNewPaneForSymbols',
      );

      // trigger the value change here
      onChangeFn(finalValue);

      expect(mockToggleComp.onChange).toHaveBeenCalled();
      expect(mockConfig.save).toHaveBeenCalled();
      expect(mockConfig.alwaysNewPaneForSymbols).toBe(finalValue);

      mockReset(mockConfig);
    });
  });

  describe('addTextAreaSetting', () => {
    let mockSetting: MockProxy<Setting>;
    let mockTextComp: MockProxy<TextAreaComponent>;
    let createSettingSpy: jest.SpyInstance;

    beforeAll(() => {
      mockSetting = mock<Setting>();
      mockTextComp = mock<TextAreaComponent>();

      mockSetting.addTextArea.mockImplementation((cb) => {
        cb(mockTextComp);
        return mockSetting;
      });

      createSettingSpy = jest.spyOn(SettingsTabSection.prototype, 'createSetting');
      createSettingSpy.mockReturnValue(mockSetting);
    });

    afterAll(() => {
      createSettingSpy.mockRestore();
    });

    it('should show the setting with the initial value', () => {
      const name = chance.sentence();
      const desc = chance.sentence();
      const initValue = 'init value';
      const placeholderValue = 'placeholder text';

      const result = sut.addTextAreaSetting(
        mockContainerEl,
        name,
        desc,
        initValue,
        'editorListCommand',
        placeholderValue,
      );

      expect(result).not.toBeNull();
      expect(createSettingSpy).toHaveBeenCalledWith(mockContainerEl, name, desc);
      expect(mockTextComp.setValue).toHaveBeenCalledWith(initValue);
      expect(mockTextComp.setPlaceholder).toHaveBeenCalledWith(placeholderValue);
    });

    it('should save the modified setting as string', () => {
      mockConfig.editorListCommand = 'editor command';
      const finalValue = 'final value';

      let onChangeFn: (v: string) => void;
      mockTextComp.onChange.mockImplementationOnce((cb) => {
        onChangeFn = cb;
        return mockTextComp;
      });

      sut.addTextAreaSetting(
        mockContainerEl,
        chance.word(),
        chance.sentence(),
        mockConfig.editorListCommand,
        'editorListCommand',
      );

      // trigger the value change here
      onChangeFn(finalValue);

      expect(mockTextComp.onChange).toHaveBeenCalled();
      expect(mockConfig.save).toHaveBeenCalled();
      expect(mockConfig.editorListCommand).toBe(finalValue);

      mockReset(mockConfig);
    });

    it('should save the modified setting as list', () => {
      mockConfig.includeSidePanelViewTypes = [chance.word()];
      const finalValue = [chance.word(), chance.word(), chance.word()];

      let onChangeFn: (v: string) => void;
      mockTextComp.onChange.mockImplementationOnce((cb) => {
        onChangeFn = cb;
        return mockTextComp;
      });

      sut.addTextAreaSetting(
        mockContainerEl,
        chance.word(),
        chance.sentence(),
        mockConfig.includeSidePanelViewTypes.join('\n'),
        'includeSidePanelViewTypes',
      );

      // trigger the value change here
      // Note: the onChange function takes a string and converts it to a list
      // by splitting on the newline '\n\
      onChangeFn(finalValue.join('\n'));

      expect(mockTextComp.onChange).toHaveBeenCalled();
      expect(mockConfig.save).toHaveBeenCalled();
      expect(mockConfig.includeSidePanelViewTypes).toEqual(finalValue);

      mockReset(mockConfig);
    });

    it('should fallback to the initial value when an empty string is set for the value', () => {
      const initValue = [chance.word()];
      mockConfig.includeSidePanelViewTypes = initValue;

      let onChangeFn: (v: string) => void;
      mockTextComp.onChange.mockImplementationOnce((cb) => {
        onChangeFn = cb;
        return mockTextComp;
      });

      sut.addTextAreaSetting(
        mockContainerEl,
        chance.word(),
        chance.sentence(),
        mockConfig.includeSidePanelViewTypes.join('\n'),
        'includeSidePanelViewTypes',
      );

      // trigger the value change here
      onChangeFn('');

      expect(mockTextComp.onChange).toHaveBeenCalled();
      expect(mockConfig.save).toHaveBeenCalled();
      expect(mockConfig.includeSidePanelViewTypes).toEqual(initValue);

      mockReset(mockConfig);
    });
  });
});
Example #13
Source File: settingsTab.ts    From obsidian-map-view with GNU General Public License v3.0 4 votes vote down vote up
refreshMarkerIcons(containerEl: HTMLElement) {
        containerEl.innerHTML = '';
        let jsonControl: TextAreaComponent = null;
        let rulesDiv = containerEl.createDiv();
        // The functions to update all icons, needed when the default rule changes
        let iconUpdateFunctions: (() => void)[] = [];
        const createRules = () => {
            rulesDiv.innerHTML = '';
            const rules = this.plugin.settings.markerIconRules;
            for (const rule of rules) {
                // Assign each icon on the default one, so the preview will show how it looks when the icon properties
                // override the default one
                const setting = new Setting(rulesDiv)
                    .addText(
                        (component) =>
                            (component
                                .setPlaceholder('Tag name')
                                .setDisabled(rule.preset)
                                .setValue(rule.ruleName)
                                .onChange(async (value) => {
                                    rule.ruleName = value;
                                    await this.plugin.saveSettings();
                                    updateIconAndJson();
                                }).inputEl.style.width = '10em')
                    )
                    .addText(
                        (component) =>
                            (component
                                .setPlaceholder('Icon name')
                                .setValue(rule.iconDetails.icon ?? '')
                                .onChange(async (value) => {
                                    if (value) rule.iconDetails.icon = value;
                                    else delete rule.iconDetails.icon;
                                    await this.plugin.saveSettings();
                                    if (rule.preset)
                                        iconUpdateFunctions.forEach((update) =>
                                            update()
                                        );
                                    else updateIconAndJson();
                                }).inputEl.style.width = '8em')
                    )
                    .addText(
                        (component) =>
                            (component
                                .setPlaceholder('Color name')
                                .setValue(rule.iconDetails.markerColor ?? '')
                                .onChange(async (value) => {
                                    if (value)
                                        rule.iconDetails.markerColor = value;
                                    else delete rule.iconDetails.markerColor;
                                    await this.plugin.saveSettings();
                                    if (rule.preset)
                                        iconUpdateFunctions.forEach((update) =>
                                            update()
                                        );
                                    else updateIconAndJson();
                                }).inputEl.style.width = '8em')
                    )
                    .addText(
                        (component) =>
                            (component
                                .setPlaceholder('Shape')
                                .setValue(rule.iconDetails.shape ?? '')
                                .onChange(async (value) => {
                                    if (value) rule.iconDetails.shape = value;
                                    else delete rule.iconDetails.shape;
                                    await this.plugin.saveSettings();
                                    if (rule.preset)
                                        iconUpdateFunctions.forEach((update) =>
                                            update()
                                        );
                                    else updateIconAndJson();
                                }).inputEl.style.width = '6em')
                    );
                setting.settingEl.style.padding = '5px';
                setting.settingEl.style.borderTop = 'none';
                if (!rule.preset) {
                    setting.addButton((component) =>
                        component
                            .setButtonText('Delete')
                            .onClick(async () => {
                                rules.remove(rule);
                                await this.plugin.saveSettings();
                                this.refreshMarkerIcons(containerEl);
                            })
                            .buttonEl.classList.add('settings-dense-button')
                    );
                    const ruleIndex = rules.indexOf(rule);
                    setting.addButton((component) =>
                        component
                            .setButtonText('\u2191')
                            .onClick(async () => {
                                // Move up
                                if (ruleIndex > 1) {
                                    rules.splice(ruleIndex, 1);
                                    rules.splice(ruleIndex - 1, 0, rule);
                                    await this.plugin.saveSettings();
                                    this.refreshMarkerIcons(containerEl);
                                }
                            })
                            .buttonEl.classList.add('settings-dense-button')
                    );
                    setting.addButton((component) =>
                        component
                            .setButtonText('\u2193')
                            .onClick(async () => {
                                // Move down
                                if (ruleIndex < rules.length - 1) {
                                    rules.splice(ruleIndex, 1);
                                    rules.splice(ruleIndex + 1, 0, rule);
                                    await this.plugin.saveSettings();
                                    this.refreshMarkerIcons(containerEl);
                                }
                            })
                            .buttonEl.classList.add('settings-dense-button')
                    );
                }
                let iconElement: HTMLElement = null;
                const updateIconAndJson = () => {
                    if (iconElement) setting.controlEl.removeChild(iconElement);
                    const compiledIcon = getIconFromOptions(
                        Object.assign(
                            {},
                            rules.find(
                                (element) => element.ruleName === 'default'
                            ).iconDetails,
                            rule.iconDetails
                        )
                    );
                    iconElement = compiledIcon.createIcon();
                    let style = iconElement.style;
                    style.marginLeft = style.marginTop = '0';
                    style.position = 'relative';
                    setting.controlEl.append(iconElement);
                    if (jsonControl)
                        jsonControl.setValue(
                            JSON.stringify(
                                this.plugin.settings.markerIconRules,
                                null,
                                2
                            )
                        );
                };
                iconUpdateFunctions.push(updateIconAndJson);
                updateIconAndJson();
            }
            let multiTagIconElement: HTMLElement = null;
            let testTagsBox: TextComponent = null;
            const ruleTestSetting = new Setting(containerEl)
                .setName('Marker preview tester')
                .addText((component) => {
                    component
                        .setPlaceholder('#tagOne #tagTwo')
                        .onChange((value) => {
                            updateMultiTagPreview();
                        });
                    testTagsBox = component;
                });
            const updateMultiTagPreview = () => {
                if (multiTagIconElement)
                    ruleTestSetting.controlEl.removeChild(multiTagIconElement);
                const compiledIcon = getIconFromRules(
                    testTagsBox.getValue().split(' '),
                    rules
                );
                multiTagIconElement = compiledIcon.createIcon();
                let style = multiTagIconElement.style;
                style.marginLeft = style.marginTop = '0';
                style.position = 'relative';
                ruleTestSetting.controlEl.append(multiTagIconElement);
            };
            updateMultiTagPreview();
        };
        createRules();
        new Setting(containerEl)
            .setName('Edit marker icons as JSON (advanced)')
            .setDesc(
                'Use this for advanced settings not controllable by the GUI above. Beware - uncareful edits can get Map View to faulty behaviors!'
            )
            .addTextArea((component) => {
                component
                    .setValue(
                        JSON.stringify(
                            this.plugin.settings.markerIconRules,
                            null,
                            2
                        )
                    )
                    .onChange(async (value) => {
                        try {
                            const newMarkerIcons = JSON.parse(value);
                            this.plugin.settings.markerIconRules =
                                newMarkerIcons;
                            await this.plugin.saveSettings();
                            createRules();
                        } catch (e) {}
                    });
                jsonControl = component;
            });
    }
Example #14
Source File: settings-tab.ts    From better-word-count with MIT License 4 votes vote down vote up
display(): void {
    let { containerEl } = this;

    containerEl.empty();
    containerEl.createEl("h2", { text: "Better Word Count Settings" });

    // General Settings
    containerEl.createEl("h3", { text: "General Settings" });
    new Setting(containerEl)
      .setName("Collect Statistics")
      .setDesc(
        "Reload Required for change to take effect. Turn on to start collecting daily statistics of your writing. Stored in the .vault-stats file in the root of your vault. This is required for counts of the day."
      )
      .addToggle((cb: ToggleComponent) => {
        cb.setValue(this.plugin.settings.collectStats);
        cb.onChange(async (value: boolean) => {
          this.plugin.settings.collectStats = value;
          await this.plugin.saveSettings();
        });
      });
    new Setting(containerEl)
      .setName("Don't Count Comments")
      .setDesc("Turn on if you don't want markdown comments to be counted.")
      .addToggle((cb: ToggleComponent) => {
        cb.setValue(this.plugin.settings.countComments);
        cb.onChange(async (value: boolean) => {
          this.plugin.settings.countComments = value;
          await this.plugin.saveSettings();
        });
      });

    // Status Bar Settings
    containerEl.createEl("h3", { text: "Status Bar Settings" });
    new Setting(containerEl)
      .setName("Select a Preset")
      .setDesc(
        "Presets are premade status bar expressions. Overides status bar settings."
      )
      .addDropdown((cb: DropdownComponent) => {
        PRESETS.forEach((preset: PresetOption) => {
          cb.addOption(preset.name, preset.name);
        });
        cb.setValue(this.plugin.settings.preset.name);

        cb.onChange(async (value: string) => {
          let newPreset = PRESETS.find((preset) => preset.name === value);
          this.plugin.settings.preset = newPreset;
          this.plugin.settings.statusBarQuery = newPreset.statusBarQuery;
          this.plugin.settings.statusBarAltQuery = newPreset.statusBarAltQuery;
          await this.plugin.saveSettings();
        });
      });
    new Setting(containerEl)
      .setName("Status Bar Text")
      .setDesc("Customize the Status Bar text with this.")
      .addTextArea((cb: TextAreaComponent) => {
        cb.setPlaceholder("Enter an expression...");
        cb.setValue(this.plugin.settings.statusBarQuery);
        cb.onChange((value: string) => {
          let newPreset = PRESETS.find((preset) => preset.name === "custom");
          this.plugin.settings.preset = newPreset;
          this.plugin.settings.statusBarQuery = value;
          this.plugin.saveSettings();
        });
      });
    new Setting(containerEl)
      .setName("Alternative Status Bar Text")
      .setDesc("Customize the Alternative Status Bar text with this.")
      .addTextArea((cb: TextAreaComponent) => {
        cb.setPlaceholder("Enter an expression...");
        cb.setValue(this.plugin.settings.statusBarAltQuery);
        cb.onChange((value: string) => {
          let newPreset = PRESETS.find((preset) => preset.name === "custom");
          this.plugin.settings.preset = newPreset;
          this.plugin.settings.statusBarAltQuery = value;
          this.plugin.saveSettings();
        });
      });

    this.containerEl.createEl("h3", {
      text: "Syntax for the status bars works like this: ",
    });

    this.containerEl.createEl("li", {
      text: "To get a stat input the name of the stat in between `{}` eg. `{word_count}`.",
    });

    this.containerEl.createEl("li", {
      text: "All other words remain.",
    });

    this.containerEl.createEl("br");

    this.containerEl.createEl("h4", {
      text: "Available Stats:",
    });

    this.containerEl.createEl("p", {
      text:
        "word_count, " +
        "character_count, " +
        "sentence_count, " +
        "total_word_count, " +
        "total_character_count, " +
        "total_sentence_count, " +
        "file_count, " +
        "words_today, " +
        "characters_today, " +
        "sentences_today, ",
    });
  }
Example #15
Source File: FileClassAttributeModal.ts    From obsidian_supercharged_links with MIT License 4 votes vote down vote up
onOpen(){
        //title
        this.titleEl.setText(this.attr ? `Manage ${this.attr.name}` : `Create a new attribute for ${this.fileClass.name}`)
        
        //name input
        const nameInputContainer = this.contentEl.createDiv()
        nameInputContainer.setText("name")
        const nameInput = new TextComponent(nameInputContainer)
        this.attr ? nameInput.setValue(this.attr.name) : nameInput.setPlaceholder("Type a name for this attribute")

        //header for select
        const typeSelectHeader = this.contentEl.createDiv()
        const attrLine = typeSelectHeader.createEl("div")
        const attrName = attrLine.createEl("strong")
        attrName.setText(`<${this.name}>`)
        attrLine.append(" fields in files with:")
        String(`---\nfileClass: ${this.fileClass.name}\n...\n---`).split('\n').forEach(line => {
            typeSelectHeader.createEl("div", "yaml-frontmatter-red").setText(line)
        })

        // type select
        const typeSelectContainer = this.contentEl.createDiv({cls: 'frontmatter-value-selector-container'})
        const typeSelectLabel = typeSelectContainer.createDiv({cls: 'frontmatter-value-selector-inline-label'})
        typeSelectLabel.setText("will: ")
        const typeSelectDropDown = typeSelectContainer.createDiv({cls: 'frontmatter-value-selector-toggler'})
        const typeSelect = new DropdownComponent(typeSelectDropDown)
        Object.keys(types).forEach(key => {
            typeSelect.addOption(key, types[key])
        })
        if(this.attr){
            typeSelect.setValue(this.type)
        }

        // options input
        const optionsInputContainer = this.contentEl.createDiv({cls: 'frontmatter-value-selector-container'})
        const optionsInputLabel = optionsInputContainer.createDiv({cls: 'frontmatter-value-selector-inline-label-top'})
        optionsInputLabel.setText("Values")
        const optionsInput = new TextAreaComponent(optionsInputContainer)
        optionsInput.inputEl.rows = 3
        optionsInput.inputEl.cols = 26
        this.attr ? optionsInput.setValue(this.type == "input" ? "" : this.options.join(", ")) : optionsInput.setPlaceholder("insert values, comma separated")
        !this.attr || this.type == "input" ? optionsInputContainer.hide() : optionsInputContainer.show()

        // event handlers
        typeSelect.onChange(type => {
            type == "input" ? optionsInputContainer.hide() : optionsInputContainer.show()
            this.type = type
        })
        optionsInput.onChange(value => this.options = value.split(",").map(item => item.trim()))
        nameInput.onChange(value => {this.name = value; attrName.setText(`<${value}>`)})

        // footer buttons
        const footer = this.contentEl.createDiv({cls: "frontmatter-value-grid-footer"})
        const saveButton = new ButtonComponent(footer)
        saveButton.setIcon("checkmark")
        saveButton.onClick(() => {
            this.fileClass.updateAttribute(this.type, this.options, this.name, this.attr)
            this.close()
        })
        if(this.attr){
            const removeButton = new ButtonComponent(footer)
            removeButton.setIcon("trash")
            removeButton.onClick(() => {
                const confirmModal = new Modal(this.app)
                confirmModal.titleEl.setText("Please confirm")
                confirmModal.contentEl.createDiv().setText(`Do you really want to remove ${this.attr.name} attribute from ${this.fileClass.name}?`)
                const confirmFooter = confirmModal.contentEl.createDiv({cls: "frontmatter-value-grid-footer"})
                const confirmButton = new ButtonComponent(confirmFooter)
                confirmButton.setIcon("checkmark")
                confirmButton.onClick(() => {
                    this.fileClass.removeAttribute(this.attr)
                    confirmModal.close()
                    this.close()
                })
                const dismissButton = new ExtraButtonComponent(confirmFooter)
                dismissButton.setIcon("cross")
                dismissButton.onClick(() => this.close())
                confirmModal.open()
            })
        }
        const cancelButton = new ExtraButtonComponent(footer)
        cancelButton.setIcon("cross")
        cancelButton.onClick(() => this.close())
    }