obsidian#addIcon TypeScript Examples

The following examples show how to use obsidian#addIcon. 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: main.ts    From Templater with GNU Affero General Public License v3.0 6 votes vote down vote up
async onload(): Promise<void> {
        await this.load_settings();

        this.templater = new Templater(this.app, this);
        await this.templater.setup();

        this.editor_handler = new Editor(this.app, this);
        await this.editor_handler.setup();

        this.fuzzy_suggester = new FuzzySuggester(this.app, this);

        this.event_handler = new EventHandler(
            this.app,
            this,
            this.templater,
            this.settings
        );
        this.event_handler.setup();

        this.command_handler = new CommandHandler(this.app, this);
        this.command_handler.setup();

        addIcon("templater-icon", ICON_DATA);
        this.addRibbonIcon("templater-icon", "Templater", async () => {
            this.fuzzy_suggester.insert_template();
        });

        this.addSettingTab(new TemplaterSettingTab(this.app, this));

        // Files might not be created yet
        this.app.workspace.onLayoutReady(() => {
            this.templater.execute_startup_scripts();
        });
    }
Example #2
Source File: appicon.ts    From obsidian-spaced-repetition with MIT License 6 votes vote down vote up
export function appIcon() {
    addIcon(
        "SpacedRepIcon",
        `<path fill="currentColor" stroke="currentColor" d="M 88.960938 17.257812 L 47.457031 17.257812 C 45.679688 17.257812 44.230469 18.703125 44.230469 20.484375 L 44.230469 86.558594 C 44.230469 88.335938 45.679688 89.785156 47.457031 89.785156 L 88.960938 89.785156 C 90.738281 89.785156 92.1875 88.335938 92.1875 86.558594 L 92.1875 20.484375 C 92.1875 18.703125 90.738281 17.257812 88.960938 17.257812 Z M 88.28125 85.878906 L 48.136719 85.878906 L 48.136719 21.164062 L 88.28125 21.164062 Z M 88.28125 85.878906 "/>
        <path fill="currentColor" stroke="currentColor"  d="M 88.960938 9.445312 L 61.667969 9.445312 C 59.925781 3.816406 54.011719 0.515625 48.269531 2.054688 L 8.183594 12.796875 C 2.304688 14.371094 -1.199219 20.4375 0.378906 26.316406 L 17.476562 90.140625 C 18.796875 95.066406 23.269531 98.324219 28.144531 98.324219 C 29.085938 98.324219 30.046875 98.199219 31 97.945312 L 40.765625 95.328125 C 42.625 96.75 44.941406 97.597656 47.457031 97.597656 L 88.960938 97.597656 C 95.046875 97.597656 100 92.644531 100 86.558594 L 100 20.484375 C 100 14.398438 95.046875 9.445312 88.960938 9.445312 Z M 29.988281 94.171875 C 26.1875 95.191406 22.269531 92.925781 21.25 89.128906 L 4.152344 25.304688 C 3.132812 21.507812 5.394531 17.585938 9.195312 16.570312 L 49.28125 5.828125 C 52.578125 4.945312 55.960938 6.53125 57.464844 9.445312 L 47.457031 9.445312 C 41.371094 9.445312 36.417969 14.398438 36.417969 20.484375 L 36.417969 86.558594 C 36.417969 88.558594 36.957031 90.433594 37.890625 92.054688 Z M 96.09375 86.558594 C 96.09375 90.492188 92.894531 93.691406 88.960938 93.691406 L 47.457031 93.691406 C 43.523438 93.691406 40.324219 90.492188 40.324219 86.558594 L 40.324219 20.484375 C 40.324219 16.550781 43.523438 13.351562 47.457031 13.351562 L 88.960938 13.351562 C 92.894531 13.351562 96.09375 16.550781 96.09375 20.484375 Z M 96.09375 86.558594 "/>
        <path fill="currentColor" stroke="currentColor"  d="M 54.101562 53.09375 L 60.070312 57.410156 L 57.789062 64.378906 C 56.90625 67.074219 59.996094 69.320312 62.285156 67.648438 L 68.210938 63.324219 L 74.132812 67.648438 C 76.421875 69.320312 79.511719 67.074219 78.628906 64.378906 L 76.347656 57.410156 L 82.320312 53.09375 C 84.613281 51.433594 83.441406 47.804688 80.605469 47.804688 L 73.242188 47.804688 L 70.988281 40.839844 C 70.117188 38.144531 66.300781 38.144531 65.429688 40.839844 L 63.179688 47.804688 L 55.8125 47.804688 C 52.980469 47.804688 51.804688 51.433594 54.101562 53.09375 Z M 54.101562 53.09375 "/>
        `
    );
}
Example #3
Source File: main.ts    From obsidian-ReadItLater with MIT License 6 votes vote down vote up
async onload(): Promise<void> {
        await this.loadSettings();
        this.parsers = [
            new YoutubeParser(this.app, this.settings),
            new TwitterParser(this.app, this.settings),
            new WebsiteParser(this.app, this.settings),
            new TextSnippetParser(this.app, this.settings),
        ];

        addIcon('read-it-later', clipboardIcon);

        this.addRibbonIcon('read-it-later', 'ReadItLater: Save clipboard', async () => {
            await this.processClipboard();
        });

        this.addCommand({
            id: 'save-clipboard-to-notice',
            name: 'Save clipboard',
            callback: async () => {
                await this.processClipboard();
            },
        });

        this.addSettingTab(new ReadItLaterSettingsTab(this.app, this));
    }
Example #4
Source File: icons.ts    From obsidian-charts with GNU Affero General Public License v3.0 5 votes vote down vote up
addIcons = (): void => {
    Object.keys(icons).forEach((key) => {
        addIcon(key, icons[key]);
    });
}
Example #5
Source File: main.ts    From obsidian-hypothesis-plugin with MIT License 5 votes vote down vote up
addIcon('hypothesisIcon', hypothesisIcon);
Example #6
Source File: icons.ts    From obsidian-initiative-tracker with GNU General Public License v3.0 5 votes vote down vote up
export function registerIcons() {
    addIcon(BASE, ICON);

    addIcon(SAVE, SAVE_ICON);
    addIcon(ADD, ADD_ICON);
    addIcon(RESTART, RESTART_ICON);
    addIcon(PLAY, PLAY_ICON);
    addIcon(FORWARD, FORWARD_ICON);
    addIcon(BACKWARD, BACKWARD_ICON);
    addIcon(STOP, STOP_ICON);
    addIcon(GRIP, GRIP_ICON);
    addIcon(HP, HP_ICON);
    addIcon(AC, AC_ICON);
    addIcon(HAMBURGER, HAMBURGER_ICON);
    addIcon(ENABLE, ENABLE_ICON);
    addIcon(DISABLE, DISABLE_ICON);
    addIcon(TAG, TAG_ICON);
    addIcon(EDIT, EDIT_ICON);
    addIcon(INITIATIVE, INITIATIVE_ICON);
    addIcon(REDO, REDO_ICON);
    addIcon(NEW, NEW_ICON);
    addIcon(DICE, DICE_ICON);
    addIcon(START_ENCOUNTER, START_ENCOUNTER_ICON);
    addIcon(MAP, MAP_ICON);
    addIcon(COPY, COPY_ICON);
    addIcon(
        GROUP,
        `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="users" class="svg-inline--fa fa-users fa-w-20" role="img" viewBox="0 0 640 512"><path fill="currentColor" d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z"/></svg>`
    );
    addIcon(
        EXPAND,
        `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="users-slash" class="svg-inline--fa fa-users-slash fa-w-20" role="img" viewBox="0 0 640 512"><path fill="currentColor" d="M132.65,212.32,36.21,137.78A63.4,63.4,0,0,0,32,160a63.84,63.84,0,0,0,100.65,52.32Zm40.44,62.28A63.79,63.79,0,0,0,128,256H64A64.06,64.06,0,0,0,0,320v32a32,32,0,0,0,32,32H97.91A146.62,146.62,0,0,1,173.09,274.6ZM544,224a64,64,0,1,0-64-64A64.06,64.06,0,0,0,544,224ZM500.56,355.11a114.24,114.24,0,0,0-84.47-65.28L361,247.23c41.46-16.3,71-55.92,71-103.23A111.93,111.93,0,0,0,320,32c-57.14,0-103.69,42.83-110.6,98.08L45.46,3.38A16,16,0,0,0,23,6.19L3.37,31.46A16,16,0,0,0,6.18,53.91L594.53,508.63A16,16,0,0,0,617,505.82l19.64-25.27a16,16,0,0,0-2.81-22.45ZM128,403.21V432a48,48,0,0,0,48,48H464a47.45,47.45,0,0,0,12.57-1.87L232,289.13C173.74,294.83,128,343.42,128,403.21ZM576,256H512a63.79,63.79,0,0,0-45.09,18.6A146.29,146.29,0,0,1,542,384h66a32,32,0,0,0,32-32V320A64.06,64.06,0,0,0,576,256Z"/></svg>`
    );
    addIcon(
        ACTIVE,
        `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="angle-right" class="svg-inline--fa fa-angle-right fa-w-8" role="img" viewBox="0 0 256 512"><path fill="currentColor" d="M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z"/></svg>`
    );
    addIcon(
        MAPMARKER,
        `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="map-marker-alt" class="svg-inline--fa fa-map-marker-alt fa-w-12" role="img" viewBox="0 0 384 512"><path fill="currentColor" d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0zM192 272c44.183 0 80-35.817 80-80s-35.817-80-80-80-80 35.817-80 80 35.817 80 80 80z"/></svg>`
    );
    addIcon(
        CREATURE,
        `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="dragon" class="svg-inline--fa fa-dragon fa-w-20" role="img" viewBox="0 0 640 512"><path fill="currentColor" d="M18.32 255.78L192 223.96l-91.28 68.69c-10.08 10.08-2.94 27.31 11.31 27.31h222.7c-9.44-26.4-14.73-54.47-14.73-83.38v-42.27l-119.73-87.6c-23.82-15.88-55.29-14.01-77.06 4.59L5.81 227.64c-12.38 10.33-3.45 30.42 12.51 28.14zm556.87 34.1l-100.66-50.31A47.992 47.992 0 0 1 448 196.65v-36.69h64l28.09 22.63c6 6 14.14 9.37 22.63 9.37h30.97a32 32 0 0 0 28.62-17.69l14.31-28.62a32.005 32.005 0 0 0-3.02-33.51l-74.53-99.38C553.02 4.7 543.54 0 533.47 0H296.02c-7.13 0-10.7 8.57-5.66 13.61L352 63.96 292.42 88.8c-5.9 2.95-5.9 11.36 0 14.31L352 127.96v108.62c0 72.08 36.03 139.39 96 179.38-195.59 6.81-344.56 41.01-434.1 60.91C5.78 478.67 0 485.88 0 494.2 0 504 7.95 512 17.76 512h499.08c63.29.01 119.61-47.56 122.99-110.76 2.52-47.28-22.73-90.4-64.64-111.36zM489.18 66.25l45.65 11.41c-2.75 10.91-12.47 18.89-24.13 18.26-12.96-.71-25.85-12.53-21.52-29.67z"/></svg>`
    );
}
Example #7
Source File: settings.ts    From obsidian-initiative-tracker with GNU General Public License v3.0 5 votes vote down vote up
addIcon(
    "initiative-tracker-warning",
    `<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="exclamation-triangle" class="svg-inline--fa fa-exclamation-triangle fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg>`
);
Example #8
Source File: icons.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 5 votes vote down vote up
addIcons = (): void => {
    Object.keys(icons).forEach((key) => {
        addIcon(key, icons[key]);
    });
}
Example #9
Source File: icons.ts    From obsidian-customizable-sidebar with MIT License 5 votes vote down vote up
export function addFeatherIcons(iconList: string[]) {
    Object.values(feather.icons).forEach((i) => {
        const svg = i.toSvg({viewBox: "0 0 24 24", width: "100", height: "100"});
        //Remove the svg tag: svg.match(/(?<=>).*(?=<\/svg>)/).first()
        addIcon("feather-" + i.name, svg);
        iconList.push("feather-" + i.name);
    });
}
Example #10
Source File: view.ts    From obsidian-fantasy-calendar with MIT License 5 votes vote down vote up
addIcon(
    "fantasy-calendar-reveal",
    `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="calendar-day" class="svg-inline--fa fa-calendar-day fa-w-14" role="img" viewBox="0 0 448 512"><path fill="currentColor" d="M0 464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V192H0v272zm64-192c0-8.8 7.2-16 16-16h96c8.8 0 16 7.2 16 16v96c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16v-96zM400 64h-48V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H160V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H48C21.5 64 0 85.5 0 112v48h448v-48c0-26.5-21.5-48-48-48z"/></svg>`
);
Example #11
Source File: view.ts    From obsidian-fantasy-calendar with MIT License 5 votes vote down vote up
addIcon(
    VIEW_TYPE,
    `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" data-prefix="far" data-icon="calendar" class="svg-inline--fa fa-calendar fa-w-14" role="img" viewBox="0 0 448 512"><path xmlns="http://www.w3.org/2000/svg" fill="currentColor" d="M400 64h-48V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H160V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zm-6 400H54c-3.3 0-6-2.7-6-6V160h352v298c0 3.3-2.7 6-6 6z"/><path fill="currentColor" d="M18.32 255.78L192 223.96l-91.28 68.69c-10.08 10.08-2.94 27.31 11.31 27.31h222.7c-9.44-26.4-14.73-54.47-14.73-83.38v-42.27l-119.73-87.6c-23.82-15.88-55.29-14.01-77.06 4.59L5.81 227.64c-12.38 10.33-3.45 30.42 12.51 28.14zm556.87 34.1l-100.66-50.31A47.992 47.992 0 0 1 448 196.65v-36.69h64l28.09 22.63c6 6 14.14 9.37 22.63 9.37h30.97a32 32 0 0 0 28.62-17.69l14.31-28.62a32.005 32.005 0 0 0-3.02-33.51l-74.53-99.38C553.02 4.7 543.54 0 533.47 0H296.02c-7.13 0-10.7 8.57-5.66 13.61L352 63.96 292.42 88.8c-5.9 2.95-5.9 11.36 0 14.31L352 127.96v108.62c0 72.08 36.03 139.39 96 179.38-195.59 6.81-344.56 41.01-434.1 60.91C5.78 478.67 0 485.88 0 494.2 0 504 7.95 512 17.76 512h499.08c63.29.01 119.61-47.56 122.99-110.76 2.52-47.28-22.73-90.4-64.64-111.36zM489.18 66.25l45.65 11.41c-2.75 10.91-12.47 18.89-24.13 18.26-12.96-.71-25.85-12.53-21.52-29.67z" style="&#10;    transform: scale(0.4125) translate(50%, 95%);&#10;"/></svg>`
);
Example #12
Source File: settings.ts    From obsidian-fantasy-calendar with MIT License 5 votes vote down vote up
addIcon(
    "fantasy-calendar-warning",
    `<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="exclamation-triangle" class="svg-inline--fa fa-exclamation-triangle fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg>`
);
Example #13
Source File: settings.ts    From obsidian-fantasy-calendar with MIT License 5 votes vote down vote up
addIcon(
    "fantasy-calendar-grip",
    `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="grip-lines" class="svg-inline--fa fa-grip-lines fa-w-16" role="img" viewBox="0 0 512 512"><path fill="currentColor" d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>`
);
Example #14
Source File: main.ts    From Obsidian_to_Anki with GNU General Public License v3.0 5 votes vote down vote up
async onload() {
		console.log('loading Obsidian_to_Anki...');
		addIcon('anki', ANKI_ICON)

		try {
			this.settings = await this.loadSettings()
		}
		catch(e) {
			new Notice("Couldn't connect to Anki! Check console for error message.")
			return
		}

		this.note_types = Object.keys(this.settings["CUSTOM_REGEXPS"])
		this.fields_dict = await this.loadFieldsDict()
		if (Object.keys(this.fields_dict).length == 0) {
			new Notice('Need to connect to Anki to generate fields dictionary...')
			try {
				this.fields_dict = await this.generateFieldsDict()
				new Notice("Fields dictionary successfully generated!")
			}
			catch(e) {
				new Notice("Couldn't connect to Anki! Check console for error message.")
				return
			}
		}
		this.added_media = await this.loadAddedMedia()
		this.file_hashes = await this.loadFileHashes()

		this.addSettingTab(new SettingsTab(this.app, this));

		this.addRibbonIcon('anki', 'Obsidian_to_Anki - Scan Vault', async () => {
			await this.scanVault()
		})

		this.addCommand({
			id: 'anki-scan-vault',
			name: 'Scan Vault',
			callback: async () => {
			 	await this.scanVault()
			 }
		})
	}
Example #15
Source File: main.ts    From obsidian-plantuml with MIT License 4 votes vote down vote up
async onload(): Promise<void> {
        console.log('loading plugin plantuml');
        await this.loadSettings();
        this.addSettingTab(new PlantUMLSettingsTab(this));
        this.replacer = new Replacer(this);

        this.serverProcessor = new ServerProcessor(this);
        if (Platform.isDesktopApp) {
            this.localProcessor = new LocalProcessors(this);
        }

        const processor = new DebouncedProcessors(this);

        if (isUsingLivePreviewEnabledEditor()) {
            const view = require("./PumlView");
            addIcon("document-" + view.VIEW_TYPE, LOGO_SVG);
            this.registerView(view.VIEW_TYPE, (leaf) => {
                return new view.PumlView(leaf, this);
            });
            this.registerExtensions(["puml", "pu"], view.VIEW_TYPE);
            this.registerEditorExtension(Prec.lowest(asyncDecoBuilderExt(this)));
        }

        this.registerMarkdownCodeBlockProcessor("plantuml", processor.png);
        this.registerMarkdownCodeBlockProcessor("plantuml-ascii", processor.ascii);
        this.registerMarkdownCodeBlockProcessor("plantuml-svg", processor.svg);
        this.registerMarkdownCodeBlockProcessor("puml", processor.png);
        this.registerMarkdownCodeBlockProcessor("puml-svg", processor.svg);
        this.registerMarkdownCodeBlockProcessor("puml-ascii", processor.ascii);

        //keep this processor for backwards compatibility
        this.registerMarkdownCodeBlockProcessor("plantuml-map", processor.png);


        //internal links
        this.observer = new MutationObserver(async (mutation) => {
            if (mutation.length !== 1) return;
            if (mutation[0].addedNodes.length !== 1) return;
            if (this.hover.linkText === null) return;
            //@ts-ignore
            if (mutation[0].addedNodes[0].className !== "popover hover-popover file-embed is-loaded") return;

            const file = this.app.metadataCache.getFirstLinkpathDest(this.hover.linkText, this.hover.sourcePath);
            if (!file) return;
            if (file.extension !== "puml" && file.extension !== "pu") return;

            const fileContent = await this.app.vault.read(file);
            const imgDiv = createDiv();
            if(this.settings.defaultProcessor === "png") {
                await this.getProcessor().png(fileContent, imgDiv, null);
            }else {
                await this.getProcessor().svg(fileContent, imgDiv, null);
            }

            const node: Node = mutation[0].addedNodes[0];
            node.empty();

            const div = createDiv("", async (element) => {
                element.appendChild(imgDiv);
                element.setAttribute('src', file.path);
                element.onClickEvent((event => {
                    event.stopImmediatePropagation();
                    const leaf = this.app.workspace.getLeaf(event.ctrlKey);
                    leaf.setViewState({
                        type: VIEW_TYPE,
                        state: {file: file.path}
                    })
                }));
            });
            node.appendChild(div);

        });

        this.registerEvent(this.app.workspace.on("hover-link", async (event: any) => {
            const linkText: string = event.linktext;
            if (!linkText) return;
            const sourcePath: string = event.sourcePath;

            if (!linkText.endsWith(".puml") && !linkText.endsWith(".pu")) {
                return;
            }

            this.hover.linkText = linkText;
            this.hover.sourcePath = sourcePath;
        }));

        this.observer.observe(document, {childList: true, subtree: true});

        //embed handling
        this.registerMarkdownPostProcessor(async (element, context) => {
            const embeddedItems = element.querySelectorAll(".internal-embed");
            if (embeddedItems.length === 0) {
                return;
            }

            for (const key in embeddedItems) {
                const item = embeddedItems[key];
                if (typeof item.getAttribute !== "function") return;

                const filename = item.getAttribute("src");
                const file = this.app.metadataCache.getFirstLinkpathDest(filename.split("#")[0], context.sourcePath);
                if (file && file instanceof TFile && (file.extension === "puml" || file.extension === "pu")) {
                    const fileContent = await this.app.vault.read(file);

                    const div = createDiv();
                    if(this.settings.defaultProcessor === "png") {
                        await this.getProcessor().png(fileContent, div, context);
                    }else {
                        await this.getProcessor().svg(fileContent, div, context);
                    }

                    item.parentElement.replaceChild(div, item);
                }
            }

        });
    }
Example #16
Source File: main.ts    From remotely-save with Apache License 2.0 4 votes vote down vote up
async onload() {
    log.info(`loading plugin ${this.manifest.id}`);

    const { iconSvgSyncWait, iconSvgSyncRunning, iconSvgLogs } = getIconSvg();

    addIcon(iconNameSyncWait, iconSvgSyncWait);
    addIcon(iconNameSyncRunning, iconSvgSyncRunning);
    addIcon(iconNameLogs, iconSvgLogs);

    this.oauth2Info = {
      verifier: "",
      helperModal: undefined,
      authDiv: undefined,
      revokeDiv: undefined,
      revokeAuthSetting: undefined,
    }; // init

    this.currSyncMsg = "";

    await this.loadSettings();
    await this.checkIfPresetRulesFollowed();

    // lang should be load early, but after settings
    this.i18n = new I18n(this.settings.lang, async (lang: LangTypeAndAuto) => {
      this.settings.lang = lang;
      await this.saveSettings();
    });
    const t = (x: TransItemType, vars?: any) => {
      return this.i18n.t(x, vars);
    };

    if (this.settings.currLogLevel !== undefined) {
      log.setLevel(this.settings.currLogLevel as any);
    }

    await this.checkIfOauthExpires();

    // MUST before prepareDB()
    // And, it's also possible to be an empty string,
    // which means the vaultRandomID is read from db later!
    const vaultRandomIDFromOldConfigFile =
      await this.getVaultRandomIDFromOldConfigFile();

    // no need to await this
    this.tryToAddIgnoreFile();

    const vaultBasePath = this.getVaultBasePath();

    try {
      await this.prepareDBAndVaultRandomID(
        vaultBasePath,
        vaultRandomIDFromOldConfigFile
      );
    } catch (err) {
      new Notice(err.message, 10 * 1000);
      throw err;
    }

    // must AFTER preparing DB
    this.addOutputToDBIfSet();
    this.enableAutoClearOutputToDBHistIfSet();

    // must AFTER preparing DB
    this.enableAutoClearSyncPlanHist();

    this.syncStatus = "idle";

    this.registerEvent(
      this.app.vault.on("delete", async (fileOrFolder) => {
        await insertDeleteRecordByVault(
          this.db,
          fileOrFolder,
          this.vaultRandomID
        );
      })
    );

    this.registerEvent(
      this.app.vault.on("rename", async (fileOrFolder, oldPath) => {
        await insertRenameRecordByVault(
          this.db,
          fileOrFolder,
          oldPath,
          this.vaultRandomID
        );
      })
    );

    this.registerObsidianProtocolHandler(COMMAND_URI, async (inputParams) => {
      const parsed = importQrCodeUri(inputParams, this.app.vault.getName());
      if (parsed.status === "error") {
        new Notice(parsed.message);
      } else {
        const copied = cloneDeep(parsed.result);
        // new Notice(JSON.stringify(copied))
        this.settings = Object.assign({}, this.settings, copied);
        this.saveSettings();
        new Notice(
          t("protocol_saveqr", {
            manifestName: this.manifest.name,
          })
        );
      }
    });

    this.registerObsidianProtocolHandler(
      COMMAND_CALLBACK,
      async (inputParams) => {
        new Notice(
          t("protocol_callbacknotsupported", {
            params: JSON.stringify(inputParams),
          })
        );
      }
    );

    this.registerObsidianProtocolHandler(
      COMMAND_CALLBACK_DROPBOX,
      async (inputParams) => {
        if (inputParams.code !== undefined) {
          if (this.oauth2Info.helperModal !== undefined) {
            this.oauth2Info.helperModal.contentEl.empty();

            t("protocol_dropbox_connecting")
              .split("\n")
              .forEach((val) => {
                this.oauth2Info.helperModal.contentEl.createEl("p", {
                  text: val,
                });
              });
          }

          let authRes = await sendAuthReqDropbox(
            this.settings.dropbox.clientID,
            this.oauth2Info.verifier,
            inputParams.code
          );

          const self = this;
          setConfigBySuccessfullAuthInplaceDropbox(
            this.settings.dropbox,
            authRes,
            () => self.saveSettings()
          );

          const client = new RemoteClient(
            "dropbox",
            undefined,
            undefined,
            this.settings.dropbox,
            undefined,
            this.app.vault.getName(),
            () => self.saveSettings()
          );

          const username = await client.getUser();
          this.settings.dropbox.username = username;
          await this.saveSettings();

          new Notice(
            t("protocol_dropbox_connect_succ", {
              username: username,
            })
          );

          this.oauth2Info.verifier = ""; // reset it
          this.oauth2Info.helperModal?.close(); // close it
          this.oauth2Info.helperModal = undefined;

          this.oauth2Info.authDiv?.toggleClass(
            "dropbox-auth-button-hide",
            this.settings.dropbox.username !== ""
          );
          this.oauth2Info.authDiv = undefined;

          this.oauth2Info.revokeAuthSetting?.setDesc(
            t("protocol_dropbox_connect_succ_revoke", {
              username: this.settings.dropbox.username,
            })
          );
          this.oauth2Info.revokeAuthSetting = undefined;
          this.oauth2Info.revokeDiv?.toggleClass(
            "dropbox-revoke-auth-button-hide",
            this.settings.dropbox.username === ""
          );
          this.oauth2Info.revokeDiv = undefined;
        } else {
          new Notice(t("protocol_dropbox_connect_fail"));
          throw Error(
            t("protocol_dropbox_connect_unknown", {
              params: JSON.stringify(inputParams),
            })
          );
        }
      }
    );

    this.registerObsidianProtocolHandler(
      COMMAND_CALLBACK_ONEDRIVE,
      async (inputParams) => {
        if (inputParams.code !== undefined) {
          if (this.oauth2Info.helperModal !== undefined) {
            this.oauth2Info.helperModal.contentEl.empty();

            t("protocol_onedrive_connecting")
              .split("\n")
              .forEach((val) => {
                this.oauth2Info.helperModal.contentEl.createEl("p", {
                  text: val,
                });
              });
          }

          let rsp = await sendAuthReqOnedrive(
            this.settings.onedrive.clientID,
            this.settings.onedrive.authority,
            inputParams.code,
            this.oauth2Info.verifier
          );

          if ((rsp as any).error !== undefined) {
            throw Error(`${JSON.stringify(rsp)}`);
          }

          const self = this;
          setConfigBySuccessfullAuthInplaceOnedrive(
            this.settings.onedrive,
            rsp as AccessCodeResponseSuccessfulType,
            () => self.saveSettings()
          );

          const client = new RemoteClient(
            "onedrive",
            undefined,
            undefined,
            undefined,
            this.settings.onedrive,
            this.app.vault.getName(),
            () => self.saveSettings()
          );
          this.settings.onedrive.username = await client.getUser();
          await this.saveSettings();

          this.oauth2Info.verifier = ""; // reset it
          this.oauth2Info.helperModal?.close(); // close it
          this.oauth2Info.helperModal = undefined;

          this.oauth2Info.authDiv?.toggleClass(
            "onedrive-auth-button-hide",
            this.settings.onedrive.username !== ""
          );
          this.oauth2Info.authDiv = undefined;

          this.oauth2Info.revokeAuthSetting?.setDesc(
            t("protocol_onedrive_connect_succ_revoke", {
              username: this.settings.onedrive.username,
            })
          );
          this.oauth2Info.revokeAuthSetting = undefined;
          this.oauth2Info.revokeDiv?.toggleClass(
            "onedrive-revoke-auth-button-hide",
            this.settings.onedrive.username === ""
          );
          this.oauth2Info.revokeDiv = undefined;
        } else {
          new Notice(t("protocol_onedrive_connect_fail"));
          throw Error(
            t("protocol_onedrive_connect_unknown", {
              params: JSON.stringify(inputParams),
            })
          );
        }
      }
    );

    this.syncRibbon = this.addRibbonIcon(
      iconNameSyncWait,
      `${this.manifest.name}`,
      async () => this.syncRun("manual")
    );

    this.addCommand({
      id: "start-sync",
      name: t("command_startsync"),
      icon: iconNameSyncWait,
      callback: async () => {
        this.syncRun("manual");
      },
    });

    this.addCommand({
      id: "start-sync-dry-run",
      name: t("command_drynrun"),
      icon: iconNameSyncWait,
      callback: async () => {
        this.syncRun("dry");
      },
    });

    this.addCommand({
      id: "export-sync-plans-json",
      name: t("command_exportsyncplans_json"),
      icon: iconNameLogs,
      callback: async () => {
        await exportVaultSyncPlansToFiles(
          this.db,
          this.app.vault,
          this.vaultRandomID,
          "json"
        );
        new Notice(t("settings_syncplans_notice"));
      },
    });

    this.addCommand({
      id: "export-sync-plans-table",
      name: t("command_exportsyncplans_table"),
      icon: iconNameLogs,
      callback: async () => {
        await exportVaultSyncPlansToFiles(
          this.db,
          this.app.vault,
          this.vaultRandomID,
          "table"
        );
        new Notice(t("settings_syncplans_notice"));
      },
    });

    this.addCommand({
      id: "export-logs-in-db",
      name: t("command_exportlogsindb"),
      icon: iconNameLogs,
      callback: async () => {
        await exportVaultLoggerOutputToFiles(
          this.db,
          this.app.vault,
          this.vaultRandomID
        );
        new Notice(t("settings_logtodbexport_notice"));
      },
    });

    this.addSettingTab(new RemotelySaveSettingTab(this.app, this));

    // this.registerDomEvent(document, "click", (evt: MouseEvent) => {
    //   log.info("click", evt);
    // });

    if (!this.settings.agreeToUploadExtraMetadata) {
      const syncAlgoV2Modal = new SyncAlgoV2Modal(this.app, this);
      syncAlgoV2Modal.open();
    } else {
      this.enableAutoSyncIfSet();
      this.enableInitSyncIfSet();
    }
  }
Example #17
Source File: main.ts    From obsidian-admonition with MIT License 4 votes vote down vote up
async onload(): Promise<void> {
        console.log("Obsidian Admonition loaded");

        this.postprocessors = new Map();

        await this.loadSettings();
        await this.iconManager.load();
        this.app.workspace.onLayoutReady(async () => {
            this.addChild((this.calloutManager = new CalloutManager(this)));

            this.registerEditorSuggest(new AdmonitionSuggest(this));

            Object.keys(this.admonitions).forEach((type) => {
                this.registerType(type);
            });

            this.addSettingTab(new AdmonitionSetting(this.app, this));

            addIcon(ADD_COMMAND_NAME, ADD_ADMONITION_COMMAND_ICON);
            addIcon(REMOVE_COMMAND_NAME, REMOVE_ADMONITION_COMMAND_ICON);
            addIcon(WARNING_ICON_NAME, WARNING_ICON);
            addIcon(SPIN_ICON_NAME, SPIN_ICON);

            /** Add generic commands. */
            this.addCommand({
                id: "collapse-admonitions",
                name: "Collapse Admonitions in Note",
                checkCallback: (checking) => {
                    // checking if the command should appear in the Command Palette
                    if (checking) {
                        // make sure the active view is a MarkdownView.
                        return !!this.app.workspace.getActiveViewOfType(
                            MarkdownView
                        );
                    }
                    let view =
                        this.app.workspace.getActiveViewOfType(MarkdownView);
                    if (!view || !(view instanceof MarkdownView)) return;

                    let admonitions = view.contentEl.querySelectorAll(
                        "details[open].admonition-plugin"
                    );
                    for (let i = 0; i < admonitions.length; i++) {
                        let admonition = admonitions[i];
                        admonition.removeAttribute("open");
                    }
                }
            });
            this.addCommand({
                id: "open-admonitions",
                name: "Open Admonitions in Note",
                checkCallback: (checking) => {
                    // checking if the command should appear in the Command Palette
                    if (checking) {
                        // make sure the active view is a MarkdownView.
                        return !!this.app.workspace.getActiveViewOfType(
                            MarkdownView
                        );
                    }
                    let view =
                        this.app.workspace.getActiveViewOfType(MarkdownView);
                    if (!view || !(view instanceof MarkdownView)) return;

                    let admonitions = view.contentEl.querySelectorAll(
                        "details:not([open]).admonition-plugin"
                    );
                    for (let i = 0; i < admonitions.length; i++) {
                        let admonition = admonitions[i];
                        admonition.setAttribute("open", "open");
                    }
                }
            });
            this.addCommand({
                id: "insert-admonition",
                name: "Insert Admonition",
                editorCallback: (editor, view) => {
                    let suggestor = new InsertAdmonitionModal(this);
                    suggestor.onClose = () => {
                        if (!suggestor.insert) return;
                        let titleLine = "",
                            collapseLine = "";
                        if (
                            suggestor.title.length &&
                            suggestor.title.toLowerCase() !=
                                suggestor.type.toLowerCase()
                        ) {
                            titleLine = `title: ${suggestor.title}\n`;
                        }
                        if (
                            (this.data.autoCollapse &&
                                suggestor.collapse !=
                                    this.data.defaultCollapseType) ||
                            (!this.data.autoCollapse &&
                                suggestor.collapse != "none")
                        ) {
                            collapseLine = `collapse: ${suggestor.collapse}\n`;
                        }
                        editor.getDoc().replaceSelection(
                            `\`\`\`ad-${
                                suggestor.type
                            }\n${titleLine}${collapseLine}
${editor.getDoc().getSelection()}
\`\`\`\n`
                        );
                        const cursor = editor.getCursor();
                        editor.setCursor(cursor.line - 3);
                    };
                    suggestor.open();
                }
            });
            this.addCommand({
                id: "insert-callout",
                name: "Insert Callout",
                editorCallback: (editor, view) => {
                    let suggestor = new InsertAdmonitionModal(this);
                    suggestor.onClose = () => {
                        if (!suggestor.insert) return;
                        let title = "",
                            collapse = "";
                        if (
                            (this.data.autoCollapse &&
                                suggestor.collapse !=
                                    this.data.defaultCollapseType) ||
                            (!this.data.autoCollapse &&
                                suggestor.collapse != "none")
                        ) {
                            switch (suggestor.collapse) {
                                case "open": {
                                    collapse = "+";
                                    break;
                                }
                                case "closed": {
                                    collapse = "-";
                                    break;
                                }
                            }
                        }
                        if (
                            suggestor.title.length &&
                            suggestor.title.toLowerCase() !=
                                suggestor.type.toLowerCase()
                        ) {
                            title = ` ${suggestor.title}`;
                        }
                        const selection = editor.getDoc().getSelection();
                        editor.getDoc().replaceSelection(
                            `> [!${suggestor.type}]${collapse}${title}
> ${selection.split("\n").join("\n> ")}
`
                        );
                    };
                    suggestor.open();
                }
            });
        });
    }
Example #18
Source File: main.ts    From obsidian-map-view with GNU General Public License v3.0 4 votes vote down vote up
async onload() {
        addIcon('globe', consts.RIBBON_ICON);

        await this.loadSettings();

        // Add a new ribbon entry to the left bar
        this.addRibbonIcon('globe', 'Open map view', () => {
            // When clicked change the active view to the map
            this.app.workspace
                .getLeaf()
                .setViewState({ type: consts.MAP_VIEW_NAME });
        });

        this.registerView(consts.MAP_VIEW_NAME, (leaf: WorkspaceLeaf) => {
            return new MapView(leaf, this.settings, this);
        });

        this.registerObsidianProtocolHandler(
            'mapview',
            (params: ObsidianProtocolData) => {
                if (params.action == 'mapview') {
                    const state = stateFromParsedUrl(params);
                    // If a saved URL is opened in another device on which there aren't the same sources, use
                    // the default source instead
                    if (
                        state.chosenMapSource >= this.settings.mapSources.length
                    )
                        state.chosenMapSource =
                            DEFAULT_SETTINGS.defaultState.chosenMapSource;
                    this.openMapWithState(state, false, false);
                }
            }
        );

        this.suggestor = new LocationSuggest(this.app, this.settings);
        this.tagSuggestor = new TagSuggest(this.app, this.settings);
        this.urlConvertor = new UrlConvertor(this.app, this.settings);

        this.registerEditorSuggest(this.suggestor);
        this.registerEditorSuggest(this.tagSuggestor);

        // Convert old settings formats that are no longer supported
        if (convertLegacyMarkerIcons(this.settings)) {
            await this.saveSettings();
            new Notice(
                'Map View: legacy marker icons were converted to the new format'
            );
        }
        if (convertLegacyTilesUrl(this.settings)) {
            await this.saveSettings();
            new Notice(
                'Map View: legacy tiles URL was converted to the new format'
            );
        }
        if (convertLegacyDefaultState(this.settings)) {
            await this.saveSettings();
            new Notice(
                'Map View: legacy default state was converted to the new format'
            );
        }
        if (removeLegacyPresets1(this.settings)) {
            await this.saveSettings();
            new Notice(
                'Map View: legacy URL parsing rules and/or map sources were converted. See the release notes'
            );
        }
        if (convertTagsToQueries(this.settings)) {
            await this.saveSettings();
            new Notice(
                'Map View: legacy tag queries were converted to the new query format'
            );
        }
        if (convertUrlParsingRules1(this.settings)) {
            await this.saveSettings();
            new Notice(
                'Map View: URL parsing rules were converted to the new format'
            );
        }

        // Register commands to the command palette
        // Command that opens the map view (same as clicking the map icon)
        this.addCommand({
            id: 'open-map-view',
            name: 'Open Map View',
            callback: () => {
                this.app.workspace
                    .getLeaf()
                    .setViewState({ type: consts.MAP_VIEW_NAME });
            },
        });

        // Command that looks up the selected text to find the location
        this.addCommand({
            id: 'convert-selection-to-location',
            name: 'Convert Selection to Geolocation',
            editorCheckCallback: (checking, editor, view) => {
                if (checking) return editor.getSelection().length > 0;
                this.suggestor.selectionToLink(editor);
            },
        });

        // Command that adds a blank inline location at the cursor location
        this.addCommand({
            id: 'insert-geolink',
            name: 'Add inline geolocation link',
            editorCallback: (editor, view) => {
                const positionBeforeInsert = editor.getCursor();
                editor.replaceSelection('[](geo:)');
                editor.setCursor({
                    line: positionBeforeInsert.line,
                    ch: positionBeforeInsert.ch + 1,
                });
            },
        });

        // Command that opens the location search dialog and creates a new note from this location
        this.addCommand({
            id: 'new-geolocation-note',
            name: 'New geolocation note',
            callback: () => {
                const dialog = new LocationSearchDialog(
                    this.app,
                    this.settings,
                    'newNote',
                    'New geolocation note'
                );
                dialog.open();
            },
        });

        // Command that opens the location search dialog and adds the location to the current note
        this.addCommand({
            id: 'add-frontmatter-geolocation',
            name: 'Add geolocation (front matter) to current note',
            editorCallback: (editor, view) => {
                const dialog = new LocationSearchDialog(
                    this.app,
                    this.settings,
                    'addToNote',
                    'Add geolocation to note',
                    editor
                );
                dialog.open();
            },
        });

        this.addCommand({
            id: 'open-map-search',
            name: 'Search active map view',
            checkCallback: (checking) => {
                const currentView = this.app.workspace.activeLeaf.view;
                if (
                    currentView &&
                    currentView.getViewType() == consts.MAP_VIEW_NAME
                ) {
                    if (!checking) (currentView as MapView).openSearch();
                    return true;
                } else return false;
            },
        });

        this.addSettingTab(new SettingsTab(this.app, this));

        // Add items to the file context menu (run when the context menu is built)
        // This is the context menu in the File Explorer and clicking "More options" (three dots) from within a file.
        this.app.workspace.on(
            'file-menu',
            async (
                menu: Menu,
                file: TAbstractFile,
                _source: string,
                leaf?: WorkspaceLeaf
            ) => {
                if (file instanceof TFile) {
                    let hasAnyLocation = false;
                    const location = getFrontMatterLocation(file, this.app);
                    if (location) {
                        // If there is a geolocation in the front matter of the file
                        // Add an option to open it in the map
                        menu.addItem((item: MenuItem) => {
                            item.setTitle('Show on map');
                            item.setIcon('globe');
                            item.onClick(
                                async (evt: MouseEvent) =>
                                    await this.openMapWithLocation(
                                        location,
                                        evt.ctrlKey
                                    )
                            );
                        });
                        // Add an option to open it in the default app
                        menu.addItem((item: MenuItem) => {
                            item.setTitle('Open with default app');
                            item.onClick((_ev) => {
                                open(`geo:${location.lat},${location.lng}`);
                            });
                        });
                        // Populate menu items from user defined "Open In" strings
                        utils.populateOpenInItems(
                            menu,
                            location,
                            this.settings
                        );
                        hasAnyLocation = true;
                    } else {
                        if (leaf && leaf.view instanceof MarkdownView) {
                            // If there is no valid geolocation in the front matter, add a menu item to populate it.
                            const editor = leaf.view.editor;
                            menu.addItem((item: MenuItem) => {
                                item.setTitle('Add geolocation (front matter)');
                                item.setIcon('globe');
                                item.onClick(async (evt: MouseEvent) => {
                                    const dialog = new LocationSearchDialog(
                                        this.app,
                                        this.settings,
                                        'addToNote',
                                        'Add geolocation to note',
                                        editor
                                    );
                                    dialog.open();
                                });
                            });
                        }
                    }
                    const contentMarkers = await getMarkersFromFileContent(
                        file,
                        this.settings,
                        this.app
                    );
                    if (contentMarkers.length > 0) {
                        hasAnyLocation = true;
                    }
                    if (hasAnyLocation) {
                        menu.addItem((item: MenuItem) => {
                            item.setTitle('Focus note in Map View');
                            item.setIcon('globe');
                            item.onClick(
                                async (evt: MouseEvent) =>
                                    await this.openMapWithState(
                                        {
                                            query: `path:"${file.path}"`,
                                        } as MapState,
                                        evt.ctrlKey,
                                        true
                                    )
                            );
                        });
                    }
                }
            }
        );

        // Add items to the editor context menu (run when the context menu is built)
        // This is the context menu when right clicking within an editor view.
        this.app.workspace.on(
            'editor-menu',
            async (menu: Menu, editor: Editor, view: MarkdownView) => {
                if (view instanceof FileView) {
                    const location = this.getLocationOnEditorLine(editor, view);
                    if (location) {
                        // If there is a geolocation on the line
                        // Add an option to open it in the map
                        menu.addItem((item: MenuItem) => {
                            item.setTitle('Show on map');
                            item.setIcon('globe');
                            item.onClick(
                                async (evt: MouseEvent) =>
                                    await this.openMapWithLocation(
                                        location,
                                        evt.ctrlKey
                                    )
                            );
                        });
                        // Add an option to open it in the default app
                        menu.addItem((item: MenuItem) => {
                            item.setTitle('Open with default app');
                            item.onClick((_ev) => {
                                open(`geo:${location.lat},${location.lng}`);
                            });
                        });
                        // Populate menu items from user defined "Open In" strings
                        utils.populateOpenInItems(
                            menu,
                            location,
                            this.settings
                        );
                    }
                    if (editor.getSelection()) {
                        // If there is text selected, add a menu item to convert it to coordinates using geosearch
                        menu.addItem((item: MenuItem) => {
                            item.setTitle('Convert to geolocation (geosearch)');
                            item.onClick(
                                async () =>
                                    await this.suggestor.selectionToLink(editor)
                            );
                        });
                    }

                    if (this.urlConvertor.hasMatchInLine(editor))
                        // If the line contains a recognized geolocation that can be converted from a URL parsing rule
                        menu.addItem(async (item: MenuItem) => {
                            item.setTitle('Convert to geolocation');
                            item.onClick(async () => {
                                this.urlConvertor.convertUrlAtCursorToGeolocation(
                                    editor
                                );
                            });
                        });

                    const clipboard = await navigator.clipboard.readText();
                    let clipboardLocation =
                        this.urlConvertor.parseLocationFromUrl(clipboard);
                    if (clipboardLocation) {
                        // If the clipboard contains a recognized geolocation that can be converted from a URL parsing rule
                        menu.addItem((item: MenuItem) => {
                            item.setTitle('Paste as geolocation');
                            item.onClick(async () => {
                                if (clipboardLocation instanceof Promise)
                                    clipboardLocation = await clipboardLocation;
                                if (clipboardLocation)
                                    this.urlConvertor.insertLocationToEditor(
                                        clipboardLocation.location,
                                        editor
                                    );
                            });
                        });
                    }
                }
            }
        );
    }