/* 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 state = require('@codemirror/state'); var view = require('@codemirror/view'); var language = require('@codemirror/language'); /****************************************************************************** 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; }; const matchTypes = { 'exact': "Exact match", 'contains': "Contains value", 'whiteSpace': "Value within whitespace separated words", 'startswith': "Starts with this value", 'endswith': "Ends with this value" }; const matchSign = { 'exact': "", 'contains': "*", 'startswith': "^", 'endswith': "$", 'whiteSpace': "~" }; const matchPreview = { 'exact': "with value", 'contains': "containing", 'whiteSpace': "containing", 'startswith': "starting with", 'endswith': "ending with" }; const matchPreviewPath = { 'exact': "is", 'contains': "contains", 'whiteSpace': "contains", 'startswith': "starts with", 'endswith': "ends with" }; const selectorType = { 'attribute': 'Attribute value', 'tag': 'Tag', 'path': 'Note path' }; class CSSLink { constructor() { this.type = 'attribute'; this.name = ""; this.value = ""; this.matchCaseSensitive = false; this.match = "exact"; let s4 = () => { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); }; //return id of format 'aaaaaaaa'-'aaaa'-'aaaa'-'aaaa'-'aaaaaaaaaaaa' this.uid = s4() + "-" + s4(); this.selectText = true; this.selectAppend = true; this.selectPrepend = true; this.selectBackground = true; } } function displayText(link, settings) { if (link.type === 'tag') { if (!link.value) { return "Please choose a tag"; } return `#${link.value}`; } else if (link.type === 'attribute') { if (settings.targetAttributes.length === 0) { return `No attributes added to "Target attributes". Go to plugin settings to add them.`; } if (!link.name) { return "Please choose an attribute name."; } if (!link.value) { return "Please choose an attribute value."; } return ` has attribute ${link.name} ${matchPreview[link.match]} ${link.value}.`; } if (!link.value) { return "Please choose a path."; } return `The path of the ${matchPreviewPath[link.match]} ${link.value}`; } function updateDisplay(textArea, link, settings) { let toDisplay = displayText(link, settings); let disabled = false; if (link.type === 'tag') { if (!link.value) { disabled = true; } } else if (link.type === 'attribute') { if (settings.targetAttributes.length === 0) { disabled = true; } else if (!link.name) { disabled = true; } else if (!link.value) { disabled = true; } } else { if (!link.value) { disabled = true; } } textArea.innerHTML = toDisplay; return disabled; } class CSSBuilderModal extends obsidian.Modal { constructor(plugin, saveCallback, cssLink = null) { super(plugin.app); this.cssLink = cssLink; if (!cssLink) { this.cssLink = new CSSLink(); } this.plugin = plugin; this.saveCallback = saveCallback; } onOpen() { this.titleEl.setText(`Select what links to style!`); // is tag const matchAttrPlaceholder = "Attribute value to match."; const matchTagPlaceholder = "Note tag to match (without #)."; const matchPathPlaceholder = "File path to match."; const matchAttrTxt = "Attribute value"; const matchTagTxt = "Tag"; const matchPathTxt = "Path"; const cssLink = this.cssLink; const plugin = this.plugin; this.contentEl.addClass("supercharged-modal"); // Type new obsidian.Setting(this.contentEl) .setName("Type of selector") .setDesc("Attributes selects YAML and DataView attributes" + ", tags chooses the tags of a note, and path considers the name of the note including in what folder it is.") .addDropdown(dc => { Object.keys(selectorType).forEach((type) => { dc.addOption(type, selectorType[type]); if (type === this.cssLink.type) { dc.setValue(type); } }); dc.onChange((type) => { cssLink.type = type; updateContainer(cssLink.type); saveButton.setDisabled(updateDisplay(preview, this.cssLink, this.plugin.settings)); }); }); // attribute name const attrName = new obsidian.Setting(this.contentEl) .setName("Attribute name") .setDesc("What attribute to target? Make sure to first add target attributes to the settings at the top!") .addDropdown(dc => { plugin.settings.targetAttributes.forEach((attribute) => { dc.addOption(attribute, attribute); if (attribute === cssLink.name) { dc.setValue(attribute); } }); dc.onChange(name => { cssLink.name = name; saveButton.setDisabled(updateDisplay(preview, cssLink, plugin.settings)); }); }); // attribute value const attrValue = new obsidian.Setting(this.contentEl) .setName("Value to match") .setDesc("TODO") .addText(t => { t.setValue(cssLink.value); t.onChange(value => { cssLink.value = value; saveButton.setDisabled(updateDisplay(preview, cssLink, plugin.settings)); }); }); this.contentEl.createEl('h4', { text: 'Advanced' }); // matching type const matchingType = new obsidian.Setting(this.contentEl) .setName("Matching type") .setDesc("How to compare the attribute or path with the given value.") .addDropdown(dc => { Object.keys(matchTypes).forEach((key) => { dc.addOption(key, matchTypes[key]); if (key == cssLink.match) { dc.setValue(key); } }); dc.onChange((value) => { cssLink.match = value; saveButton.setDisabled(updateDisplay(preview, cssLink, plugin.settings)); }); }); // case sensitive const caseSensitiveTogglerContainer = new obsidian.Setting(this.contentEl) .setName("Case sensitive matching") .setDesc("Should the matching of the value be case sensitive?") .addToggle(b => { b.setValue(cssLink.matchCaseSensitive); b.onChange(value => { cssLink.matchCaseSensitive = value; b.setDisabled(updateDisplay(preview, cssLink, plugin.settings)); }); }); if (!this.cssLink.name && this.plugin.settings.targetAttributes.length > 0) { this.cssLink.name = this.plugin.settings.targetAttributes[0]; } const updateContainer = function (type) { if (type === 'attribute') { attrName.settingEl.show(); attrValue.nameEl.setText(matchAttrTxt); attrValue.descEl.setText(matchAttrPlaceholder); matchingType.settingEl.show(); caseSensitiveTogglerContainer.settingEl.show(); } else if (type === 'tag') { attrName.settingEl.hide(); attrValue.nameEl.setText(matchTagTxt); attrValue.descEl.setText(matchTagPlaceholder); matchingType.settingEl.hide(); caseSensitiveTogglerContainer.settingEl.hide(); } else { attrName.settingEl.hide(); attrValue.nameEl.setText(matchPathTxt); attrValue.descEl.setText(matchPathPlaceholder); matchingType.settingEl.show(); caseSensitiveTogglerContainer.settingEl.show(); } }; new obsidian.Setting(this.contentEl) .setName("Style options") .setDesc("What styling options are active? " + "Disabling options you won't use can improve performance slightly.") .addToggle(t => { t.onChange(value => { cssLink.selectText = value; }); t.setValue(cssLink.selectText); t.setTooltip("Style link text"); }) .addToggle(t => { t.onChange(value => { cssLink.selectPrepend = value; }); t.setValue(cssLink.selectPrepend); t.setTooltip("Add content before link"); }) .addToggle(t => { t.onChange(value => { cssLink.selectAppend = value; }); t.setValue(cssLink.selectAppend); t.setTooltip("Add content after link"); }) .addToggle(t => { t.onChange(value => { cssLink.selectBackground = value; }); t.setValue(cssLink.selectBackground); t.setTooltip("Add optional background or underline to link"); }); this.contentEl.createEl('h4', { text: 'Result' }); const modal = this; const saveButton = new obsidian.Setting(this.contentEl) .setName("Preview") .setDesc("") .addButton(b => { b.setButtonText("Save"); b.onClick(() => { modal.saveCallback(cssLink); modal.close(); }); }); // generate button const preview = saveButton.nameEl; updateContainer(cssLink.type); saveButton.setDisabled(updateDisplay(preview, this.cssLink, this.plugin.settings)); } } const colorSet = [[ '#0089BA', '#2C73D2', '#008E9B', '#0081CF', '#008F7A', '#008E9B', ], [ '#D65DB1', '#0082C1', '#9270D3', '#007F93', '#007ED9', '#007660', ], [ '#FF9671', '#A36AAA', '#F27D88', '#6967A9', '#D26F9D', '#1b6299', ], [ '#FFC75F', '#4C9A52', '#C3BB4E', '#00855B', '#88AC4B', '#006F61', ], [ '#FF6F91', '#6F7F22', '#E07250', '#257A3E', '#AC7C26', '#006F5F', ], [ '#d9d867', '#2FAB63', '#B8E067', '#008E63', '#78C664', '#007160', ]]; const colors = []; for (const i of Array(6).keys()) { for (const j of Array(6).keys()) { colors.push(colorSet[j][i]); } } function hash(uid) { let hash = 0; for (let i = 0; i < uid.length; i++) { const char = uid.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32bit integer } hash = Math.abs(hash); return hash; } function buildCSS(selectors, plugin) { return __awaiter(this, void 0, void 0, function* () { var _a; const instructions = [ "/* WARNING: This file will be overwritten by the plugin.", "Do not edit this file directly! First copy this file and rename it if you want to edit things. */", "", ":root {" ]; selectors.forEach((selector, i) => { if (selector.selectText) { instructions.push(` --${selector.uid}-color: ${colors[hash(selector.uid) % 36]};`); instructions.push(` --${selector.uid}-weight: initial;`); } if (selector.selectPrepend) { instructions.push(` --${selector.uid}-before: '';`); } if (selector.selectAppend) { instructions.push(` --${selector.uid}-after: '';`); } if (selector.selectBackground) { instructions.push(` --${selector.uid}-background-color: #ffffff;`); instructions.push(` --${selector.uid}-decoration: initial;`); } }); instructions.push("}"); selectors.forEach(selector => { let cssSelector; if (selector.type === 'attribute') { cssSelector = `[data-link-${selector.name}${matchSign[selector.match]}="${selector.value}" ${selector.matchCaseSensitive ? "" : " i"}]`; } else if (selector.type === 'tag') { cssSelector = `[data-link-tags*="${selector.value}" i]`; } else { cssSelector = `[data-link-path${matchSign[selector.match]}="${selector.value}" ${selector.matchCaseSensitive ? "" : "i"}]`; } if (selector.selectText) { instructions.push(...[ "", `div[data-id="${selector.uid}"] div.setting-item-description,`, cssSelector + " {", ` color: var(--${selector.uid}-color) !important;`, ` font-weight: var(--${selector.uid}-weight);`, "}" ]); } if (selector.selectBackground) { instructions.push(...["", `.c-${selector.uid}-use-background div[data-id="${selector.uid}"] div.setting-item-description,`, `.c-${selector.uid}-use-background .data-link-text${cssSelector} {`, ` background-color: var(--${selector.uid}-background-color) !important;`, ` border-radius: 5px;`, ` padding-left: 2px;`, ` padding-right: 2px;`, ` text-decoration: var(--${selector.uid}-decoration) !important;`, "}"]); } if (selector.selectPrepend) { instructions.push(...["", `div[data-id="${selector.uid}"] div.setting-item-description::before,`, `.data-link-icon${cssSelector}::before {`, ` content: var(--${selector.uid}-before);`, "}"]); } if (selector.selectAppend) { instructions.push(...["", `div[data-id="${selector.uid}"] div.setting-item-description::after,`, `.data-link-icon-after${cssSelector}::after {`, ` content: var(--${selector.uid}-after);`, "}"]); } }); instructions.push(...[ "/* @settings", "name: Supercharged Links", "id: supercharged-links", "settings:", ]); selectors.forEach((selector, i) => { let name = selector.name; let value = selector.value; if (selector.type === 'tag') { name = 'tag'; // value = "\#" + value; } else if (selector.type === 'path') { name = 'path'; } instructions.push(...[ " - ", ` id: ${selector.uid}`, ` title: ${name} is ${value}`, ` description: Example note`, " type: heading", " collapsed: true", " level: 3" ]); if (selector.selectText) { instructions.push(...[ " - ", ` id: ${selector.uid}-color`, ` title: Link color`, " type: variable-color", " format: hex", ` default: '${colors[hash(selector.uid) % 36]}'`, " - ", ` id: ${selector.uid}-weight`, ` title: Font weight`, " type: variable-select", ` default: initial`, ` options:`, ` - initial`, ` - lighter`, ` - normal`, ` - bold`, ` - bolder`, " - ", ` id: ${selector.uid}-decoration`, ` title: Font decoration`, " type: variable-select", ` default: initial`, ` options:`, ` - initial`, ` - underline`, ` - overline`, ` - line-through` ]); } if (selector.selectPrepend) { instructions.push(...[" - ", ` id: ${selector.uid}-before`, ` title: Prepend text`, ` description: Add some text, such as an emoji, before the links.`, " type: variable-text", ` default: ''`, ` quotes: true`]); } if (selector.selectAppend) { instructions.push(...[" - ", ` id: ${selector.uid}-after`, ` title: Append text`, ` description: Add some text, such as an emoji, after the links.`, " type: variable-text", ` default: ''`, ` quotes: true`]); } if (selector.selectBackground) { instructions.push(...[" - ", ` id: c-${selector.uid}-use-background`, ` title: Use background color`, ` description: Adds a background color to the link. This can look buggy in live preview.`, " type: class-toggle", " - ", ` id: ${selector.uid}-background-color`, ` title: Background color`, " type: variable-color", " format: hex", ` default: '#ffffff'`]); } }); instructions.push("*/"); const vault = plugin.app.vault; const configDir = (_a = vault.configDir) !== null && _a !== void 0 ? _a : ".obsidian"; const pathDir = configDir + "/snippets"; yield vault.adapter.mkdir(pathDir); const path = pathDir + "/supercharged-links-gen.css"; if (yield vault.adapter.exists(path)) { yield vault.adapter.remove(path); } yield plugin.app.vault.create(path, instructions.join('\n')); // Activate snippet if (plugin.settings.activateSnippet) { // @ts-ignore const customCss = plugin.app.customCss; customCss.enabledSnippets.add('supercharged-links-gen'); customCss.requestLoadSnippets(); } // Ensure Style Settings reads changes plugin.app.workspace.trigger("parse-style-settings"); }); } function clearExtraAttributes(link) { Object.values(link.attributes).forEach(attr => { if (attr.name.includes("data-link")) { link.removeAttribute(attr.name); } }); } function fetchTargetAttributesSync(app, settings, dest, addDataHref) { var _a; let new_props = { tags: "" }; const cache = app.metadataCache.getFileCache(dest); if (!cache) return new_props; const frontmatter = cache.frontmatter; if (frontmatter) { settings.targetAttributes.forEach(attribute => { if (Object.keys(frontmatter).includes(attribute)) { if (attribute === 'tag' || attribute === 'tags') { new_props['tags'] += frontmatter[attribute]; } else { new_props[attribute] = frontmatter[attribute]; } } }); } if (settings.targetTags) { new_props["tags"] += obsidian.getAllTags(cache).join(' '); } if (addDataHref) { new_props['data-href'] = dest.basename; } new_props['path'] = dest.path; //@ts-ignore const getResults = (api) => { const page = api.page(dest.path); if (!page) { return; } settings.targetAttributes.forEach((field) => { const value = page[field]; if (value) new_props[field] = value; }); }; if (settings.getFromInlineField && app.plugins.enabledPlugins.has("dataview")) { const api = (_a = app.plugins.plugins.dataview) === null || _a === void 0 ? void 0 : _a.api; if (api) { getResults(api); } else this.plugin.registerEvent(this.app.metadataCache.on("dataview:api-ready", (api) => getResults(api))); } return new_props; } function setLinkNewProps(link, new_props) { // @ts-ignore for (const a of link.attributes) { if (a.name.includes("data-link") && !(a.name in new_props)) { link.removeAttribute(a.name); } } Object.keys(new_props).forEach(key => { var _a; const name = "data-link-" + key; const newValue = new_props[key]; const curValue = link.getAttribute(name); // Only update if value is different if (!newValue || curValue != newValue) { link.setAttribute("data-link-" + key, new_props[key]); if (((_a = new_props[key]) === null || _a === void 0 ? void 0 : _a.startsWith) && (new_props[key].startsWith('http') || new_props[key].startsWith('data:'))) { link.style.setProperty(`--data-link-${key}`, `url(${new_props[key]})`); } else { link.style.setProperty(`--data-link-${key}`, new_props[key]); } } }); if (!link.hasClass("data-link-icon")) { link.addClass("data-link-icon"); } if (!link.hasClass("data-link-icon-after")) { link.addClass("data-link-icon-after"); } if (!link.hasClass("data-link-text")) { link.addClass("data-link-text"); } } function updateLinkExtraAttributes(app, settings, link, destName) { var _a, _b; const linkHref = (_b = (_a = link.getAttribute('href')) === null || _a === void 0 ? void 0 : _a.split('#')) === null || _b === void 0 ? void 0 : _b[0]; if (linkHref) { const dest = app.metadataCache.getFirstLinkpathDest(linkHref, destName); if (dest) { const new_props = fetchTargetAttributesSync(app, settings, dest, false); setLinkNewProps(link, new_props); } } } function updateDivExtraAttributes(app, settings, link, destName, linkName) { if (link.parentElement.getAttribute("class").contains('mod-collapsible')) return; // Bookmarks Folder if (!linkName) { linkName = link.textContent; } if (!!link.parentElement.getAttribute('data-path')) { // File Browser linkName = link.parentElement.getAttribute('data-path'); } else if (link.parentElement.getAttribute("class") == "suggestion-content" && !!link.nextElementSibling) { // Auto complete linkName = link.nextElementSibling.textContent + linkName; } const dest = app.metadataCache.getFirstLinkpathDest(obsidian.getLinkpath(linkName), destName); if (dest) { const new_props = fetchTargetAttributesSync(app, settings, dest, true); setLinkNewProps(link, new_props); } } function updateElLinks(app, plugin, el, ctx) { const settings = plugin.settings; const links = el.querySelectorAll('a.internal-link'); const destName = ctx.sourcePath.replace(/(.*).md/, "$1"); links.forEach((link) => { updateLinkExtraAttributes(app, settings, link, destName); }); } function updatePropertiesPane(propertiesEl, file, app, plugin) { var _a; const frontmatter = (_a = app.metadataCache.getCache(file.path)) === null || _a === void 0 ? void 0 : _a.frontmatter; if (!!frontmatter) { const nodes = propertiesEl.querySelectorAll("div.internal-link > .multi-select-pill-content"); for (let i = 0; i < nodes.length; ++i) { const el = nodes[i]; const linkText = el.textContent; const keyEl = el.parentElement.parentElement.parentElement.parentElement.children[0].children[1]; // @ts-ignore const key = keyEl.value; const listOfLinks = frontmatter[key]; let foundS = null; if (!listOfLinks) { continue; } for (const s of listOfLinks) { if (s.length > 4 && s.startsWith("[[") && s.endsWith("]]")) { const slicedS = s.slice(2, -2); const split = slicedS.split("|"); if (split.length == 1 && split[0] == linkText) { foundS = split[0]; break; } else if (split.length == 2 && split[1] == linkText) { foundS = split[0]; break; } } } if (!!foundS) { updateDivExtraAttributes(plugin.app, plugin.settings, el, "", foundS); } } const singleNodes = propertiesEl.querySelectorAll("div.metadata-link-inner"); for (let i = 0; i < singleNodes.length; ++i) { const el = singleNodes[i]; const linkText = el.textContent; const keyEl = el.parentElement.parentElement.parentElement.children[0].children[1]; // @ts-ignore const key = keyEl.value; const link = frontmatter[key]; if (!link) { continue; } let foundS = null; if ((link === null || link === void 0 ? void 0 : link.length) > 4 && link.startsWith("[[") && link.endsWith("]]")) { const slicedS = link.slice(2, -2); const split = slicedS.split("|"); if (split.length == 1 && split[0] == linkText) { foundS = split[0]; } else if (split.length == 2 && split[1] == linkText) { foundS = split[0]; } } if (!!foundS) { updateDivExtraAttributes(plugin.app, plugin.settings, el, "", foundS); } } } } function updateVisibleLinks(app, plugin) { const settings = plugin.settings; app.workspace.iterateRootLeaves((leaf) => { var _a, _b; if (leaf.view instanceof obsidian.MarkdownView && leaf.view.file) { const file = leaf.view.file; const cachedFile = app.metadataCache.getFileCache(file); // @ts-ignore const metadata = (_b = (_a = leaf.view) === null || _a === void 0 ? void 0 : _a.metadataEditor) === null || _b === void 0 ? void 0 : _b.contentEl; if (!!metadata) { updatePropertiesPane(metadata, file, app, plugin); } //@ts-ignore const tabHeader = leaf.tabHeaderInnerTitleEl; if (settings.enableTabHeader) { // Supercharge tab headers updateDivExtraAttributes(app, settings, tabHeader, "", file.path); } else { clearExtraAttributes(tabHeader); } if (cachedFile === null || cachedFile === void 0 ? void 0 : cachedFile.links) { cachedFile.links.forEach((link) => { const fileName = file.path.replace(/(.*).md/, "$1"); const dest = app.metadataCache.getFirstLinkpathDest(link.link, fileName); if (dest) { const new_props = fetchTargetAttributesSync(app, settings, dest, false); const internalLinks = leaf.view.containerEl.querySelectorAll(`a.internal-link[href="${link.link}"]`); internalLinks.forEach((internalLink) => setLinkNewProps(internalLink, new_props)); } }); } } }); } class SuperchargedLinksSettingTab extends obsidian.PluginSettingTab { constructor(app, plugin) { super(app, plugin); this.plugin = plugin; this.debouncedGenerate = obsidian.debounce(this._generateSnippet, 1000, true); // Generate CSS immediately rather than 1 second - feels laggy this._generateSnippet(); } display() { let { containerEl } = this; containerEl.empty(); /* Managing extra attirbutes for a.internal-link */ new obsidian.Setting(containerEl) .setName('Target Attributes for styling') .setDesc('Frontmatter attributes to target, comma separated') .addTextArea((text) => { text .setPlaceholder('Enter attributes as string, comma separated') .setValue(this.plugin.settings.targetAttributes.join(', ')) .onChange((value) => __awaiter(this, void 0, void 0, function* () { this.plugin.settings.targetAttributes = value.replace(/\s/g, '').split(','); if (this.plugin.settings.targetAttributes.length === 1 && !this.plugin.settings.targetAttributes[0]) { this.plugin.settings.targetAttributes = []; } yield this.plugin.saveSettings(); })); text.inputEl.rows = 6; text.inputEl.cols = 25; }); containerEl.createEl('h4', { text: 'Styling' }); const styleSettingDescription = containerEl.createDiv(); styleSettingDescription.innerHTML = ` Styling can be done using the Style Settings plugin.
has tag