[FEAT] Favorite/Unfavorite for installed plugins (#8)

* Fix favorite themes loading logic

* Validate environment variables for favorite plugins and themes on load

* Add community plugins settings tab favorite icon

* Enhance README with usage details and screenshots

Updated the README to clarify ease of use and added additional screenshots.

* Security Audit fix
This commit is contained in:
4Source 2026-03-01 22:30:15 +01:00 committed by GitHub
parent 7303174298
commit 40c4930ba1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 204 additions and 78 deletions

View file

@ -4,14 +4,12 @@ Stop re-searching the same plugins or themes in every vault. With one central li
# Features
- **Global Favorites for Plugins & Themes** - Mark your go to plugins and themes once and use them in all vaults
- **Ease of Use** - Favorite/unfavorite directly from the Obsidian's plugin and theme details browser
- **Ease of Use** - Favorite/unfavorite directly inside the Obsidian's
- Plugin browser
- Community plugins tab
- Theme browser
- **Vault Independence** - Favorites are stored globally on your device, not tied to a single vault
# Screenshots
<img width="1104" height="1004" alt="image" src="https://github.com/user-attachments/assets/61b41e7b-4569-4509-95f3-d5e8a667d653" />
<img width="1104" height="1004" alt="image" src="https://github.com/user-attachments/assets/960eac0d-fea2-48e1-8faf-e54a7504149e" />
# How It Works
1. Install and enable ***Favorites***.
2. Open Obsidian's plugin or theme browser.
@ -19,6 +17,15 @@ Stop re-searching the same plugins or themes in every vault. With one central li
4. Use the Favorite button.
5. Your favorites are saved globally and appear in every vault.
For plugins you can also favorite already installed plugins directly from the Community plugins tab.
# Screenshots
<img width="1104" height="1004" alt="image" src="https://github.com/user-attachments/assets/61b41e7b-4569-4509-95f3-d5e8a667d653" />
<img width="1100" height="1000" alt="image" src="https://github.com/user-attachments/assets/a0b35f98-b194-433f-bd9e-66eecb5dd111" />
<img width="1104" height="1004" alt="image" src="https://github.com/user-attachments/assets/960eac0d-fea2-48e1-8faf-e54a7504149e" />
# Contribution
Feel free to contribute.

99
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "favorites",
"version": "1.1.1",
"version": "1.1.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "favorites",
"version": "1.1.1",
"version": "1.1.2",
"license": "MIT",
"devDependencies": {
"@stylistic/eslint-plugin": "^3.1.0",
@ -68,6 +68,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz",
"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
"dev": true,
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
@ -1059,10 +1060,11 @@
}
},
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -1105,10 +1107,11 @@
}
},
"node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -1175,10 +1178,11 @@
}
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@ -1574,8 +1578,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
"dev": true,
"peer": true
"dev": true
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
@ -1979,6 +1982,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz",
"integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
"dev": true,
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "7.18.0",
"@typescript-eslint/types": "7.18.0",
@ -2156,6 +2160,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@ -2207,10 +2212,11 @@
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@ -2490,6 +2496,7 @@
"url": "https://github.com/sponsors/ai"
}
],
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001688",
"electron-to-chromium": "^1.5.73",
@ -3108,6 +3115,7 @@
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@ -3226,10 +3234,11 @@
}
},
"node_modules/eslint/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -3443,10 +3452,11 @@
}
},
"node_modules/filelist/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"version": "5.1.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@ -3667,10 +3677,11 @@
}
},
"node_modules/glob/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -4118,10 +4129,11 @@
}
},
"node_modules/jake/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -4134,6 +4146,7 @@
"resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
"dev": true,
"peer": true,
"dependencies": {
"@jest/core": "^29.7.0",
"@jest/types": "^29.6.3",
@ -4730,10 +4743,11 @@
"dev": true
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@ -5026,12 +5040,13 @@
}
},
"node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"version": "9.0.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
"brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@ -5806,8 +5821,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
"dev": true,
"peer": true
"dev": true
},
"node_modules/supports-color": {
"version": "7.2.0",
@ -5864,10 +5878,11 @@
}
},
"node_modules/test-exclude/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -6030,6 +6045,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
"dev": true,
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@ -6120,8 +6136,7 @@
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
"dev": true,
"peer": true
"dev": true
},
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",

View file

@ -1,6 +1,8 @@
export const PLUGIN_ID = 'favorite';
export const MONKEY_KEY_MODAL_OPEN = `${PLUGIN_ID}-Modal-open`;
export const MONKEY_KEY_SETTINGS_MODAL_OPEN_TAB = `${PLUGIN_ID}-SettingsModal-openTab`;
export const MONKEY_KEY_PLUGIN_BROWSER_MODAL_UPDATE_ITEMS = `${PLUGIN_ID}-CommunityPluginModal-updateItems`;
export const MONKEY_KEY_PLUGIN_BROWSER_MODAL_SHOW_ITEMS = `${PLUGIN_ID}-CommunityPluginModal-showItems`;
export const MONKEY_KEY_THEME_BROWSER_MODAL_UPDATE_ITEMS = `${PLUGIN_ID}-ThemePluginModal-updateItems`;
export const MONKEY_KEY_THEME_BROWSER_MODAL_SHOW_ITEMS = `${PLUGIN_ID}-ThemePluginModal-showItems`;
export const MONKEY_KEY_THEME_BROWSER_MODAL_SHOW_ITEMS = `${PLUGIN_ID}-ThemePluginModal-showItems`;
export const MONKEY_KEY_COMMUNITY_PLUGIN_SETTINGS_TAB_RENDER_INSTALLED_PLUGIN = `${PLUGIN_ID}-CommunityPluginsSettingTab-renderInstalledPlugin`;

View file

@ -1,6 +1,6 @@
import { CommunityItem, CommunityModal, Modal, Plugin } from 'obsidian';
import { CommunityItem, CommunityModal, CommunityPluginsSettingTab, Modal, Plugin, setIcon, SettingsModal, SettingTab, setTooltip } from 'obsidian';
import { dedupe, around } from 'monkey-around';
import { MONKEY_KEY_PLUGIN_BROWSER_MODAL_UPDATE_ITEMS, MONKEY_KEY_MODAL_OPEN, MONKEY_KEY_THEME_BROWSER_MODAL_UPDATE_ITEMS, MONKEY_KEY_THEME_BROWSER_MODAL_SHOW_ITEMS, MONKEY_KEY_PLUGIN_BROWSER_MODAL_SHOW_ITEMS } from './constants';
import { MONKEY_KEY_PLUGIN_BROWSER_MODAL_UPDATE_ITEMS, MONKEY_KEY_MODAL_OPEN, MONKEY_KEY_THEME_BROWSER_MODAL_UPDATE_ITEMS, MONKEY_KEY_THEME_BROWSER_MODAL_SHOW_ITEMS, MONKEY_KEY_PLUGIN_BROWSER_MODAL_SHOW_ITEMS, MONKEY_KEY_SETTINGS_MODAL_OPEN_TAB, MONKEY_KEY_COMMUNITY_PLUGIN_SETTINGS_TAB_RENDER_INSTALLED_PLUGIN } from './constants';
export default class FavoritesPlugin extends Plugin {
pluginsKey: string;
@ -10,19 +10,103 @@ export default class FavoritesPlugin extends Plugin {
communityPluginModalPrototype?: CommunityModal;
communityThemesModalPrototype?: CommunityModal;
uninstallModalOpen?: () => void;
uninstallSettingsModalOpenTab?: () => void;
uninstallPluginBrowserModalUpdateItems?: () => void;
uninstallPluginBrowserModalShowItem?: () => void;
uninstallThemeBrowserModalUpdateItems?: () => void;
uninstallThemeBrowserModalShowItem?: () => void;
uninstallCommunityPluginsSettingTabRenderInstalledPlugin?: () => void;
onload() {
this.pluginsKey = process.env.FAVORITE_PLUGINS_KEY || '';
this.themesKey = process.env.FAVORITE_THEMES_KEY || '';
if (process.env.FAVORITE_PLUGINS_KEY) {
this.pluginsKey = process.env.FAVORITE_PLUGINS_KEY;
}
else {
throw Error('Missing environment variable \'FAVORITE_PLUGINS_KEY\'');
}
if (process.env.FAVORITE_THEMES_KEY) {
this.themesKey = process.env.FAVORITE_THEMES_KEY;
}
else {
throw Error('Missing environment variable \'FAVORITE_THEMES_KEY\'');
}
console.debug(`Plugins key: ${this.pluginsKey} Themes key: ${this.themesKey}`);
// eslint-disable-next-line @typescript-eslint/no-this-alias -- Is required because the this context wil change inside the 'monkey-around' functions but the plugin is required to be accessible
const plugin = this;
// Patch the opening of SettingsModal
if (!this.uninstallSettingsModalOpenTab) {
console.debug('Patch SettingsModal.openTab');
this.uninstallSettingsModalOpenTab = around(this.app.setting as SettingsModal, {
openTab(oldMethod) {
return dedupe(MONKEY_KEY_SETTINGS_MODAL_OPEN_TAB, oldMethod, function (...args) {
console.debug('Call SettingsModal.openTab');
const tab = args[0] as SettingTab;
if (tab.id === 'community-plugins') {
if (!plugin.uninstallCommunityPluginsSettingTabRenderInstalledPlugin) {
console.debug('Patch CommunityPluginsSettingTab.renderInstalledPlugin');
plugin.uninstallCommunityPluginsSettingTabRenderInstalledPlugin = around((tab as CommunityPluginsSettingTab), {
renderInstalledPlugin(oldMethod) {
return dedupe(MONKEY_KEY_COMMUNITY_PLUGIN_SETTINGS_TAB_RENDER_INSTALLED_PLUGIN, oldMethod, function (...args) {
console.debug('Call CommunityPluginsSettingTab.renderInstalledPlugin');
oldMethod && oldMethod.apply(this, args);
// Load the favorite plugins
plugin.loadFavoritePlugins();
const selectedPluginID = args[0].id;
const isFavorite = plugin.favoritePlugins?.contains(selectedPluginID);
const favEl = createDiv('clickable-icon extra-setting-button');
plugin.registerDomEvent(favEl, 'click', () => {
if (isFavorite) {
plugin.favoritePlugins?.remove(selectedPluginID);
}
else {
plugin.favoritePlugins?.push(selectedPluginID);
}
plugin.saveFavorites();
// Redraw
(tab as CommunityPluginsSettingTab).render(false);
});
if (isFavorite) {
setIcon(favEl, 'star-off');
setTooltip(favEl, 'Unfavorite');
}
else {
setIcon(favEl, 'star');
setTooltip(favEl, 'Favorite');
}
// Add Favorite Icon to plugin control
const controlEl: HTMLElement = this.installedPlugins.listEl.lastChild?.getElementsByClassName('setting-item-control')[0];
controlEl.insertBefore(favEl, controlEl.children[0]);
});
},
});
}
else {
console.debug('CommunityPluginsSettingTab.renderInstalledPlugin already patched!');
}
}
if (plugin.uninstallSettingsModalOpenTab && plugin.uninstallCommunityPluginsSettingTabRenderInstalledPlugin) {
console.debug('Uninstall SettingsModal.openTab');
plugin.uninstallSettingsModalOpenTab();
plugin.uninstallSettingsModalOpenTab = undefined;
}
return oldMethod && oldMethod.apply(this, args);
});
},
});
}
if (!this.uninstallModalOpen) {
console.debug('Patch Modal.open');
this.uninstallModalOpen = around(Modal.prototype, {
@ -64,7 +148,7 @@ export default class FavoritesPlugin extends Plugin {
});
}
else {
console.warn('PluginBrowserModal.updateItems already patched!');
console.debug('PluginBrowserModal.updateItems already patched!');
}
// Patch showItem method
@ -118,7 +202,7 @@ export default class FavoritesPlugin extends Plugin {
});
}
else {
console.warn('PluginBrowserModal.showItem already patched!');
console.debug('PluginBrowserModal.showItem already patched!');
}
}
@ -160,7 +244,7 @@ export default class FavoritesPlugin extends Plugin {
});
}
else {
console.warn('ThemeBrowserModal.updateItems already patched!');
console.debug('ThemeBrowserModal.updateItems already patched!');
}
// Patch showItems method
@ -219,7 +303,7 @@ export default class FavoritesPlugin extends Plugin {
});
}
else {
console.warn('ThemeBrowserModal.showItem already patched!');
console.debug('ThemeBrowserModal.showItem already patched!');
}
}
@ -254,6 +338,11 @@ export default class FavoritesPlugin extends Plugin {
this.uninstallModalOpen();
this.uninstallModalOpen = undefined;
}
if (this.uninstallSettingsModalOpenTab) {
console.debug('Uninstall SettingsModal.openTab');
this.uninstallSettingsModalOpenTab();
this.uninstallSettingsModalOpenTab = undefined;
}
if (this.uninstallPluginBrowserModalUpdateItems) {
console.debug('Uninstall PluginBrowserModal.updateItem');
this.uninstallPluginBrowserModalUpdateItems();
@ -274,6 +363,11 @@ export default class FavoritesPlugin extends Plugin {
this.uninstallThemeBrowserModalShowItem();
this.uninstallThemeBrowserModalShowItem = undefined;
}
if (this.uninstallCommunityPluginsSettingTabRenderInstalledPlugin) {
console.debug('Uninstall CommunityPluginsSettingTab.renderInstalledPlugin');
this.uninstallCommunityPluginsSettingTabRenderInstalledPlugin();
this.uninstallCommunityPluginsSettingTabRenderInstalledPlugin = undefined;
}
}
catch (e) {
console.error(e);
@ -287,7 +381,7 @@ export default class FavoritesPlugin extends Plugin {
loadFavoriteThemes() {
// Load the favorite plugins
this.favoritePlugins = JSON.parse(localStorage.getItem(this.themesKey) || '[]');
this.favoriteThemes = JSON.parse(localStorage.getItem(this.themesKey) || '[]');
}
saveFavorites() {

48
src/types.d.ts vendored
View file

@ -1,37 +1,45 @@
import { } from 'obsidian';
declare module 'obsidian' {
interface App {
setting: SettingsModal
}
interface CommunityItem {
id: string;
// ...
}
interface CommunityModal {
update(): void;
updateItems(): CommunityItem[];
showItem(item: CommunityItem): void;
// ...
// Additional from this plugin
/**
* This is the backup of the original ``updateItems()`` function. Do not use otherwise than restoring!
*/
originalUpdateItems?(): CommunityItem[];
/**
* This is the backup of the original ``showItem()`` function. Do not use otherwise than restoring!
*/
originalShowItem?(item: CommunityItem): void;
}
interface Modal {
// Additional form this plugin
/**
* This is the backup of the original ``open()`` function. Do not use otherwise than restoring!
*/
originalOpen?(): void;
}
interface SettingsModal {
openTab(settingTab: SettingTab): unknown;
}
interface SettingTab {
id: string;
setting: unknown;
containerEl: HTMLElement;
navEl: HTMLElement;
app: App;
}
interface CommunityPluginsSettingTab extends SettingTab {
id: 'community-plugins';
installedPlugins: {
listEl: HTMLElement
};
display(): void;
render(e: boolean): void;
renderInstalledPlugin(plugin: CommunityItem, t: unknown, n: unknown, i: unknown, r: unknown): void;
updateSearch(e: unknown): void
}
}