mirror of
https://github.com/4source/favorites-obsidian-plugin.git
synced 2026-07-22 06:44:46 +00:00
Use monkey-around to patch functions
This commit is contained in:
parent
2fa7bce535
commit
a7adffdac5
4 changed files with 76 additions and 126 deletions
11
package-lock.json
generated
11
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "favorites",
|
||||
"version": "0.0.1",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "favorites",
|
||||
"version": "0.0.1",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@stylistic/eslint-plugin": "^3.1.0",
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
"eslint": "^8.57.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"monkey-around": "^3.0.0",
|
||||
"obsidian": "latest",
|
||||
"semver": "^7.6.0",
|
||||
"ts-jest": "^29.1.2",
|
||||
|
|
@ -5048,6 +5049,12 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/monkey-around": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/monkey-around/-/monkey-around-3.0.0.tgz",
|
||||
"integrity": "sha512-jL6uY2lEAoaHxZep1cNRkCZjoIWY4g5VYCjriEWmcyHU7w8NU1+JH57xE251UVTohK0lCxMjv0ZV4ByDLIXEpw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
"eslint": "^8.57.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"monkey-around": "^3.0.0",
|
||||
"obsidian": "latest",
|
||||
"semver": "^7.6.0",
|
||||
"ts-jest": "^29.1.2",
|
||||
|
|
@ -33,4 +34,4 @@
|
|||
"typescript": "4.7.4"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
src/constants.ts
Normal file
6
src/constants.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export const PLUGIN_ID = 'favorite';
|
||||
export const MONKEY_KEY_MODAL_OPEN = `${PLUGIN_ID}-Modal-open`;
|
||||
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`;
|
||||
182
src/main.ts
182
src/main.ts
|
|
@ -1,44 +1,39 @@
|
|||
import { CommunityItem, CommunityModal, Modal, Plugin } 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';
|
||||
|
||||
export default class FavoritesPlugin extends Plugin {
|
||||
favoritePlugins?: string[];
|
||||
favoriteThemes?: string[];
|
||||
communityPluginModalPrototype?: CommunityModal;
|
||||
communityThemesModalPrototype?: CommunityModal;
|
||||
uninstallModalOpen: () => void;
|
||||
uninstallPluginBrowserModalUpdateItems: () => void;
|
||||
uninstallPluginBrowserModalShowItem: () => void;
|
||||
uninstallThemeBrowserModalUpdateItems: () => void;
|
||||
uninstallThemeBrowserModalShowItem: () => void;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
|
||||
if (!Modal.prototype.originalOpen) {
|
||||
Modal.prototype.originalOpen = Modal.prototype.open;
|
||||
const originalModalOpen = Modal.prototype.open;
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const plugin = this;
|
||||
|
||||
Modal.prototype.open = (function (originalModalOpen, plugin) {
|
||||
return function () {
|
||||
originalModalOpen?.apply(this);
|
||||
this.uninstallModalOpen = around(Modal.prototype, {
|
||||
open(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_MODAL_OPEN, oldMethod, function (...args) {
|
||||
const result = oldMethod && oldMethod.apply(this, args);
|
||||
|
||||
// Check the opened Modal is the Community plugin browse modal
|
||||
if (this.containerEl?.querySelector('.mod-community-plugin')) {
|
||||
// Store the Community Plugin Browse Modal prototype to be able to reset to the original
|
||||
plugin.communityPluginModalPrototype = this.constructor.prototype;
|
||||
|
||||
// Check the plugin updateItems is already overwritten
|
||||
if (!this.constructor.prototype.originalUpdateItems) {
|
||||
// Save original method
|
||||
this.constructor.prototype.originalUpdateItems = this.constructor.prototype.updateItems;
|
||||
const originalUpdateItems = this.constructor.prototype.updateItems;
|
||||
if (!this.constructor.prototype.originalUpdateItems) {
|
||||
console.error('Favorites plugin: Failed to access original updateItems method!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Overwrite method with additional functionality
|
||||
this.constructor.prototype.updateItems = (function (originalUpdateItems, plugin) {
|
||||
return function () {
|
||||
// Patch updateItems method
|
||||
plugin.uninstallPluginBrowserModalUpdateItems = around(this.constructor.prototype, {
|
||||
updateItems(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_PLUGIN_BROWSER_MODAL_UPDATE_ITEMS, oldMethod, function () {
|
||||
// Load the favorite plugins
|
||||
plugin.favoritePlugins = JSON.parse(localStorage.getItem('favorite-plugins') || '[]');
|
||||
|
||||
const result = originalUpdateItems.apply(this);
|
||||
const result = oldMethod && oldMethod.apply(this, args);
|
||||
|
||||
// Add to the favorite plugins a tag to visualize it for the user
|
||||
if (plugin.favoritePlugins) {
|
||||
|
|
@ -53,27 +48,18 @@ export default class FavoritesPlugin extends Plugin {
|
|||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
})(originalUpdateItems, plugin);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Check the plugin showItem is already overwritten
|
||||
if (!this.constructor.prototype.originalShowItem) {
|
||||
// Save original method
|
||||
this.constructor.prototype.originalShowItem = this.constructor.prototype.showItem;
|
||||
const originalShowItem = this.constructor.prototype.showItem;
|
||||
if (!this.constructor.prototype.originalShowItem) {
|
||||
console.error('Favorites: Failed to access original showItem method!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Overwrite method with additional functionality
|
||||
this.constructor.prototype.showItem = (function (originalShowItem, plugin) {
|
||||
return function (...args: CommunityItem[]) {
|
||||
// Patch showItem method
|
||||
plugin.uninstallPluginBrowserModalShowItem = around(this.constructor.prototype, {
|
||||
showItem(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_PLUGIN_BROWSER_MODAL_SHOW_ITEMS, oldMethod, async function (...args: CommunityItem[]) {
|
||||
// Load the favorite plugins
|
||||
plugin.favoritePlugins = JSON.parse(localStorage.getItem('favorite-plugins') || '[]');
|
||||
|
||||
return originalShowItem.apply(this, args).then(async (r: void) => {
|
||||
return oldMethod && oldMethod.apply(this, args).then(async (r: void) => {
|
||||
const infoEl = await this.detailsEl.getElementsByClassName('community-modal-info')[0];
|
||||
const infoNameEl = await infoEl?.getElementsByClassName('community-modal-info-name')[0];
|
||||
const buttonContainerEl = await infoEl?.getElementsByClassName('community-modal-button-container')[0];
|
||||
|
|
@ -108,33 +94,21 @@ export default class FavoritesPlugin extends Plugin {
|
|||
|
||||
return r;
|
||||
});
|
||||
};
|
||||
})(originalShowItem, plugin);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Check the opened Modal is the Community themes browse modal
|
||||
if (this.containerEl?.querySelector('.mod-community-theme')) {
|
||||
// Store the Community Theme Browse Modal prototype to be able to reset to the original
|
||||
plugin.communityThemesModalPrototype = this.constructor.prototype;
|
||||
|
||||
// Check the theme updateItems is already overwritten
|
||||
if (!this.constructor.prototype.originalUpdateItems) {
|
||||
// Save original method
|
||||
this.constructor.prototype.originalUpdateItems = this.constructor.prototype.updateItems;
|
||||
const originalUpdateItems = this.constructor.prototype.updateItems;
|
||||
if (!this.constructor.prototype.originalUpdateItems) {
|
||||
console.error('Favorites: Failed to access original updateItems method!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Overwrite method with additional functionality
|
||||
this.constructor.prototype.updateItems = (function (originalUpdateItems, plugin) {
|
||||
return function () {
|
||||
// Patch updateItems method
|
||||
plugin.uninstallThemeBrowserModalUpdateItems = around(this.constructor.prototype, {
|
||||
updateItems(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_THEME_BROWSER_MODAL_UPDATE_ITEMS, oldMethod, function () {
|
||||
// Load the favorite themes
|
||||
plugin.favoriteThemes = JSON.parse(localStorage.getItem('favorite-themes') || '[]');
|
||||
|
||||
const result = originalUpdateItems.apply(this);
|
||||
const result = oldMethod && oldMethod.apply(this, args);
|
||||
|
||||
// Ignore the default theme
|
||||
if (this.selectedItemId === '') {
|
||||
|
|
@ -154,27 +128,18 @@ export default class FavoritesPlugin extends Plugin {
|
|||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
})(originalUpdateItems, plugin);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Check the theme showItem is already overwritten
|
||||
if (!this.constructor.prototype.originalShowItem) {
|
||||
// Save original method
|
||||
this.constructor.prototype.originalShowItem = this.constructor.prototype.showItem;
|
||||
const originalShowItem = this.constructor.prototype.showItem;
|
||||
if (!this.constructor.prototype.originalShowItem) {
|
||||
console.error('Favorites: Failed to access original showItem method!');
|
||||
return;
|
||||
}
|
||||
// Patch showItems method
|
||||
plugin.uninstallThemeBrowserModalShowItem = around(this.constructor.prototype, {
|
||||
showItem(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_THEME_BROWSER_MODAL_SHOW_ITEMS, oldMethod, async function (...args: CommunityItem[]) {
|
||||
// Load the favorite themes
|
||||
plugin.favoriteThemes = JSON.parse(localStorage.getItem('favorite-themes') || '[]');
|
||||
|
||||
// Overwrite method with additional functionality
|
||||
this.constructor.prototype.showItem = (function (originalShowItem, plugin) {
|
||||
// Load the favorite themes
|
||||
plugin.favoriteThemes = JSON.parse(localStorage.getItem('favorite-themes') || '[]');
|
||||
|
||||
return function (...args: CommunityItem[]) {
|
||||
return originalShowItem.apply(this, args).then(async (r: void) => {
|
||||
return oldMethod && oldMethod.apply(this, args).then(async (r: void) => {
|
||||
// Ignore the default theme
|
||||
if (this.selectedItemId === '') {
|
||||
return;
|
||||
|
|
@ -214,22 +179,17 @@ export default class FavoritesPlugin extends Plugin {
|
|||
|
||||
return r;
|
||||
});
|
||||
};
|
||||
})(originalShowItem, plugin);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Restore the original Modal open function as soon as the CommunityPluginModal and CommunityThemesModal is opened once
|
||||
if (Modal.prototype.originalOpen && plugin.communityPluginModalPrototype && plugin.communityThemesModalPrototype) {
|
||||
Modal.prototype.open = Modal.prototype.originalOpen;
|
||||
delete Modal.prototype.originalOpen;
|
||||
}
|
||||
};
|
||||
})(originalModalOpen, this);
|
||||
}
|
||||
else {
|
||||
console.warn('Favorites plugin: Modal prototype already has originalOpen, this is not intended!');
|
||||
}
|
||||
return result;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: Redraw modals if local storage 'favorite-plugins' or 'favorite-themes' changed
|
||||
|
||||
/*
|
||||
* TODO: Add command to save and reload the favorites list
|
||||
|
|
@ -239,36 +199,12 @@ export default class FavoritesPlugin extends Plugin {
|
|||
}
|
||||
|
||||
async onunload() {
|
||||
// Restore the original Modal open function
|
||||
|
||||
if (Modal.prototype.originalOpen) {
|
||||
Modal.prototype.open = Modal.prototype.originalOpen;
|
||||
delete Modal.prototype.originalOpen;
|
||||
}
|
||||
|
||||
// Restore the original plugin updateItems function
|
||||
if (this.communityPluginModalPrototype && this.communityPluginModalPrototype.originalUpdateItems) {
|
||||
this.communityPluginModalPrototype.updateItems = this.communityPluginModalPrototype.originalUpdateItems;
|
||||
delete this.communityPluginModalPrototype.originalUpdateItems;
|
||||
}
|
||||
|
||||
// Restore the original plugin showItem function
|
||||
if (this.communityPluginModalPrototype && this.communityPluginModalPrototype.originalShowItem) {
|
||||
this.communityPluginModalPrototype.showItem = this.communityPluginModalPrototype.originalShowItem;
|
||||
delete this.communityPluginModalPrototype.originalShowItem;
|
||||
}
|
||||
|
||||
// Restore the original theme updateItems function
|
||||
if (this.communityThemesModalPrototype && this.communityThemesModalPrototype.originalUpdateItems) {
|
||||
this.communityThemesModalPrototype.updateItems = this.communityThemesModalPrototype.originalUpdateItems;
|
||||
delete this.communityThemesModalPrototype.originalUpdateItems;
|
||||
}
|
||||
|
||||
// Restore the original theme showItem function
|
||||
if (this.communityThemesModalPrototype && this.communityThemesModalPrototype.originalShowItem) {
|
||||
this.communityThemesModalPrototype.showItem = this.communityThemesModalPrototype.originalShowItem;
|
||||
delete this.communityThemesModalPrototype.originalShowItem;
|
||||
}
|
||||
// Restore the original functions
|
||||
this.uninstallModalOpen();
|
||||
this.uninstallPluginBrowserModalUpdateItems();
|
||||
this.uninstallPluginBrowserModalShowItem();
|
||||
this.uninstallThemeBrowserModalUpdateItems();
|
||||
this.uninstallThemeBrowserModalShowItem();
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue