454 lines
17 KiB
JavaScript
454 lines
17 KiB
JavaScript
/*
|
|
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
*/
|
|
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
|
|
// src/main.ts
|
|
var main_exports = {};
|
|
__export(main_exports, {
|
|
default: () => ZeroQoLModulesPlugin
|
|
});
|
|
module.exports = __toCommonJS(main_exports);
|
|
var import_obsidian4 = require("obsidian");
|
|
|
|
// src/modules/attachment-clean-paste/index.ts
|
|
var import_obsidian = require("obsidian");
|
|
|
|
// src/modules/base-module.ts
|
|
var BaseModule = class {
|
|
constructor() {
|
|
this.cleanupFns = [];
|
|
}
|
|
get defaultSettings() {
|
|
return {};
|
|
}
|
|
onunload(_plugin) {
|
|
for (const fn of this.cleanupFns) {
|
|
fn();
|
|
}
|
|
this.cleanupFns = [];
|
|
}
|
|
renderInlineSettings(_containerEl, _settings, _saveSettings) {
|
|
}
|
|
registerCleanup(fn) {
|
|
this.cleanupFns.push(fn);
|
|
}
|
|
};
|
|
|
|
// src/locales/en.ts
|
|
var en = {
|
|
settings: {
|
|
title: "ZeroQ QoL Modules",
|
|
description: "Enable or disable modules as you wish."
|
|
},
|
|
modules: {
|
|
"attachment-clean-paste": {
|
|
name: "Attachment Clean Paste",
|
|
description: "Replaces ![[embed]] with [[path/file|name]] for configured file extensions on paste/drop",
|
|
descriptionShort: "Replaces ![[embed]] with [[path/file|name]] for specified file extensions.",
|
|
extensionsLabel: "File extensions",
|
|
extensionsDesc: "Comma-separated extensions (e.g.: png, jpg, pdf, mp3). Files with these extensions will be inserted as [[path/file|name]] instead of ![[path/file]].",
|
|
extensionsPlaceholder: "png, jpg, jpeg, gif, svg, webp, pdf"
|
|
},
|
|
"preserve-link-aliases": {
|
|
name: "Preserve Link Aliases",
|
|
description: "Preserves original link aliases when attachments are renamed",
|
|
processEmbedsLabel: "Process embed links",
|
|
processEmbedsDesc: "Also process ![[embed]] links (disabled by default)",
|
|
processCanvasLabel: "Process Canvas files",
|
|
processCanvasDesc: "Also process links in Canvas (.canvas) files"
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/locales/ru.ts
|
|
var ru = {
|
|
settings: {
|
|
title: "ZeroQ QoL Modules",
|
|
description: "\u0412\u043A\u043B\u044E\u0447\u0430\u0439\u0442\u0435 \u0438 \u043E\u0442\u043A\u043B\u044E\u0447\u0430\u0439\u0442\u0435 \u043C\u043E\u0434\u0443\u043B\u0438 \u043F\u043E \u0441\u0432\u043E\u0435\u043C\u0443 \u0443\u0441\u043C\u043E\u0442\u0440\u0435\u043D\u0438\u044E."
|
|
},
|
|
modules: {
|
|
"attachment-clean-paste": {
|
|
name: "Attachment Clean Paste",
|
|
description: "\u0417\u0430\u043C\u0435\u043D\u044F\u0435\u0442 ![[\u0432\u043B\u043E\u0436\u0435\u043D\u0438\u0435]] \u043D\u0430 [[\u0432\u043B\u043E\u0436\u0435\u043D\u0438\u0435|\u0438\u043C\u044F]] \u0434\u043B\u044F \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u044B\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0439 \u043F\u0440\u0438 \u0432\u0441\u0442\u0430\u0432\u043A\u0435/\u043F\u0435\u0440\u0435\u0442\u0430\u0441\u043A\u0438\u0432\u0430\u043D\u0438\u0438",
|
|
descriptionShort: "\u0417\u0430\u043C\u0435\u043D\u044F\u0435\u0442 ![[\u0432\u043B\u043E\u0436\u0435\u043D\u0438\u0435]] \u043D\u0430 [[\u0432\u043B\u043E\u0436\u0435\u043D\u0438\u0435|\u0438\u043C\u044F]] \u0434\u043B\u044F \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u044B\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0439.",
|
|
extensionsLabel: "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u0444\u0430\u0439\u043B\u043E\u0432",
|
|
extensionsDesc: "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043F\u044F\u0442\u0443\u044E (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: png, jpg, pdf, mp3). \u0424\u0430\u0439\u043B\u044B \u0441 \u044D\u0442\u0438\u043C\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F\u043C\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u0441\u0442\u0430\u0432\u043B\u044F\u0442\u044C\u0441\u044F \u043A\u0430\u043A [[path/file|name]] \u0432\u043C\u0435\u0441\u0442\u043E ![[path/file]].",
|
|
extensionsPlaceholder: "png, jpg, jpeg, gif, svg, webp, pdf"
|
|
},
|
|
"preserve-link-aliases": {
|
|
name: "\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0435 \u0430\u043B\u0438\u0430\u0441\u043E\u0432 \u0441\u0441\u044B\u043B\u043E\u043A",
|
|
description: "\u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442 \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\u044B\u0435 \u0430\u043B\u0438\u0430\u0441\u044B \u0441\u0441\u044B\u043B\u043E\u043A \u043F\u0440\u0438 \u043F\u0435\u0440\u0435\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0438 \u0432\u043B\u043E\u0436\u0435\u043D\u0438\u0439",
|
|
processEmbedsLabel: "\u041E\u0431\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u0442\u044C embed-\u0441\u0441\u044B\u043B\u043A\u0438",
|
|
processEmbedsDesc: "\u0422\u0430\u043A\u0436\u0435 \u043E\u0431\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u0442\u044C ![[embed]] \u0441\u0441\u044B\u043B\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0432\u044B\u043A\u043B\u044E\u0447\u0435\u043D\u043E)",
|
|
processCanvasLabel: "\u041E\u0431\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u0442\u044C Canvas-\u0444\u0430\u0439\u043B\u044B",
|
|
processCanvasDesc: "\u0422\u0430\u043A\u0436\u0435 \u043E\u0431\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0438 \u0432 Canvas (.canvas) \u0444\u0430\u0439\u043B\u0430\u0445"
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/locales/index.ts
|
|
var locales = { en, ru };
|
|
function detectLocale() {
|
|
const lang = (document.documentElement.lang || "en").slice(0, 2);
|
|
return locales[lang] || en;
|
|
}
|
|
var locale = detectLocale();
|
|
|
|
// src/modules/attachment-clean-paste/index.ts
|
|
var MODULE_ID = "attachment-clean-paste";
|
|
var AttachmentCleanPasteModule = class extends BaseModule {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.id = MODULE_ID;
|
|
this.name = locale.modules["attachment-clean-paste"].name;
|
|
this.description = locale.modules["attachment-clean-paste"].description;
|
|
}
|
|
get defaultSettings() {
|
|
return {
|
|
extensions: "png, jpg, jpeg, gif, svg, webp, bmp, pdf"
|
|
};
|
|
}
|
|
onload(plugin, moduleSettings) {
|
|
this.app = plugin.app;
|
|
const rawSettings = moduleSettings;
|
|
const pasteRef = plugin.app.workspace.on(
|
|
"editor-paste",
|
|
this.createPasteHandler(rawSettings)
|
|
);
|
|
this.registerCleanup(() => plugin.app.workspace.offref(pasteRef));
|
|
const dropRef = plugin.app.workspace.on(
|
|
"editor-drop",
|
|
this.createDropHandler(rawSettings)
|
|
);
|
|
this.registerCleanup(() => plugin.app.workspace.offref(dropRef));
|
|
}
|
|
renderInlineSettings(containerEl, settings, saveSettings) {
|
|
const loc = locale.modules["attachment-clean-paste"];
|
|
const extSettings = settings;
|
|
new import_obsidian.Setting(containerEl).setName(loc.extensionsLabel).setDesc(loc.extensionsDesc).addTextArea((textarea) => {
|
|
var _a;
|
|
textarea.setPlaceholder(loc.extensionsPlaceholder).setValue((_a = extSettings == null ? void 0 : extSettings.extensions) != null ? _a : "").onChange(async (value) => {
|
|
settings.extensions = value;
|
|
await saveSettings();
|
|
});
|
|
textarea.inputEl.rows = 4;
|
|
textarea.inputEl.style.width = "100%";
|
|
});
|
|
}
|
|
async processAll(files, editor, settings) {
|
|
const matchingFiles = Array.from(files).filter(
|
|
(f) => this.shouldProcess(f.name, settings)
|
|
);
|
|
if (matchingFiles.length === 0)
|
|
return;
|
|
const links = [];
|
|
for (const file of matchingFiles) {
|
|
const link = await this.processFile(file, settings);
|
|
if (link)
|
|
links.push(link);
|
|
}
|
|
if (links.length === 0)
|
|
return;
|
|
editor.replaceSelection(links.join("\n\n"));
|
|
}
|
|
createPasteHandler(settings) {
|
|
return async (evt, editor, _info) => {
|
|
var _a;
|
|
const files = (_a = evt.clipboardData) == null ? void 0 : _a.files;
|
|
if (!files || files.length === 0)
|
|
return;
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
await this.processAll(files, editor, settings);
|
|
};
|
|
}
|
|
createDropHandler(settings) {
|
|
return async (evt, editor, _info) => {
|
|
var _a;
|
|
const files = (_a = evt.dataTransfer) == null ? void 0 : _a.files;
|
|
if (!files || files.length === 0)
|
|
return;
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
await this.processAll(files, editor, settings);
|
|
};
|
|
}
|
|
shouldProcess(filename, settings) {
|
|
const dotIndex = filename.lastIndexOf(".");
|
|
if (dotIndex === -1)
|
|
return false;
|
|
const ext = filename.slice(dotIndex + 1).toLowerCase();
|
|
const exts = settings.extensions.split(",").map((e) => e.trim().toLowerCase()).filter((e) => e.length > 0);
|
|
return exts.some((e) => {
|
|
const cleanExt = e.startsWith(".") ? e.slice(1) : e;
|
|
return cleanExt === ext;
|
|
});
|
|
}
|
|
async processFile(file, _settings) {
|
|
try {
|
|
const arrayBuffer = await file.arrayBuffer();
|
|
const filename = file.name;
|
|
const nameWithoutExt = filename.replace(/\.[^/.]+$/, "");
|
|
let attachmentFolder = this.app.vault.getConfig(
|
|
"attachmentFolderPath"
|
|
);
|
|
if (!attachmentFolder)
|
|
attachmentFolder = "attachments";
|
|
const folderPath = (0, import_obsidian.normalizePath)(attachmentFolder);
|
|
if (!await this.app.vault.adapter.exists(folderPath)) {
|
|
await this.app.vault.createFolder(folderPath);
|
|
}
|
|
const ext = filename.slice(filename.lastIndexOf(".") + 1);
|
|
const basePath = (0, import_obsidian.normalizePath)(`${folderPath}/${nameWithoutExt}`);
|
|
const availablePath = await this.app.vault.getAvailablePath(
|
|
basePath,
|
|
ext
|
|
);
|
|
await this.app.vault.createBinary(availablePath, arrayBuffer);
|
|
return `[[${availablePath}|${nameWithoutExt}]]`;
|
|
} catch (e) {
|
|
new import_obsidian.Notice(`Clean Paste error: ${e.message}`);
|
|
console.error("Attachment Clean Paste:", e);
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// src/modules/preserve-link-aliases/index.ts
|
|
var import_obsidian2 = require("obsidian");
|
|
var MODULE_ID2 = "preserve-link-aliases";
|
|
var PreserveLinkAliasesModule = class extends BaseModule {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.id = MODULE_ID2;
|
|
this.name = locale.modules["preserve-link-aliases"].name;
|
|
this.description = locale.modules["preserve-link-aliases"].description;
|
|
}
|
|
get defaultSettings() {
|
|
return {
|
|
processEmbeds: false,
|
|
processCanvas: false
|
|
};
|
|
}
|
|
onload(plugin, moduleSettings) {
|
|
this.vault = plugin.app.vault;
|
|
const rawSettings = moduleSettings;
|
|
const renameRef = plugin.app.vault.on(
|
|
"rename",
|
|
(file, oldPath) => this.handleRename(file, oldPath, rawSettings)
|
|
);
|
|
this.registerCleanup(() => plugin.app.vault.offref(renameRef));
|
|
}
|
|
renderInlineSettings(containerEl, settings, saveSettings) {
|
|
const loc = locale.modules["preserve-link-aliases"];
|
|
const s = settings;
|
|
new import_obsidian2.Setting(containerEl).setName(loc.processEmbedsLabel).setDesc(loc.processEmbedsDesc).addToggle(
|
|
(toggle) => toggle.setValue(s.processEmbeds).onChange(async (value) => {
|
|
s.processEmbeds = value;
|
|
await saveSettings();
|
|
})
|
|
);
|
|
new import_obsidian2.Setting(containerEl).setName(loc.processCanvasLabel).setDesc(loc.processCanvasDesc).addToggle(
|
|
(toggle) => toggle.setValue(s.processCanvas).onChange(async (value) => {
|
|
s.processCanvas = value;
|
|
await saveSettings();
|
|
})
|
|
);
|
|
}
|
|
async handleRename(file, oldPath, settings) {
|
|
var _a;
|
|
const oldName = (_a = oldPath.split("/").pop()) != null ? _a : "";
|
|
const newName = file.name;
|
|
const oldBasename = oldName.replace(/\.[^/.]+$/, "");
|
|
const newBasename = newName.replace(/\.[^/.]+$/, "");
|
|
if (oldBasename === newBasename)
|
|
return;
|
|
const files = this.getFilesToProcess(settings);
|
|
for (const f of files) {
|
|
const content = await this.vault.read(f);
|
|
const updated = this.processContent(content, newName, newBasename, oldBasename, settings);
|
|
if (updated !== content) {
|
|
await this.vault.modify(f, updated);
|
|
}
|
|
}
|
|
}
|
|
getFilesToProcess(settings) {
|
|
const files = [];
|
|
for (const file of this.vault.getMarkdownFiles()) {
|
|
files.push(file);
|
|
}
|
|
if (settings.processCanvas) {
|
|
const abstractFiles = this.vault.getFiles();
|
|
for (const file of abstractFiles) {
|
|
if (file.extension === "canvas") {
|
|
files.push(file);
|
|
}
|
|
}
|
|
}
|
|
return files;
|
|
}
|
|
processContent(content, newFileName, newBasename, oldBasename, settings) {
|
|
const wikiLinkRe = /(!?)\[\[([^\]]*?)]]/g;
|
|
return content.replace(wikiLinkRe, (fullMatch, prefix, inner) => {
|
|
if (prefix === "!" && !settings.processEmbeds) {
|
|
return fullMatch;
|
|
}
|
|
const pipeIndex = inner.indexOf("|");
|
|
if (pipeIndex === -1)
|
|
return fullMatch;
|
|
const linkPath = inner.slice(0, pipeIndex);
|
|
const alias = inner.slice(pipeIndex + 1);
|
|
if (alias !== newBasename)
|
|
return fullMatch;
|
|
const linkFilename = linkPath.split("/").pop();
|
|
if (linkFilename !== newFileName)
|
|
return fullMatch;
|
|
return `${prefix}[[${linkPath}|${oldBasename}]]`;
|
|
});
|
|
}
|
|
};
|
|
|
|
// src/modules/index.ts
|
|
var MODULES = [
|
|
new AttachmentCleanPasteModule(),
|
|
new PreserveLinkAliasesModule()
|
|
];
|
|
|
|
// src/settings.ts
|
|
var import_obsidian3 = require("obsidian");
|
|
var MODULE_DEFAULTS = MODULES.reduce(
|
|
(acc, mod) => {
|
|
acc[mod.id] = {
|
|
enabled: true,
|
|
settings: { ...mod.defaultSettings }
|
|
};
|
|
return acc;
|
|
},
|
|
{}
|
|
);
|
|
var DEFAULT_SETTINGS = {
|
|
modules: MODULE_DEFAULTS
|
|
};
|
|
function getModuleSettings(settings, moduleId) {
|
|
var _a, _b;
|
|
return (_b = (_a = settings.modules[moduleId]) == null ? void 0 : _a.settings) != null ? _b : {};
|
|
}
|
|
var ZeroQSettingTab = class extends import_obsidian3.PluginSettingTab {
|
|
constructor(app, plugin) {
|
|
super(app, plugin);
|
|
this.plugin = plugin;
|
|
}
|
|
display() {
|
|
const { containerEl } = this;
|
|
containerEl.empty();
|
|
containerEl.createEl("h1", { text: locale.settings.title });
|
|
containerEl.createEl("p", {
|
|
text: locale.settings.description,
|
|
attr: { style: "color: var(--text-muted); margin-bottom: 20px;" }
|
|
});
|
|
for (const module2 of MODULES) {
|
|
const moduleCfg = this.plugin.settings.modules[module2.id];
|
|
new import_obsidian3.Setting(containerEl).setName(module2.name).setDesc(module2.description).addToggle(
|
|
(toggle) => {
|
|
var _a;
|
|
return toggle.setValue((_a = moduleCfg == null ? void 0 : moduleCfg.enabled) != null ? _a : true).onChange(async (value) => {
|
|
if (!this.plugin.settings.modules[module2.id]) {
|
|
this.plugin.settings.modules[module2.id] = {
|
|
enabled: value,
|
|
settings: { ...module2.defaultSettings }
|
|
};
|
|
} else {
|
|
this.plugin.settings.modules[module2.id].enabled = value;
|
|
}
|
|
await this.plugin.saveSettings();
|
|
if (value) {
|
|
this.plugin.loadModule(module2);
|
|
} else {
|
|
this.plugin.unloadModule(module2);
|
|
}
|
|
});
|
|
}
|
|
);
|
|
if (moduleCfg) {
|
|
module2.renderInlineSettings(
|
|
containerEl,
|
|
moduleCfg.settings,
|
|
() => this.plugin.saveSettings()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/main.ts
|
|
var ZeroQoLModulesPlugin = class extends import_obsidian4.Plugin {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.loadedModules = /* @__PURE__ */ new Set();
|
|
}
|
|
async onload() {
|
|
await this.loadSettings();
|
|
this.addSettingTab(new ZeroQSettingTab(this.app, this));
|
|
for (const module2 of MODULES) {
|
|
const moduleCfg = this.settings.modules[module2.id];
|
|
if (moduleCfg == null ? void 0 : moduleCfg.enabled) {
|
|
this.loadModule(module2);
|
|
}
|
|
}
|
|
}
|
|
onunload() {
|
|
for (const module2 of MODULES) {
|
|
this.unloadModule(module2);
|
|
}
|
|
}
|
|
async loadSettings() {
|
|
this.settings = Object.assign(
|
|
{},
|
|
DEFAULT_SETTINGS,
|
|
await this.loadData()
|
|
);
|
|
for (const module2 of MODULES) {
|
|
if (!this.settings.modules[module2.id]) {
|
|
this.settings.modules[module2.id] = {
|
|
enabled: true,
|
|
settings: { ...module2.defaultSettings }
|
|
};
|
|
}
|
|
}
|
|
}
|
|
async saveSettings() {
|
|
await this.saveData(this.settings);
|
|
}
|
|
loadModule(module2) {
|
|
if (this.loadedModules.has(module2.id))
|
|
return;
|
|
const moduleSettings = getModuleSettings(this.settings, module2.id);
|
|
module2.onload(this, moduleSettings);
|
|
this.loadedModules.add(module2.id);
|
|
}
|
|
unloadModule(module2) {
|
|
if (!this.loadedModules.has(module2.id))
|
|
return;
|
|
module2.onunload(this);
|
|
this.loadedModules.delete(module2.id);
|
|
}
|
|
};
|