generated from obsidianmd/obsidian-sample-plugin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.ts
137 lines (112 loc) · 4.01 KB
/
main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import { Notice, Plugin, TFile, TFolder } from 'obsidian';
export default class PromoteNotePlugin extends Plugin {
async onload() {
this.registerEvent(
this.app.workspace.on("file-menu", (menu, file) => {
if (file instanceof TFile && file.extension == "md") {
menu.addItem((item) => {
item
.setTitle("Promote Note to Folder")
.setIcon("folder")
.onClick(async () => this.promoteNote(file));
});
}
})
)
}
onunload() {
}
async promoteNote(file: TFile) {
// Check if we have embeds, so we need to move them too
const fileCache = this.app.metadataCache.getFileCache(file);
const hasEmbeds = (fileCache && fileCache.embeds)
// Extract the base name without the .md extension
const baseName = file.basename;
let newFolderPath: string;
// Construct the path for the new folder
if (file.parent) {
newFolderPath = file.parent.path + '/' + baseName;
} else {
newFolderPath = baseName;
}
// Create the new folder
await this.app.vault.createFolder(newFolderPath);
// Construct the new path for the file
const newFilePath = newFolderPath + '/' + file.name;
let attachmentsFolderPath = "";
if (hasEmbeds) {
// we must get the attachment folder before moving
attachmentsFolderPath = await this.getAvailablePathForAttachments("", "", file);
}
// Move the file to the new folder
await this.app.fileManager.renameFile(file, newFilePath);
if (hasEmbeds) {
const newFile = this.app.vault.getAbstractFileByPath(newFilePath);
if (newFile instanceof TFile) {
await this.moveLinkedFiles(file, attachmentsFolderPath, newFile);
}
new Notice(`${newFilePath} created and images moved`);
if (await this.deleteIfEmpty(attachmentsFolderPath)) {
new Notice(`${attachmentsFolderPath} folder deleted`);
}
} else {
new Notice(`${newFilePath} created`);
}
}
async moveLinkedFiles(oldFile: TFile, attachmentsFolderPath: string, newFile: TFile) {
// Retrieve the file cache for the note
const fileCache = this.app.metadataCache.getFileCache(oldFile);
const newAttachmentsFolderPath = await this.getAvailablePathForAttachments("", "", newFile);
// Check if there are any links in the file cache
if (fileCache && fileCache.embeds) {
for (const embed of fileCache.embeds) {
// Construct the full path of the embedded file
const embedFile = this.app.metadataCache.getFirstLinkpathDest(embed.link, oldFile.path);
if (embedFile instanceof TFile) {
const embedFilePath = embedFile.path;
// Check if the file is an image and in the 'images' subfolder
if (embedFilePath.startsWith(attachmentsFolderPath)) {
const newImageFilePath = `${newAttachmentsFolderPath}${embedFile.name}`;
// Move the image file to the new folder
await this.app.fileManager.renameFile(embedFile, newImageFilePath);
}
}
}
}
}
async deleteIfEmpty(folderPath: string): Promise<boolean> {
// Get the folder object
if (folderPath.endsWith('/')) {
folderPath = folderPath.slice(0, -1);
}
const folder = this.app.vault.getAbstractFileByPath(folderPath);
// Make sure it's a folder and not a file
if (folder instanceof TFolder) {
// Get the contents of the folder
const contents = folder.children;
// If the folder is empty (no files or subfolders)
if (contents.length === 0) {
// Delete the folder
await this.app.vault.trash(folder, true);
return true;
}
}
return false;
}
/**
* This is a helper method for an undocumented API of Obsidian.
*
* @param fileName The Filename for your Attachment
* @param format The Fileformat of your Attachment
* @param sourceFile The Sourcefile from where the Attachment gets added, this is needed because the Attachment Folder might be different based on where it gets inserted.
* @returns The Attachment Path
*/
async getAvailablePathForAttachments(
fileName: string,
format: string,
sourceFile: TFile
): Promise<string> {
//@ts-expect-error
return this.app.vault.getAvailablePathForAttachments(fileName, format, sourceFile);
}
}