Skip to content

Commit

Permalink
Release 1.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mnowotnik committed Nov 16, 2024
1 parent f59d8a3 commit 760cfa9
Show file tree
Hide file tree
Showing 25 changed files with 426 additions and 112 deletions.
186 changes: 89 additions & 97 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,140 +1,132 @@
# User Plugins for Obsidian
# Obsidian User Plugins

User Plugins is a simple plugin that lets you use Obsidian plugin API in your snippets or javascript files to modify
the behaviour of Obsidian just as if you created a plugin, but without the hassle.
Lets you use the Obsidian plugin API in your snippets or JavaScript files to modify the behavior of Obsidian, just as if you created a plugin, but without the hassle.

# Stop and read

> :warning: **This plugin is for advanced users only**: DO NOT use code in scripts you do not fully
> understand. It can delete your notes or worse. See [legal notice](#Notice).
> :warning: **This plugin is for advanced users only**: DO NOT use code in scripts you do not fully understand.
> It can delete your notes or worse. See [legal notice](#Notice).
## Use cases
# Caveats

- [adding custom commands](https://docs.obsidian.md/Reference/TypeScript+API/Command)
- testing an idea for a plugin
- using plugin API to do anything you want
## Obsidian API compatibility

## Motivating example
> :warning: Do not assume user scripts can run any Obsidian API functions other
> than what is shown in the examples. Creating settings is especially not supported, but it is on the [roadmap](#roadmap).
Add command `Create new note in given folder` that allows you to choose
a folder before creating a note.
## Versioning

Newer versions of this plugin will usually require the newest Obsidian version due to its API changes. Consider this plugin "bleeding edge" for now.

# Use cases

- [Adding custom commands](https://docs.obsidian.md/Reference/TypeScript+API/Command)
- Testing an idea for a plugin
- Using Obsidian plugin API to do anything you want

# Motivating example

Add command `Create new note in folder` that allows you to choose a folder
before creating a note:

```javascript
module.exports = {}

module.exports.onload = async (plugin) => {
const MarkdownView = plugin.passedModules.obsidian.MarkdownView
plugin.addCommand({
id: 'new-note-in-folder',
name: 'Create new note in a folder',
callback: async () => {
const folders = plugin.app.vault.getAllLoadedFiles().filter(i => i.children).map(folder => folder.path);
const folder = await plugin.helpers.suggest(folders, folders);
const created_note = await plugin.app.vault.create(folder + "/Untitled.md", "")
const active_leaf = plugin.app.workspace.activeLeaf;
if (!active_leaf) {
return;
}
await active_leaf.openFile(created_note, {
state: { mode: "source" },
});
plugin.app.workspace.trigger("create",created_note)
const view = app.workspace.getActiveViewOfType(MarkdownView);
if (view) {
const editor = view.editor;
editor.focus()
}
}
});
}
module.exports = {
async onload(plugin) {
plugin.addCommand({
id: "new-note-in-folder",
name: "Create new note in a folder",
callback: async () => {
const api = plugin.api;
const folders = api.getAllFolders();
const folder = await api.suggest(folders, folders);
const createdNote = await plugin.app.vault.create(folder + "/Hello World.md", "Hello World!");
api.openFile(createdNote);
},
});
},
async onunload() {
// optional
console.log("unloading plugin");
},
};

```

![Command in palette](https://user-images.githubusercontent.com/8244123/167032593-0dbe59b1-2c2a-4700-83f4-01609cf0d30a.png)

## Quick start

### Installation
# Quick start

~This plugin is not yet available in the Community Plugins panel.~
## Installation

You can easily add this plugin from Community Plugins panel.
Alternatively, here's a manual way:

`git clone` this repo to `<YOUR VAULT>/.obsidian/plugins` folder and then execute:
Clone this repository into the `<YOUR VAULT>/.obsidian/plugins` folder and then execute:

```bash
npm install
npm run build
```

### Usage
## Usage

Scripts can be added either by manually adding snippets or enabling each individual file in
a scripts directory in a vault. Scripts have access to a `Plugin` object. Its API is declared [here](https://github.com/obsidianmd/obsidian-api/blob/master/obsidian.d.ts).
`plugin` has two additional members:
You can add scripts either by manually adding snippets or enabling each individual file in the defined scripts directory in your vault.

- `helpers`
To use scripts, specify a scripts folder in settings, hit the reload button to search for scripts in the specified path,
then enable each script found using a toggle button.

Currently it has a single method that opens a suggester modal:
There are a few types of scripts that you can use.

```javascript
suggest<T>(
textItems: string[] | ((item: T) => string),
items: T[],
placeholder?: string,
limit?: number
)
```
### Obsidian plugin type

- `passedModules`
Has the basic structure of an Obsidian plugin:

Currently only gives access to the `obsidian` module
```typescript
import { Plugin } from "obsidian";

#### Snippet
export default class MyPlugin extends Plugin {
async onload() {
// code here
}
}
```
Written in either [Typescript](./examples/ts-plugin/main.ts) or [Javascript](./examples/js-plugin/plugin.js) flavour.

A snippet is just a javascript block of code that has access to a `plugin` variable.
It is executed in the `onload` method of the plugin.
Example:
You have access to [Helper API](#helper-api) by getting `obsidian-user-plugins` via `this.app.plugins.getPlugin`.

```javascript
plugin.addCommand({
id: 'foo-bar',
name: 'FooBar',
callback: () => {
console.log('foobar');
}
});
```
### Module type

#### Script file
A JavaScript module that exports at least an `async onload(plugin): void` method and
optionally an `async onnunload(): void` method. It has access to the global function
`require` to get the `obsidian` module.
The `plugin` parameter is an instance of `obsidian-user-plugins` with the [Helper API](#helper-api).

A script file follows CommonJS module specification and exports at least `onload` function that
takes a single argument `plugin` as an input. You must specify `onload` function in the exported
module and you can also specify `onunload` if needed.
See [example](./examples/js-module/module.js).

To use scripts specify scripts folder in settings, hit the reload button to search for scripts in the specified path
and then enable each found script using a toggle button.
### Snippet

Example:
```javascript
module.exports = {}
module.exports.onload = function(plugin) {
plugin.addCommand({
id: 'foo-bar',
name: 'FooBar',
callback: () => {
console.log('foobar');
}
});
}
module.exports.onunload = function(plugin) {
console.log('unload')
}
```
## Obsidian developer documentation
A snippet is a JavaScript block of code that has access to the global `plugin`
variable. It also has access to the global function `require` to get the `obsidian`
module. Snippets are executed during the plugin initialization phase in `onload()`.
You can also access [Helper API](#helper-api) via the `plugin.api` object.

See [example](./examples/js-snippet/snippet.js).

# Helper API

This plugin exposes an `api` object with handy methods. Check them out [here](./src/helpers/Helpers.ts).

# Roadmap

- [ ] Custom configuration per script file
- [ ] Additional functions in the [Helper API](#helper-api)

# Obsidian Plugin API

The Obsidian plugin API is declared [here](https://github.com/obsidianmd/obsidian-api/blob/master/obsidian.d.ts).

The [Obsidian Developer platform](https://docs.obsidian.md/Reference/TypeScript+API/) contains extensive documentation for the various plugin methods and interfaces, e.g. for the [Command](https://docs.obsidian.md/Reference/TypeScript+API/Command) interface or the [Plugin](https://docs.obsidian.md/Reference/TypeScript+API/Plugin) class.

## Notice
# Notice

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3 changes: 3 additions & 0 deletions examples/js-module/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Sample JS module

Put it in the directory set in Obsidian User Plugins configuration. Should appear on the list of available scripts.
19 changes: 19 additions & 0 deletions examples/js-module/module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module.exports = {
async onload(plugin) {
plugin.addCommand({
id: "new-note-in-folder",
name: "Create new note in a folder",
callback: async () => {
const api = plugin.api;
const folders = api.getAllFolders();
const folder = await api.suggest(folders, folders);
const createdNote = await plugin.app.vault.create(folder + "/Hello World.md", "Hello World!");
api.openFile(createdNote);
},
});
},
async onunload() {
// optional
console.log("unloading plugin");
},
};
3 changes: 3 additions & 0 deletions examples/js-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Sample JS plugin

Put it in the directory set in Obsidian User Plugins configuration. Should appear on the list of available scripts.
17 changes: 17 additions & 0 deletions examples/js-plugin/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = {};
const Plugin = require('obsidian').Plugin;
module.exports.default = class MyPlugin extends Plugin {
async onload() {
this.addCommand({
id: "new-note-in-folder",
name: "Create new note in a folder",
callback: async () => {
const api = this.app.plugins.getPlugin("obsidian-user-plugins").api;
const folders = api.getAllFolders();
const folder = await api.suggest(folders, folders);
const createdNote = await this.app.vault.create(folder + "/Hello World.md", "Hello World!");
api.openFile(createdNote);
},
});
}
}
3 changes: 3 additions & 0 deletions examples/js-snippet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Sample JS snippet

Paste it as one of the snippets in Obsidian User Plugins configuration.
10 changes: 10 additions & 0 deletions examples/js-snippet/snippet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
plugin.addCommand({
id: "new-note-in-folder",
name: "Create new note in a folder",
callback: async () => {
const folders = plugin.api.getAllFolders();
const folder = await plugin.api.suggest(folders, folders);
const createdNote = await plugin.app.vault.create(folder + "/Hello World.md", "Hello World!");
plugin.api.openFile(createdNote);
},
});
10 changes: 10 additions & 0 deletions examples/ts-plugin/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# top-most EditorConfig file
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = 2
tab_width = 2
3 changes: 3 additions & 0 deletions examples/ts-plugin/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/

main.js
23 changes: 23 additions & 0 deletions examples/ts-plugin/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"env": { "node": true },
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"parserOptions": {
"sourceType": "module"
},
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
"@typescript-eslint/ban-ts-comment": "off",
"no-prototype-builtins": "off",
"@typescript-eslint/no-empty-function": "off"
}
}
22 changes: 22 additions & 0 deletions examples/ts-plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# vscode
.vscode

# Intellij
*.iml
.idea

# npm
node_modules

# Don't include the compiled main.js file in the repo.
# They should be uploaded to GitHub releases instead.
main.js

# Exclude sourcemaps
*.map

# obsidian
data.json

# Exclude macOS Finder (System Explorer) View States
.DS_Store
1 change: 1 addition & 0 deletions examples/ts-plugin/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tag-version-prefix=""
14 changes: 14 additions & 0 deletions examples/ts-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Sample Plugin

This is just cloned [Obsidian sample plugin](https://github.com/obsidianmd/obsidian-sample-plugin) with [main.ts](./main.ts) modified.

Compile it with

```bash
npm install
npm run build
```

and set the directory in Obsidian User Plugins.
The file `main.js` should appear on the list of available scripts.
Change `esbuild.config.mjs` to modify the name of the output file `main.js`.
Loading

0 comments on commit 760cfa9

Please sign in to comment.