Files
StudyDiary/.obsidian/plugins/obsidian-file-link/main.js
T
2026-07-23 20:36:13 +08:00

1170 lines
42 KiB
JavaScript
Executable File

/*
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
if you want to view the source visit the plugins github repository
*/
'use strict';
var obsidian = require('obsidian');
var require$$0 = require('electron');
var fs = require('fs');
var path = require('path');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
const DEFAULT_SETTINGS = {
linkPrefix: "",
showFileEnding: false,
linkFolder: false,
useFolderName: false,
embedFile: false,
};
const SUPPORTED_EMBED_FILE_TYPES = [
".md",
".png",
".jpg",
".jpeg",
".gif",
".bmp",
".svg",
".mp3",
".webm",
".wav",
".m4a",
".ogg",
".3gp",
".flac",
".mp4",
".webm",
".ogv",
".pdf",
];
class FileLinkSettingTab extends obsidian.PluginSettingTab {
plugin;
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
display() {
let { containerEl } = this;
containerEl.empty();
containerEl.createEl("h2", { text: "Better File Link Settings" });
new obsidian.Setting(containerEl)
.setName("List style for multiple files")
.setDesc("Specify the characters shown before every file link.")
.addText((text) => text
.setPlaceholder("-")
.setValue(this.plugin.settings.linkPrefix)
.onChange(async (value) => {
this.plugin.settings.linkPrefix = value;
await this.plugin.saveSettings();
}));
new obsidian.Setting(containerEl)
.setName("Show file extension")
.setDesc("Will show file endings when activated.")
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.showFileEnding)
.onChange(async () => {
this.plugin.settings.showFileEnding = toggle.getValue();
await this.plugin.saveSettings();
}));
new obsidian.Setting(containerEl)
.setName("Embed file")
.setDesc("Will copy the file to Obsidian and embed it in the note.")
.addToggle((toggle) => toggle.setValue(this.plugin.settings.embedFile).onChange(async () => {
this.plugin.settings.embedFile = toggle.getValue();
await this.plugin.saveSettings();
}));
new obsidian.Setting(containerEl)
.setName("Link folder instead of file")
.setDesc("Link will open the folder where the file is located instead of opening the file itself.")
.addToggle((toggle) => toggle.setValue(this.plugin.settings.linkFolder).onChange(async () => {
this.plugin.settings.linkFolder = toggle.getValue();
await this.plugin.saveSettings();
}));
new obsidian.Setting(containerEl)
.setName("Use folder name")
.setDesc('When linking to a folder, show only the folder name instead of the full path (e.g. "baz" instead of "/Users/foo/bar/baz").')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.useFolderName)
.onChange(async () => {
this.plugin.settings.useFolderName = toggle.getValue();
await this.plugin.saveSettings();
}));
}
}
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
var renderer$1 = {};
var remote = {};
var callbacksRegistry = {};
var hasRequiredCallbacksRegistry;
function requireCallbacksRegistry () {
if (hasRequiredCallbacksRegistry) return callbacksRegistry;
hasRequiredCallbacksRegistry = 1;
Object.defineProperty(callbacksRegistry, "__esModule", { value: true });
callbacksRegistry.CallbacksRegistry = void 0;
class CallbacksRegistry {
constructor() {
this.nextId = 0;
this.callbacks = {};
this.callbackIds = new WeakMap();
this.locationInfo = new WeakMap();
}
add(callback) {
// The callback is already added.
let id = this.callbackIds.get(callback);
if (id != null)
return id;
id = this.nextId += 1;
this.callbacks[id] = callback;
this.callbackIds.set(callback, id);
// Capture the location of the function and put it in the ID string,
// so that release errors can be tracked down easily.
const regexp = /at (.*)/gi;
const stackString = (new Error()).stack;
if (!stackString)
return id;
let filenameAndLine;
let match;
while ((match = regexp.exec(stackString)) !== null) {
const location = match[1];
if (location.includes('(native)'))
continue;
if (location.includes('(<anonymous>)'))
continue;
if (location.includes('callbacks-registry.js'))
continue;
if (location.includes('remote.js'))
continue;
if (location.includes('@electron/remote/dist'))
continue;
const ref = /([^/^)]*)\)?$/gi.exec(location);
if (ref)
filenameAndLine = ref[1];
break;
}
this.locationInfo.set(callback, filenameAndLine);
return id;
}
get(id) {
return this.callbacks[id] || function () { };
}
getLocation(callback) {
return this.locationInfo.get(callback);
}
apply(id, ...args) {
return this.get(id).apply(commonjsGlobal, ...args);
}
remove(id) {
const callback = this.callbacks[id];
if (callback) {
this.callbackIds.delete(callback);
delete this.callbacks[id];
}
}
}
callbacksRegistry.CallbacksRegistry = CallbacksRegistry;
return callbacksRegistry;
}
var typeUtils = {};
var hasRequiredTypeUtils;
function requireTypeUtils () {
if (hasRequiredTypeUtils) return typeUtils;
hasRequiredTypeUtils = 1;
Object.defineProperty(typeUtils, "__esModule", { value: true });
typeUtils.deserialize = typeUtils.serialize = typeUtils.isSerializableObject = typeUtils.isPromise = void 0;
const electron_1 = require$$0;
function isPromise(val) {
return (val &&
val.then &&
val.then instanceof Function &&
val.constructor &&
val.constructor.reject &&
val.constructor.reject instanceof Function &&
val.constructor.resolve &&
val.constructor.resolve instanceof Function);
}
typeUtils.isPromise = isPromise;
const serializableTypes = [
Boolean,
Number,
String,
Date,
Error,
RegExp,
ArrayBuffer
];
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#Supported_types
function isSerializableObject(value) {
return value === null || ArrayBuffer.isView(value) || serializableTypes.some(type => value instanceof type);
}
typeUtils.isSerializableObject = isSerializableObject;
const objectMap = function (source, mapper) {
const sourceEntries = Object.entries(source);
const targetEntries = sourceEntries.map(([key, val]) => [key, mapper(val)]);
return Object.fromEntries(targetEntries);
};
function serializeNativeImage(image) {
const representations = [];
const scaleFactors = image.getScaleFactors();
// Use Buffer when there's only one representation for better perf.
// This avoids compressing to/from PNG where it's not necessary to
// ensure uniqueness of dataURLs (since there's only one).
if (scaleFactors.length === 1) {
const scaleFactor = scaleFactors[0];
const size = image.getSize(scaleFactor);
const buffer = image.toBitmap({ scaleFactor });
representations.push({ scaleFactor, size, buffer });
}
else {
// Construct from dataURLs to ensure that they are not lost in creation.
for (const scaleFactor of scaleFactors) {
const size = image.getSize(scaleFactor);
const dataURL = image.toDataURL({ scaleFactor });
representations.push({ scaleFactor, size, dataURL });
}
}
return { __ELECTRON_SERIALIZED_NativeImage__: true, representations };
}
function deserializeNativeImage(value) {
const image = electron_1.nativeImage.createEmpty();
// Use Buffer when there's only one representation for better perf.
// This avoids compressing to/from PNG where it's not necessary to
// ensure uniqueness of dataURLs (since there's only one).
if (value.representations.length === 1) {
const { buffer, size, scaleFactor } = value.representations[0];
const { width, height } = size;
image.addRepresentation({ buffer, scaleFactor, width, height });
}
else {
// Construct from dataURLs to ensure that they are not lost in creation.
for (const rep of value.representations) {
const { dataURL, size, scaleFactor } = rep;
const { width, height } = size;
image.addRepresentation({ dataURL, scaleFactor, width, height });
}
}
return image;
}
function serialize(value) {
if (value && value.constructor && value.constructor.name === 'NativeImage') {
return serializeNativeImage(value);
}
if (Array.isArray(value)) {
return value.map(serialize);
}
else if (isSerializableObject(value)) {
return value;
}
else if (value instanceof Object) {
return objectMap(value, serialize);
}
else {
return value;
}
}
typeUtils.serialize = serialize;
function deserialize(value) {
if (value && value.__ELECTRON_SERIALIZED_NativeImage__) {
return deserializeNativeImage(value);
}
else if (Array.isArray(value)) {
return value.map(deserialize);
}
else if (isSerializableObject(value)) {
return value;
}
else if (value instanceof Object) {
return objectMap(value, deserialize);
}
else {
return value;
}
}
typeUtils.deserialize = deserialize;
return typeUtils;
}
var moduleNames = {};
var getElectronBinding = {};
var hasRequiredGetElectronBinding;
function requireGetElectronBinding () {
if (hasRequiredGetElectronBinding) return getElectronBinding;
hasRequiredGetElectronBinding = 1;
Object.defineProperty(getElectronBinding, "__esModule", { value: true });
getElectronBinding.getElectronBinding = void 0;
const getElectronBinding$1 = (name) => {
if (process._linkedBinding) {
return process._linkedBinding('electron_common_' + name);
}
else if (process.electronBinding) {
return process.electronBinding(name);
}
else {
return null;
}
};
getElectronBinding.getElectronBinding = getElectronBinding$1;
return getElectronBinding;
}
var hasRequiredModuleNames;
function requireModuleNames () {
if (hasRequiredModuleNames) return moduleNames;
hasRequiredModuleNames = 1;
(function (exports$1) {
var _a, _b;
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.browserModuleNames = exports$1.commonModuleNames = void 0;
const get_electron_binding_1 = requireGetElectronBinding();
exports$1.commonModuleNames = [
'clipboard',
'nativeImage',
'shell',
];
exports$1.browserModuleNames = [
'app',
'autoUpdater',
'BaseWindow',
'BrowserView',
'BrowserWindow',
'contentTracing',
'crashReporter',
'dialog',
'globalShortcut',
'ipcMain',
'inAppPurchase',
'Menu',
'MenuItem',
'nativeTheme',
'net',
'netLog',
'MessageChannelMain',
'Notification',
'powerMonitor',
'powerSaveBlocker',
'protocol',
'pushNotifications',
'safeStorage',
'screen',
'session',
'ServiceWorkerMain',
'ShareMenu',
'systemPreferences',
'TopLevelWindow',
'TouchBar',
'Tray',
'utilityProcess',
'View',
'webContents',
'WebContentsView',
'webFrameMain',
].concat(exports$1.commonModuleNames);
const features = get_electron_binding_1.getElectronBinding('features');
if (((_a = features === null || features === void 0 ? void 0 : features.isDesktopCapturerEnabled) === null || _a === void 0 ? void 0 : _a.call(features)) !== false) {
exports$1.browserModuleNames.push('desktopCapturer');
}
if (((_b = features === null || features === void 0 ? void 0 : features.isViewApiEnabled) === null || _b === void 0 ? void 0 : _b.call(features)) !== false) {
exports$1.browserModuleNames.push('ImageView');
}
} (moduleNames));
return moduleNames;
}
var hasRequiredRemote;
function requireRemote () {
if (hasRequiredRemote) return remote;
hasRequiredRemote = 1;
(function (exports$1) {
Object.defineProperty(exports$1, "__esModule", { value: true });
exports$1.createFunctionWithReturnValue = exports$1.getGlobal = exports$1.getCurrentWebContents = exports$1.getCurrentWindow = exports$1.getBuiltin = void 0;
const callbacks_registry_1 = requireCallbacksRegistry();
const type_utils_1 = requireTypeUtils();
const electron_1 = require$$0;
const module_names_1 = requireModuleNames();
const get_electron_binding_1 = requireGetElectronBinding();
const { Promise } = commonjsGlobal;
const callbacksRegistry = new callbacks_registry_1.CallbacksRegistry();
const remoteObjectCache = new Map();
const finalizationRegistry = new FinalizationRegistry((id) => {
const ref = remoteObjectCache.get(id);
if (ref !== undefined && ref.deref() === undefined) {
remoteObjectCache.delete(id);
electron_1.ipcRenderer.send("REMOTE_BROWSER_DEREFERENCE" /* BROWSER_DEREFERENCE */, contextId, id, 0);
}
});
const electronIds = new WeakMap();
const isReturnValue = new WeakSet();
function getCachedRemoteObject(id) {
const ref = remoteObjectCache.get(id);
if (ref !== undefined) {
const deref = ref.deref();
if (deref !== undefined)
return deref;
}
}
function setCachedRemoteObject(id, value) {
const wr = new WeakRef(value);
remoteObjectCache.set(id, wr);
finalizationRegistry.register(value, id);
return value;
}
function getContextId() {
const v8Util = get_electron_binding_1.getElectronBinding('v8_util');
if (v8Util) {
return v8Util.getHiddenValue(commonjsGlobal, 'contextId');
}
else {
throw new Error('Electron >=v13.0.0-beta.6 required to support sandboxed renderers');
}
}
// An unique ID that can represent current context.
const contextId = process.contextId || getContextId();
// Notify the main process when current context is going to be released.
// Note that when the renderer process is destroyed, the message may not be
// sent, we also listen to the "render-view-deleted" event in the main process
// to guard that situation.
process.on('exit', () => {
const command = "REMOTE_BROWSER_CONTEXT_RELEASE" /* BROWSER_CONTEXT_RELEASE */;
electron_1.ipcRenderer.send(command, contextId);
});
const IS_REMOTE_PROXY = Symbol('is-remote-proxy');
// Convert the arguments object into an array of meta data.
function wrapArgs(args, visited = new Set()) {
const valueToMeta = (value) => {
// Check for circular reference.
if (visited.has(value)) {
return {
type: 'value',
value: null
};
}
if (value && value.constructor && value.constructor.name === 'NativeImage') {
return { type: 'nativeimage', value: type_utils_1.serialize(value) };
}
else if (Array.isArray(value)) {
visited.add(value);
const meta = {
type: 'array',
value: wrapArgs(value, visited)
};
visited.delete(value);
return meta;
}
else if (value instanceof Buffer) {
return {
type: 'buffer',
value
};
}
else if (type_utils_1.isSerializableObject(value)) {
return {
type: 'value',
value
};
}
else if (typeof value === 'object') {
if (type_utils_1.isPromise(value)) {
return {
type: 'promise',
then: valueToMeta(function (onFulfilled, onRejected) {
value.then(onFulfilled, onRejected);
})
};
}
else if (electronIds.has(value)) {
return {
type: 'remote-object',
id: electronIds.get(value)
};
}
const meta = {
type: 'object',
name: value.constructor ? value.constructor.name : '',
members: []
};
visited.add(value);
for (const prop in value) { // eslint-disable-line guard-for-in
meta.members.push({
name: prop,
value: valueToMeta(value[prop])
});
}
visited.delete(value);
return meta;
}
else if (typeof value === 'function' && isReturnValue.has(value)) {
return {
type: 'function-with-return-value',
value: valueToMeta(value())
};
}
else if (typeof value === 'function') {
return {
type: 'function',
id: callbacksRegistry.add(value),
location: callbacksRegistry.getLocation(value),
length: value.length
};
}
else {
return {
type: 'value',
value
};
}
};
return args.map(valueToMeta);
}
// Populate object's members from descriptors.
// The |ref| will be kept referenced by |members|.
// This matches |getObjectMemebers| in rpc-server.
function setObjectMembers(ref, object, metaId, members) {
if (!Array.isArray(members))
return;
for (const member of members) {
if (Object.prototype.hasOwnProperty.call(object, member.name))
continue;
const descriptor = { enumerable: member.enumerable };
if (member.type === 'method') {
const remoteMemberFunction = function (...args) {
let command;
if (this && this.constructor === remoteMemberFunction) {
command = "REMOTE_BROWSER_MEMBER_CONSTRUCTOR" /* BROWSER_MEMBER_CONSTRUCTOR */;
}
else {
command = "REMOTE_BROWSER_MEMBER_CALL" /* BROWSER_MEMBER_CALL */;
}
const ret = electron_1.ipcRenderer.sendSync(command, contextId, metaId, member.name, wrapArgs(args));
return metaToValue(ret);
};
let descriptorFunction = proxyFunctionProperties(remoteMemberFunction, metaId, member.name);
descriptor.get = () => {
descriptorFunction.ref = ref; // The member should reference its object.
return descriptorFunction;
};
// Enable monkey-patch the method
descriptor.set = (value) => {
descriptorFunction = value;
return value;
};
descriptor.configurable = true;
}
else if (member.type === 'get') {
descriptor.get = () => {
const command = "REMOTE_BROWSER_MEMBER_GET" /* BROWSER_MEMBER_GET */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, metaId, member.name);
return metaToValue(meta);
};
if (member.writable) {
descriptor.set = (value) => {
const args = wrapArgs([value]);
const command = "REMOTE_BROWSER_MEMBER_SET" /* BROWSER_MEMBER_SET */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, metaId, member.name, args);
if (meta != null)
metaToValue(meta);
return value;
};
}
}
Object.defineProperty(object, member.name, descriptor);
}
}
// Populate object's prototype from descriptor.
// This matches |getObjectPrototype| in rpc-server.
function setObjectPrototype(ref, object, metaId, descriptor) {
if (descriptor === null)
return;
const proto = {};
setObjectMembers(ref, proto, metaId, descriptor.members);
setObjectPrototype(ref, proto, metaId, descriptor.proto);
Object.setPrototypeOf(object, proto);
}
// Wrap function in Proxy for accessing remote properties
function proxyFunctionProperties(remoteMemberFunction, metaId, name) {
let loaded = false;
// Lazily load function properties
const loadRemoteProperties = () => {
if (loaded)
return;
loaded = true;
const command = "REMOTE_BROWSER_MEMBER_GET" /* BROWSER_MEMBER_GET */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, metaId, name);
setObjectMembers(remoteMemberFunction, remoteMemberFunction, meta.id, meta.members);
};
return new Proxy(remoteMemberFunction, {
set: (target, property, value) => {
if (property !== 'ref')
loadRemoteProperties();
target[property] = value;
return true;
},
get: (target, property) => {
if (property === IS_REMOTE_PROXY)
return true;
if (!Object.prototype.hasOwnProperty.call(target, property))
loadRemoteProperties();
const value = target[property];
if (property === 'toString' && typeof value === 'function') {
return value.bind(target);
}
return value;
},
ownKeys: (target) => {
loadRemoteProperties();
return Object.getOwnPropertyNames(target);
},
getOwnPropertyDescriptor: (target, property) => {
const descriptor = Object.getOwnPropertyDescriptor(target, property);
if (descriptor)
return descriptor;
loadRemoteProperties();
return Object.getOwnPropertyDescriptor(target, property);
}
});
}
// Convert meta data from browser into real value.
function metaToValue(meta) {
if (!meta)
return {};
if (meta.type === 'value') {
return meta.value;
}
else if (meta.type === 'array') {
return meta.members.map((member) => metaToValue(member));
}
else if (meta.type === 'nativeimage') {
return type_utils_1.deserialize(meta.value);
}
else if (meta.type === 'buffer') {
return Buffer.from(meta.value.buffer, meta.value.byteOffset, meta.value.byteLength);
}
else if (meta.type === 'promise') {
return Promise.resolve({ then: metaToValue(meta.then) });
}
else if (meta.type === 'error') {
return metaToError(meta);
}
else if (meta.type === 'exception') {
if (meta.value.type === 'error') {
throw metaToError(meta.value);
}
else {
throw new Error(`Unexpected value type in exception: ${meta.value.type}`);
}
}
else {
let ret;
if ('id' in meta) {
const cached = getCachedRemoteObject(meta.id);
if (cached !== undefined) {
return cached;
}
}
// A shadow class to represent the remote function object.
if (meta.type === 'function') {
const remoteFunction = function (...args) {
let command;
if (this && this.constructor === remoteFunction) {
command = "REMOTE_BROWSER_CONSTRUCTOR" /* BROWSER_CONSTRUCTOR */;
}
else {
command = "REMOTE_BROWSER_FUNCTION_CALL" /* BROWSER_FUNCTION_CALL */;
}
const obj = electron_1.ipcRenderer.sendSync(command, contextId, meta.id, wrapArgs(args));
return metaToValue(obj);
};
ret = remoteFunction;
}
else {
ret = {};
}
setObjectMembers(ret, ret, meta.id, meta.members);
setObjectPrototype(ret, ret, meta.id, meta.proto);
if (ret.constructor && ret.constructor[IS_REMOTE_PROXY]) {
Object.defineProperty(ret.constructor, 'name', { value: meta.name });
}
// Track delegate obj's lifetime & tell browser to clean up when object is GCed.
electronIds.set(ret, meta.id);
setCachedRemoteObject(meta.id, ret);
return ret;
}
}
function metaToError(meta) {
const obj = meta.value;
for (const { name, value } of meta.members) {
obj[name] = metaToValue(value);
}
return obj;
}
function hasSenderId(input) {
return typeof input.senderId === "number";
}
function handleMessage(channel, handler) {
electron_1.ipcRenderer.on(channel, (event, passedContextId, id, ...args) => {
if (hasSenderId(event)) {
if (event.senderId !== 0 && event.senderId !== undefined) {
console.error(`Message ${channel} sent by unexpected WebContents (${event.senderId})`);
return;
}
}
if (passedContextId === contextId) {
handler(id, ...args);
}
else {
// Message sent to an un-exist context, notify the error to main process.
electron_1.ipcRenderer.send("REMOTE_BROWSER_WRONG_CONTEXT_ERROR" /* BROWSER_WRONG_CONTEXT_ERROR */, contextId, passedContextId, id);
}
});
}
const enableStacks = process.argv.includes('--enable-api-filtering-logging');
function getCurrentStack() {
const target = { stack: undefined };
if (enableStacks) {
Error.captureStackTrace(target, getCurrentStack);
}
return target.stack;
}
// Browser calls a callback in renderer.
handleMessage("REMOTE_RENDERER_CALLBACK" /* RENDERER_CALLBACK */, (id, args) => {
callbacksRegistry.apply(id, metaToValue(args));
});
// A callback in browser is released.
handleMessage("REMOTE_RENDERER_RELEASE_CALLBACK" /* RENDERER_RELEASE_CALLBACK */, (id) => {
callbacksRegistry.remove(id);
});
exports$1.require = (module) => {
const command = "REMOTE_BROWSER_REQUIRE" /* BROWSER_REQUIRE */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, module, getCurrentStack());
return metaToValue(meta);
};
// Alias to remote.require('electron').xxx.
function getBuiltin(module) {
const command = "REMOTE_BROWSER_GET_BUILTIN" /* BROWSER_GET_BUILTIN */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, module, getCurrentStack());
return metaToValue(meta);
}
exports$1.getBuiltin = getBuiltin;
function getCurrentWindow() {
const command = "REMOTE_BROWSER_GET_CURRENT_WINDOW" /* BROWSER_GET_CURRENT_WINDOW */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, getCurrentStack());
return metaToValue(meta);
}
exports$1.getCurrentWindow = getCurrentWindow;
// Get current WebContents object.
function getCurrentWebContents() {
const command = "REMOTE_BROWSER_GET_CURRENT_WEB_CONTENTS" /* BROWSER_GET_CURRENT_WEB_CONTENTS */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, getCurrentStack());
return metaToValue(meta);
}
exports$1.getCurrentWebContents = getCurrentWebContents;
// Get a global object in browser.
function getGlobal(name) {
const command = "REMOTE_BROWSER_GET_GLOBAL" /* BROWSER_GET_GLOBAL */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, name, getCurrentStack());
return metaToValue(meta);
}
exports$1.getGlobal = getGlobal;
// Get the process object in browser.
Object.defineProperty(exports$1, 'process', {
enumerable: true,
get: () => exports$1.getGlobal('process')
});
// Create a function that will return the specified value when called in browser.
function createFunctionWithReturnValue(returnValue) {
const func = () => returnValue;
isReturnValue.add(func);
return func;
}
exports$1.createFunctionWithReturnValue = createFunctionWithReturnValue;
const addBuiltinProperty = (name) => {
Object.defineProperty(exports$1, name, {
enumerable: true,
get: () => exports$1.getBuiltin(name)
});
};
module_names_1.browserModuleNames
.forEach(addBuiltinProperty);
} (remote));
return remote;
}
var hasRequiredRenderer$1;
function requireRenderer$1 () {
if (hasRequiredRenderer$1) return renderer$1;
hasRequiredRenderer$1 = 1;
(function (exports$1) {
var __createBinding = (renderer$1 && renderer$1.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (renderer$1 && renderer$1.__exportStar) || function(m, exports$1) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports$1, p)) __createBinding(exports$1, m, p);
};
Object.defineProperty(exports$1, "__esModule", { value: true });
if (process.type === 'browser')
throw new Error(`"@electron/remote" cannot be required in the browser process. Instead require("@electron/remote/main").`);
__exportStar(requireRemote(), exports$1);
} (renderer$1));
return renderer$1;
}
var renderer;
var hasRequiredRenderer;
function requireRenderer () {
if (hasRequiredRenderer) return renderer;
hasRequiredRenderer = 1;
renderer = requireRenderer$1();
return renderer;
}
var rendererExports = requireRenderer();
class FileEmbeder {
settings;
constructor(settings) {
this.settings = settings;
}
getEmbedMarkdownLink(filePath) {
const { ext } = this.getPathInformation(filePath);
if (!SUPPORTED_EMBED_FILE_TYPES.includes(ext)) {
new obsidian.Notice(`Files of this type are not supported for embedding in Obsidian.`);
}
return "!" + this.getMarkdownLink(filePath, false);
}
copyFile(sourcePath, targetDir) {
try {
fs__namespace.mkdirSync(targetDir, { recursive: true });
const filename = path__namespace.basename(sourcePath);
const destPath = path__namespace.join(targetDir, filename);
fs__namespace.copyFileSync(sourcePath, destPath);
return destPath;
}
catch (err) {
console.error("Copy failed:", err);
throw new Error(`File copy failed: ${err.message}`);
}
}
getPathInformation(filePath) {
const normalizedPath = path__namespace.normalize(filePath);
const parsedPath = path__namespace.parse(normalizedPath);
return {
fullPath: normalizedPath,
dir: parsedPath.dir,
filename: parsedPath.base,
name: parsedPath.name,
ext: parsedPath.ext,
};
}
getMarkdownLink(filePath, printPrefix) {
const pathInfo = this.getPathInformation(filePath);
const prefix = printPrefix ? this.settings.linkPrefix : "";
let linkText = pathInfo.name;
if (this.settings.linkFolder) {
linkText = this.settings.useFolderName
? path__namespace.basename(pathInfo.dir)
: pathInfo.dir;
}
if (this.settings.showFileEnding) {
linkText = pathInfo.filename;
}
const linkPath = this.settings.linkFolder
? pathInfo.dir
: pathInfo.fullPath;
return this.formatMarkdownLink(prefix, linkText, linkPath);
}
formatMarkdownLink(prefix, text, path) {
const space = prefix && prefix !== "!" ? " " : "";
return `${prefix}${space}[${text}](<file:///${path}>)\n`;
}
}
class FileLinkModal extends obsidian.Modal {
plugin;
selectedFilesDiv = document.createElement("div");
filePaths = [];
constructor(app, plugin) {
super(app);
this.plugin = plugin;
}
async onOpen() {
const { contentEl } = this;
const mainContainer = contentEl.createEl("div", {
cls: "bfl-container",
});
const fileSelectionSection = mainContainer.createEl("div", {
cls: "bfl-selection-section",
});
const fileButton = fileSelectionSection.createEl("button", {
text: "Select files",
cls: "mod-cta",
});
this.selectedFilesDiv = fileSelectionSection.createEl("div", {
cls: "bfl-selected-files",
});
this.displaySelectedFiles([]);
const checkboxContainer = mainContainer.createEl("div", {
cls: "bfl-checkbox-container",
});
const createCheckboxGroup = (id, label, initialValue) => {
const wrapper = checkboxContainer.createEl("div", {
cls: "bfl-checkbox-group",
});
const checkbox = wrapper.createEl("input", {
type: "checkbox",
attr: {
id: id,
style: "margin: 0;",
},
});
wrapper.createEl("label", {
text: label,
attr: {
for: id,
style: "margin: 0; user-select: none;",
},
});
checkbox.checked = initialValue;
return checkbox;
};
const checkboxEmbed = createCheckboxGroup("embed", "Embed file", this.plugin.settings.embedFile);
const checkboxFileFolder = createCheckboxGroup("file-folder", "Link folder", this.plugin.settings.linkFolder);
const checkboxFolderName = createCheckboxGroup("folder-name", "Use folder name", this.plugin.settings.useFolderName);
const checkboxFileEnding = createCheckboxGroup("file-ending", "Show file extension", this.plugin.settings.showFileEnding);
const buttonContainer = mainContainer.createEl("div", {
cls: "button-container",
attr: {
style: "margin-top: 5px;",
},
});
const submitButton = buttonContainer.createEl("button", {
text: "Add file link",
cls: "mod-cta",
});
contentEl.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
e.preventDefault();
submitButton.click();
}
});
fileButton.addEventListener("click", async () => {
try {
const result = await rendererExports.dialog.showOpenDialog({
properties: ["openFile", "multiSelections"],
filters: [{ name: "All Files", extensions: ["*"] }],
});
if (!result.canceled && result.filePaths.length > 0) {
this.filePaths = result.filePaths;
this.displaySelectedFiles(this.filePaths);
}
}
catch (error) {
new obsidian.Notice("Error selecting files: " + error.message);
}
});
submitButton.addEventListener("click", () => {
if (this.filePaths.length > 0) {
// Update settings
this.plugin.settings.linkFolder = checkboxFileFolder.checked;
this.plugin.settings.useFolderName = checkboxFolderName.checked;
this.plugin.settings.showFileEnding = checkboxFileEnding.checked;
this.plugin.settings.embedFile = checkboxEmbed.checked;
const fe = new FileEmbeder(this.plugin.settings);
if (checkboxEmbed.checked) {
this.filePaths.forEach((file) => {
const embedMarkdownLink = fe.getEmbedMarkdownLink(file);
this.addAtCursor(embedMarkdownLink);
});
}
else {
let linkString = "";
this.filePaths.forEach((file) => {
linkString += fe.getMarkdownLink(file, this.filePaths.length > 1);
});
this.addAtCursor(linkString);
}
this.close();
new obsidian.Notice(`Added ${this.filePaths.length} file link(s)`);
}
else {
new obsidian.Notice("No files selected");
}
});
}
displaySelectedFiles(files) {
this.selectedFilesDiv.empty();
if (files.length === 0) {
this.selectedFilesDiv.createEl("p", {
text: "No files selected",
cls: "no-files-message",
attr: {
style: "color: var(--text-muted); font-style: italic; margin: 0; padding: 8px;",
},
});
return;
}
const fileList = this.selectedFilesDiv.createEl("ul", {
cls: "selected-files-list",
attr: {
style: "list-style: none; padding: 0; margin: 0;",
},
});
files.forEach((filePath) => {
const fileName = filePath.split(/[\\/]/).pop() || filePath;
fileList.createEl("li", {
text: fileName,
cls: "selected-file-item",
attr: {
style: "padding: 4px 8px; border-bottom: 1px solid var(--background-modifier-border);",
},
});
});
}
addAtCursor(s) {
const markdownView = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
if (markdownView) {
const editor = markdownView.editor;
const currentLine = editor.getCursor();
editor.replaceRange(s, currentLine, currentLine);
}
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
}
const FILE_URI_REGEX = /file:\/\/[^\s)>"]+/g;
async function findBrokenFileLinks(vault) {
const results = new Map();
const files = vault.getMarkdownFiles();
for (const file of files) {
const content = await vault.read(file);
const broken = [];
let match;
FILE_URI_REGEX.lastIndex = 0;
while ((match = FILE_URI_REGEX.exec(content)) !== null) {
const uri = match[0];
const filePath = decodeURIComponent(new URL(uri).pathname);
if (!fs__namespace.existsSync(filePath)) {
broken.push(uri);
}
}
if (broken.length > 0) {
results.set(file, broken);
}
}
return results;
}
class BrokenLinksModal extends obsidian.Modal {
brokenLinks;
constructor(app, brokenLinks) {
super(app);
this.brokenLinks = brokenLinks;
}
onOpen() {
const { contentEl } = this;
contentEl.createEl("h2", { text: "Broken File Links" });
for (const [file, links] of this.brokenLinks) {
const header = contentEl.createEl("h3");
const noteLink = header.createEl("a", { text: file.basename });
noteLink.addEventListener("click", () => {
this.app.workspace.getLeaf().openFile(file);
this.close();
});
const list = contentEl.createEl("ul");
for (const link of links) {
const item = list.createEl("li");
item.createEl("span", {
text: link,
attr: { style: "word-break: break-all;" },
});
}
}
}
onClose() {
this.contentEl.empty();
}
}
class FileLink extends obsidian.Plugin {
settings = DEFAULT_SETTINGS;
async onload() {
console.log("loading plugin file-link");
await this.loadSettings();
this.addSettingTab(new FileLinkSettingTab(this.app, this));
this.addCommand({
id: "add-file-link",
name: "Add File Link",
editorCallback: () => {
new FileLinkModal(this.app, this).open();
},
});
this.addCommand({
id: "check-broken-file-links",
name: "Check for broken file links",
callback: async () => {
new obsidian.Notice("Scanning for broken file links...");
const brokenLinks = await findBrokenFileLinks(this.app.vault);
if (brokenLinks.size === 0) {
new obsidian.Notice("No broken file links found.");
return;
}
new BrokenLinksModal(this.app, brokenLinks).open();
},
});
}
onunload() {
console.log("unloading plugin file-link");
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
}
module.exports = FileLink;
/* nosourcemap */