From 6a8e9ed259faece1c10bd99e1f3016b06b0f9281 Mon Sep 17 00:00:00 2001 From: CrazyJasonwell Date: Wed, 16 Jul 2025 16:23:45 +0800 Subject: [PATCH] vault backup: 2025-07-16 16:23:44 --- .obsidian/community-plugins.json | 4 +- .../plugins/file-explorer-note-count/main.js | 970 +++++ .../file-explorer-note-count/manifest.json | 10 + .../file-explorer-note-count/styles.css | 34 + .../data.json | 45 + .../plugins/obsidian-image-toolkit/main.js | 3425 +++++++++++++++++ .../obsidian-image-toolkit/manifest.json | 10 + .../plugins/obsidian-image-toolkit/styles.css | 747 ++++ .obsidian/workspace.json | 18 +- ...¡) Obsidian知识管理体系搭建实战指南 - 知乎.md | 1562 ++++++++ ...记流动起来——Obsidian重塑知识体系 - 少数派.md | 154 + 11 files changed, 6969 insertions(+), 10 deletions(-) create mode 100644 .obsidian/plugins/file-explorer-note-count/main.js create mode 100644 .obsidian/plugins/file-explorer-note-count/manifest.json create mode 100644 .obsidian/plugins/file-explorer-note-count/styles.css create mode 100644 .obsidian/plugins/obsidian-image-toolkit/main.js create mode 100644 .obsidian/plugins/obsidian-image-toolkit/manifest.json create mode 100644 .obsidian/plugins/obsidian-image-toolkit/styles.css create mode 100644 10-WebClipper/(74 封私信) Obsidian知识管理体系搭建实战指南 - 知乎.md create mode 100644 10-WebClipper/让笔记流动起来——Obsidian重塑知识体系 - 少数派.md diff --git a/.obsidian/community-plugins.json b/.obsidian/community-plugins.json index 95fa5841..7d33aeb0 100644 --- a/.obsidian/community-plugins.json +++ b/.obsidian/community-plugins.json @@ -31,5 +31,7 @@ "better-export-pdf", "obsidian-calibre-plugin", "obsidian-enhancing-mindmap", - "ob-smm" + "ob-smm", + "file-explorer-note-count", + "obsidian-image-toolkit" ] \ No newline at end of file diff --git a/.obsidian/plugins/file-explorer-note-count/main.js b/.obsidian/plugins/file-explorer-note-count/main.js new file mode 100644 index 00000000..0ff6c0ee --- /dev/null +++ b/.obsidian/plugins/file-explorer-note-count/main.js @@ -0,0 +1,970 @@ +'use strict'; + +var obsidian = require('obsidian'); + +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}; + +// 'path' module extracted from Node.js v8.11.1 (only the posix part) + +function assertPath(path) { + if (typeof path !== 'string') { + throw new TypeError('Path must be a string. Received ' + JSON.stringify(path)); + } +} + +// Resolves . and .. elements in a path with directory names +function normalizeStringPosix(path, allowAboveRoot) { + var res = ''; + var lastSegmentLength = 0; + var lastSlash = -1; + var dots = 0; + var code; + for (var i = 0; i <= path.length; ++i) { + if (i < path.length) + code = path.charCodeAt(i); + else if (code === 47 /*/*/) + break; + else + code = 47 /*/*/; + if (code === 47 /*/*/) { + if (lastSlash === i - 1 || dots === 1) ; else if (lastSlash !== i - 1 && dots === 2) { + if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 /*.*/ || res.charCodeAt(res.length - 2) !== 46 /*.*/) { + if (res.length > 2) { + var lastSlashIndex = res.lastIndexOf('/'); + if (lastSlashIndex !== res.length - 1) { + if (lastSlashIndex === -1) { + res = ''; + lastSegmentLength = 0; + } else { + res = res.slice(0, lastSlashIndex); + lastSegmentLength = res.length - 1 - res.lastIndexOf('/'); + } + lastSlash = i; + dots = 0; + continue; + } + } else if (res.length === 2 || res.length === 1) { + res = ''; + lastSegmentLength = 0; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + if (res.length > 0) + res += '/..'; + else + res = '..'; + lastSegmentLength = 2; + } + } else { + if (res.length > 0) + res += '/' + path.slice(lastSlash + 1, i); + else + res = path.slice(lastSlash + 1, i); + lastSegmentLength = i - lastSlash - 1; + } + lastSlash = i; + dots = 0; + } else if (code === 46 /*.*/ && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} + +function _format(sep, pathObject) { + var dir = pathObject.dir || pathObject.root; + var base = pathObject.base || (pathObject.name || '') + (pathObject.ext || ''); + if (!dir) { + return base; + } + if (dir === pathObject.root) { + return dir + base; + } + return dir + sep + base; +} + +var posix = { + // path.resolve([from ...], to) + resolve: function resolve() { + var resolvedPath = ''; + var resolvedAbsolute = false; + var cwd; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path; + if (i >= 0) + path = arguments[i]; + else { + if (cwd === undefined) + cwd = process.cwd(); + path = cwd; + } + + assertPath(path); + + // Skip empty entries + if (path.length === 0) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charCodeAt(0) === 47 /*/*/; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute); + + if (resolvedAbsolute) { + if (resolvedPath.length > 0) + return '/' + resolvedPath; + else + return '/'; + } else if (resolvedPath.length > 0) { + return resolvedPath; + } else { + return '.'; + } + }, + + normalize: function normalize(path) { + assertPath(path); + + if (path.length === 0) return '.'; + + var isAbsolute = path.charCodeAt(0) === 47 /*/*/; + var trailingSeparator = path.charCodeAt(path.length - 1) === 47 /*/*/; + + // Normalize the path + path = normalizeStringPosix(path, !isAbsolute); + + if (path.length === 0 && !isAbsolute) path = '.'; + if (path.length > 0 && trailingSeparator) path += '/'; + + if (isAbsolute) return '/' + path; + return path; + }, + + isAbsolute: function isAbsolute(path) { + assertPath(path); + return path.length > 0 && path.charCodeAt(0) === 47 /*/*/; + }, + + join: function join() { + if (arguments.length === 0) + return '.'; + var joined; + for (var i = 0; i < arguments.length; ++i) { + var arg = arguments[i]; + assertPath(arg); + if (arg.length > 0) { + if (joined === undefined) + joined = arg; + else + joined += '/' + arg; + } + } + if (joined === undefined) + return '.'; + return posix.normalize(joined); + }, + + relative: function relative(from, to) { + assertPath(from); + assertPath(to); + + if (from === to) return ''; + + from = posix.resolve(from); + to = posix.resolve(to); + + if (from === to) return ''; + + // Trim any leading backslashes + var fromStart = 1; + for (; fromStart < from.length; ++fromStart) { + if (from.charCodeAt(fromStart) !== 47 /*/*/) + break; + } + var fromEnd = from.length; + var fromLen = fromEnd - fromStart; + + // Trim any leading backslashes + var toStart = 1; + for (; toStart < to.length; ++toStart) { + if (to.charCodeAt(toStart) !== 47 /*/*/) + break; + } + var toEnd = to.length; + var toLen = toEnd - toStart; + + // Compare paths to find the longest common path from root + var length = fromLen < toLen ? fromLen : toLen; + var lastCommonSep = -1; + var i = 0; + for (; i <= length; ++i) { + if (i === length) { + if (toLen > length) { + if (to.charCodeAt(toStart + i) === 47 /*/*/) { + // We get here if `from` is the exact base path for `to`. + // For example: from='/foo/bar'; to='/foo/bar/baz' + return to.slice(toStart + i + 1); + } else if (i === 0) { + // We get here if `from` is the root + // For example: from='/'; to='/foo' + return to.slice(toStart + i); + } + } else if (fromLen > length) { + if (from.charCodeAt(fromStart + i) === 47 /*/*/) { + // We get here if `to` is the exact base path for `from`. + // For example: from='/foo/bar/baz'; to='/foo/bar' + lastCommonSep = i; + } else if (i === 0) { + // We get here if `to` is the root. + // For example: from='/foo'; to='/' + lastCommonSep = 0; + } + } + break; + } + var fromCode = from.charCodeAt(fromStart + i); + var toCode = to.charCodeAt(toStart + i); + if (fromCode !== toCode) + break; + else if (fromCode === 47 /*/*/) + lastCommonSep = i; + } + + var out = ''; + // Generate the relative path based on the path difference between `to` + // and `from` + for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { + if (i === fromEnd || from.charCodeAt(i) === 47 /*/*/) { + if (out.length === 0) + out += '..'; + else + out += '/..'; + } + } + + // Lastly, append the rest of the destination (`to`) path that comes after + // the common path parts + if (out.length > 0) + return out + to.slice(toStart + lastCommonSep); + else { + toStart += lastCommonSep; + if (to.charCodeAt(toStart) === 47 /*/*/) + ++toStart; + return to.slice(toStart); + } + }, + + _makeLong: function _makeLong(path) { + return path; + }, + + dirname: function dirname(path) { + assertPath(path); + if (path.length === 0) return '.'; + var code = path.charCodeAt(0); + var hasRoot = code === 47 /*/*/; + var end = -1; + var matchedSlash = true; + for (var i = path.length - 1; i >= 1; --i) { + code = path.charCodeAt(i); + if (code === 47 /*/*/) { + if (!matchedSlash) { + end = i; + break; + } + } else { + // We saw the first non-path separator + matchedSlash = false; + } + } + + if (end === -1) return hasRoot ? '/' : '.'; + if (hasRoot && end === 1) return '//'; + return path.slice(0, end); + }, + + basename: function basename(path, ext) { + if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string'); + assertPath(path); + + var start = 0; + var end = -1; + var matchedSlash = true; + var i; + + if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { + if (ext.length === path.length && ext === path) return ''; + var extIdx = ext.length - 1; + var firstNonSlashEnd = -1; + for (i = path.length - 1; i >= 0; --i) { + var code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else { + if (firstNonSlashEnd === -1) { + // We saw the first non-path separator, remember this index in case + // we need it if the extension ends up not matching + matchedSlash = false; + firstNonSlashEnd = i + 1; + } + if (extIdx >= 0) { + // Try to match the explicit extension + if (code === ext.charCodeAt(extIdx)) { + if (--extIdx === -1) { + // We matched the extension, so mark this as the end of our path + // component + end = i; + } + } else { + // Extension does not match, so our result is the entire path + // component + extIdx = -1; + end = firstNonSlashEnd; + } + } + } + } + + if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length; + return path.slice(start, end); + } else { + for (i = path.length - 1; i >= 0; --i) { + if (path.charCodeAt(i) === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; + } + } + + if (end === -1) return ''; + return path.slice(start, end); + } + }, + + extname: function extname(path) { + assertPath(path); + var startDot = -1; + var startPart = 0; + var end = -1; + var matchedSlash = true; + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + var preDotState = 0; + for (var i = path.length - 1; i >= 0; --i) { + var code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === 46 /*.*/) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { + return ''; + } + return path.slice(startDot, end); + }, + + format: function format(pathObject) { + if (pathObject === null || typeof pathObject !== 'object') { + throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject); + } + return _format('/', pathObject); + }, + + parse: function parse(path) { + assertPath(path); + + var ret = { root: '', dir: '', base: '', ext: '', name: '' }; + if (path.length === 0) return ret; + var code = path.charCodeAt(0); + var isAbsolute = code === 47 /*/*/; + var start; + if (isAbsolute) { + ret.root = '/'; + start = 1; + } else { + start = 0; + } + var startDot = -1; + var startPart = 0; + var end = -1; + var matchedSlash = true; + var i = path.length - 1; + + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + var preDotState = 0; + + // Get non-dir info + for (; i >= start; --i) { + code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === 46 /*.*/) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { + if (end !== -1) { + if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);else ret.base = ret.name = path.slice(startPart, end); + } + } else { + if (startPart === 0 && isAbsolute) { + ret.name = path.slice(1, startDot); + ret.base = path.slice(1, end); + } else { + ret.name = path.slice(startPart, startDot); + ret.base = path.slice(startPart, end); + } + ret.ext = path.slice(startDot, end); + } + + if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = '/'; + + return ret; + }, + + sep: '/', + delimiter: ':', + win32: null, + posix: null +}; + +posix.posix = posix; + +var pathBrowserify = posix; + +const withSubfolderClass = 'oz-with-subfolder'; +const showAllNumbersClass = 'oz-show-all-num'; +const isFolder = (item) => item.file instanceof obsidian.TFolder; +const iterateItems = (items, callback) => { + for (const key in items) { + if (!Object.prototype.hasOwnProperty.call(items, key)) + continue; + callback(items[key]); + } +}; +const getParentPath = (src) => { + if (src === '/') + return null; + const path = pathBrowserify.dirname(src); + if (path === '.') + return '/'; + else + return path; +}; +const equals = (arr1, arr2) => { + // if the other array is a falsy value, return + if (!Array.isArray(arr1) || !Array.isArray(arr2)) + return false; + // compare lengths - can save a lot of time + if (arr1.length != arr2.length) + return false; + return arr1.every((v, i) => v === arr2[i]); +}; +const isParent = (parent, child) => { + if (child === parent) + return false; + if (parent === '/') + parent = ''; + if (child === '/') + child = ''; + const parentTokens = parent.split('/').filter((i) => i.length); + return parentTokens.every((t, i) => child.split('/')[i] === t); +}; +// Helper to play with the File Explorer (if exists) +const doWithFileExplorer = (plugin, callback) => { + let leaves; + let count = 0; + const tryGetView = () => { + leaves = plugin.app.workspace.getLeavesOfType('file-explorer'); + if (leaves.length === 0) { + if (count++ > 5) + console.error('failed to get file-explorer'); + else { + console.log('file-explorer not found, retrying...'); + setTimeout(tryGetView, 500); + } + } + else { + if (leaves.length > 1) + console.warn('more then one file-explorer'); + callback(leaves[0].view); + } + }; + tryGetView(); +}; + +function around(obj, factories) { + const removers = Object.keys(factories).map(key => around1(obj, key, factories[key])); + return removers.length === 1 ? removers[0] : function () { removers.forEach(r => r()); }; +} +function around1(obj, method, createWrapper) { + const original = obj[method], hadOwn = obj.hasOwnProperty(method); + let current = createWrapper(original); + // Let our wrapper inherit static props from the wrapping method, + // and the wrapping method, props from the original method + if (original) + Object.setPrototypeOf(current, original); + Object.setPrototypeOf(wrapper, current); + obj[method] = wrapper; + // Return a callback to allow safe removal + return remove; + function wrapper(...args) { + // If we have been deactivated and are no longer wrapped, remove ourselves + if (current === original && obj[method] === wrapper) + remove(); + return current.apply(this, args); + } + function remove() { + // If no other patches, just do a direct removal + if (obj[method] === wrapper) { + if (hadOwn) + obj[method] = original; + else + delete obj[method]; + } + if (current === original) + return; + // Else pass future calls through, and remove wrapper from the prototype chain + current = original; + Object.setPrototypeOf(wrapper, original || Function); + } +} + +const countFolderChildren = (folder, filter) => { + let count = 0; + for (const af of folder.children) { + if (filter(af)) + count++; + if (af instanceof obsidian.TFolder) + count += countFolderChildren(af, filter); + } + return count; +}; +/** filter out all path that is the parent of existing path */ +const filterParent = (pathList) => { + const list = Array.from(pathList); + list.sort(); + for (let i = 0; i < list.length; i++) { + if (i < list.length - 1 && (list[i] === list[i + 1] || isParent(list[i], list[i + 1]))) { + list.shift(); + i--; + } + } + return new Set(list); +}; +/** get all parents and add to set if not exist */ +const getAllParents = (path, set) => { + let parent = getParentPath(path); + while (parent && !set.has(parent)) { + set.add(parent); + parent = getParentPath(parent); + } +}; +/** + * Update folder count of target's parent + */ +const updateCount = (targetList, plugin) => { + const set = filterParent(targetList); + for (const path of targetList) { + getAllParents(path, set); + } + // set count of path + const { fileExplorer, fileFilter } = plugin; + if (!fileExplorer) { + console.error('fileExplorer missing'); + return; + } + for (const path of set) { + // check if path available + if (!fileExplorer.fileItems[path]) + continue; + setCount(fileExplorer.fileItems[path], fileFilter); + } + // Update root separately + if (plugin.rootFolderEl && plugin.settings.addRootFolder) { + setupRootCount(plugin); + } + // empty waitingList + targetList.length = 0; +}; +const setupRootCount = (plugin) => { + if (plugin.rootFolderEl) { + let rootFolderElChildren = plugin.rootFolderEl.children; + if (rootFolderElChildren && rootFolderElChildren.length > 0) { + let totalCount = countFolderChildren(plugin.app.vault.getAbstractFileByPath('/'), plugin.fileFilter); + rootFolderElChildren[0].setAttr('data-count', totalCount.toString()); + } + } +}; +const setupCount = (plugin, revert = false) => { + if (!plugin.fileExplorer) + throw new Error('fileExplorer not found'); + // For each setup, first setup the root folder + plugin.setupRootFolder(); + setupRootCount(plugin); + // Iterate other items and include new counts + iterateItems(plugin.fileExplorer.fileItems, (item) => { + if (!isFolder(item)) + return; + if (revert) + removeCount(item); + else + setCount(item, plugin.fileFilter); + }); +}; +const setCount = (item, filter) => { + // if (item.file.isRoot()) return; + const count = countFolderChildren(item.file, filter); + item.selfEl.dataset['count'] = count.toString(); + item.selfEl.toggleClass(withSubfolderClass, Array.isArray(item.file.children) && item.file.children.some((af) => af instanceof obsidian.TFolder)); +}; +const removeCount = (item) => { + if (item.selfEl.dataset['count']) + delete item.selfEl.dataset['count']; + item.selfEl.removeClass(withSubfolderClass); +}; + +class VaultHandler { + get app() { + return this.plugin.app; + } + get vault() { + return this.plugin.app.vault; + } + constructor(plugin) { + this.waitingList = []; + this.update = obsidian.debounce(() => updateCount(this.waitingList, this.plugin), 500, true); + this.handler = (...args) => { + var _a; + for (const arg of args) { + const path = arg instanceof obsidian.TAbstractFile ? arg.path : arg; + this.waitingList.push((_a = getParentPath(path)) !== null && _a !== void 0 ? _a : '/'); + } + this.update(); + }; + this.registerVaultEvent = () => { + this.plugin.registerEvent(this.vault.on('create', this.handler)); + this.plugin.registerEvent(this.vault.on('rename', this.handler)); + this.plugin.registerEvent(this.vault.on('delete', this.handler)); + }; + this.plugin = plugin; + } +} + +const DEFAULT_SETTINGS = { + showAllNumbers: false, + filterList: ['md'], + blacklist: false, + addRootFolder: false, +}; +class FENoteCountSettingTab extends obsidian.PluginSettingTab { + constructor(app, plugin) { + super(app, plugin); + this.plugin = plugin; + } + get showOnlyNoteValue() { + const { settings } = this.plugin; + return settings.blacklist === DEFAULT_SETTINGS.blacklist && equals(settings.filterList, DEFAULT_SETTINGS.filterList); + } + set showOnlyNoteValue(value) { + const { blacklist, filterList } = DEFAULT_SETTINGS; + this.plugin.settings.blacklist = blacklist; + if (value) { + // do deep copy + this.plugin.settings.filterList = Array.from(filterList); + } + else { + this.plugin.settings.filterList.length = 0; + } + } + display() { + let { containerEl } = this; + containerEl.empty(); + containerEl.createEl('h2', { + text: 'File Explorer Note Count Settings', + }); + new obsidian.Setting(containerEl) + .setName('Show All Numbers') + .setDesc('Turn on this option if you want to see the number of notes even after you expand the collapsed folders') + .addToggle((toggle) => toggle.setValue(this.plugin.settings.showAllNumbers).onChange((value) => { + document.body.toggleClass('oz-show-all-num', value); + this.plugin.settings.showAllNumbers = value; + this.plugin.saveSettings(); + })); + new obsidian.Setting(containerEl) + .setName('Add Root Folder') + .setDesc('By default, there is no root folder provided by Obsidian. It is moved to drop-down menu to switch between vaults. ' + + 'Enable this option if you want to see root folder and its count in the file explorer') + .addToggle((toggle) => toggle.setValue(this.plugin.settings.addRootFolder).onChange((value) => { + this.plugin.settings.addRootFolder = value; + this.plugin.saveSettings(); + this.plugin.reloadCount(); + })); + this.filterOpt(); + } + filterOpt() { + new obsidian.Setting(this.containerEl) + .setName('Show Only Markdown Notes') + .setDesc('Turn off this option to choose file that should be counted') + .addToggle((toggle) => toggle.setValue(this.showOnlyNoteValue).onChange((value) => { + this.showOnlyNoteValue = value; + this.plugin.reloadCount(); + this.plugin.saveSettings(); + this.display(); + })); + if (!this.showOnlyNoteValue) { + new obsidian.Setting(this.containerEl) + .setName('Filter List') + .setDesc(createFragment((descEl) => { + descEl.appendText('Extension list to include/exclude file during counting'); + descEl.appendChild(document.createElement('br')); + descEl.appendText('Separated by comma'); + })) + .addTextArea((text) => { + const onChange = (value) => __awaiter(this, void 0, void 0, function* () { + const list = value.split(',').map((v) => v.trim()); + this.plugin.settings.filterList = list; + this.plugin.reloadCount(); + yield this.plugin.saveSettings(); + }); + text.setPlaceholder('Leave it empty to count all types of files'); + text.setValue(this.plugin.settings.filterList.join(', ')).onChange(obsidian.debounce(onChange, 500, true)); + text.inputEl.rows = 2; + text.inputEl.cols = 25; + }); + new obsidian.Setting(this.containerEl) + .setName('Enable Blacklist') + .setDesc('Turn on this option to use Filter List to exclude files') + .addToggle((toggle) => toggle.setValue(this.plugin.settings.blacklist).onChange((value) => { + this.plugin.settings.blacklist = value; + this.plugin.reloadCount(); + this.plugin.saveSettings(); + })); + } + } +} + +class FileExplorerNoteCount extends obsidian.Plugin { + constructor() { + super(...arguments); + this.settings = DEFAULT_SETTINGS; + this.vaultHandler = new VaultHandler(this); + this.rootFolderEl = null; + this.explorerNavHeaderSelector = '.workspace-leaf-content[data-type="file-explorer"] .nav-header'; + this.rootFolderClassName = 'oz-explorer-root-folder'; + this.initialize = (revert = false) => { + let plugin = this; + // First Check if the root folder exists + let explorerHeaderEl = document.querySelector(`${this.explorerNavHeaderSelector} .${this.rootFolderClassName}`); + if (explorerHeaderEl) + this.rootFolderEl = explorerHeaderEl; + const getViewHandler = (revert) => (view) => { + this.fileExplorer = view; + setupCount(this, revert); + this.setupRootFolder(revert); + if (!revert) { + this.registerEvent(this.app.workspace.on('css-change', this.setupRootFolder)); + this.vaultHandler.registerVaultEvent(); + if (this.settings.showAllNumbers) + document.body.addClass('oz-show-all-num'); + } + else { + for (const el of document.getElementsByClassName(withSubfolderClass)) { + el.removeClass(withSubfolderClass); + } + document.body.removeClass(showAllNumbersClass); + } + if (!revert) { + // when file explorer is closed (workspace changed) + // try to update fehanlder with new file explorer instance + this.register(around(view, { + onClose: (next) => function () { + setTimeout(() => doWithFileExplorer(plugin, getViewHandler(false)), 1e3); + return next.apply(this); + }, + })); + } + }; + doWithFileExplorer(plugin, getViewHandler(revert)); + }; + this.setupRootFolder = (revert = false) => { + var _a, _b, _c; + if (!this.fileExplorer) { + console.error('file-explorer not found'); + return; + } + if (this.rootFolderEl && !this.settings.addRootFolder) { + this.rootFolderEl.remove(); + this.rootFolderEl = null; + } + // Check if root is provided by Obsidian (it shouldn't be in the new releases) + const root = (_c = (_b = (_a = this.fileExplorer) === null || _a === void 0 ? void 0 : _a.fileItems) === null || _b === void 0 ? void 0 : _b['/']) !== null && _c !== void 0 ? _c : null; + if (!root) { + // Get the Nav Header + let explorerHeaderEl = document.querySelector(this.explorerNavHeaderSelector); + if (!explorerHeaderEl) + return; + if (!this.rootFolderEl && this.settings.addRootFolder) { + this.rootFolderEl = explorerHeaderEl.createEl('div', { + cls: ['tree-item', 'nav-folder', this.rootFolderClassName], + }); + this.rootFolderEl.innerHTML = ` +
+ +
+ `; + } + } + }; + } + onload() { + return __awaiter(this, void 0, void 0, function* () { + console.log('loading FileExplorerNoteCount'); + this.addSettingTab(new FENoteCountSettingTab(this.app, this)); + yield this.loadSettings(); + this.app.workspace.onLayoutReady(this.initialize); + }); + } + onunload() { + console.log('unloading FileExplorerNoteCount'); + this.initialize(true); + } + loadSettings() { + return __awaiter(this, void 0, void 0, function* () { + this.settings = Object.assign(Object.assign({}, this.settings), (yield this.loadData())); + }); + } + saveSettings() { + return __awaiter(this, void 0, void 0, function* () { + yield this.saveData(this.settings); + }); + } + reloadCount() { + setupCount(this); + } + get fileFilter() { + let list = this.settings.filterList; + return (af) => { + if (af instanceof obsidian.TFile) { + const { extension: target } = af; + // if list is empty, filter nothing + if (list.length === 0) + return true; + else if (this.settings.blacklist) + return !list.includes(target); + else + return list.includes(target); + } + else + return false; + }; + } +} + +module.exports = FileExplorerNoteCount; + +/* nosourcemap */ \ No newline at end of file diff --git a/.obsidian/plugins/file-explorer-note-count/manifest.json b/.obsidian/plugins/file-explorer-note-count/manifest.json new file mode 100644 index 00000000..f13b359a --- /dev/null +++ b/.obsidian/plugins/file-explorer-note-count/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "file-explorer-note-count", + "name": "File Explorer Note Count", + "version": "1.2.3", + "minAppVersion": "1.2.0", + "description": "The plugin helps you to see the number of notes under each folder within the file explorer.", + "author": "Ozan Tellioglu", + "authorUrl": "https://www.ozan.pl", + "isDesktopOnly": false +} diff --git a/.obsidian/plugins/file-explorer-note-count/styles.css b/.obsidian/plugins/file-explorer-note-count/styles.css new file mode 100644 index 00000000..07a579f1 --- /dev/null +++ b/.obsidian/plugins/file-explorer-note-count/styles.css @@ -0,0 +1,34 @@ +.nav-folder-title[data-count]::after { + content: attr(data-count); + display: inline-block; + position: relative; + font-size: calc(100% * 0.8); + margin-right: 4px; + /* border-radius: 3px; */ + padding: 2px 0; + /* background-color: var(--background-secondary-alt); */ + transition: opacity 100ms ease-in-out; +} + +.oz-explorer-root-nav-folder-title { + display: flex; +} + +.oz-explorer-root-nav-folder-title[data-count]::after { + content: attr(data-count); + margin-right: 4px; + font-size: calc(100% * 0.8); + display: inline-block; +} + +body:not(.oz-show-all-num) .nav-folder:not(.is-collapsed) > .nav-folder-title.oz-with-subfolder[data-count]:not([data-path='/'])::after { + opacity: 0; +} + +.nav-folder-title-content { + flex-grow: 1; +} + +.oz-explorer-root-folder { + margin-top: 15px; +} diff --git a/.obsidian/plugins/obsidian-image-auto-upload-plugin/data.json b/.obsidian/plugins/obsidian-image-auto-upload-plugin/data.json index 0fe2b3f9..898432cc 100644 --- a/.obsidian/plugins/obsidian-image-auto-upload-plugin/data.json +++ b/.obsidian/plugins/obsidian-image-auto-upload-plugin/data.json @@ -522,6 +522,51 @@ "id": "f9f2be1c-e32c-4769-928b-c0323ba09c8e", "createdAt": 1752564654889, "updatedAt": 1752564654889 + }, + { + "isEncrypted": 1, + "EncryptedData": "3ec36d499393360ecde54768ccbb6792:e3ce75b759f99fe9056295375b4e4392fe0dd6f19d596aa2b3f3d4cca0baca5af3715e535fabe7826a3e60667ff995c816071f6b2ba92ce6b224190855bd79405c281d6d35618f9ac1170104eb9293d5dd5374116c6d81801b12f2d3003b1f00d1a06abe0639e993e62148f3feb4a96d15f5a8a2897c0d4c918e81e7bb9174a423232c4ff3393e8915aa95dad4647f2b44f27452049881cdbc9a96755cb541c42b9fe99d81c350809d0c0a39ef8b92f5ee15fca8a1dd1fc52033f1f67803a3c509ff59b819fb08293cbb33c175dde85058cf922b6e5fa26d0fec0068671b96a9ab7849856036adb76bef84af743c2a111badc78f90073e416f01575d1a3f720ed8fdc39ef2012b8e3449cca2edaf5958d6f7640d56cbdcedcfc2b6506b0e76b7ba157f749e825e9f76307e8b32489b49a6fc06b94829b88bc2d2a4565dd6e873b3815c53b80f51437d8424f5c538600188b73652ecd3866cf7a24dd58680944052fcea58a1cbbba9ade98c028f7bbe007ec215ed7e72a985c2f1f4f92aeae5916eb561ea990f0641ab6f8c7a53048d7c530f6d4f27d18eefa6309050f7de420a4fd12b2902931eba0b6477d2ffa5b2b02dccb6aa945bd0c5cf9c786a2ef0cc6c0a6da9d189abe3a2d697ea8813eeac6bfad73f6235f6b6099e0714a1f674c701c814bf3e2a926244d49fea46e0185c22bb7dcbff956cb8481632afb6a7992b22c934206e4708a6961e2314b954e3a54ae9d0749b4935d7bf4bac583808c6f302f7c80e2ce0c35fe0c56e4858a7c6edb173b580c9e6b6e7a4b152709af14693ee0b812c0483d2b33f2c5944998588ac188a76e5655cf0981a678008f5fbed5f7719c2db7ec362968ef4cc4c5f300d985b776c3671b67cdd54a51e03c3741807a8156dcf54c73f22955cbc443f209a5ac6", + "fileName": "image.png", + "width": 1120, + "height": 630, + "extname": ".png", + "imgUrl": "https://joyimg.cpolar.top/i/2025/07/16/687760805338c.png", + "hash": "21C34v", + "type": "lskyplist", + "shortUrl": "https://joyimg.cpolar.top/i/2025/07/16/687760805338c.png", + "id": "df0b4c93-8756-42bf-9e5b-e4321cde8e34", + "createdAt": 1752653953003, + "updatedAt": 1752653953003 + }, + { + "isEncrypted": 1, + "EncryptedData": "147ae87f11c9e002274c0b34476f6d9f:ae0deaadafb525f18e80e1c7261158ea36b7675c388ec65a1b877da20a2b885f5585f8ce8b0fd9a571f28d7a48f16428c21a5f3701351da1fc8d2888979796d9cfb7d8c117af83c223a07babe9f0a581f339fea00da07f7f5931859d43a2306e2dca3dbacc5449d266ecee08f441202ce50a41e5ab274b17fa2a9fb37d05fb9e652a73fb7efc9ac9e2bcaaf279cbaef6a5bc561119a2fddf8e52c25e006b3b432147b09c8151ac7dd857299aeec28fdf17479ddcb87a30e8ba125e6237ebdd5c35d5c2c72fff4125434480342b59786129fda39d719aebae0a069270d638a608119c5406c0ba804727fa195e98c890b727530b9905b139112cfdb2658485f9a12fad39b6c334fb14bd22f24fb553aefb884ea5b3426cb460706ade2ce9cd58666381b70726971ae26374a497f511d94fa1cff92a48c03ddae6abee30b1a37af6c45b617d0708af433126b3e784a6e2c3f4cd2ead2dd10e819564d2c9e8f0c47a50f033adc2f5b77e8bc44d5d85b8d9e858df9f8818044f535ac9864efce42c4f29fe28cafeb790a640e0e172e2da2537f7aba3adb2b365c8240bfe1565fe202c6efdd4533a58e2a2f0a20d94a88bec8048f6e22493356d9904baa4689ac779d3bafa065b5342b4ad2ea67fc9a2ebdd93924e89afed19d62f489974a4f0f7a3ad67cc9e4be66f1d6560f77e4933f6d6a3a50b507df46b46799be761af37981226b6df22ecfe69bd9043938e007e0dc8b81a5abba6e1e48af6e01153782187aa5cb611043b1ad6b492e7604c465d831349e7ca062c30049b25ca2bfd5dac80f2de315fc3d01c5a416a7e7ca12dc10b6304cd5b67b94d5ada3bbb1d589de099f1f527e879d3b9e9dfa9154d4f339ff33ce8222f56dc821c7781266cb649914a1520c522f3cd65cc2c2c5175bd810a3fa74c", + "fileName": "image.png", + "width": 1120, + "height": 630, + "extname": ".png", + "imgUrl": "https://joyimg.cpolar.top/i/2025/07/16/68776125c62a9.png", + "hash": "GeOZ5g", + "type": "lskyplist", + "shortUrl": "https://joyimg.cpolar.top/i/2025/07/16/68776125c62a9.png", + "id": "ba308be8-84f4-4191-9716-b13525b3747b", + "createdAt": 1752654118042, + "updatedAt": 1752654118042 + }, + { + "isEncrypted": 1, + "EncryptedData": "2779fc31da4419fe6c12b1632a814bf5:d3d26a8da370bf19b15f6ad3a4474f110e45e3ccedf5c6a9a54d104034f5823b5e3708617178374174e9faa43ea9cebc4e56da938fbfd39a6be034693205de82f1b15aeea8b189ed422c4a3036f4c7febf755c649dcc866d0771f10bcee7686e111d5d2e6497bf167cb86f7623ac90e5be23fbb33921313ec7a77bca6fb9ece181004be624a034cdd4e0a7c7665f6f95310d53f121bdf8912b6ddcea63601eaaa82ee313bdda41c81d28b8dc4fabb82668909688e8c863d7c65bbbaa8402817ae59fad00d219704b43fffdfc0f81abad8ef048e9f0c446d6092c78687c7b4ce0b4c959f204aa2d4d74b390c3be5990ba167b7f160024eda010b1e716b279128f0fd3be23e1cb6315dcfc41e155867ab449949ebfdd69616423304aee172a7c08b616ec8638a1099c5e490ab533f6fa53ecfe762bdb5f12e7d938f00965102edf3508855f7fac64b71dd25f8aaf89abd0acf3b1ecf63c093808c32bffd960bf9a159673f21cb07ceee9a51138dbd73f78a43a514102211455d2ecdce691b18535341c2a469346fa3e0a5dad030d220d3f484756f84c596f0cad3b2a6b604f5c40a49bac6e41c2043fbc9ff6a6bb5337fc5dce17233f52f0f4aff81ebad6cd8b833f2737d9b9c2333d7742eddc95f64e637e03c3ad24ceba001c0614ee28c7fd79bc84d43f67348ca704deb864bf904611755ad2fb9c2f7ecf7ff59ebaed6a75e1c56fa49795a37c4614b295d50b0890acc10643f36ee58206948241d8899680bd654fd9bd7a7751e63886a6ae1606ea6a80c90c6cffb8a0943f392b43477f29b50120131de856ac80d56ff80d933e2b553778153cea425f4e9dfec9defb948d83cd5c5afb52ba865c80d4ef8cfc054e97566602fdaabcc4c6828419a22b8adee2b5a367ac211ad71fc3a92ca72bdb78f0", + "fileName": "image.png", + "width": 1120, + "height": 630, + "extname": ".png", + "imgUrl": "https://joyimg.cpolar.top/i/2025/07/16/68776157496e8.png", + "hash": "FQLSU0", + "type": "lskyplist", + "shortUrl": "https://joyimg.cpolar.top/i/2025/07/16/68776157496e8.png", + "id": "afab77dd-b8ff-4476-abca-54551cfc0e24", + "createdAt": 1752654167605, + "updatedAt": 1752654167605 } ] } \ No newline at end of file diff --git a/.obsidian/plugins/obsidian-image-toolkit/main.js b/.obsidian/plugins/obsidian-image-toolkit/main.js new file mode 100644 index 00000000..0ed5ae52 --- /dev/null +++ b/.obsidian/plugins/obsidian-image-toolkit/main.js @@ -0,0 +1,3425 @@ +'use strict'; + +var obsidian = require('obsidian'); +var crypto = require('crypto'); + +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}; + +// العربية +var ar = {}; + +// čeština +var cz = {}; + +// Dansk +var da = {}; + +// Deutsch +var de = {}; + +// English +var en = { + // settings + IMAGE_TOOLKIT_SETTINGS_TITLE: 'Image Toolkit Settings', + // >>>Common Settings: + COMMON_SETTINGS: 'Common Settings:', + VIEW_MODE_NAME: 'Choose a mode to view images', + VIEW_MODE_NORMAL: '🖼 Normal', + VIEW_MODE_PIN: '📌 Pin', + // >>>View Trigger Settings: + VIEW_TRIGGER_SETTINGS: 'View Trigger Settings:', + VIEW_IMAGE_GLOBAL_NAME: 'Click and view an image globally', + VIEW_IMAGE_GLOBAL_DESC: 'You can zoom, rotate, drag, and invert it on the popup layer when clicking an image.', + VIEW_IMAGE_IN_EDITOR_NAME: 'Click and view an image in the Editor Area', + VIEW_IMAGE_IN_EDITOR_DESC: 'Turn on this option if you want to click and view an image in the Editor Area.', + // CPB = COMMUNITY_PLUGINS_BROWSER + VIEW_IMAGE_IN_CPB_NAME: 'Click and view an image in the Community Plugins browser', + VIEW_IMAGE_IN_CPB_DESC: 'Turn on this option if you want to click and view an image in the Community Plugins browser.', + VIEW_IMAGE_WITH_A_LINK_NAME: 'Click and view an image with a link', + VIEW_IMAGE_WITH_A_LINK_DESC: 'Turn on this option if you want to click and view an image with a link. (NOTE: The browser will be opened for you to visit the link and the image will be popped up for being viewed at the same time when you click the image.)', + VIEW_IMAGE_OTHER_NAME: 'Click and view in the other areas except the above', + VIEW_IMAGE_OTHER_DESC: 'Except for the above mentioned, it also supports other areas, like some modal user interface components.', + // >>> PIN_MODE_SETTINGS + PIN_MODE_SETTINGS: "Pin Mode Settings:", + PIN_MODE_NAME: "📌 Pin an image", + PIN_MODE_DESC: "You can pin an image onto the top of the screen. And have more options by right click. (press Esc to close the image where your mouse cursor is hovering)", + PIN_MAXIMUM_NAME: "The maximum images you can pin", + PIN_COVER_NAME: "Cover mode", + PIN_COVER_DESC: "After those pinned images reach maximum, you can cover the earliest pinned image when you click an image once again.", + PIN_MAXIMUM_NOTICE: "Exceeded maximum images you can pin (non cover mode)", + // >>>View Detail Settings: + VIEW_DETAILS_SETTINGS: 'View Detail Settings:', + IMAGE_MOVE_SPEED_NAME: 'Set the moving speed of the image', + IMAGE_MOVE_SPEED_DESC: 'When you move an image on the popup layer by keyboard (up, down, left, right), the moving speed of the image can be set here.', + IMAGE_TIP_TOGGLE_NAME: "Display the image's zoom number", + IMAGE_TIP_TOGGLE_DESC: "Turn on this option if you want to display the zoom number when you zoom the image.", + IMG_FULL_SCREEN_MODE_NAME: 'Full-screen preview mode', + // preview mode options: + FIT: 'Fit', + FILL: 'Fill', + STRETCH: 'Stretch', + IMG_VIEW_BACKGROUND_COLOR_NAME: "Set the background color of the previewed image (Only support the image with transparent background)", + // >>>Image Border Settings: + IMAGE_BORDER_SETTINGS: 'Image Border Settings:', + IMAGE_BORDER_TOGGLE_NAME: "Display the image's border", + IMAGE_BORDER_TOGGLE_DESC: "The clicked image's border can be displayed after you exit previewing and close the popup layer.", + IMAGE_BORDER_WIDTH_NAME: "Set the image's border width", + IMAGE_BORDER_STYLE_NAME: "Set the image's border style", + IMAGE_BORDER_COLOR_NAME: "Set the image's border color", + // IMG_BORDER_WIDTH options: + THIN: 'thin', + MEDIUM: 'medium', + THICK: 'thick', + // IMG_BORDER_STYLE options: + //HIDDEN: 'hidden', + DOTTED: 'dotted', + DASHED: 'dashed', + SOLID: 'solid', + DOUBLE: 'double', + GROOVE: 'groove', + RIDGE: 'ridge', + INSET: 'inset', + OUTSET: 'outset', + // IMAGE_BORDER_COLOR_NAME options: + BLACK: 'black', + BLUE: 'blue', + DARK_GREEN: 'dark green', + GREEN: 'green', + LIME: 'lime', + STEEL_BLUE: 'steel blue', + INDIGO: 'indigo', + PURPLE: 'purple', + GRAY: 'gray', + DARK_RED: 'dark red', + LIGHT_GREEN: 'light green', + BROWN: 'brown', + LIGHT_BLUE: 'light blue', + SILVER: 'silver', + RED: 'red', + PINK: 'pink', + ORANGE: 'orange', + GOLD: 'gold', + YELLOW: 'yellow', + // >>>Gallery Navbar Settings: + GALLERY_NAVBAR_SETTINGS: 'Gallery Navbar Settings (Experimental):', + GALLERY_NAVBAR_TOGGLE_NAME: "Display gallery navbar", + GALLERY_NAVBAR_TOGGLE_DESC: "All of the images in the current pane view can be displayed at the bottom of the popup layer.", + GALLERY_NAVBAR_DEFAULT_COLOR_NAME: "Set the background color of the gallery navbar (default state)", + GALLERY_NAVBAR_HOVER_COLOR_NAME: "Set the background color of the gallery navbar (hovering state)", + GALLERY_IMG_BORDER_TOGGLE_NAME: "Display the selected image on the gallery navbar", + GALLERY_IMG_BORDER_TOGGLE_DESC: "When you select an image, the image's border will be displayed, so you can know which image is currently active.", + GALLERY_IMG_BORDER_ACTIVE_COLOR_NAME: 'Set the border color of the selected image', + // >>>HOTKEYS_SETTINGS: + HOTKEY_SETTINGS: "Hotkey Settings:", + HOTKEY_SETTINGS_DESC: "📢 You cannot set the same hotkey for 'Move the image' and 'Switch the image' at the same time. (NOT SUPPORT in Pin Mode)", + MOVE_THE_IMAGE_NAME: "Set the hotkey for moving the image", + MOVE_THE_IMAGE_DESC: "You can move the image on the popup layer by hotkey.", + SWITCH_THE_IMAGE_NAME: "Set the hotkey for switching the image", + SWITCH_THE_IMAGE_DESC: "You can switch to the previous/next image on the gallery navbar by hotkey. (NOTE: You need to turn on 'Display gallery navbar' first, if you wanna use this hotkey.)", + DOUBLE_CLICK_TOOLBAR_NAME: "Double click", + VIEW_TRIGGER_HOTKEY_NAME: "Set the hotkey for triggering viewing an image", + VIEW_TRIGGER_HOTKEY_DESC: "When you set 'None', you can directly click and preview an image without holding any modifier keys; otherwise, you must hold the configured modifier keys to click and preview an image.", + // MODIFIER_HOTKEYS + NONE: "None", + CTRL: "Ctrl", + ALT: "Alt", + SHIFT: "Shift", + CTRL_ALT: "Ctrl+Alt", + CTRL_SHIFT: "Ctrl+Shift", + SHIFT_ALT: "Shift+Alt", + CTRL_SHIFT_ALT: "Ctrl+Shift+Alt", + // toolbar icon title + ZOOM_TO_100: "zoom to 100%", + ZOOM_IN: "zoom in", + ZOOM_OUT: "zoom out", + FULL_SCREEN: 'full screen', + REFRESH: "refresh", + ROTATE_LEFT: "rotate left", + ROTATE_RIGHT: "rotate right", + SCALE_X: 'flip along x-axis', + SCALE_Y: 'flip along y-axis', + INVERT_COLOR: 'invert color', + COPY: 'copy', + CLOSE: 'close', + // tip: + COPY_IMAGE_SUCCESS: 'Copy the image successfully!', + COPY_IMAGE_ERROR: 'Fail to copy the image!' +}; + +// British English +var enGB = {}; + +// Español +var es = {}; + +// français +var fr = {}; + +// हिन्दी +var hi = {}; + +// Bahasa Indonesia +var id = {}; + +// Italiano +var it = {}; + +// 日本語 +var ja = {}; + +// 한국어 +var ko = {}; + +// Nederlands +var nl = {}; + +// Norsk +var no = {}; + +// język polski +var pl = {}; + +// Português +var pt = {}; + +// Português do Brasil +// Brazilian Portuguese +var ptBR = {}; + +// Română +var ro = {}; + +// русский +var ru = {}; + +// Türkçe +var tr = {}; + +// 简体中文 +var zhCN = { + // settings + IMAGE_TOOLKIT_SETTINGS_TITLE: "Image Toolkit 设置", + // >>>Common Settings: + COMMON_SETTINGS: '通用设置:', + VIEW_MODE_NAME: '选择查看模式', + VIEW_MODE_NORMAL: '🖼 普通', + VIEW_MODE_PIN: '📌 贴图', + // >>> 预览触发配置: + VIEW_TRIGGER_SETTINGS: '预览触发配置:', + VIEW_IMAGE_GLOBAL_NAME: '支持全局预览图片', + VIEW_IMAGE_GLOBAL_DESC: '开启后,在任何地方点击图片都可以弹出预览界面,可对图片进行缩放、旋转、拖动、和反色等。', + VIEW_IMAGE_IN_EDITOR_NAME: '支持在编辑区域预览图片', + VIEW_IMAGE_IN_EDITOR_DESC: '开启后,支持在编辑区域,点击图片预览。', + // CPB = COMMUNITY_PLUGINS_BROWSER + VIEW_IMAGE_IN_CPB_NAME: '支持在社区插件页面预览图片', + VIEW_IMAGE_IN_CPB_DESC: '开启后,支持在社区插件页面,点击图片预览。', + VIEW_IMAGE_WITH_A_LINK_NAME: '支持预览带链接的图片', + VIEW_IMAGE_WITH_A_LINK_DESC: '开启后,支持点击带链接的图片(注意:点击该图片,会同时打开浏览器访问指定地址和弹出预览图片)', + VIEW_IMAGE_OTHER_NAME: '支持除上述其他地方来预览图片', + VIEW_IMAGE_OTHER_DESC: '除上述支持范围外,还支持一些其他区域,如Modal用户界面组件。', + // >>> PIN_MODE_SETTINGS + PIN_MODE_SETTINGS: "贴图模式设置:", + PIN_MODE_NAME: "📌 将所点击的图片贴到屏幕上", + PIN_MODE_DESC: "你可以将当前所点击的图片贴到屏幕上,并且可以通过右击图片选择更多操作(按 Esc 关闭已贴图片的展示)", + PIN_MAXIMUM_NAME: "最大贴图数量", + PIN_COVER_NAME: "覆盖模式", + PIN_COVER_DESC: "当贴图数量达到最大值后,此时再次点击图片,该图片会覆盖最早弹出的那个贴图。", + PIN_MAXIMUM_NOTICE: "超过最大Pin图设置(非覆盖模式)", + // >>>查看细节设置: + VIEW_DETAILS_SETTINGS: '查看细节设置:', + IMAGE_MOVE_SPEED_NAME: '图片移动速度设置', + IMAGE_MOVE_SPEED_DESC: '当使用键盘(上、下、左、右)移动图片时,可对图片移动速度进行设置。', + IMAGE_TIP_TOGGLE_NAME: "展示缩放比例提示", + IMAGE_TIP_TOGGLE_DESC: "开启后,当你缩放图片时会展示当前缩放的比例。", + IMG_FULL_SCREEN_MODE_NAME: '全屏预览模式', + // 全屏预览模式 下拉: + FIT: '自适应', + FILL: '填充', + STRETCH: '拉伸', + IMG_VIEW_BACKGROUND_COLOR_NAME: "设置预览图片的背景色(仅对透明背景的图片生效)", + // >>>图片边框设置: + IMAGE_BORDER_SETTINGS: '图片边框设置:', + IMAGE_BORDER_TOGGLE_NAME: "展示被点击图片的边框", + IMAGE_BORDER_TOGGLE_DESC: "当离开图片预览和关闭弹出层后,突出展示被点击图片的边框。", + IMAGE_BORDER_WIDTH_NAME: "设置图片边框宽度", + IMAGE_BORDER_STYLE_NAME: "设置图片边框样式", + IMAGE_BORDER_COLOR_NAME: "设置图片边框颜色", + // IMG_BORDER_WIDTH 下拉: + THIN: '较细', + MEDIUM: '正常', + THICK: '较粗', + // IMG_BORDER_STYLE 下拉: + //HIDDEN: '隐藏', + DOTTED: '点状', + DASHED: '虚线', + SOLID: '实线', + DOUBLE: '双线', + GROOVE: '凹槽', + RIDGE: ' 垄状', + INSET: '凹边', + OUTSET: '凸边', + // IMAGE_BORDER_COLOR_NAME 下拉: + BLACK: '黑色', + BLUE: '蓝色', + DARK_GREEN: '深绿色', + GREEN: '绿色', + LIME: '淡黄绿色', + STEEL_BLUE: '钢青色', + INDIGO: '靛蓝色', + PURPLE: '紫色', + GRAY: '灰色', + DARK_RED: '深红色', + LIGHT_GREEN: '浅绿色', + BROWN: '棕色', + LIGHT_BLUE: '浅蓝色', + SILVER: '银色', + RED: '红色', + PINK: '粉红色', + ORANGE: '橘黄色', + GOLD: '金色', + YELLOW: '黄色', + // >>>Gallery Navbar Settings: + GALLERY_NAVBAR_SETTINGS: '图片导航设置 (体验版):', + GALLERY_NAVBAR_TOGGLE_NAME: "展示图片导航", + GALLERY_NAVBAR_TOGGLE_DESC: "当前文档的所有图片会展示在弹出层的底部,可随意切换展示不同图片。", + GALLERY_NAVBAR_DEFAULT_COLOR_NAME: "设置图片导航底栏背景色(默认展示)", + GALLERY_NAVBAR_HOVER_COLOR_NAME: "设置图片导航底栏背景色(鼠标悬浮时)", + GALLERY_IMG_BORDER_TOGGLE_NAME: "展示图片导航上被选中的图片", + GALLERY_IMG_BORDER_TOGGLE_DESC: "当你选中正查看某一图片,对应图片导航底栏上将突出显示该缩略图片的边框。", + GALLERY_IMG_BORDER_ACTIVE_COLOR_NAME: '设置被选中图片的边框色', + // >>>HOTKEYS_SETTINGS: + HOTKEY_SETTINGS: "快捷键设置:", + HOTKEY_SETTINGS_DESC: "📢 你无法为'移动图片'和'切换图片'设置相同的快捷键。(不支持贴图模式)", + MOVE_THE_IMAGE_NAME: "为移动图片设置快捷键", + MOVE_THE_IMAGE_DESC: "你可以利用快捷键来移动弹出层上的图片。", + SWITCH_THE_IMAGE_NAME: "为切换图片设置快捷键", + SWITCH_THE_IMAGE_DESC: "你可以利用快捷键来切换在图片导航栏上的图片至上一张/下一张。(注意: 仅当开启“展示图片导航”后,才能使用该快捷键来控制切换图片。)", + DOUBLE_CLICK_TOOLBAR_NAME: "双击", + VIEW_TRIGGER_HOTKEY_NAME: "为触发弹出查看图片设置快捷键", + VIEW_TRIGGER_HOTKEY_DESC: "当你设置为“无”,你可以直接点击预览图片;否则,须按住已配置的修改键(Ctrl、Alt、Shift)才能点击查看某个图片。", + // MODIFIER_HOTKEYS + NONE: "无", + // toolbar icon title + ZOOM_TO_100: "缩放至100%", + ZOOM_IN: "放大", + ZOOM_OUT: "缩小", + FULL_SCREEN: "全屏", + REFRESH: "刷新", + ROTATE_LEFT: "左旋", + ROTATE_RIGHT: "右旋", + SCALE_X: 'x轴翻转', + SCALE_Y: 'y轴翻转', + INVERT_COLOR: '反色', + COPY: '复制', + CLOSE: '关闭', + // tip: + COPY_IMAGE_SUCCESS: '拷贝图片成功!', + COPY_IMAGE_ERROR: '拷贝图片失败!' +}; + +// 繁體中文 +var zhTW = { + // settings + IMAGE_TOOLKIT_SETTINGS_TITLE: "image toolkit 設定", + // toolbar icon title + ZOOM_IN: "放大", + ZOOM_OUT: "縮小", + FULL_SCREEN: '全螢幕', + REFRESH: "重整", + ROTATE_LEFT: "向左旋轉", + ROTATE_RIGHT: "向右旋轉", + SCALE_X: 'x 軸縮放', + SCALE_Y: 'y 軸縮放', + INVERT_COLOR: '色彩反轉', + COPY: '複製', + COPY_IMAGE_SUCCESS: '成功複製圖片!' +}; + +const localeMap = { + ar, + cs: cz, + da, + de, + en, + "en-gb": enGB, + es, + fr, + hi, + id, + it, + ja, + ko, + nl, + nn: no, + pl, + pt, + "pt-br": ptBR, + ro, + ru, + tr, + "zh-cn": zhCN, + "zh-tw": zhTW, +}; +const locale = localeMap[obsidian.moment.locale()]; +function t(str) { + if (!locale) { + console.error("[oit] Image toolkit locale not found", obsidian.moment.locale()); + } + return (locale && locale[str]) || en[str]; +} + +var ViewMode; +(function (ViewMode) { + ViewMode["Normal"] = "Normal"; + ViewMode["Pin"] = "Pin"; +})(ViewMode || (ViewMode = {})); +const DEFAULT_VIEW_MODE = ViewMode.Normal; +const OIT_CLASS = { + CONTAINER_ROOT: 'oit', + CONTAINER_NORMAL: 'oit-normal', + CONTAINER_PIN: 'oit-pin', + // the place for storing images + IMG_CONTAINER: 'oit-img-container', + IMG_VIEW: 'oit-img-view', + IMG_TTP: 'oit-img-tip', + IMG_FOOTER: 'oit-img-footer', + IMG_TITLE: 'oit-img-title', + IMG_TITLE_NAME: 'oit-img-title-name', + IMG_TITLE_INDEX: 'oit-img-title-index', + IMG_TOOLBAR: 'oit-img-toolbar', + IMG_PLAYER: 'img-player', + IMG_FULLSCREEN: 'img-fullscreen', +}; +const ZOOM_FACTOR = 0.8; +const IMG_VIEW_MIN = 30; +const ICONS = [{ + id: 'zoom-to-100', + svg: ` 1:1 ` + }]; +const SEPARATOR_SYMBOL = "---"; +const TOOLBAR_CONF = [{ + title: "ZOOM_TO_100", + class: 'toolbar_zoom_to_100', + icon: 'zoom-to-100', + enableToolbarIcon: true, + enableMenu: true, + enableHotKey: true + }, { + title: "ZOOM_IN", + class: 'toolbar_zoom_in', + icon: 'zoom-in', + enableToolbarIcon: true, + enableMenu: false, + enableHotKey: true + }, { + title: "ZOOM_OUT", + class: 'toolbar_zoom_out', + icon: 'zoom-out', + enableToolbarIcon: true, + enableMenu: false, + enableHotKey: true + }, { + title: "FULL_SCREEN", + class: 'toolbar_full_screen', + icon: 'expand', + enableToolbarIcon: true, + enableMenu: true, + enableHotKey: true + }, { + title: "REFRESH", + class: 'toolbar_refresh', + icon: 'refresh-ccw', + enableToolbarIcon: true, + enableMenu: true, + enableHotKey: true + }, { + title: "ROTATE_LEFT", + class: 'toolbar_rotate_left', + icon: 'rotate-ccw', + enableToolbarIcon: true, + enableMenu: true, + enableHotKey: true + }, { + title: "ROTATE_RIGHT", + class: 'toolbar_rotate_right', + icon: 'rotate-cw', + enableToolbarIcon: true, + enableMenu: true, + enableHotKey: true + }, { + title: "SCALE_X", + class: 'toolbar_scale_x', + icon: 'move-horizontal', + enableToolbarIcon: true, + enableMenu: true, + enableHotKey: true + }, { + title: "SCALE_Y", + class: 'toolbar_scale_y', + icon: 'move-vertical', + enableToolbarIcon: true, + enableMenu: true, + enableHotKey: true + }, { + title: "INVERT_COLOR", + class: 'toolbar_invert_color', + icon: 'droplet', + enableToolbarIcon: true, + enableMenu: true, + enableHotKey: true + }, { + title: "COPY", + class: 'toolbar_copy', + icon: 'copy', + enableToolbarIcon: true, + enableMenu: true, + enableHotKey: true + }, { + title: SEPARATOR_SYMBOL, + enableToolbarIcon: false, + enableMenu: true, + enableHotKey: false + }, { + title: "CLOSE", + class: 'toolbar_close', + icon: 'trash', + enableToolbarIcon: false, + enableMenu: true, + enableHotKey: true + }]; +const IMG_FULL_SCREEN_MODE = { + FIT: 'FIT', + FILL: 'FILL', + STRETCH: 'STRETCH' +}; +const VIEW_IMG_SELECTOR = { + EDITOR_AREAS: `.workspace-leaf-content[data-type='markdown'] img,.workspace-leaf-content[data-type='image'] img`, + EDITOR_AREAS_NO_LINK: `.workspace-leaf-content[data-type='markdown'] img:not(a img),.workspace-leaf-content[data-type='image'] img:not(a img)`, + CPB: `.community-modal-details img`, + CPB_NO_LINK: `.community-modal-details img:not(a img)`, + OTHER: `.modal-content img`, + OTHER_NO_LINK: `.modal-content img:not(a img)`, +}; +const IMG_BORDER_WIDTH = { + THIN: 'thin', + MEDIUM: 'medium', + THICK: 'thick' +}; +const IMG_BORDER_STYLE = { + // HIDDEN: 'hidden', + DOTTED: 'dotted', + DASHED: 'dashed', + SOLID: 'solid', + DOUBLE: 'double', + GROOVE: 'groove', + RIDGE: 'ridge', + INSET: 'inset', + OUTSET: 'outset' +}; +// https://www.runoob.com/cssref/css-colorsfull.html +const IMG_BORDER_COLOR = { + BLACK: 'black', + BLUE: 'blue', + DARK_GREEN: 'darkgreen', + GREEN: 'green', + LIME: 'lime', + STEEL_BLUE: 'steelblue', + INDIGO: 'indigo', + PURPLE: 'purple', + GRAY: 'gray', + DARK_RED: 'darkred', + LIGHT_GREEN: 'lightgreen', + BROWN: 'brown', + LIGHT_BLUE: 'lightblue', + SILVER: 'silver', + RED: 'red', + PINK: 'pink', + ORANGE: 'orange', + GOLD: 'gold', + YELLOW: 'yellow' +}; +const GALLERY_NAVBAR_DEFAULT_COLOR = '#0000001A'; // rgba(0, 0, 0, 0.1) +const GALLERY_NAVBAR_HOVER_COLOR = '#0000004D'; // rgba(0, 0, 0, 0.3) +const GALLERY_IMG_BORDER_ACTIVE_COLOR = '#FF0000'; // red +const MODIFIER_HOTKEYS = { + NONE: "NONE", + CTRL: "CTRL", + ALT: "ALT", + SHIFT: "SHIFT", + CTRL_ALT: "CTRL_ALT", + CTRL_SHIFT: "CTRL_SHIFT", + SHIFT_ALT: "SHIFT_ALT", + CTRL_SHIFT_ALT: "CTRL_SHIFT_ALT" +}; +const MOVE_THE_IMAGE = { + CODE: "MOVE_THE_IMAGE", + DEFAULT_HOTKEY: MODIFIER_HOTKEYS.NONE, + SVG: `` +}; +const SWITCH_THE_IMAGE = { + CODE: "SWITCH_THE_IMAGE", + DEFAULT_HOTKEY: MODIFIER_HOTKEYS.CTRL, + SVG: `` +}; +const IMG_DEFAULT_BACKGROUND_COLOR = '#00000000'; + +function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +function createCommonjsModule(fn) { + var module = { exports: {} }; + return fn(module, module.exports), module.exports; +} + +/*! Pickr 1.9.1 MIT | https://github.com/Simonwep/pickr */ + +var pickr_min = createCommonjsModule(function (module, exports) { +!function(t,e){module.exports=e();}(self,(()=>(()=>{var t={d:(e,o)=>{for(var n in o)t.o(o,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:o[n]});},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0});}},e={};t.d(e,{default:()=>E});var o={};function n(t,e,o,n,i={}){e instanceof HTMLCollection||e instanceof NodeList?e=Array.from(e):Array.isArray(e)||(e=[e]),Array.isArray(o)||(o=[o]);for(const s of e)for(const e of o)s[t](e,n,{capture:!1,...i});return Array.prototype.slice.call(arguments,1)}t.r(o),t.d(o,{adjustableInputNumbers:()=>p,createElementFromString:()=>r,createFromTemplate:()=>a,eventPath:()=>l,off:()=>s,on:()=>i,resolveElement:()=>c});const i=n.bind(null,"addEventListener"),s=n.bind(null,"removeEventListener");function r(t){const e=document.createElement("div");return e.innerHTML=t.trim(),e.firstElementChild}function a(t){const e=(t,e)=>{const o=t.getAttribute(e);return t.removeAttribute(e),o},o=(t,n={})=>{const i=e(t,":obj"),s=e(t,":ref"),r=i?n[i]={}:n;s&&(n[s]=t);for(const n of Array.from(t.children)){const t=e(n,":arr"),i=o(n,t?{}:r);t&&(r[t]||(r[t]=[])).push(Object.keys(i).length?i:n);}return n};return o(r(t))}function l(t){let e=t.path||t.composedPath&&t.composedPath();if(e)return e;let o=t.target.parentElement;for(e=[t.target,o];o=o.parentElement;)e.push(o);return e.push(document,window),e}function c(t){return t instanceof Element?t:"string"==typeof t?t.split(/>>/g).reduce(((t,e,o,n)=>(t=t.querySelector(e),ot)){function o(o){const n=[.001,.01,.1][Number(o.shiftKey||2*o.ctrlKey)]*(o.deltaY<0?1:-1);let i=0,s=t.selectionStart;t.value=t.value.replace(/[\d.]+/g,((t,o)=>o<=s&&o+t.length>=s?(s=o,e(Number(t),n,i)):(i++,t))),t.focus(),t.setSelectionRange(s,s),o.preventDefault(),t.dispatchEvent(new Event("input"));}i(t,"focus",(()=>i(window,"wheel",o,{passive:!1}))),i(t,"blur",(()=>s(window,"wheel",o)));}const{min:u,max:h,floor:d,round:m}=Math;function f(t,e,o){e/=100,o/=100;const n=d(t=t/360*6),i=t-n,s=o*(1-e),r=o*(1-i*e),a=o*(1-(1-i)*e),l=n%6;return [255*[o,r,s,s,a,o][l],255*[a,o,o,r,s,s][l],255*[s,s,a,o,o,r][l]]}function v(t,e,o){const n=(2-(e/=100))*(o/=100)/2;return 0!==n&&(e=1===n?0:n<.5?e*o/(2*n):e*o/(2-2*n)),[t,100*e,100*n]}function b(t,e,o){const n=u(t/=255,e/=255,o/=255),i=h(t,e,o),s=i-n;let r,a;if(0===s)r=a=0;else {a=s/i;const n=((i-t)/6+s/2)/s,l=((i-e)/6+s/2)/s,c=((i-o)/6+s/2)/s;t===i?r=c-l:e===i?r=1/3+n-c:o===i&&(r=2/3+l-n),r<0?r+=1:r>1&&(r-=1);}return [360*r,100*a,100*i]}function y(t,e,o,n){e/=100,o/=100;return [...b(255*(1-u(1,(t/=100)*(1-(n/=100))+n)),255*(1-u(1,e*(1-n)+n)),255*(1-u(1,o*(1-n)+n)))]}function g(t,e,o){e/=100;const n=2*(e*=(o/=100)<.5?o:1-o)/(o+e)*100,i=100*(o+e);return [t,isNaN(n)?0:n,i]}function _(t){return b(...t.match(/.{2}/g).map((t=>parseInt(t,16))))}function w(t){t=t.match(/^[a-zA-Z]+$/)?function(t){if("black"===t.toLowerCase())return "#000";const e=document.createElement("canvas").getContext("2d");return e.fillStyle=t,"#000"===e.fillStyle?null:e.fillStyle}(t):t;const e={cmyk:/^cmyk\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)/i,rgba:/^rgba?\D+([\d.]+)(%?)\D+([\d.]+)(%?)\D+([\d.]+)(%?)\D*?(([\d.]+)(%?)|$)/i,hsla:/^hsla?\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)\D*?(([\d.]+)(%?)|$)/i,hsva:/^hsva?\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)\D*?(([\d.]+)(%?)|$)/i,hexa:/^#?(([\dA-Fa-f]{3,4})|([\dA-Fa-f]{6})|([\dA-Fa-f]{8}))$/i},o=t=>t.map((t=>/^(|\d+)\.\d+|\d+$/.test(t)?Number(t):void 0));let n;t:for(const i in e)if(n=e[i].exec(t))switch(i){case"cmyk":{const[,t,e,s,r]=o(n);if(t>100||e>100||s>100||r>100)break t;return {values:y(t,e,s,r),type:i}}case"rgba":{let[,t,,e,,s,,,r]=o(n);if(t="%"===n[2]?t/100*255:t,e="%"===n[4]?e/100*255:e,s="%"===n[6]?s/100*255:s,r="%"===n[9]?r/100:r,t>255||e>255||s>255||r<0||r>1)break t;return {values:[...b(t,e,s),r],a:r,type:i}}case"hexa":{let[,t]=n;4!==t.length&&3!==t.length||(t=t.split("").map((t=>t+t)).join(""));const e=t.substring(0,6);let o=t.substring(6);return o=o?parseInt(o,16)/255:void 0,{values:[..._(e),o],a:o,type:i}}case"hsla":{let[,t,e,s,,r]=o(n);if(r="%"===n[6]?r/100:r,t>360||e>100||s>100||r<0||r>1)break t;return {values:[...g(t,e,s),r],a:r,type:i}}case"hsva":{let[,t,e,s,,r]=o(n);if(r="%"===n[6]?r/100:r,t>360||e>100||s>100||r<0||r>1)break t;return {values:[t,e,s,r],a:r,type:i}}}return {values:null,type:null}}function A(t=0,e=0,o=0,n=1){const i=(t,e)=>(o=-1)=>e(~o?t.map((t=>Number(t.toFixed(o)))):t),s={h:t,s:e,v:o,a:n,toHSVA(){const t=[s.h,s.s,s.v,s.a];return t.toString=i(t,(t=>`hsva(${t[0]}, ${t[1]}%, ${t[2]}%, ${s.a})`)),t},toHSLA(){const t=[...v(s.h,s.s,s.v),s.a];return t.toString=i(t,(t=>`hsla(${t[0]}, ${t[1]}%, ${t[2]}%, ${s.a})`)),t},toRGBA(){const t=[...f(s.h,s.s,s.v),s.a];return t.toString=i(t,(t=>`rgba(${t[0]}, ${t[1]}, ${t[2]}, ${s.a})`)),t},toCMYK(){const t=function(t,e,o){const n=f(t,e,o),i=n[0]/255,s=n[1]/255,r=n[2]/255,a=u(1-i,1-s,1-r);return [100*(1===a?0:(1-i-a)/(1-a)),100*(1===a?0:(1-s-a)/(1-a)),100*(1===a?0:(1-r-a)/(1-a)),100*a]}(s.h,s.s,s.v);return t.toString=i(t,(t=>`cmyk(${t[0]}%, ${t[1]}%, ${t[2]}%, ${t[3]}%)`)),t},toHEXA(){const t=function(t,e,o){return f(t,e,o).map((t=>m(t).toString(16).padStart(2,"0")))}(s.h,s.s,s.v),e=s.a>=1?"":Number((255*s.a).toFixed(0)).toString(16).toUpperCase().padStart(2,"0");return e&&t.push(e),t.toString=()=>`#${t.join("").toUpperCase()}`,t},clone:()=>A(s.h,s.s,s.v,s.a)};return s}const $=t=>Math.max(Math.min(t,1),0);function C(t){const e={options:Object.assign({lock:null,onchange:()=>0,onstop:()=>0},t),_keyboard(t){const{options:o}=e,{type:n,key:i}=t;if(document.activeElement===o.wrapper){const{lock:o}=e.options,s="ArrowUp"===i,r="ArrowRight"===i,a="ArrowDown"===i,l="ArrowLeft"===i;if("keydown"===n&&(s||r||a||l)){let n=0,i=0;"v"===o?n=s||r?1:-1:"h"===o?n=s||r?-1:1:(i=s?-1:a?1:0,n=l?-1:r?1:0),e.update($(e.cache.x+.01*n),$(e.cache.y+.01*i)),t.preventDefault();}else i.startsWith("Arrow")&&(e.options.onstop(),t.preventDefault());}},_tapstart(t){i(document,["mouseup","touchend","touchcancel"],e._tapstop),i(document,["mousemove","touchmove"],e._tapmove),t.cancelable&&t.preventDefault(),e._tapmove(t);},_tapmove(t){const{options:o,cache:n}=e,{lock:i,element:s,wrapper:r}=o,a=r.getBoundingClientRect();let l=0,c=0;if(t){const e=t&&t.touches&&t.touches[0];l=t?(e||t).clientX:0,c=t?(e||t).clientY:0,la.left+a.width&&(l=a.left+a.width),ca.top+a.height&&(c=a.top+a.height),l-=a.left,c-=a.top;}else n&&(l=n.x*a.width,c=n.y*a.height);"h"!==i&&(s.style.left=`calc(${l/a.width*100}% - ${s.offsetWidth/2}px)`),"v"!==i&&(s.style.top=`calc(${c/a.height*100}% - ${s.offsetHeight/2}px)`),e.cache={x:l/a.width,y:c/a.height};const p=$(l/a.width),u=$(c/a.height);switch(i){case"v":return o.onchange(p);case"h":return o.onchange(u);default:return o.onchange(p,u)}},_tapstop(){e.options.onstop(),s(document,["mouseup","touchend","touchcancel"],e._tapstop),s(document,["mousemove","touchmove"],e._tapmove);},trigger(){e._tapmove();},update(t=0,o=0){const{left:n,top:i,width:s,height:r}=e.options.wrapper.getBoundingClientRect();"h"===e.options.lock&&(o=t),e._tapmove({clientX:n+s*t,clientY:i+r*o});},destroy(){const{options:t,_tapstart:o,_keyboard:n}=e;s(document,["keydown","keyup"],n),s([t.wrapper,t.element],"mousedown",o),s([t.wrapper,t.element],"touchstart",o,{passive:!1});}},{options:o,_tapstart:n,_keyboard:r}=e;return i([o.wrapper,o.element],"mousedown",n),i([o.wrapper,o.element],"touchstart",n,{passive:!1}),i(document,["keydown","keyup"],r),e}function k(t={}){t=Object.assign({onchange:()=>0,className:"",elements:[]},t);const e=i(t.elements,"click",(e=>{t.elements.forEach((o=>o.classList[e.target===o?"add":"remove"](t.className))),t.onchange(e),e.stopPropagation();}));return {destroy:()=>s(...e)}}const S={variantFlipOrder:{start:"sme",middle:"mse",end:"ems"},positionFlipOrder:{top:"tbrl",right:"rltb",bottom:"btrl",left:"lrbt"},position:"bottom",margin:8,padding:0},O=(t,e,o)=>{const n="object"!=typeof t||t instanceof HTMLElement?{reference:t,popper:e,...o}:t;return {update(t=n){const{reference:e,popper:o}=Object.assign(n,t);if(!o||!e)throw new Error("Popper- or reference-element missing.");return ((t,e,o)=>{const{container:n,arrow:i,margin:s,padding:r,position:a,variantFlipOrder:l,positionFlipOrder:c}={container:document.documentElement.getBoundingClientRect(),...S,...o},{left:p,top:u}=e.style;e.style.left="0",e.style.top="0";const h=t.getBoundingClientRect(),d=e.getBoundingClientRect(),m={t:h.top-d.height-s,b:h.bottom+s,r:h.right+s,l:h.left-d.width-s},f={vs:h.left,vm:h.left+h.width/2-d.width/2,ve:h.left+h.width-d.width,hs:h.top,hm:h.bottom-h.height/2-d.height/2,he:h.bottom-d.height},[v,b="middle"]=a.split("-"),y=c[v],g=l[b],{top:_,left:w,bottom:A,right:$}=n;for(const t of y){const o="t"===t||"b"===t;let n=m[t];const[s,a]=o?["top","left"]:["left","top"],[l,c]=o?[d.height,d.width]:[d.width,d.height],[p,u]=o?[A,$]:[$,A],[v,b]=o?[_,w]:[w,_];if(!(np))for(const p of g){let m=f[(o?"v":"h")+p];if(!(mu)){if(m-=d[a],n-=d[s],e.style[a]=`${m}px`,e.style[s]=`${n}px`,i){const e=o?h.width/2:h.height/2,r=c/2,u=e>r,d=m+{s:u?r:e,m:r,e:u?r:c-e}[p],f=n+{t:l,b:0,r:0,l}[t];i.style[a]=`${d}px`,i.style[s]=`${f}px`;}return t+p}}}return e.style.left=p,e.style.top=u,null})(e,o,n)}}};class E{static utils=o;static version="1.9.1";static I18N_DEFAULTS={"ui:dialog":"color picker dialog","btn:toggle":"toggle color picker dialog","btn:swatch":"color swatch","btn:last-color":"use previous color","btn:save":"Save","btn:cancel":"Cancel","btn:clear":"Clear","aria:btn:save":"save and close","aria:btn:cancel":"cancel and close","aria:btn:clear":"clear and close","aria:input":"color input field","aria:palette":"color selection area","aria:hue":"hue selection slider","aria:opacity":"selection slider"};static DEFAULT_OPTIONS={appClass:null,theme:"classic",useAsButton:!1,padding:8,disabled:!1,comparison:!0,closeOnScroll:!1,outputPrecision:0,lockOpacity:!1,autoReposition:!0,container:"body",components:{interaction:{}},i18n:{},swatches:null,inline:!1,sliders:null,default:"#42445a",defaultRepresentation:null,position:"bottom-middle",adjustableNumbers:!0,showAlways:!1,closeWithKey:"Escape"};_initializingActive=!0;_recalc=!0;_nanopop=null;_root=null;_color=A();_lastColor=A();_swatchColors=[];_setupAnimationFrame=null;_eventListener={init:[],save:[],hide:[],show:[],clear:[],change:[],changestop:[],cancel:[],swatchselect:[]};constructor(t){this.options=t=Object.assign({...E.DEFAULT_OPTIONS},t);const{swatches:e,components:o,theme:n,sliders:i,lockOpacity:s,padding:r}=t;["nano","monolith"].includes(n)&&!i&&(t.sliders="h"),o.interaction||(o.interaction={});const{preview:a,opacity:l,hue:c,palette:p}=o;o.opacity=!s&&l,o.palette=p||a||l||c,this._preBuild(),this._buildComponents(),this._bindEvents(),this._finalBuild(),e&&e.length&&e.forEach((t=>this.addSwatch(t)));const{button:u,app:h}=this._root;this._nanopop=O(u,h,{margin:r}),u.setAttribute("role","button"),u.setAttribute("aria-label",this._t("btn:toggle"));const d=this;this._setupAnimationFrame=requestAnimationFrame((function e(){if(!h.offsetWidth)return requestAnimationFrame(e);d.setColor(t.default),d._rePositioningPicker(),t.defaultRepresentation&&(d._representation=t.defaultRepresentation,d.setColorRepresentation(d._representation)),t.showAlways&&d.show(),d._initializingActive=!1,d._emit("init");}));}static create=t=>new E(t);_preBuild(){const{options:t}=this;for(const e of ["el","container"])t[e]=c(t[e]);this._root=(t=>{const{components:e,useAsButton:o,inline:n,appClass:i,theme:s,lockOpacity:r}=t.options,l=t=>t?"":'style="display:none" hidden',c=e=>t._t(e),p=a(`\n
\n\n ${o?"":''}\n\n
\n
\n
\n \n
\n
\n\n
\n
\n
\n
\n\n
\n
\n
\n
\n\n
\n
\n
\n
\n
\n\n
\n\n
\n \n\n \n \n \n \n \n\n \n \n \n
\n
\n
\n `),u=p.interaction;return u.options.find((t=>!t.hidden&&!t.classList.add("active"))),u.type=()=>u.options.find((t=>t.classList.contains("active"))),p})(this),t.useAsButton&&(this._root.button=t.el),t.container.appendChild(this._root.root);}_finalBuild(){const t=this.options,e=this._root;if(t.container.removeChild(e.root),t.inline){const o=t.el.parentElement;t.el.nextSibling?o.insertBefore(e.app,t.el.nextSibling):o.appendChild(e.app);}else t.container.appendChild(e.app);t.useAsButton?t.inline&&t.el.remove():t.el.parentNode.replaceChild(e.root,t.el),t.disabled&&this.disable(),t.comparison||(e.button.style.transition="none",t.useAsButton||(e.preview.lastColor.style.transition="none")),this.hide();}_buildComponents(){const t=this,e=this.options.components,o=(t.options.sliders||"v").repeat(2),[n,i]=o.match(/^[vh]+$/g)?o:[],s=()=>this._color||(this._color=this._lastColor.clone()),r={palette:C({element:t._root.palette.picker,wrapper:t._root.palette.palette,onstop:()=>t._emit("changestop","slider",t),onchange(o,n){if(!e.palette)return;const i=s(),{_root:r,options:a}=t,{lastColor:l,currentColor:c}=r.preview;t._recalc&&(i.s=100*o,i.v=100-100*n,i.v<0&&(i.v=0),t._updateOutput("slider"));const p=i.toRGBA().toString(0);this.element.style.background=p,this.wrapper.style.background=`\n linear-gradient(to top, rgba(0, 0, 0, ${i.a}), transparent),\n linear-gradient(to left, hsla(${i.h}, 100%, 50%, ${i.a}), rgba(255, 255, 255, ${i.a}))\n `,a.comparison?a.useAsButton||t._lastColor||l.style.setProperty("--pcr-color",p):(r.button.style.setProperty("--pcr-color",p),r.button.classList.remove("clear"));const u=i.toHEXA().toString();for(const{el:e,color:o}of t._swatchColors)e.classList[u===o.toHEXA().toString()?"add":"remove"]("pcr-active");c.style.setProperty("--pcr-color",p);}}),hue:C({lock:"v"===i?"h":"v",element:t._root.hue.picker,wrapper:t._root.hue.slider,onstop:()=>t._emit("changestop","slider",t),onchange(o){if(!e.hue||!e.palette)return;const n=s();t._recalc&&(n.h=360*o),this.element.style.backgroundColor=`hsl(${n.h}, 100%, 50%)`,r.palette.trigger();}}),opacity:C({lock:"v"===n?"h":"v",element:t._root.opacity.picker,wrapper:t._root.opacity.slider,onstop:()=>t._emit("changestop","slider",t),onchange(o){if(!e.opacity||!e.palette)return;const n=s();t._recalc&&(n.a=Math.round(100*o)/100),this.element.style.background=`rgba(0, 0, 0, ${n.a})`,r.palette.trigger();}}),selectable:k({elements:t._root.interaction.options,className:"active",onchange(e){t._representation=e.target.getAttribute("data-type").toUpperCase(),t._recalc&&t._updateOutput("swatch");}})};this._components=r;}_bindEvents(){const{_root:t,options:e}=this,o=[i(t.interaction.clear,"click",(()=>this._clearColor())),i([t.interaction.cancel,t.preview.lastColor],"click",(()=>{this.setHSVA(...(this._lastColor||this._color).toHSVA(),!0),this._emit("cancel");})),i(t.interaction.save,"click",(()=>{!this.applyColor()&&!e.showAlways&&this.hide();})),i(t.interaction.result,["keyup","input"],(t=>{this.setColor(t.target.value,!0)&&!this._initializingActive&&(this._emit("change",this._color,"input",this),this._emit("changestop","input",this)),t.stopImmediatePropagation();})),i(t.interaction.result,["focus","blur"],(t=>{this._recalc="blur"===t.type,this._recalc&&this._updateOutput(null);})),i([t.palette.palette,t.palette.picker,t.hue.slider,t.hue.picker,t.opacity.slider,t.opacity.picker],["mousedown","touchstart"],(()=>this._recalc=!0),{passive:!0})];if(!e.showAlways){const n=e.closeWithKey;o.push(i(t.button,"click",(()=>this.isOpen()?this.hide():this.show())),i(document,"keyup",(t=>this.isOpen()&&(t.key===n||t.code===n)&&this.hide())),i(document,["touchstart","mousedown"],(e=>{this.isOpen()&&!l(e).some((e=>e===t.app||e===t.button))&&this.hide();}),{capture:!0}));}if(e.adjustableNumbers){const e={rgba:[255,255,255,1],hsva:[360,100,100,1],hsla:[360,100,100,1],cmyk:[100,100,100,100]};p(t.interaction.result,((t,o,n)=>{const i=e[this.getColorRepresentation().toLowerCase()];if(i){const e=i[n],s=t+(e>=100?1e3*o:o);return s<=0?0:Number((s{n.isOpen()&&(e.closeOnScroll&&n.hide(),null===t?(t=setTimeout((()=>t=null),100),requestAnimationFrame((function e(){n._rePositioningPicker(),null!==t&&requestAnimationFrame(e);}))):(clearTimeout(t),t=setTimeout((()=>t=null),100)));}),{capture:!0}));}this._eventBindings=o;}_rePositioningPicker(){const{options:t}=this;if(!t.inline){if(!this._nanopop.update({container:document.body.getBoundingClientRect(),position:t.position})){const t=this._root.app,e=t.getBoundingClientRect();t.style.top=(window.innerHeight-e.height)/2+"px",t.style.left=(window.innerWidth-e.width)/2+"px";}}}_updateOutput(t){const{_root:e,_color:o,options:n}=this;if(e.interaction.type()){const t=`to${e.interaction.type().getAttribute("data-type")}`;e.interaction.result.value="function"==typeof o[t]?o[t]().toString(n.outputPrecision):"";}!this._initializingActive&&this._recalc&&this._emit("change",o,t,this);}_clearColor(t=!1){const{_root:e,options:o}=this;o.useAsButton||e.button.style.setProperty("--pcr-color","rgba(0, 0, 0, 0.15)"),e.button.classList.add("clear"),o.showAlways||this.hide(),this._lastColor=null,this._initializingActive||t||(this._emit("save",null),this._emit("clear"));}_parseLocalColor(t){const{values:e,type:o,a:n}=w(t),{lockOpacity:i}=this.options,s=void 0!==n&&1!==n;return e&&3===e.length&&(e[3]=void 0),{values:!e||i&&s?null:e,type:o}}_t(t){return this.options.i18n[t]||E.I18N_DEFAULTS[t]}_emit(t,...e){this._eventListener[t].forEach((t=>t(...e,this)));}on(t,e){return this._eventListener[t].push(e),this}off(t,e){const o=this._eventListener[t]||[],n=o.indexOf(e);return ~n&&o.splice(n,1),this}addSwatch(t){const{values:e}=this._parseLocalColor(t);if(e){const{_swatchColors:t,_root:o}=this,n=A(...e),s=r(`