obsidian#Modal TypeScript Examples

The following examples show how to use obsidian#Modal. 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: FileClassAttributeSelectModal.ts    From obsidian_supercharged_links with MIT License 7 votes vote down vote up
export default class FileClassAttributeSelectModal extends Modal{

    plugin: SuperchargedLinks
    file: TFile

    constructor(plugin: SuperchargedLinks, file: TFile){
        super(plugin.app)
        this.file = file
        this.plugin = plugin
    }

    onOpen(){
        this.titleEl.setText(`Select the field to update`)
        createFileClass(this.plugin, this.file.basename).then(fileClass => {
            this.titleEl.setText(`Select the field to update in ${fileClass.name}`)
            const selectContainer = this.contentEl.createDiv()
            const select = new DropdownComponent(selectContainer)
            select.addOption("select an attribute", "--select an attribute--")
            fileClass.attributes.forEach(attr => {
                select.addOption(attr.name, attr.name)
            })

            select.addOption("++newAttr++", "++Add a new attribute++")
            select.onChange((attrName) => {
                if(attrName == "++newAttr"){
                    const modal = new FileClassAttributeModal(this.plugin.app, fileClass)
                    modal.open()
                    this.close()
                } else {
                    const modal = new FileClassAttributeModal(this.plugin.app, fileClass, fileClass.attributes.filter(attr => attr.name == attrName)[0])
                    modal.open()
                    this.close()
                }
            })
        })
    }
}
Example #2
Source File: switcherPlusSettingTab.ts    From obsidian-switcher-plus with GNU General Public License v3.0 6 votes vote down vote up
private validateExcludeFolderList(settingName: string, excludes: string[]) {
    let isValid = true;
    let failedMsg = '';

    for (const str of excludes) {
      try {
        new RegExp(str);
      } catch (err) {
        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
        failedMsg += `<span class="qsp-warning">${str}</span><br/>${err}<br/><br/>`;
        isValid = false;
      }
    }

    if (!isValid) {
      const popup = new Modal(this.app);
      popup.titleEl.setText(settingName);
      popup.contentEl.innerHTML = `Changes not saved. The following regex contain errors:<br/><br/>${failedMsg}`;
      popup.open();
    }

    return isValid;
  }
Example #3
Source File: modal.ts    From obsidian-calendar-plugin with MIT License 6 votes vote down vote up
export class ConfirmationModal extends Modal {
  constructor(app: App, config: IConfirmationDialogParams) {
    super(app);

    const { cta, onAccept, text, title } = config;

    this.contentEl.createEl("h2", { text: title });
    this.contentEl.createEl("p", { text });

    this.contentEl.createDiv("modal-button-container", (buttonsEl) => {
      buttonsEl
        .createEl("button", { text: "Never mind" })
        .addEventListener("click", () => this.close());

      buttonsEl
        .createEl("button", {
          cls: "mod-cta",
          text: cta,
        })
        .addEventListener("click", async (e) => {
          await onAccept(e);
          this.close();
        });
    });
  }
}
Example #4
Source File: MessageModal.ts    From obsidian-rss with GNU General Public License v3.0 6 votes vote down vote up
export class MessageModal extends Modal {

    message: string;

    constructor(plugin: RssReaderPlugin, message: string) {
        super(plugin.app);
        this.message = message;
    }

    onOpen() : void {
        this.display();
    }

    display() : void {
        const {contentEl} = this;

        contentEl.empty();

        contentEl.createEl("h1", {text: this.message});
        contentEl.createEl("p", {text: t("do_not_close")});
    }

    setMessage(message: string) : void {
        this.message = message;
        this.display();
    }

}
Example #5
Source File: valueToggleModal.ts    From obsidian_supercharged_links with MIT License 6 votes vote down vote up
export default class valueToggleModal extends Modal {
    app: App
    file: TFile
    name: string
    value: boolean

    constructor(app: App, file: TFile, name: string, value: boolean){
        super(app)
        this.app = app
        this.file = file
        this.name = name
        this.value = value
    }

    onOpen(){
        const inputDiv = this.contentEl.createDiv({
            cls: "frontmatter-toggler"
        })
        this.buildInputEl(inputDiv)
    }

    buildInputEl(inputDiv: HTMLDivElement): void{
        const inputEl = new ToggleComponent(inputDiv)
        inputEl.setValue(this.value)
        inputEl.onChange(v => {
            replaceValues(this.app, this.file, this.name, v ? "true" : "false")
        })
    }
}
Example #6
Source File: enterTokenModal.ts    From obsidian-todoist-plugin with MIT License 6 votes vote down vote up
export default class TodoistApiTokenModal extends Modal {
  public token: string;
  public waitForClose: Promise<void>;

  private resolvePromise: () => void;

  private modalContent: EnterTokenModalContent;

  constructor(app: App) {
    super(app);

    this.token = "";
    this.waitForClose = new Promise(
      (resolve) => (this.resolvePromise = resolve)
    );

    this.titleEl.innerText = "Setup Todoist API token";

    this.modalContent = new EnterTokenModalContent({
      target: this.contentEl,
      props: {
        onSubmit: (value: string) => {
          this.token = value;
          this.close();
        },
      },
    });

    this.open();
  }

  onClose() {
    super.onClose();
    this.modalContent.$destroy();
    this.resolvePromise();
  }
}
Example #7
Source File: NoteFieldsCommandsModal.ts    From obsidian_supercharged_links with MIT License 6 votes vote down vote up
export default class NoteFieldsCommandsModal extends Modal {
    public app: App;
    private plugin: SuperchargedLinks;
    private file: TFile
    private select: SelectModal
    optionsList: OptionsList

    constructor(app: App, plugin: SuperchargedLinks, file: TFile) {
        super(app);
        this.app = app;
        this.plugin = plugin;
        this.file = file
    }

    onOpen(){
        this.titleEl.setText(`Select the field to manage`)
        const optionsListContainer = this.contentEl.createDiv()
        this.select = new SelectModal(optionsListContainer)
        this.select.addOption("---", "Choose Field")
        this.optionsList = new OptionsList(this.plugin, this.file, this.select)
        this.optionsList.createExtraOptionList()
        this.select.onChange((value) => {
            this.select.modals[value]()
            this.close()
        })
        this.select.selectEl.focus()
    }
}
Example #8
Source File: creationHelperModal.ts    From obsidian-charts with GNU Affero General Public License v3.0 6 votes vote down vote up
export class CreationHelperModal extends Modal {
	view: MarkdownView;
	settings: ChartPluginSettings;
	renderer: Renderer;

	constructor(app: App, view: MarkdownView, settings: ChartPluginSettings, renderer: Renderer) {
		super(app);
		this.settings = settings;
		this.view = view;
		this.renderer = renderer;
	}

	onOpen() {
		let { contentEl, view, settings, renderer} = this;
		contentEl.empty();
		const modal = new HelperModal({target: contentEl, props: {editor: view.editor, renderer}});
		modal.$on('close', () => this.close());
	}

	onClose() {
		let { contentEl } = this;
		contentEl.empty();
	}
}
Example #9
Source File: localDictionaryBuilder.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 6 votes vote down vote up
class OverwriteModal extends Modal {
    path: string;
    content: string;
    openNote: boolean;

    constructor(plugin: DictionaryPlugin, path: string, content: string, openNote: boolean) {
        super(plugin.app);
        this.path = path;
        this.content = content;
        this.openNote = openNote;
    }

    onOpen() {
        this.contentEl.appendChild(createEl("p", { text: t("A existing File with the same Name was found, do you want to overwrite it?"), cls: "dictionarycenter" }));
        const buttonDiv = this.contentEl.appendChild(createDiv({ cls: "dictionarybuttons" }))
        buttonDiv.appendChild(createEl("button", { text: t("Yes, overwrite the old File."), cls: "mod-cta" })).onClickEvent(async () => {
            this.app.vault.modify(this.app.vault.getAbstractFileByPath(this.path) as TFile, this.content);
            let oldPaneOpen = false;
            this.app.workspace.iterateAllLeaves((leaf) => {
                if (leaf.view instanceof MarkdownView) {
                    if ((leaf.getViewState().state.file as string).endsWith(this.path)) {
                        oldPaneOpen = true;
                        this.app.workspace.setActiveLeaf(leaf);
                    }
                }
            });
            if (!oldPaneOpen && this.openNote) {
                const leaf = this.app.workspace.splitActiveLeaf();
                await leaf.openFile(this.app.vault.getAbstractFileByPath(this.path) as TFile);
                this.app.workspace.setActiveLeaf(leaf);
            }
            this.close();
        });
        buttonDiv.appendChild(createEl("button", { text: t("No, keep the old File."), cls: "mod-cta" })).onClickEvent(() => {
            this.close();
        });
    }
}
Example #10
Source File: main.ts    From obsidian-linter with MIT License 6 votes vote down vote up
// https://github.com/nothingislost/obsidian-workspaces-plus/blob/bbba928ec64b30b8dec7fe8fc9e5d2d96543f1f3/src/modal.ts#L68
class LintConfirmationModal extends Modal {
  constructor(app: App, startModalMessageText: string, submitBtnText: string,
      submitBtnNoticeText: string, btnSubmitAction: () => Promise<void>) {
    super(app);
    this.modalEl.addClass('confirm-modal');

    this.contentEl.createEl('h3', {text: 'Warning'});

    const e: HTMLParagraphElement = this.contentEl.createEl('p',
        {text: startModalMessageText + ' Make sure you have backed up your files.'});
    e.id = 'confirm-dialog';

    this.contentEl.createDiv('modal-button-container', (buttonsEl) => {
      buttonsEl.createEl('button', {text: 'Cancel'}).addEventListener('click', () => this.close());

      const btnSumbit = buttonsEl.createEl('button', {
        attr: {type: 'submit'},
        cls: 'mod-cta',
        text: submitBtnText,
      });
      btnSumbit.addEventListener('click', async (e) => {
        new Notice(submitBtnNoticeText);
        this.close();
        await btnSubmitAction();
      });
      setTimeout(() => {
        btnSumbit.focus();
      }, 50);
    });
  }
}
Example #11
Source File: apiTokenModal.ts    From obsidian-hypothesis-plugin with MIT License 6 votes vote down vote up
export default class ApiTokenModal extends Modal {
    public waitForClose: Promise<void>;
    private resolvePromise: () => void;
    private modalContent: ApiTokenModalContent;
    private tokenManager: TokenManager;

    constructor(app: App, tokenManager: TokenManager) {
        super(app);

        this.tokenManager = tokenManager;
        this.waitForClose = new Promise(
            (resolve) => (this.resolvePromise = resolve)
        );

        this.titleEl.innerText = "Enter Hypothesis API token";

        this.modalContent = new ApiTokenModalContent({
            target: this.contentEl,
            props: {
                onSubmit: async (value: string) => {
                    await this.tokenManager.setToken(value);
                    this.close();
                },
            },
        });

        this.open();
    }

    onClose() {
        super.onClose();
        this.modalContent.$destroy();
        this.resolvePromise();
    }
}
Example #12
Source File: confirm.ts    From obsidian-admonition with MIT License 6 votes vote down vote up
export class ConfirmModal extends Modal {
    constructor(
        app: App,
        public text: string,
        public buttons: { cta: string; secondary: string }
    ) {
        super(app);
    }
    confirmed: boolean = false;
    async display() {
        this.contentEl.empty();
        this.contentEl.addClass("confirm-modal");
        this.contentEl.createEl("p", {
            text: this.text
        });
        const buttonEl = this.contentEl.createDiv(
            "fantasy-calendar-confirm-buttons"
        );
        new ButtonComponent(buttonEl)
            .setButtonText(this.buttons.cta)
            .setCta()
            .onClick(() => {
                this.confirmed = true;
                this.close();
            });
        new ButtonComponent(buttonEl)
            .setButtonText(this.buttons.secondary)
            .onClick(() => {
                this.close();
            });
    }
    onOpen() {
        this.display();
    }
}
Example #13
Source File: settings.ts    From obsidian-initiative-tracker with GNU General Public License v3.0 6 votes vote down vote up
export class ConfirmModal extends Modal {
    constructor(
        app: App,
        public text: string,
        public buttons: { cta: string; secondary: string }
    ) {
        super(app);
    }
    confirmed: boolean = false;
    async display() {
        new Promise((resolve) => {
            this.contentEl.empty();
            this.contentEl.addClass("confirm-modal");
            this.contentEl.createEl("p", {
                text: this.text
            });
            const buttonEl = this.contentEl.createDiv(
                "fantasy-calendar-confirm-buttons"
            );
            new ButtonComponent(buttonEl)
                .setButtonText(this.buttons.cta)
                .setCta()
                .onClick(() => {
                    this.confirmed = true;
                    this.close();
                });
            new ButtonComponent(buttonEl)
                .setButtonText(this.buttons.secondary)
                .onClick(() => {
                    this.close();
                });
        });
    }
    onOpen() {
        this.display();
    }
}
Example #14
Source File: resyncDelFileModal.ts    From obsidian-hypothesis-plugin with MIT License 5 votes vote down vote up
export default class ResyncDelFileModal extends Modal {
    private syncHypothesis!: SyncHypothesis;
    public waitForClose: Promise<void>;
    private resolvePromise: () => void;
    private modalContent: ResyncDelFileModalContent;
    private vault: Vault;
    private fileManager: FileManager

    constructor(app: App) {
        super(app);
        this.vault = app.vault;
        this.fileManager = new FileManager(this.vault, this.app.metadataCache);

        this.waitForClose = new Promise(
            (resolve) => (this.resolvePromise = resolve)
        );

        this.open();

    }

    async onOpen() {
        super.onOpen()
		this.syncHypothesis = new SyncHypothesis(this.fileManager);
        const deletedFiles = await this.retrieveDeletedFiles();

        this.titleEl.innerText = "Hypothes.is: Resync deleted file(s)";

        this.modalContent = new ResyncDelFileModalContent({
            target: this.contentEl,
            props: {
                deletedFiles: deletedFiles,
                onSubmit: async (value: { selected }) => {
                    if((!!value.selected) && value.selected.length > 0 ){
                        this.startResync(value.selected)
                    } else{
                        console.log('No files selected')
                    }
                    this.close();
                },
            },
        });

    }

    onClose() {
        super.onClose();
        this.modalContent.$destroy();
        this.resolvePromise();
    }

    async retrieveDeletedFiles(): Promise<SyncedFile[]> {
        const token = get(settingsStore).token;
        const userid = get(settingsStore).user;
        const apiManager = new ApiManager(token, userid);

        // Fetch all annotated articles that *should* be present
        const allAnnotations = await apiManager.getHighlights()
        const allArticles: [] = Object.values(await parseSyncResponse(allAnnotations));

        // Check which files are actually present
        const deletedArticles = await Promise.all(allArticles.filter(async article => !(await this.fileManager.isArticleSaved(article))));
        return deletedArticles.map((article: Article) => 
            ({ uri: article.metadata.url, filename: this.fileManager.getNewArticleFilePath(article)})
        );
    }

    async startResync(selectedFiles: SyncedFile[]): Promise<void> {
        selectedFiles.forEach(async selected => {
		console.log(`Start resync deleted file - ${selected.filename}`)
		await this.syncHypothesis.startSync(selected.uri);
        })
	}
}
Example #15
Source File: chooseSectionModal.ts    From obsidian_supercharged_links with MIT License 5 votes vote down vote up
export default class chooseSectionModal extends Modal {

    plugin: SuperchargedLinks
    file: TFile

    constructor(plugin: SuperchargedLinks, file:TFile){
        super(plugin.app)
        this.file = file
        this.plugin = plugin
    }

    onOpen(){
        this.titleEl.setText("Add a field in this note after:")
        const inputDiv = this.contentEl.createDiv({
            cls: "frontmatter-modal-value"
        })
        const selectEl = new DropdownComponent(inputDiv)
        selectEl.selectEl.addClass("frontmatter-select")
        selectEl.addOption("","Select line")
        selectEl.addOption("top_0","top")
        this.app.vault.read(this.file).then(result => {
			let foreHeadText = false
			let frontmatterStart = false
			let frontmatterEnd = false
			let inFrontmatter = false
            result.split("\n").forEach((line, lineNumber) => {
                if(line!="---" && !foreHeadText && !frontmatterStart){
					foreHeadText = true
				}
				if(line == "---" && !foreHeadText){
					if(!frontmatterStart){
						frontmatterStart = true
						inFrontmatter = true
					} else if(!frontmatterEnd){
						frontmatterEnd = true
						inFrontmatter = false
					}
				}
				if(inFrontmatter){
                    selectEl.addOption(`frontmatter_${lineNumber}`, `${line.substring(0, 30)}${line.length > 30 ? "..." : ""}`)
                }else{
                    selectEl.addOption(`body_${lineNumber}`, `${line.substring(0, 30)}${line.length > 30 ? "..." : ""}`)
                }
            })
            selectEl.onChange(value => {
                const valueArray = selectEl.getValue().match(/(\w+)_(\d+)/)
                const position = valueArray[1]
                const lineNumber = Number(valueArray[2])
                const inFrontmatter = position == "frontmatter" ? true : false
                const top = position == "top" ? true : false
                const modal = new fieldSelectModal(this.plugin, this.file, lineNumber, result.split('\n')[lineNumber], inFrontmatter, top)
                this.close()
                modal.open()
            })
        })
    }
}
Example #16
Source File: main.ts    From luhman-obsidian-plugin with GNU General Public License v3.0 5 votes vote down vote up
class NewZettelModal extends Modal {
  public completion: (text: string) => void;
  private textBox: HTMLInputElement;

  constructor(app: App, completion: (title: string) => void) {
    super(app);
    this.completion = completion;

    let { contentEl } = this;
    contentEl.parentElement!.addClass("zettel-modal");
    this.titleEl.setText("New zettel title...");

    let container = contentEl.createEl("div", {
      cls: "zettel-modal-container",
    });
    this.textBox = contentEl.createEl("input", {
      type: "text",
      cls: "zettel-modal-textbox",
    });
    this.textBox.id = "zettel-modal-textbox";
    this.textBox.addEventListener("keydown", (event) => {
      if (event.key == "Enter") {
        event.preventDefault();
        this.goTapped();
      }
    });
    container.append(this.textBox);

    let button = contentEl.createEl("input", {
      type: "button",
      value: "GO",
      cls: "zettel-modal-button",
    });
    button.addEventListener("click", (e: Event) => this.goTapped());
    container.append(button);

    contentEl.append(container);
  }

  onOpen() {
    window.setTimeout(() => {
      this.textBox.focus();
    }, 0);
  }

  goTapped() {
    let title = this.textBox.value;
    this.completion(title);
    this.close();
  }
}
Example #17
Source File: manageGroupsModal.ts    From obsidian-hypothesis-plugin with MIT License 5 votes vote down vote up
export default class ManageGroupsModal extends Modal {
    public waitForClose: Promise<void>;
    private resolvePromise: () => void;
    private modalContent: ManageGroupsModalContent;
    vault: Vault;

    constructor(app: App) {
        super(app);

        this.waitForClose = new Promise(
            (resolve) => (this.resolvePromise = resolve)
        );

        this.open();

    }

    async onOpen() {
        super.onOpen()
        const groups = get(settingsStore).groups;

        this.titleEl.innerText = "Hypothes.is: Manage groups to be synced";

        this.modalContent = new ManageGroupsModalContent({
            target: this.contentEl,
            props: {
                groups: groups,
                onSubmit: async (value: { selectedGroups }) => {
                    this.setGroupsSettings(value.selectedGroups);
                    this.close();
                },
            },
        });

    }

    onClose() {
        super.onClose();
        this.modalContent.$destroy();
        this.resolvePromise();
    }

    async setGroupsSettings(selectedGroups) {

        const groups = get(settingsStore).groups;

        groups.forEach(group => {
            group.selected = selectedGroups.some((selectedGroup) => selectedGroup.id === group.id);
        })

        await settingsStore.actions.setGroups(groups);

    }

}
Example #18
Source File: valueSelectModal.ts    From obsidian_supercharged_links with MIT License 5 votes vote down vote up
export default class valueToggleModal extends Modal {
    app: App
    file: TFile
    name: string
    value: string
    settings: Field
    newValue: string
    lineNumber: number
    inFrontmatter: boolean
    top: boolean

    constructor(app: App, file: TFile, name: string, value: string, settings: Field, lineNumber: number = -1, inFrontMatter: boolean = false, top: boolean = false){
        super(app)
        this.app = app
        this.file = file
        this.name = name
        this.value = value
        this.settings = settings
        this.newValue = null
        this.lineNumber = lineNumber
        this.inFrontmatter = inFrontMatter
        this.top = top
    }

    onOpen(){
        const inputDiv = this.contentEl.createDiv({
            cls: "frontmatter-modal-value"
        })
        this.buildInputEl(inputDiv)
    }

    buildInputEl(inputDiv: HTMLDivElement): void{
        const selectEl = new DropdownComponent(inputDiv)
        selectEl.selectEl.addClass("frontmatter-select")
        const values = this.settings.values
        selectEl.addOption("","--Empty--")
        Object.keys(values).forEach(key => {
            selectEl.addOption(values[key], values[key])
        });
        if(Object.values(values).includes(this.value)){
            selectEl.setValue(this.value)
        }
        FieldSetting.getValuesListFromNote(this.settings.valuesListNotePath, this.app).then(listNoteValues => {
            listNoteValues.forEach(value => selectEl.addOption(value, value))
            if(listNoteValues.includes(this.value)){
                selectEl.setValue(this.value)
            }
            selectEl.onChange(value => this.newValue = value != "--Empty--" ? value : "")
            const submitButton = new ButtonComponent(inputDiv)
            submitButton.setTooltip("Save")
            .setIcon("checkmark")
            .onClick(async () => {
                if(this.lineNumber == -1){
                    if(this.newValue || this.newValue == ""){
                        replaceValues(this.app, this.file, this.name, this.newValue)
                    }
                } else {
                    this.app.vault.read(this.file).then(result => {
                        let newContent: string[] = []
                        if(this.top){
                            newContent.push(`${this.name}${this.inFrontmatter ? ":" : "::"} ${selectEl.getValue()}`)
                            result.split("\n").forEach((line, _lineNumber) => newContent.push(line))
                        } else {
                            result.split("\n").forEach((line, _lineNumber) => {
                                newContent.push(line)
                                if(_lineNumber == this.lineNumber){
                                    newContent.push(`${this.name}${this.inFrontmatter ? ":" : "::"} ${selectEl.getValue()}`)
                                }
                            })
                        }
                        this.app.vault.modify(this.file, newContent.join('\n'))
                        this.close()
                    })
                }
                this.close()
            })
        })
        
    }
}
Example #19
Source File: settings.ts    From remotely-save with Apache License 2.0 5 votes vote down vote up
export class OnedriveAuthModal extends Modal {
  readonly plugin: RemotelySavePlugin;
  readonly authDiv: HTMLDivElement;
  readonly revokeAuthDiv: HTMLDivElement;
  readonly revokeAuthSetting: Setting;
  constructor(
    app: App,
    plugin: RemotelySavePlugin,
    authDiv: HTMLDivElement,
    revokeAuthDiv: HTMLDivElement,
    revokeAuthSetting: Setting
  ) {
    super(app);
    this.plugin = plugin;
    this.authDiv = authDiv;
    this.revokeAuthDiv = revokeAuthDiv;
    this.revokeAuthSetting = revokeAuthSetting;
  }

  async onOpen() {
    let { contentEl } = this;

    const { authUrl, verifier } = await getAuthUrlAndVerifierOnedrive(
      this.plugin.settings.onedrive.clientID,
      this.plugin.settings.onedrive.authority
    );
    this.plugin.oauth2Info.verifier = verifier;

    const t = (x: TransItemType, vars?: any) => {
      return this.plugin.i18n.t(x, vars);
    };

    t("modal_onedriveauth_shortdesc")
      .split("\n")
      .forEach((val) => {
        contentEl.createEl("p", {
          text: val,
        });
      });
    const div2 = contentEl.createDiv();
    div2.createEl(
      "button",
      {
        text: t("modal_onedriveauth_copybutton"),
      },
      (el) => {
        el.onclick = async () => {
          await navigator.clipboard.writeText(authUrl);
          new Notice(t("modal_onedriveauth_copynotice"));
        };
      }
    );

    contentEl.createEl("p").createEl("a", {
      href: authUrl,
      text: authUrl,
    });
  }

  onClose() {
    let { contentEl } = this;
    contentEl.empty();
  }
}
Example #20
Source File: sectionContentModal.ts    From obsidian_supercharged_links with MIT License 5 votes vote down vote up
export default class sectionContentModal extends Modal {
    file: TFile
    startLine: number
    endLine: number

    constructor(app: App, file: TFile,startLine: number, endLine: number){
        super(app)
        this.file = file
        this.startLine = startLine
        this.endLine = endLine
    }

    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 #21
Source File: settings.ts    From remotely-save with Apache License 2.0 5 votes vote down vote up
export class OnedriveRevokeAuthModal extends Modal {
  readonly plugin: RemotelySavePlugin;
  readonly authDiv: HTMLDivElement;
  readonly revokeAuthDiv: HTMLDivElement;
  constructor(
    app: App,
    plugin: RemotelySavePlugin,
    authDiv: HTMLDivElement,
    revokeAuthDiv: HTMLDivElement
  ) {
    super(app);
    this.plugin = plugin;
    this.authDiv = authDiv;
    this.revokeAuthDiv = revokeAuthDiv;
  }

  async onOpen() {
    let { contentEl } = this;
    const t = (x: TransItemType, vars?: any) => {
      return this.plugin.i18n.t(x, vars);
    };

    contentEl.createEl("p", {
      text: t("modal_onedriverevokeauth_step1"),
    });
    const consentUrl = "https://microsoft.com/consent";
    contentEl.createEl("p").createEl("a", {
      href: consentUrl,
      text: consentUrl,
    });

    contentEl.createEl("p", {
      text: t("modal_onedriverevokeauth_step2"),
    });

    new Setting(contentEl)
      .setName(t("modal_onedriverevokeauth_clean"))
      .setDesc(t("modal_onedriverevokeauth_clean_desc"))
      .addButton(async (button) => {
        button.setButtonText(t("modal_onedriverevokeauth_clean_button"));
        button.onClick(async () => {
          try {
            this.plugin.settings.onedrive = JSON.parse(
              JSON.stringify(DEFAULT_ONEDRIVE_CONFIG)
            );
            await this.plugin.saveSettings();
            this.authDiv.toggleClass(
              "onedrive-auth-button-hide",
              this.plugin.settings.onedrive.username !== ""
            );
            this.revokeAuthDiv.toggleClass(
              "onedrive-revoke-auth-button-hide",
              this.plugin.settings.onedrive.username === ""
            );
            new Notice(t("modal_onedriverevokeauth_clean_notice"));
            this.close();
          } catch (err) {
            console.error(err);
            new Notice(t("modal_onedriverevokeauth_clean_fail"));
          }
        });
      });
  }

  onClose() {
    let { contentEl } = this;
    contentEl.empty();
  }
}
Example #22
Source File: PromptModal.ts    From Templater with GNU Affero General Public License v3.0 5 votes vote down vote up
export class PromptModal extends Modal {
    private promptEl: HTMLInputElement;
    private resolve: (value: string) => void;
    private reject: (reason?: TemplaterError) => void;
    private submitted = false;

    constructor(
        app: App,
        private prompt_text: string,
        private default_value: string
    ) {
        super(app);
    }

    onOpen(): void {
        this.titleEl.setText(this.prompt_text);
        this.createForm();
    }

    onClose(): void {
        this.contentEl.empty();
        if (!this.submitted) {
            this.reject(new TemplaterError("Cancelled prompt"));
        }
    }

    createForm(): void {
        const div = this.contentEl.createDiv();
        div.addClass("templater-prompt-div");

        const form = div.createEl("form");
        form.addClass("templater-prompt-form");
        form.type = "submit";
        form.onsubmit = (e: Event) => {
            this.submitted = true;
            e.preventDefault();
            this.resolve(this.promptEl.value);
            this.close();
        };

        this.promptEl = form.createEl("input");
        this.promptEl.type = "text";
        this.promptEl.placeholder = "Type text here...";
        this.promptEl.value = this.default_value ?? "";
        this.promptEl.addClass("templater-prompt-input");
        this.promptEl.select();
    }

    async openAndGetValue(
        resolve: (value: string) => void,
        reject: (reason?: TemplaterError) => void
    ): Promise<void> {
        this.resolve = resolve;
        this.reject = reject;
        this.open();
    }
}
Example #23
Source File: GenericYesNoPrompt.ts    From quickadd with MIT License 5 votes vote down vote up
export default class GenericYesNoPrompt extends Modal {
    private resolvePromise: (input: boolean) => void;
    private rejectPromise: (reason?: any) => void;
    private input: boolean;
    public waitForClose: Promise<boolean>;
    private didSubmit: boolean = false;

    public static Prompt(app: App, header: string, text?: string): Promise<boolean> {
        const newPromptModal = new GenericYesNoPrompt(app, header, text);
        return newPromptModal.waitForClose;
    }

    private constructor(app: App, private header: string, private text?: string) {
        super(app);

        this.waitForClose = new Promise<boolean>(
            (resolve, reject) => {
                this.resolvePromise = resolve;
                this.rejectPromise = reject;
            }
        );

        this.open();
        this.display();
    }

    private display() {
        this.containerEl.addClass('quickAddModal', 'qaYesNoPrompt')
        this.contentEl.empty();
        this.titleEl.textContent = this.header;
        this.contentEl.createEl('p', {text: this.text});

        const buttonsDiv = this.contentEl.createDiv({cls: 'yesNoPromptButtonContainer'})

        const noButton = new ButtonComponent(buttonsDiv)
            .setButtonText('No')
            .onClick(() => this.submit(false));

        const yesButton = new ButtonComponent(buttonsDiv)
            .setButtonText('Yes')
            .onClick(() => this.submit(true))
            .setWarning();

        yesButton.buttonEl.focus();

    }

    private submit(input: boolean) {
        this.input = input;
        this.didSubmit = true;
        this.close();
    }

    onClose() {
        super.onClose();

        if(!this.didSubmit) this.rejectPromise("No answer given.");
        else this.resolvePromise(this.input);
    }
}
Example #24
Source File: addNewFieldModal.ts    From obsidian_supercharged_links with MIT License 5 votes vote down vote up
export default class addNewFieldModal extends Modal {

    plugin: SuperchargedLinks
    lineNumber: number
    file: TFile
    inFrontmatter: boolean
    top: boolean

    constructor(plugin: SuperchargedLinks, lineNumber: number, file: TFile, inFrontmatter: boolean, top: boolean){
        super(plugin.app)
        this.lineNumber = lineNumber
        this.inFrontmatter = inFrontmatter
        this.file = file
        this.top = top
    }

    onOpen(){
        this.titleEl.setText("Insert new field")
        const addNewFieldContainer = this.contentEl.createDiv()
        const nameInputContainer = addNewFieldContainer.createDiv()
        nameInputContainer.setText("Field Name: ")
        const nameInputEl = new TextComponent(nameInputContainer)
        nameInputEl.setPlaceholder("Field name")
        const valueInputContainer = addNewFieldContainer.createDiv()
        valueInputContainer.setText("Field value: ")
        const valueInputEl = new TextComponent(valueInputContainer)
        valueInputEl.setPlaceholder("Field value")
        const footerButtons = this.contentEl.createDiv({
            cls: 'frontmatter-textarea-buttons'
        })
        const saveButton = new ButtonComponent(footerButtons)
        saveButton.setIcon("checkmark")
        saveButton.onClick(() => {
            this.app.vault.read(this.file).then(result => {
                let newContent: string[] = []
                if(this.top){
                    newContent.push(`${nameInputEl.getValue()}${this.inFrontmatter ? ":" : "::"} ${valueInputEl.getValue()}`)
                    result.split("\n").forEach((line, _lineNumber) => newContent.push(line))
                } else {
                    result.split("\n").forEach((line, _lineNumber) => {
                        newContent.push(line)
                        if(_lineNumber == this.lineNumber){
                            newContent.push(`${nameInputEl.getValue()}${this.inFrontmatter ? ":" : "::"} ${valueInputEl.getValue()}`)
                        }
                    })
                }
                this.app.vault.modify(this.file, newContent.join('\n'))
                this.close()
            })
        })
        const cancelButton = new ExtraButtonComponent(footerButtons)
        cancelButton.setIcon("cross")
        cancelButton.onClick(() => {
            this.close()
        })


    }
}
Example #25
Source File: genericCheckboxPrompt.ts    From quickadd with MIT License 5 votes vote down vote up
export default class GenericCheckboxPrompt extends Modal{
    private resolvePromise: (value: string[]) => void;
    private rejectPromise: (reason?: any) => void;
    public promise: Promise<string[]>;
    private resolved: boolean;
    private _selectedItems: string[];

    public static Open(app: App, items: string[], selectedItems?: string[]) {
        const newSuggester = new GenericCheckboxPrompt(app, items, selectedItems);
        return newSuggester.promise;
    }

    public constructor(app: App, private items: string[], readonly selectedItems: string[] = []) {
        super(app);
		// This clones the item so that we don't get any unexpected modifications of the
		// arguments
        this._selectedItems = [...selectedItems];

        this.promise = new Promise<string[]>(
            (resolve, reject) => {(this.resolvePromise = resolve); (this.rejectPromise = reject)}
        );

        this.display();
        this.open();
    }

    private display() {
        this.contentEl.empty();
        this.containerEl.addClass('quickAddModal', 'checkboxPrompt')
        this.addCheckboxRows();
        this.addSubmitButton();
    }

    onClose() {
        super.onClose();

        if (!this.resolved)
            this.rejectPromise("no input given.");
    }

    private addCheckboxRows() {
        const rowContainer: HTMLDivElement = this.contentEl.createDiv('checkboxRowContainer');
        this.items.forEach(item => this.addCheckboxRow(item, rowContainer));
    }

    private addCheckboxRow(item: string, container: HTMLDivElement) {
        const checkboxRow: HTMLDivElement = container.createDiv('checkboxRow');

        const text: HTMLSpanElement = checkboxRow.createEl('span', {text: item});
        const checkbox: ToggleComponent = new ToggleComponent(checkboxRow);
        checkbox
			.setTooltip(`Toggle ${item}`)
			.setValue(this._selectedItems.contains(item))
			.onChange(value => {
				if (value)
					this._selectedItems.push(item);
				else {
					const index = this._selectedItems.findIndex(value => item === value);
					this._selectedItems.splice(index, 1);
				}
			});
    }

    private addSubmitButton() {
        const submitButtonContainer: HTMLDivElement = this.contentEl.createDiv('submitButtonContainer');
        const submitButton: ButtonComponent = new ButtonComponent(submitButtonContainer);

        submitButton.setButtonText("Submit").setCta().onClick(evt => {
           this.resolved = true;
           this.resolvePromise(this._selectedItems);

           this.close();
        });
    }
}
Example #26
Source File: newPresetDialog.ts    From obsidian-map-view with GNU General Public License v3.0 5 votes vote down vote up
export class NewPresetDialog extends Modal {
    private plugin: MapViewPlugin;
    private settings: PluginSettings;
    private stateToSave: MapState;
    private callback: (index: string) => void;

    constructor(
        app: App,
        stateToSave: MapState,
        plugin: MapViewPlugin,
        settings: PluginSettings,
        callback: (index: string) => void
    ) {
        super(app);
        this.plugin = plugin;
        this.settings = settings;
        this.stateToSave = stateToSave;
        this.callback = callback;
    }

    onOpen() {
        let statusLabel: HTMLDivElement = null;
        const grid = this.contentEl.createDiv({ cls: 'newPresetDialogGrid' });
        const row1 = grid.createDiv({ cls: 'newPresetDialogLine' });
        const row2 = grid.createDiv({ cls: 'newPresetDialogLine' });
        const row3 = grid.createDiv({ cls: 'newPresetDialogLine' });
        let name = new TextComponent(row1).onChange((value) => {
            if (value == 'Default' || value.length === 0)
                saveButton.disabled = true;
            else saveButton.disabled = false;
            if (this.findPresetByName(value))
                statusLabel.setText(
                    "Clicking 'Save' will overwrite an existing preset."
                );
            else statusLabel.setText('');
        });
        name.inputEl.style.width = '100%';
        name.inputEl.addEventListener('keypress', (ev: KeyboardEvent) => {
            if (ev.key == 'Enter') saveButton.buttonEl.click();
        });
        const includeMapSource = row2.createEl('input', { type: 'checkbox' });
        includeMapSource.id = 'includeMapSource';
        const includeMapSourceLabel = row2.createEl('label');
        includeMapSourceLabel.setAttribute('for', 'includeMapSource');
        includeMapSourceLabel.textContent = 'Include chosen map source';
        let saveButton = new ButtonComponent(row3)
            .setButtonText('Save')
            .onClick(async () => {
                let existingPreset = this.findPresetByName(name.getValue());
                let newState = { ...this.stateToSave, name: name.getValue() };
                if (!(includeMapSource as HTMLInputElement).checked)
                    newState.chosenMapSource = undefined;
                if (existingPreset) {
                    Object.assign(existingPreset, newState);
                    newState = existingPreset;
                } else {
                    this.settings.savedStates.push(newState);
                }
                await this.plugin.saveSettings();
                // Update the presets list
                const presetIndex = this.settings.savedStates.indexOf(newState);
                // Select the new preset in the view's controls
                this.callback((presetIndex + 1).toString());
                this.close();
            });
        new ButtonComponent(row3).setButtonText('Cancel').onClick(() => {
            this.close();
        });
        statusLabel = row3.createDiv();
        name.onChanged();
        name.inputEl.focus();
    }

    findPresetByName(name: string) {
        return this.settings.savedStates?.find(
            (preset) => preset.name === name
        );
    }
}
Example #27
Source File: modal.ts    From obsidian-fantasy-calendar with MIT License 5 votes vote down vote up
export abstract class FantasyCalendarModal extends Modal {
    constructor(public app: App) {
        super(app);
        this.containerEl.addClass("fantasy-calendar-modal")
    }
}
Example #28
Source File: ImgurAuthModal.ts    From obsidian-imgur-plugin with MIT License 5 votes vote down vote up
export default class ImgurAuthModal extends Modal {
  secondsLeft = OPEN_BROWSER_IN_SECONDS;

  private opened = false;

  get isOpen(): boolean {
    return this.opened;
  }

  private timerDiv: HTMLDivElement;

  private readonly authLink: string;

  private intervalId: NodeJS.Timeout | null = null;

  constructor(
    clientId: string,
    app: App,
    private readonly afterClose?: () => Promise<void>
  ) {
    super(app);
    this.authLink = `https://api.imgur.com/oauth2/authorize?client_id=${clientId}&response_type=token`;
  }

  onOpen(): void {
    this.opened = true;

    this.timerDiv = this.modalEl.createDiv();
    this.updateText();

    this.intervalId = setInterval(() => {
      this.secondsLeft -= 1;
      this.updateText();

      if (this.secondsLeft === 0) {
        window.open(this.authLink);
        clearInterval(this.intervalId);
      }
    }, ONE_SECOND_MILLIS);
    this.addNoWaitDiv(this.intervalId);

    new ButtonComponent(this.modalEl.createDiv())
      .setButtonText("Cancel")
      .setCta()
      .onClick(() => this.close());
  }

  async onClose(): Promise<void> {
    clearInterval(this.intervalId);
    this.opened = false;
    // console.log(this.afterClose);
    if (this.afterClose) await this.afterClose();
  }

  private addNoWaitDiv(interval: NodeJS.Timeout) {
    const linkEl = createEl("a", { href: this.authLink, text: "here" });
    const noWaitDiv = this.modalEl.createDiv();
    noWaitDiv.appendText("If you do not want to wait, click ");
    noWaitDiv.append(linkEl);
    linkEl.onclick = () => {
      clearInterval(interval);
      this.secondsLeft = 0;
      this.updateText();
    };
    return noWaitDiv;
  }

  private updateText() {
    this.timerDiv.setText(
      `Please complete authentication at imgur.com; Opening browser in ${this.secondsLeft} seconds...`
    );
  }
}
Example #29
Source File: choiceBuilder.ts    From quickadd with MIT License 5 votes vote down vote up
export abstract class ChoiceBuilder extends Modal {
    private resolvePromise: (input: IChoice) => void;
    private rejectPromise: (reason?: any) => void;
    private input: IChoice;
    public waitForClose: Promise<IChoice>;
    abstract choice: IChoice;
    private didSubmit: boolean = false;
    protected svelteElements: SvelteComponent[] = [];

    protected constructor(app: App) {
        super(app);

        this.waitForClose = new Promise<IChoice>(
            (resolve, reject) => {
                this.resolvePromise = resolve;
                this.rejectPromise = reject;
            }
        );

        this.containerEl.addClass('quickAddModal');
        this.open();
    }

    protected abstract display();

    protected reload() {
        this.contentEl.empty();
        this.display();
    }

    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;
    }

    protected addCenteredChoiceNameHeader(choice: IChoice): void {
        const headerEl: HTMLHeadingElement = this.contentEl.createEl('h2', {cls: "choiceNameHeader"});
        headerEl.setText(choice.name);

        headerEl.addEventListener('click', async ev => {
            try {
                const newName: string = await GenericInputPrompt.Prompt(this.app, choice.name, "Choice name", choice.name);
                if (newName !== choice.name) {
                    choice.name = newName;
                    headerEl.setText(newName);
                }
            }
            catch (e) {
                log.logMessage(`No new name given for ${choice.name}`);
            }
        });
    }

    onClose() {
        super.onClose();
        this.resolvePromise(this.choice);
        this.svelteElements.forEach(el => {
            if (el && el.$destroy) el.$destroy();
        })

        if(!this.didSubmit) this.rejectPromise("No answer given.");
        else this.resolvePromise(this.input);
    }
}