/* 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('()')) 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}]()\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 */