mirror of
https://github.com/netajam/obsidian_note_uid_generator.git
synced 2026-07-22 05:45:32 +00:00
v 1.0.6
This commit is contained in:
parent
961eac27b9
commit
64c2e0f88f
8 changed files with 121 additions and 55 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { Editor, MarkdownView, TFile, TFolder, Notice, normalizePath, WorkspaceLeaf } from 'obsidian';
|
||||
import { Editor, MarkdownView, TFile, TFolder, Notice, normalizePath, WorkspaceLeaf, FileExplorerView } from 'obsidian';
|
||||
import UIDGenerator from './main';
|
||||
import * as uidUtils from './uidUtils';
|
||||
|
||||
|
|
@ -126,7 +126,6 @@ export function handleCopyTitleUid(plugin: UIDGenerator, specificFile?: TFile):
|
|||
|
||||
/** Logic for Folder Context Menu Action */
|
||||
export async function handleCopyTitlesAndUidsFromFolder(plugin: UIDGenerator, folder: TFolder): Promise<void> {
|
||||
console.log(`[UIDGenerator] Copying titles+${plugin.settings.uidKey}s for folder: ${folder.path}`);
|
||||
const markdownFiles = plugin.app.vault.getMarkdownFiles();
|
||||
const filesInFolder: TFile[] = [];
|
||||
const targetPath = folder.path;
|
||||
|
|
@ -182,8 +181,6 @@ export async function handleCopyTitlesAndUidsForMultipleFiles(plugin: UIDGenerat
|
|||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIDGenerator] Copying titles+${plugin.settings.uidKey}s for ${files.length} selected files via context menu.`);
|
||||
|
||||
let outputLines: string[] = [];
|
||||
let filesWithUidCount = 0;
|
||||
const formatExists = plugin.settings.copyFormatString;
|
||||
|
|
@ -213,23 +210,34 @@ export async function handleCopyTitlesAndUidsForMultipleFiles(plugin: UIDGenerat
|
|||
|
||||
/** Logic for Command Palette: Copy titles+UIDs for selected files in File Explorer */
|
||||
export async function handleCopyTitlesAndUidsForSelection(plugin: UIDGenerator): Promise<void> {
|
||||
// Find the active File Explorer leaf/view
|
||||
const fileExplorerLeaf = plugin.app.workspace.getLeavesOfType('file-explorer')
|
||||
.find(leaf => (leaf.view as any).selectedFiles && plugin.app.workspace.activeLeaf === leaf);
|
||||
// 1. Find the active File Explorer leaf more reliably
|
||||
let fileExplorerLeaf: WorkspaceLeaf | undefined = undefined;
|
||||
const explorerLeaves = plugin.app.workspace.getLeavesOfType('file-explorer');
|
||||
if (explorerLeaves.length > 0) {
|
||||
// Prefer the active leaf if it's a file explorer
|
||||
if (plugin.app.workspace.activeLeaf && plugin.app.workspace.activeLeaf.view.getViewType() === 'file-explorer') {
|
||||
fileExplorerLeaf = plugin.app.workspace.activeLeaf;
|
||||
} else {
|
||||
fileExplorerLeaf = explorerLeaves[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!fileExplorerLeaf || !(fileExplorerLeaf.view as any).selectedFiles) {
|
||||
new Notice("No active file explorer with selected files found.");
|
||||
if (!fileExplorerLeaf) {
|
||||
new Notice("No active file explorer found.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Access selected files
|
||||
const selectedPaths: string[] = (fileExplorerLeaf.view as any).selectedFiles || [];
|
||||
|
||||
if (selectedPaths.length === 0) {
|
||||
// 2. Assert the view type and check for selectedFiles property
|
||||
const view = fileExplorerLeaf.view as FileExplorerView;
|
||||
if (!view || !view.selectedFiles || view.selectedFiles.length === 0) {
|
||||
new Notice("No files selected in the file explorer.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Get the selected paths
|
||||
const selectedPaths: string[] = view.selectedFiles;
|
||||
|
||||
// 4. Filter for Markdown files
|
||||
const filesToProcess: TFile[] = [];
|
||||
for (const path of selectedPaths) {
|
||||
const file = plugin.app.vault.getAbstractFileByPath(path);
|
||||
|
|
@ -243,7 +251,7 @@ export async function handleCopyTitlesAndUidsForSelection(plugin: UIDGenerator):
|
|||
return;
|
||||
}
|
||||
|
||||
// Delegate to the same logic used by the context menu
|
||||
// 5. Delegate to the multi-file handler (no changes needed here)
|
||||
await handleCopyTitlesAndUidsForMultipleFiles(plugin, filesToProcess);
|
||||
}
|
||||
|
||||
|
|
@ -256,7 +264,6 @@ export async function handleClearUIDsInFolder(plugin: UIDGenerator, folderPath:
|
|||
const folder = plugin.app.vault.getAbstractFileByPath(normalizedFolderPath);
|
||||
if (!folder || !(folder instanceof TFolder)) { new Notice(`Folder not found or path is not a folder: ${folderPath}`); return; }
|
||||
|
||||
console.log(`[UIDGenerator] Starting UID clearing process for folder: ${folder.path} using key "${plugin.settings.uidKey}"`);
|
||||
new Notice(`Clearing ${plugin.settings.uidKey}s in "${folder.name}"... This may take a moment.`);
|
||||
|
||||
const markdownFiles = plugin.app.vault.getMarkdownFiles();
|
||||
|
|
@ -275,7 +282,6 @@ export async function handleClearUIDsInFolder(plugin: UIDGenerator, folderPath:
|
|||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIDGenerator] Found ${filesToProcess.length} markdown files to process.`);
|
||||
let clearedCount = 0;
|
||||
let errorCount = 0;
|
||||
|
||||
|
|
@ -293,7 +299,6 @@ export async function handleClearUIDsInFolder(plugin: UIDGenerator, folderPath:
|
|||
message += ` Encountered ${errorCount} errors (check console).`;
|
||||
}
|
||||
new Notice(message, 10000);
|
||||
console.log(`[UIDGenerator] UID clearing finished. Removed: ${clearedCount}, Errors: ${errorCount}`);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -327,7 +332,6 @@ export async function handleAutoGenerateUid(plugin: UIDGenerator, file: TFile |
|
|||
}
|
||||
|
||||
// Generate and set
|
||||
console.log(`[UIDGenerator] Auto-generating ${plugin.settings.uidKey} for: ${file.path}`);
|
||||
const newUid = uidUtils.generateUID();
|
||||
await uidUtils.setUID(plugin, file, newUid, false);
|
||||
}
|
||||
|
|
@ -347,7 +351,6 @@ export async function handleAddMissingUidsInScope(plugin: UIDGenerator): Promise
|
|||
const noticeMessage = `Processing ${totalFiles} files for missing UIDs...`;
|
||||
const notice = new Notice(noticeMessage, 0); // Show notice indefinitely until updated/hidden
|
||||
|
||||
console.log(`[UIDGenerator] Starting bulk check for missing UIDs. Scope: ${plugin.settings.autoGenerationScope}.`);
|
||||
|
||||
try { // Wrap the loop for final notice update
|
||||
for (let i = 0; i < totalFiles; i++) {
|
||||
|
|
@ -422,6 +425,5 @@ export async function handleAddMissingUidsInScope(plugin: UIDGenerator): Promise
|
|||
}
|
||||
|
||||
new Notice(summary, 10000 + errorCount * 100); // Show longer if errors
|
||||
console.log(`[UIDGenerator] ${summary.replace(/\n- /g, ', ')}`);
|
||||
}
|
||||
}
|
||||
31
src/main.ts
31
src/main.ts
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
App, Editor, MarkdownView, Notice, Plugin, TFile, TFolder,
|
||||
debounce, Menu, TAbstractFile, WorkspaceLeaf
|
||||
debounce, Menu, TAbstractFile, WorkspaceLeaf,
|
||||
FileExplorerView
|
||||
} from 'obsidian';
|
||||
import { UIDGeneratorSettings, DEFAULT_SETTINGS, UIDSettingTab } from './settings';
|
||||
import * as commands from './commands';
|
||||
|
|
@ -10,7 +11,6 @@ export default class UIDGenerator extends Plugin {
|
|||
settings: UIDGeneratorSettings;
|
||||
|
||||
async onload() {
|
||||
console.log('Loading UID Generator Plugin v7 (files-menu)');
|
||||
await this.loadSettings();
|
||||
|
||||
// --- Ribbon Icon ---
|
||||
|
|
@ -98,16 +98,24 @@ export default class UIDGenerator extends Plugin {
|
|||
name: `Copy titles+${this.settings.uidKey}s for selected files`,
|
||||
checkCallback: (checking: boolean): boolean | void => {
|
||||
const fileExplorerLeaf = this.app.workspace.getLeavesOfType('file-explorer')
|
||||
?.find(leaf => (leaf.view as any).selectedFiles && this.app.workspace.activeLeaf === leaf);
|
||||
?.find(leaf => leaf.view.getViewType() === 'file-explorer' && this.app.workspace.activeLeaf === leaf); // More robust check
|
||||
|
||||
let markdownSelected = false;
|
||||
if (fileExplorerLeaf) {
|
||||
const selectedPaths: string[] = (fileExplorerLeaf.view as any).selectedFiles || [];
|
||||
markdownSelected = selectedPaths.some(path => {
|
||||
const file = this.app.vault.getAbstractFileByPath(path);
|
||||
return file instanceof TFile && file.extension === 'md';
|
||||
});
|
||||
}
|
||||
|
||||
let markdownSelected = false;
|
||||
if (fileExplorerLeaf) {
|
||||
// Use the augmented interface with a type assertion
|
||||
const view = fileExplorerLeaf.view as FileExplorerView; // <-- Use the interface
|
||||
const selectedPaths: string[] = view.selectedFiles || []; // <-- Access via typed view
|
||||
|
||||
// Check if at least one selected file is markdown
|
||||
markdownSelected = selectedPaths.some(path => {
|
||||
// 'this' refers to the Plugin instance in main.ts
|
||||
// 'plugin' refers to the Plugin instance in commands.ts
|
||||
// Make sure to use the correct variable (this or plugin) depending on the file
|
||||
const file = this.app.vault.getAbstractFileByPath(path); // Or plugin.app.vault...
|
||||
return file instanceof TFile && file.extension === 'md';
|
||||
});
|
||||
}
|
||||
|
||||
const canRun = !!fileExplorerLeaf && markdownSelected;
|
||||
|
||||
|
|
@ -166,7 +174,6 @@ export default class UIDGenerator extends Plugin {
|
|||
}
|
||||
|
||||
onunload() {
|
||||
console.log('Unloading UID Generator Plugin v7 (files-menu)');
|
||||
}
|
||||
|
||||
// --- Settings Management ---
|
||||
|
|
|
|||
|
|
@ -118,23 +118,15 @@ export class UIDSettingTab extends PluginSettingTab {
|
|||
new FolderExclusionModal(this.app, this.plugin, () => this.display()).open();
|
||||
}));
|
||||
|
||||
// Display the current list of excluded folders (read-only in this view)
|
||||
const exclusionListEl = containerEl.createEl('ul', { cls: 'uid-exclusion-list' });
|
||||
if (this.plugin.settings.autoGenerationExclusions.length > 0) {
|
||||
// Sort before displaying for consistency
|
||||
const sortedExclusions = [...this.plugin.settings.autoGenerationExclusions].sort();
|
||||
sortedExclusions.forEach(folderPath => {
|
||||
exclusionListEl.createEl('li', { text: folderPath });
|
||||
});
|
||||
} else {
|
||||
// Display message if no folders are excluded
|
||||
exclusionListEl.createEl('li', { text: 'No folders excluded.' });
|
||||
}
|
||||
// Basic styling for the list
|
||||
exclusionListEl.style.marginTop = '5px';
|
||||
exclusionListEl.style.marginBottom = '15px';
|
||||
exclusionListEl.style.paddingLeft = '20px';
|
||||
exclusionListEl.style.listStyle = 'none'; // Or 'disc', 'circle' etc.
|
||||
|
||||
}
|
||||
new Setting(containerEl)
|
||||
|
|
@ -227,7 +219,6 @@ export class UIDSettingTab extends PluginSettingTab {
|
|||
autoGenWasOn = true;
|
||||
this.plugin.settings.autoGenerateUid = false;
|
||||
await this.plugin.saveSettings();
|
||||
console.log("[UIDGenerator] Automatic UID generation temporarily disabled due to manual clear action.");
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
|||
16
src/typings/obsidian.d.ts
vendored
16
src/typings/obsidian.d.ts
vendored
|
|
@ -1,5 +1,5 @@
|
|||
// src/obsidian.d.ts
|
||||
import 'obsidian';
|
||||
// src/typings/obsidian.d.ts
|
||||
import 'obsidian';
|
||||
|
||||
declare module 'obsidian' {
|
||||
interface Workspace {
|
||||
|
|
@ -7,11 +7,19 @@ declare module 'obsidian' {
|
|||
name: 'files-menu',
|
||||
callback: (
|
||||
menu: Menu,
|
||||
files: TAbstractFile[],
|
||||
files: TAbstractFile[], // Note: it's an array
|
||||
source: string,
|
||||
leaf?: WorkspaceLeaf
|
||||
) => any,
|
||||
ctx?: any
|
||||
): EventRef;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface FileExplorerView extends View {
|
||||
selectedFiles?: string[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { App, Modal, TFolder, Setting, debounce } from 'obsidian';
|
||||
import { App, Modal, TFolder, debounce } from 'obsidian';
|
||||
import UIDGenerator from '../main';
|
||||
|
||||
export class FolderExclusionModal extends Modal {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ export async function setUID(plugin: UIDGenerator, file: TFile, uid: string, ove
|
|||
initialUidExists = currentUid !== undefined && currentUid !== null && currentUid !== ''; // Check before potential modification
|
||||
|
||||
if (initialUidExists && !overwrite) {
|
||||
console.log(`[UIDGenerator] ${key} already exists for ${file.path}, not overwriting.`);
|
||||
uidWasSetOrOverwritten = false; // Explicitly false
|
||||
return; // Exit processor
|
||||
}
|
||||
|
|
@ -83,7 +82,6 @@ export async function setUID(plugin: UIDGenerator, file: TFile, uid: string, ove
|
|||
if (uidWasSetOrOverwritten) {
|
||||
// Determine action based on initial state and overwrite flag
|
||||
const action = initialUidExists && overwrite ? 'Overwrote' : 'Set';
|
||||
console.log(`[UIDGenerator] ${action} ${key} for ${file.path}.`);
|
||||
}
|
||||
return uidWasSetOrOverwritten;
|
||||
|
||||
|
|
@ -112,7 +110,6 @@ export async function removeUID(plugin: UIDGenerator, file: TFile): Promise<bool
|
|||
}
|
||||
});
|
||||
if (uidWasPresent) {
|
||||
console.log(`[UIDGenerator] Removed key "${key}" from ${file.path}`);
|
||||
}
|
||||
return uidWasPresent;
|
||||
} catch (error) {
|
||||
|
|
|
|||
65
styles.css
65
styles.css
|
|
@ -1,8 +1,63 @@
|
|||
/*
|
||||
/* Styles for UID Generator Plugin Settings */
|
||||
|
||||
This CSS file will be included with your plugin, and
|
||||
available in the app when your plugin is enabled.
|
||||
/* Style the list of excluded folders in settings */
|
||||
.uid-generator-exclusion-list {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 15px;
|
||||
padding-left: 20px; /* Indent list slightly */
|
||||
list-style: none; /* Remove default bullets */
|
||||
max-height: 150px; /* Optional: Limit height */
|
||||
overflow-y: auto; /* Optional: Allow scrolling */
|
||||
background-color: var(--background-secondary); /* Optional: Subtle background */
|
||||
border: 1px solid var(--background-modifier-border); /* Optional: Border */
|
||||
border-radius: var(--radius-m); /* Optional: Rounded corners */
|
||||
padding-top: 5px; /* Optional: Inner padding */
|
||||
padding-bottom: 5px; /* Optional: Inner padding */
|
||||
}
|
||||
|
||||
If your plugin does not need CSS, delete this file.
|
||||
.uid-generator-exclusion-list li {
|
||||
padding: 2px 0; /* Optional: Spacing between list items */
|
||||
}
|
||||
|
||||
*/
|
||||
/* You might also want the styles for the FolderExclusionModal here */
|
||||
.uid-folder-exclusion-modal .uid-search-input {
|
||||
width: 95%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.uid-folder-exclusion-modal .uid-suggestion-container {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: var(--radius-m);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.uid-folder-exclusion-modal .setting-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 5px 8px;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
.uid-folder-exclusion-modal .setting-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.uid-folder-exclusion-modal .setting-item-info {
|
||||
flex-grow: 1;
|
||||
margin-right: 10px;
|
||||
overflow: hidden; /* Prevent long paths breaking layout */
|
||||
text-overflow: ellipsis; /* Show ... for long paths */
|
||||
white-space: nowrap; /* Keep path on one line */
|
||||
}
|
||||
.uid-folder-exclusion-modal .setting-item-control button {
|
||||
margin-left: auto;
|
||||
flex-shrink: 0; /* Prevent button shrinking */
|
||||
}
|
||||
|
||||
.uid-no-results {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
|
@ -18,7 +18,13 @@
|
|||
"ES7"
|
||||
]
|
||||
},
|
||||
"typeRoots": [
|
||||
"./node_modules/@types", // Standard location for installed types
|
||||
"./src/typings" // Your custom typings folder
|
||||
],
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
"**/*.ts","**/*.d.ts", "src/typings/obsidian.d.ts"
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue