(formerly known as Fix Require Modules
)
This plugin is meant for the developers and other code writers. If you find the purpose of the plugin is not clear enough, I would be more than welcome to accept the PR to improve the README
(formerly known as Fix Require Modules
)
This plugin is meant for the developers and other code writers. If you find the purpose of the plugin is not clear enough, I would be more than welcome to accept the PR to improve the README
Started porting my Templater scripts and User Plugins js scripts over to be used by your plugin today.
Reasons for doing so:
On a personal note, Mikhael is one of my most liked developers, not only for his intuitive solutions, but his all-around availability.
I recommend checking out his other actively maintained plugins as well.
Cheers
It is possible to avoid duplication between Create
and Insert
using one template with according check
Not sure I follow you. A conditional? How would Templater know what I would want to use the script as? Never heard of this.
This is how I differentiate them:
So I can see the ones with the (not yet learnt shortcut), that they are the Insert ones.
You are right. I confused with another thing I used. Sorry
I was not very keen to use Templater as I didn’t want to take on a liability and Obsidian API is enough.
But I was still trying to find a way to use the Templater functionality.
Once I managed to find a solution with Claude (VSCode Copilot), I had it write up a guide.
@mnaoumov Please comment if you find anything wrong in it:
Here’s a comprehensive list of available Templater functions we can add to the interface:
interface TemplaterPlugin {
templater: {
current_functions_object: {
app: any;
date: {
now: (format: string) => Promise<string>;
tomorrow: (format?: string) => Promise<string>;
yesterday: (format?: string) => Promise<string>;
weekday: (format?: string, weekday?: number) => Promise<string>;
};
file: {
path: (full?: boolean) => string;
folder: (full?: boolean) => string;
title: string;
selection: () => string;
tags: string[];
creation_date: (format?: string) => Promise<string>;
last_modified_date: (format?: string) => Promise<string>;
move: (path: string) => Promise<void>;
rename: (newName: string) => Promise<void>;
find_tfile: (path: string) => TFile | null;
include: (path: string) => Promise<string>;
cursor: (order?: number) => number;
cursor_append: (content: string) => void;
exists: (path: string) => boolean;
create_new: (template: string, filename: string, open?: boolean) => Promise<void>;
};
frontmatter: {
[key: string]: any;
};
system: {
clipboard: () => Promise<string>;
prompt: (prompt_text: string, default_value?: string, throw_on_cancel?: boolean) => Promise<string>;
suggester: <T>(
text_items: ((item: T) => string) | string[],
items: T[],
throw_on_cancel?: boolean,
placeholder?: string,
limit?: boolean
) => Promise<T>;
};
web: {
daily_quote: () => Promise<string>;
random_picture: () => Promise<string>;
request: (url: string) => Promise<any>;
};
obsidian: {
// Access to Obsidian API
[key: string]: any;
};
user: {
// Custom user scripts
[key: string]: any;
};
};
};
}
Key Functions Available:
Date Functions:
now()
- Current date/timetomorrow()
- Tomorrow’s dateyesterday()
- Yesterday’s dateweekday()
- Get specific weekdayFile Operations:
path()
- Get file pathtitle
- Get file titleselection()
- Get selected textmove()
- Move filerename()
- Rename filecreate_new()
- Create new fileSystem Interactions:
clipboard()
- Get clipboard contentprompt()
- Show user promptsuggester()
- Show selection menuWeb Functions:
daily_quote()
- Get daily quoterandom_picture()
- Get random picturerequest()
- Make web requestsMeta Functions:
Example Usage:
// Get user input
const userInput = await tp.system.prompt("Enter value");
// Use suggester for selection
const selected = await tp.system.suggester(
items => items.display,
items
);
// Include another template
const content = await tp.file.include("path/to/template.md");
// Create new file from template
await tp.file.create_new("template.md", "New File", true);
const templaterPlugin = app.plugins.plugins['templater-obsidian'] as any;
const tp = templaterPlugin?.templater?.current_functions_object;
// Check availability
if (!tp?.date?.now) {
console.error("Required Templater functions not found!");
return;
}
// Dates
const getDate = async () => await tp.date.now("YYYY-MM-DD[T]HH:mm");
// Files
const getCurrentFile = () => tp.file.find_tfile(tp.file.path(true));
// System
const userInput = await tp.system.prompt("Enter value");
const selected = await tp.system.suggester(
items => items.display,
items
);
try {
const date = await tp.date.now(format);
} catch (error) {
console.error("Templater error:", error);
// Provide fallback
return moment().format(format);
}
if (!app.plugins.plugins['templater-obsidian']) {
console.error("Templater plugin not found!");
return;
}
return new Promise<void>(async (resolve) => {
try {
// Templater code here
} catch (error) {
console.error('Error:', error);
} finally {
resolve();
}
});
import { App, Plugin, TFile } from 'obsidian';
interface TemplaterPlugin {
templater: {
current_functions_object: {
// Add needed functions
};
};
}
async function yourFunction(app: App): Promise<void> {
return new Promise<void>(async (resolve) => {
try {
const templaterPlugin = app.plugins.plugins['templater-obsidian'] as any;
const tp = templaterPlugin?.templater?.current_functions_object;
if (!tp) {
console.error("Templater not found!");
return resolve();
}
// Your code using tp functions
} catch (error) {
console.error('Error:', error);
} finally {
resolve();
}
});
}
// ...existing Plugin class and invoke function...
Templater functions are async - use await
Functions might be unavailable - always check
Mobile needs Promise wrapper
Use fallbacks for critical functions
@Yurcee there are many places that I would consider wrong here
TemplaterPlugin
are not correct. I will provide the correct typings in a bitconst templaterPlugin = app.plugins.plugins['templater-obsidian'] as TemplaterPlugin;
I would not recommend using TemplaterPlugin
outside of Templater
. For example, it won’t be initialized if you try to use it before any templates were running.
Use Promise wrapper for mobile compatibility
is an anti-pattern, it’s quite bad to use async
inside Promise
constructor
The correct way is
const asyncFn = async () => {
// ...
};
const promise = asyncFn();
return promise;
import * as obsidian from 'obsidian';
import {
App,
TFile,
TFolder,
} from 'obsidian';
enum RunMode {
CreateNewFromTemplate,
AppendActiveFile,
OverwriteFile,
OverwriteActiveFile,
DynamicProcessor,
StartupTemplate,
}
interface TemplaterPlugin {
templater: {
current_functions_object: {
app: App;
config: {
active_file: TFile;
run_mode: RunMode;
target_file: TFile;
template_file: TFile;
};
date: {
// default format is 'YYYY-MM-DD'
now(format?: string, offset?: number | string, reference?: string, reference_format?: string): string;
tomorrow(format?: string): string;
weekday(format?: string, weekday?: number, reference?: string, reference_format?: string): string;
yesterday(format?: string): string;
};
file: {
content: string;
tags: string[];
title: string;
create_new(template: TFile | string, filename?: string, open_new?: boolean, folder?: TFolder | string): Promise<TFile | undefined>;
// default format is 'YYYY-MM-DD HH:mm'
creation_date(format?: string): string;
cursor(order?: number): string;
cursor_append(content: string): string | undefined;
exists(filepath: string): Promise<boolean>;
find_tfile(filename: string): TFile | null;
folder(absolute?: boolean): string;
include(include_link: string | TFile): Promise<string>;
// default format is 'YYYY-MM-DD HH:mm'
last_modified_date(format: string): string;
move(new_path: string, file_to_move?: TFile): Promise<string>;
path(relative: boolean): string;
rename(new_title: string): Promise<string>;
selection(): string;
};
frontmatter: {
[key: string]: unknown;
};
hooks: {
on_all_templates_executed(callback_function: () => unknown): void;
};
obsidian: typeof obsidian;
system: {
clipboard(): Promise<string | null>;
prompt(prompt_text?: string, default_value?: string, throw_on_cancel?: boolean, multiline?: boolean): Promise<string | null>;
suggester<T>(text_items: string[] | ((item: T) => string), items: T[], throw_on_cancel?: boolean, placeholder?: string, limit?: number): Promise<T>;
};
user: {
[key: string]: unknown;
};
web: {
daily_quote(): Promise<string>;
random_picture(size?: string, query?: string, include_size?: boolean): Promise<string>;
request(url: string, path?: string): Promise<string>;
};
};
};
}
Yeah, that’s why an empty Templater template is advisable to run for this purpose on startup. I mean even for normal js scripts, for Templater function availability.
Then I’ll need to fix that for mobile compatibility even for scripts I didn’t use Templater for (so far only one and I kept the non-Templater version ts file for backup). That’s important, yes, even for Templater js.
Thanks very much for commenting on this on short notice.
Cheers
As far as I can see, currently, only one startup script is allowed:
Would be better (if it’s possbile) if we just specified the folder and anything in that folder would be loaded on startup.
(My example scripts on the screenshot are not actual startup files – I just added two random files there.)
Yes, you have only one startup script, but you can call from it all others
startup/main.ts
import { invoke as freezeDataView } from './Freeze DataView.ts';
import { invoke as redoLastCommand } from './RedoLastCommand.ts';
export async function invoke(app: App): Promise<void> {
await freezeDataView(app);
await redoLastCommand(app);
}
Will do, thanks!
This way, you will have a better control over the execution order.
And additionally, this forum is not the best place for the BUG/FEATURE REQUESTS. For better maintainability, they are better be added to GitHub
Right.
Was just trying to raise awareness of the plugin a bit more.
Cheers