1491 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1491 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
| 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 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);
 | |
|         }
 | |
|         // This is crashing for some people. I think ignoring it will be ok. 
 | |
|         // else
 | |
|         //     this.plugin.registerEvent(
 | |
|         //         app.metadataCache.on("dataview:api-ready", (api: any) =>
 | |
|         //             getResults(api)
 | |
|         //         )
 | |
|         //     );
 | |
|     }
 | |
|     // Replace spaces with hyphens in the keys of new_props
 | |
|     const hyphenated_props = {};
 | |
|     for (const key in new_props) {
 | |
|         const hyphenatedKey = key.replace(/ /g, '-');
 | |
|         hyphenated_props[hyphenatedKey] = new_props[key];
 | |
|     }
 | |
|     new_props = hyphenated_props;
 | |
|     return new_props;
 | |
| }
 | |
| function processKey(key) {
 | |
|     // Replace spaces with hyphens (v0.13.4+)
 | |
|     return key.replace(/ /g, '-');
 | |
| }
 | |
| function processValue(key, value) {
 | |
|     // TODO: This is a hack specifically for Emile's setup. Should be commented in releases.
 | |
|     if (key.contains("publishedIn") && (value === null || value === void 0 ? void 0 : value.length) && value.length === 1 && value[0].startsWith && value[0].startsWith("[[") && value[0].endsWith("]]")) {
 | |
|         return value[0].slice(2, -2);
 | |
|     }
 | |
|     return value;
 | |
| }
 | |
| 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 => {
 | |
|         const dom_key = processKey(key);
 | |
|         const name = "data-link-" + dom_key;
 | |
|         const curValue = link.getAttribute(name);
 | |
|         const newValue = processValue(key, new_props[key]);
 | |
|         // Only update if value is different
 | |
|         if (!newValue || curValue != newValue) {
 | |
|             link.setAttribute(name, newValue);
 | |
|             if ((newValue === null || newValue === void 0 ? void 0 : newValue.startsWith) && (newValue.startsWith('http') || newValue.startsWith('data:'))) {
 | |
|                 link.style.setProperty(`--data-link-${dom_key}`, `url(${newValue})`);
 | |
|             }
 | |
|             else {
 | |
|                 link.style.setProperty(`--data-link-${dom_key}`, newValue);
 | |
|             }
 | |
|         }
 | |
|     });
 | |
|     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, filter_collapsible = false) {
 | |
|     if (filter_collapsible && 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));
 | |
|                     }
 | |
|                 });
 | |
|             }
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| function displayText(link, settings) {
 | |
|     if (link.type === 'tag') {
 | |
|         if (!link.value) {
 | |
|             return "<b>Please choose a tag</b>";
 | |
|         }
 | |
|         return `<span class="data-link-icon data-link-text data-link-icon-after" data-link-tags="${link.value}">Note</span> has tag <a class="tag">#${link.value}</a>`;
 | |
|     }
 | |
|     else if (link.type === 'attribute') {
 | |
|         if (settings.targetAttributes.length === 0) {
 | |
|             return `<b>No attributes added to "Target attributes". Go to plugin settings to add them.</b>`;
 | |
|         }
 | |
|         if (!link.name) {
 | |
|             return "<b>Please choose an attribute name.</b>";
 | |
|         }
 | |
|         if (!link.value) {
 | |
|             return "<b>Please choose an attribute value.</b>";
 | |
|         }
 | |
|         return `<span class="data-link-icon data-link-text data-link-icon-after" data-link-${link.name}="${link.value}">Note</span> has attribute <b>${link.name.replace(/-/g, ' ')}</b> ${matchPreview[link.match]} <b>${link.value}</b>.`;
 | |
|     }
 | |
|     if (!link.value) {
 | |
|         return "<b>Please choose a path.</b>";
 | |
|     }
 | |
|     return `The path of the <span class="data-link-icon data-link-text data-link-icon-after" data-link-path="${link.value}">note</span> ${matchPreviewPath[link.match]} <b>${link.value}</b>`;
 | |
| }
 | |
| 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) => {
 | |
|                 const dom_attribute = processKey(attribute);
 | |
|                 dc.addOption(dom_attribute, attribute);
 | |
|                 if (dom_attribute === cssLink.name) {
 | |
|                     dc.setValue(dom_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");
 | |
|     });
 | |
| }
 | |
| 
 | |
| 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.split(',').map(attr => attr.trim());
 | |
|                 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. 
 | |
|  <ol>
 | |
|  <li>Create selectors down below.</li>
 | |
|  <li>Go to the Style Settings tab and style your links!</li>
 | |
| </ol>`;
 | |
|         const selectorDiv = containerEl.createDiv();
 | |
|         this.drawSelectors(selectorDiv);
 | |
|         containerEl.createEl('h4', { text: 'Settings' });
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Enable in Editor')
 | |
|             .setDesc('If true, this will also supercharge internal links in the editor view of a note.')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.enableEditor);
 | |
|             toggle.onChange(value => {
 | |
|                 this.plugin.settings.enableEditor = value;
 | |
|                 this.plugin.saveSettings();
 | |
|                 updateVisibleLinks(this.app, this.plugin);
 | |
|             });
 | |
|         });
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Enable in tab headers')
 | |
|             .setDesc('If true, this will also supercharge the headers of a tab.')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.enableTabHeader);
 | |
|             toggle.onChange(value => {
 | |
|                 this.plugin.settings.enableTabHeader = value;
 | |
|                 this.plugin.saveSettings();
 | |
|                 updateVisibleLinks(this.app, this.plugin);
 | |
|             });
 | |
|         });
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Enable in File Browser')
 | |
|             .setDesc('If true, this will also supercharge the file browser.')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.enableFileList);
 | |
|             toggle.onChange(value => {
 | |
|                 this.plugin.settings.enableFileList = value;
 | |
|                 this.plugin.saveSettings();
 | |
|             });
 | |
|         });
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Enable in Bases')
 | |
|             .setDesc('If true, this will also supercharge Obsidian Bases.')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.enableBases);
 | |
|             toggle.onChange(value => {
 | |
|                 this.plugin.settings.enableBases = value;
 | |
|                 this.plugin.saveSettings();
 | |
|             });
 | |
|         });
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Enable in Plugins')
 | |
|             .setDesc('If true, this will also supercharge plugins like the backlinks and forward links panels.')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.enableBacklinks);
 | |
|             toggle.onChange(value => {
 | |
|                 this.plugin.settings.enableBacklinks = value;
 | |
|                 this.plugin.saveSettings();
 | |
|             });
 | |
|         });
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Enable in Quick Switcher')
 | |
|             .setDesc('If true, this will also supercharge the quick switcher.')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.enableQuickSwitcher);
 | |
|             toggle.onChange(value => {
 | |
|                 this.plugin.settings.enableQuickSwitcher = value;
 | |
|                 this.plugin.saveSettings();
 | |
|             });
 | |
|         });
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Enable in Link Autocompleter')
 | |
|             .setDesc('If true, this will also supercharge the link autocompleter.')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.enableSuggestor);
 | |
|             toggle.onChange(value => {
 | |
|                 this.plugin.settings.enableSuggestor = value;
 | |
|                 this.plugin.saveSettings();
 | |
|             });
 | |
|         });
 | |
|         containerEl.createEl('h4', { text: 'Advanced' });
 | |
|         // Managing choice wether you want to parse tags both from normal tags and in the frontmatter
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Parse all tags in the file')
 | |
|             .setDesc('Sets the `data-link-tags`-attribute to look for tags both in the frontmatter and in the file as #tag-name')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.targetTags);
 | |
|             toggle.onChange((value) => __awaiter(this, void 0, void 0, function* () {
 | |
|                 this.plugin.settings.targetTags = value;
 | |
|                 yield this.plugin.saveSettings();
 | |
|             }));
 | |
|         });
 | |
|         // Managing choice wether you get attributes from inline fields and frontmatter or only frontmater
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Search for attribute in Inline fields like <field::>')
 | |
|             .setDesc('Sets the `data-link-<field>`-attribute to the value of inline fields')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.getFromInlineField);
 | |
|             toggle.onChange((value) => __awaiter(this, void 0, void 0, function* () {
 | |
|                 this.plugin.settings.getFromInlineField = value;
 | |
|                 yield this.plugin.saveSettings();
 | |
|             }));
 | |
|         });
 | |
|         // Automatically activate snippet
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Automatically activate snippet')
 | |
|             .setDesc('If true, this will automatically activate the generated CSS snippet "supercharged-links-gen.css". ' +
 | |
|             'Turn this off if you don\'t want this to happen.')
 | |
|             .addToggle(toggle => {
 | |
|             toggle.setValue(this.plugin.settings.activateSnippet);
 | |
|             toggle.onChange((value) => __awaiter(this, void 0, void 0, function* () {
 | |
|                 this.plugin.settings.activateSnippet = value;
 | |
|                 yield this.plugin.saveSettings();
 | |
|             }));
 | |
|         });
 | |
|         /* Managing predefined values for properties */
 | |
|         /* Manage menu options display*/
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName("Display field options in context menu")
 | |
|             .setDesc("This feature has been migrated to metadata-menu plugin https://github.com/mdelobelle/metadatamenu");
 | |
|     }
 | |
|     generateSnippet() {
 | |
|         this.debouncedGenerate();
 | |
|     }
 | |
|     _generateSnippet() {
 | |
|         return __awaiter(this, void 0, void 0, function* () {
 | |
|             yield buildCSS(this.plugin.settings.selectors, this.plugin);
 | |
|             // new Notice("Generated supercharged-links-gen.css");
 | |
|         });
 | |
|     }
 | |
|     drawSelectors(div) {
 | |
|         div.empty();
 | |
|         this.generateSnippet();
 | |
|         const selectors = this.plugin.settings.selectors;
 | |
|         selectors.forEach((selector, i) => {
 | |
|             const s = new obsidian.Setting(div)
 | |
|                 .addButton(button => {
 | |
|                 button.onClick(() => {
 | |
|                     const oldSelector = selectors[i + 1];
 | |
|                     selectors[i + 1] = selector;
 | |
|                     selectors[i] = oldSelector;
 | |
|                     this.drawSelectors(div);
 | |
|                 });
 | |
|                 button.setIcon("down-arrow-with-tail");
 | |
|                 button.setTooltip("Move selector down");
 | |
|                 if (i === selectors.length - 1) {
 | |
|                     button.setDisabled(true);
 | |
|                 }
 | |
|             })
 | |
|                 .addButton(button => {
 | |
|                 button.onClick(() => {
 | |
|                     const oldSelector = selectors[i - 1];
 | |
|                     selectors[i - 1] = selector;
 | |
|                     selectors[i] = oldSelector;
 | |
|                     this.drawSelectors(div);
 | |
|                 });
 | |
|                 button.setIcon("up-arrow-with-tail");
 | |
|                 button.setTooltip("Move selector up");
 | |
|                 if (i === 0) {
 | |
|                     button.setDisabled(true);
 | |
|                 }
 | |
|             })
 | |
|                 .addButton(button => {
 | |
|                 button.onClick(() => {
 | |
|                     const formModal = new CSSBuilderModal(this.plugin, (newSelector) => {
 | |
|                         this.plugin.settings.selectors[i] = newSelector;
 | |
|                         this.plugin.saveSettings();
 | |
|                         updateDisplay(s.nameEl, selector, this.plugin.settings);
 | |
|                         this.generateSnippet();
 | |
|                     }, selector);
 | |
|                     formModal.open();
 | |
|                 });
 | |
|                 button.setIcon("pencil");
 | |
|                 button.setTooltip("Edit selector");
 | |
|             })
 | |
|                 .addButton(button => {
 | |
|                 button.onClick(() => {
 | |
|                     this.plugin.settings.selectors.remove(selector);
 | |
|                     this.plugin.saveSettings();
 | |
|                     this.drawSelectors(div);
 | |
|                 });
 | |
|                 button.setIcon("cross");
 | |
|                 button.setTooltip("Remove selector");
 | |
|             });
 | |
|             updateDisplay(s.nameEl, selector, this.plugin.settings);
 | |
|         });
 | |
|         new obsidian.Setting(div)
 | |
|             .setName("New selector")
 | |
|             .setDesc("Create a new selector to style with Style Settings.")
 | |
|             .addButton(button => {
 | |
|             button.onClick(() => {
 | |
|                 const formModal = new CSSBuilderModal(this.plugin, (newSelector) => {
 | |
|                     this.plugin.settings.selectors.push(newSelector);
 | |
|                     this.plugin.saveSettings();
 | |
|                     this.drawSelectors(div);
 | |
|                     // TODO: Force redraw somehow?
 | |
|                 });
 | |
|                 formModal.open();
 | |
|             });
 | |
|             button.setButtonText("New");
 | |
|         });
 | |
|     }
 | |
| }
 | |
| 
 | |
| const DEFAULT_SETTINGS = {
 | |
|     targetAttributes: [],
 | |
|     targetTags: true,
 | |
|     getFromInlineField: false,
 | |
|     enableTabHeader: true,
 | |
|     activateSnippet: true,
 | |
|     enableEditor: true,
 | |
|     enableFileList: true,
 | |
|     enableBacklinks: true,
 | |
|     enableQuickSwitcher: true,
 | |
|     enableSuggestor: true,
 | |
|     enableBases: true,
 | |
|     selectors: []
 | |
| };
 | |
| 
 | |
| function buildCMViewPlugin(app, _settings) {
 | |
|     // Implements the live preview supercharging
 | |
|     // Code structure based on https://github.com/nothingislost/obsidian-cm6-attributes/blob/743d71b0aa616407149a0b6ea5ffea28e2154158/src/main.ts
 | |
|     // Code help credits to @NothingIsLost! They have been a great help getting this to work properly.
 | |
|     class HeaderWidget extends view.WidgetType {
 | |
|         constructor(attributes, after) {
 | |
|             super();
 | |
|             this.attributes = attributes;
 | |
|             this.after = after;
 | |
|         }
 | |
|         toDOM() {
 | |
|             var _a;
 | |
|             let headerEl = document.createElement("span");
 | |
|             headerEl.setAttrs(this.attributes);
 | |
|             for (let key in this.attributes) {
 | |
|                 // CSS doesn't allow interpolation of variables for URLs, so do it beforehand to be nice.
 | |
|                 if (((_a = this.attributes[key]) === null || _a === void 0 ? void 0 : _a.startsWith) && (this.attributes[key].startsWith('http') || this.attributes[key].startsWith('data:'))) {
 | |
|                     headerEl.style.setProperty(`--${key}`, `url(${this.attributes[key]})`);
 | |
|                 }
 | |
|                 else {
 | |
|                     headerEl.style.setProperty(`--${key}`, processValue(key, this.attributes[key]));
 | |
|                 }
 | |
|             }
 | |
|             if (this.after) {
 | |
|                 headerEl.addClass('data-link-icon-after');
 | |
|             }
 | |
|             else {
 | |
|                 headerEl.addClass('data-link-icon');
 | |
|             }
 | |
|             // create a naive bread crumb
 | |
|             return headerEl;
 | |
|         }
 | |
|         ignoreEvent() {
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
|     const settings = _settings;
 | |
|     const viewPlugin = view.ViewPlugin.fromClass(class {
 | |
|         constructor(view) {
 | |
|             this.decorations = this.buildDecorations(view);
 | |
|         }
 | |
|         update(update) {
 | |
|             if (update.docChanged) {
 | |
|                 this.decorations = this.decorations.map(update.changes);
 | |
|                 update.changes.iterChanges((fromA, toA, fromB, toB, t) => {
 | |
|                     // Update all 'line blocks' between the range changed. Prevents weird graphical bugs
 | |
|                     const minFrom = update.view.lineBlockAt(fromB).from;
 | |
|                     const maxTo = update.view.lineBlockAt(toB).to;
 | |
|                     // remove things within bounds
 | |
|                     this.decorations = this.decorations.update({
 | |
|                         filter: (from, to) => to < minFrom || from > maxTo
 | |
|                     });
 | |
|                     // Update decorations within bounds
 | |
|                     this.decorations = state.RangeSet.join([this.decorations,
 | |
|                         this.buildDecorations(update.view, minFrom, maxTo)]);
 | |
|                 });
 | |
|             }
 | |
|             else if (update.viewportChanged) {
 | |
|                 this.decorations = this.buildDecorations(update.view);
 | |
|             }
 | |
|         }
 | |
|         destroy() {
 | |
|         }
 | |
|         buildDecorations(view$1, updateFrom = -1, updateTo = -1) {
 | |
|             let builder = new state.RangeSetBuilder();
 | |
|             if (!settings.enableEditor) {
 | |
|                 return builder.finish();
 | |
|             }
 | |
|             const mdView = view$1.state.field(obsidian.editorViewField);
 | |
|             let lastAttributes = {};
 | |
|             let iconDecoAfter = null;
 | |
|             let iconDecoAfterWhere = null;
 | |
|             let mdAliasFrom = null;
 | |
|             let mdAliasTo = null;
 | |
|             for (let { from, to } of view$1.visibleRanges) {
 | |
|                 // When updating, only changes the range given.
 | |
|                 if (updateFrom !== -1 && (to < updateFrom || from > updateTo))
 | |
|                     continue;
 | |
|                 language.syntaxTree(view$1.state).iterate({
 | |
|                     from,
 | |
|                     to,
 | |
|                     enter: (node) => {
 | |
|                         if (updateFrom !== -1 && (node.to < updateFrom || node.from > updateTo))
 | |
|                             return;
 | |
|                         const tokenProps = node.type.prop(language.tokenClassNodeProp);
 | |
|                         if (tokenProps) {
 | |
|                             const props = new Set(tokenProps.split(" "));
 | |
|                             // Square Brackets of links both internal (`[[`, `]]`) and md link (`[`, `]`)
 | |
|                             const isMDFormatting = props.has('formatting-link') || props.has('formatting-link-string');
 | |
|                             if (isMDFormatting)
 | |
|                                 return;
 | |
|                             // Parts of internal links
 | |
|                             const isLink = props.has("hmd-internal-link"); // [[`Note` or `|` or `Alias`]]
 | |
|                             const isAlias = props.has("link-alias"); // [[Note| `Alias`]]
 | |
|                             const isPipe = props.has("link-alias-pipe"); // [[Note `|` Alias]]
 | |
|                             // The 'alias' of the md link (or its brackets)
 | |
|                             const isMDLink = props.has('link'); // `[` or `Alias` or `]`(URL)
 | |
|                             // The 'internal link' of the md link (or its brackets)
 | |
|                             const isMDUrl = props.has('url'); // [Alias]`(` or `URL` or `)`
 | |
|                             if (isMDLink) {
 | |
|                                 // This catches the alias of md links i.e. [ `Alias` ](URL)
 | |
|                                 // We'll apply the styling in the next iteration when we analyze the `URL`
 | |
|                                 mdAliasFrom = node.from;
 | |
|                                 mdAliasTo = node.to;
 | |
|                             }
 | |
|                             if (!isPipe && !isAlias) {
 | |
|                                 if (iconDecoAfter) {
 | |
|                                     builder.add(iconDecoAfterWhere, iconDecoAfterWhere, iconDecoAfter);
 | |
|                                     iconDecoAfter = null;
 | |
|                                     iconDecoAfterWhere = null;
 | |
|                                 }
 | |
|                             }
 | |
|                             if (isLink && !isAlias && !isPipe || isMDUrl) {
 | |
|                                 let linkText = view$1.state.doc.sliceString(node.from, node.to);
 | |
|                                 linkText = linkText.split("#")[0];
 | |
|                                 let file = app.metadataCache.getFirstLinkpathDest(linkText, mdView.file.basename);
 | |
|                                 if (isMDUrl && !file) {
 | |
|                                     try {
 | |
|                                         file = app.vault.getAbstractFileByPath(decodeURIComponent(linkText));
 | |
|                                     }
 | |
|                                     catch (e) { }
 | |
|                                 }
 | |
|                                 if (file) {
 | |
|                                     let _attributes = fetchTargetAttributesSync(app, settings, file, true);
 | |
|                                     let attributes = {};
 | |
|                                     for (let key in _attributes) {
 | |
|                                         attributes["data-link-" + key] = _attributes[key];
 | |
|                                     }
 | |
|                                     let deco = view.Decoration.mark({
 | |
|                                         attributes,
 | |
|                                         class: "data-link-text"
 | |
|                                     });
 | |
|                                     let iconDecoBefore = view.Decoration.widget({
 | |
|                                         widget: new HeaderWidget(attributes, false),
 | |
|                                     });
 | |
|                                     iconDecoAfter = view.Decoration.widget({
 | |
|                                         widget: new HeaderWidget(attributes, true),
 | |
|                                     });
 | |
|                                     if (isMDUrl) {
 | |
|                                         // Apply retroactively to the alias found before
 | |
|                                         let deco = view.Decoration.mark({
 | |
|                                             attributes: attributes,
 | |
|                                             class: "data-link-text"
 | |
|                                         });
 | |
|                                         builder.add(mdAliasFrom, mdAliasFrom, iconDecoBefore);
 | |
|                                         builder.add(mdAliasFrom, mdAliasTo, deco);
 | |
|                                         if (iconDecoAfter) {
 | |
|                                             builder.add(mdAliasTo, mdAliasTo, iconDecoAfter);
 | |
|                                             iconDecoAfter = null;
 | |
|                                             iconDecoAfterWhere = null;
 | |
|                                             mdAliasFrom = null;
 | |
|                                             mdAliasTo = null;
 | |
|                                         }
 | |
|                                     }
 | |
|                                     else {
 | |
|                                         builder.add(node.from, node.from, iconDecoBefore);
 | |
|                                     }
 | |
|                                     builder.add(node.from, node.to, deco);
 | |
|                                     lastAttributes = attributes;
 | |
|                                     iconDecoAfterWhere = node.to;
 | |
|                                 }
 | |
|                             }
 | |
|                             else if (isLink && isAlias) {
 | |
|                                 let deco = view.Decoration.mark({
 | |
|                                     attributes: lastAttributes,
 | |
|                                     class: "data-link-text"
 | |
|                                 });
 | |
|                                 builder.add(node.from, node.to, deco);
 | |
|                                 if (iconDecoAfter) {
 | |
|                                     builder.add(node.to, node.to, iconDecoAfter);
 | |
|                                     iconDecoAfter = null;
 | |
|                                     iconDecoAfterWhere = null;
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 });
 | |
|             }
 | |
|             return builder.finish();
 | |
|         }
 | |
|     }, {
 | |
|         decorations: v => v.decorations
 | |
|     });
 | |
|     return viewPlugin;
 | |
| }
 | |
| 
 | |
| class SuperchargedLinks extends obsidian.Plugin {
 | |
|     constructor() {
 | |
|         super(...arguments);
 | |
|         this.modalObservers = [];
 | |
|     }
 | |
|     onload() {
 | |
|         return __awaiter(this, void 0, void 0, function* () {
 | |
|             console.log('Supercharged links loaded');
 | |
|             yield this.loadSettings();
 | |
|             this.addSettingTab(new SuperchargedLinksSettingTab(this.app, this));
 | |
|             this.registerMarkdownPostProcessor((el, ctx) => {
 | |
|                 updateElLinks(this.app, this, el, ctx);
 | |
|             });
 | |
|             const plugin = this;
 | |
|             const updateLinks = function (_file) {
 | |
|                 updateVisibleLinks(plugin.app, plugin);
 | |
|                 plugin.observers.forEach(([observer, type, own_class]) => {
 | |
|                     const leaves = plugin.app.workspace.getLeavesOfType(type);
 | |
|                     leaves.forEach(leaf => {
 | |
|                         plugin.updateContainer(leaf.view.containerEl, plugin, own_class);
 | |
|                     });
 | |
|                 });
 | |
|             };
 | |
|             // Live preview
 | |
|             const ext = state.Prec.lowest(buildCMViewPlugin(this.app, this.settings));
 | |
|             this.registerEditorExtension(ext);
 | |
|             this.observers = [];
 | |
|             this.app.workspace.onLayoutReady(() => {
 | |
|                 this.initViewObservers(this);
 | |
|                 this.initModalObservers(this, document);
 | |
|                 updateVisibleLinks(this.app, this);
 | |
|             });
 | |
|             // Initialization
 | |
|             this.registerEvent(this.app.workspace.on("window-open", (window, win) => this.initModalObservers(this, window.getContainer().doc)));
 | |
|             // Update when
 | |
|             // Debounced to prevent lag when writing
 | |
|             this.registerEvent(this.app.metadataCache.on('changed', obsidian.debounce(updateLinks, 500, true)));
 | |
|             // Update when layout changes
 | |
|             // @ts-ignore
 | |
|             this.registerEvent(this.app.workspace.on("layout-change", obsidian.debounce(updateLinks, 10, true)));
 | |
|             // Update plugin views when layout changes
 | |
|             // TODO: This is an expensive operation that seems like it is called fairly frequently. Maybe we can do this more efficiently?
 | |
|             this.registerEvent(this.app.workspace.on("layout-change", () => this.initViewObservers(this)));
 | |
|             // DEBUG: When adding a new view, to get the proper id of that view, uncomment this and reload the plugin
 | |
|             // this.app.workspace.iterateAllLeaves(leaf => {
 | |
|             // 	console.log(leaf.view.getViewType());
 | |
|             // });
 | |
|         });
 | |
|     }
 | |
|     initViewObservers(plugin) {
 | |
|         var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
 | |
|         // Reset observers
 | |
|         plugin.observers.forEach(([observer, type]) => {
 | |
|             observer.disconnect();
 | |
|         });
 | |
|         plugin.observers = [];
 | |
|         // Register new observers for particular file panes
 | |
|         plugin.registerViewType('backlink', plugin, ".tree-item-inner", true);
 | |
|         plugin.registerViewType('outgoing-link', plugin, ".tree-item-inner", true);
 | |
|         plugin.registerViewType('search', plugin, ".tree-item-inner");
 | |
|         if ((_c = (_b = (_a = plugin.app) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.plugins) === null || _c === void 0 ? void 0 : _c.breadcrumbs) {
 | |
|             // console.log('Supercharged links: Enabling breadcrumbs support');
 | |
|             plugin.registerViewType('bc-matrix-view', plugin, 'span.internal-link');
 | |
|             plugin.registerViewType('BC-ducks', plugin, '.internal-link');
 | |
|             plugin.registerViewType('bc-tree-view', plugin, 'span.internal-link');
 | |
|             // Breadcrumbs codeblock support as suggested by https://github.com/mdelobelle/obsidian_supercharged_links/issues/248#issuecomment-3231706063
 | |
|             plugin.registerViewType('markdown', plugin, '.BC-page-views span.internal-link, .BC-codeblock-tree span.internal-link, .nodes a.internal-link');
 | |
|         }
 | |
|         plugin.registerViewType('graph-analysis', plugin, '.internal-link');
 | |
|         plugin.registerViewType('starred', plugin, '.nav-file-title-content');
 | |
|         plugin.registerViewType('file-explorer', plugin, '.nav-file-title-content');
 | |
|         if ((_f = (_e = (_d = plugin.app) === null || _d === void 0 ? void 0 : _d.plugins) === null || _e === void 0 ? void 0 : _e.plugins) === null || _f === void 0 ? void 0 : _f['folder-notes']) {
 | |
|             // console.log('Supercharged links: Enabling folder notes support');
 | |
|             plugin.registerViewType('file-explorer', plugin, '.has-folder-note .tree-item-inner');
 | |
|         }
 | |
|         plugin.registerViewType('recent-files', plugin, '.nav-file-title-content');
 | |
|         plugin.registerViewType('bookmarks', plugin, '.tree-item-inner', false, true);
 | |
|         // @ts-ignore
 | |
|         if (((_k = (_j = (_h = (_g = plugin.app) === null || _g === void 0 ? void 0 : _g.internalPlugins) === null || _h === void 0 ? void 0 : _h.plugins) === null || _j === void 0 ? void 0 : _j.bases) === null || _k === void 0 ? void 0 : _k.enabled) && plugin.settings.enableBases) {
 | |
|             // console.log('Supercharged links: Enabling bases support');
 | |
|             plugin.registerViewType('bases', plugin, '.internal-link');
 | |
|             // For embedded bases
 | |
|             plugin.registerViewType('markdown', plugin, 'div.bases-table-cell  .internal-link');
 | |
|         }
 | |
|         if ((_o = (_m = (_l = plugin.app) === null || _l === void 0 ? void 0 : _l.plugins) === null || _m === void 0 ? void 0 : _m.plugins) === null || _o === void 0 ? void 0 : _o['similar-notes']) {
 | |
|             plugin.registerViewType('markdown', plugin, '.similar-notes-pane .tree-item-inner', true);
 | |
|         }
 | |
|         // If backlinks in editor is on
 | |
|         // @ts-ignore
 | |
|         if (((_s = (_r = (_q = (_p = plugin.app) === null || _p === void 0 ? void 0 : _p.internalPlugins) === null || _q === void 0 ? void 0 : _q.plugins) === null || _r === void 0 ? void 0 : _r.backlink) === null || _s === void 0 ? void 0 : _s.enabled) && ((_y = (_x = (_w = (_v = (_u = (_t = plugin.app) === null || _t === void 0 ? void 0 : _t.internalPlugins) === null || _u === void 0 ? void 0 : _u.plugins) === null || _v === void 0 ? void 0 : _v.backlink) === null || _w === void 0 ? void 0 : _w.instance) === null || _x === void 0 ? void 0 : _x.options) === null || _y === void 0 ? void 0 : _y.backlinkInDocument)) {
 | |
|             // console.log("Supercharged links: Enabling backlinks in document support");
 | |
|             plugin.registerViewType('markdown', plugin, '.embedded-backlinks .tree-item-inner', true);
 | |
|         }
 | |
|         const propertyLeaves = this.app.workspace.getLeavesOfType("file-properties");
 | |
|         for (let i = 0; i < propertyLeaves.length; i++) {
 | |
|             const container = propertyLeaves[i].view.containerEl;
 | |
|             let observer = new MutationObserver((records, _) => {
 | |
|                 const file = this.app.workspace.getActiveFile();
 | |
|                 if (!!file) {
 | |
|                     updatePropertiesPane(container, this.app.workspace.getActiveFile(), this.app, plugin);
 | |
|                 }
 | |
|             });
 | |
|             observer.observe(container, { subtree: true, childList: true, attributes: false });
 | |
|             plugin.observers.push([observer, "file-properties" + i, ""]);
 | |
|             // TODO: No proper unloading!
 | |
|         }
 | |
|         plugin.registerViewType('file-properties', plugin, 'div.internal-link > .multi-select-pill-content');
 | |
|     }
 | |
|     initModalObservers(plugin, doc) {
 | |
|         const config = {
 | |
|             subtree: false,
 | |
|             childList: true,
 | |
|             attributes: false
 | |
|         };
 | |
|         this.modalObservers.push(new MutationObserver(records => {
 | |
|             records.forEach((mutation) => {
 | |
|                 if (mutation.type === 'childList') {
 | |
|                     mutation.addedNodes.forEach(n => {
 | |
|                         if ('className' in n &&
 | |
|                             // @ts-ignore
 | |
|                             (n.className.includes('modal-container') && plugin.settings.enableQuickSwitcher
 | |
|                                 // @ts-ignore
 | |
|                                 || n.className.includes('suggestion-container') && plugin.settings.enableSuggestor)) {
 | |
|                             let selector = ".suggestion-title, .suggestion-note, .another-quick-switcher__item__title, .omnisearch-result__title > span";
 | |
|                             // @ts-ignore
 | |
|                             if (n.className.includes('suggestion-container')) {
 | |
|                                 selector = ".suggestion-title, .suggestion-note";
 | |
|                             }
 | |
|                             plugin.updateContainer(n, plugin, selector);
 | |
|                             plugin._watchContainer(null, n, plugin, selector);
 | |
|                         }
 | |
|                     });
 | |
|                 }
 | |
|             });
 | |
|         }));
 | |
|         this.modalObservers.last().observe(doc.body, config);
 | |
|     }
 | |
|     registerViewType(viewTypeName, plugin, selector, updateDynamic = false, filter_collapsible = false) {
 | |
|         const leaves = this.app.workspace.getLeavesOfType(viewTypeName);
 | |
|         // if (leaves.length > 1) {
 | |
|         for (let i = 0; i < leaves.length; i++) {
 | |
|             const container = leaves[i].view.containerEl;
 | |
|             if (updateDynamic) {
 | |
|                 plugin._watchContainerDynamic(viewTypeName + i, container, plugin, selector);
 | |
|             }
 | |
|             else {
 | |
|                 plugin._watchContainer(viewTypeName + i, container, plugin, selector, filter_collapsible);
 | |
|             }
 | |
|         }
 | |
|         // }
 | |
|         // else if (leaves.length < 1) return;
 | |
|         // else {
 | |
|         // 	const container = leaves[0].view.containerEl;
 | |
|         // 	this.updateContainer(container, plugin, selector);
 | |
|         // 	if (updateDynamic) {
 | |
|         // 		plugin._watchContainerDynamic(viewTypeName, container, plugin, selector)
 | |
|         // 	}
 | |
|         // 	else {
 | |
|         // 		plugin._watchContainer(viewTypeName, container, plugin, selector);
 | |
|         // 	}
 | |
|         // }
 | |
|     }
 | |
|     updateContainer(container, plugin, selector, filter_collapsible = false) {
 | |
|         if (!plugin.settings.enableBacklinks && container.getAttribute("data-type") !== "file-explorer")
 | |
|             return;
 | |
|         if (!plugin.settings.enableFileList && container.getAttribute("data-type") === "file-explorer")
 | |
|             return;
 | |
|         const nodes = container.findAll(selector);
 | |
|         for (let i = 0; i < nodes.length; ++i) {
 | |
|             const el = nodes[i];
 | |
|             updateDivExtraAttributes(plugin.app, plugin.settings, el, "", undefined, filter_collapsible);
 | |
|         }
 | |
|     }
 | |
|     removeFromContainer(container, selector) {
 | |
|         const nodes = container.findAll(selector);
 | |
|         for (let i = 0; i < nodes.length; ++i) {
 | |
|             const el = nodes[i];
 | |
|             clearExtraAttributes(el);
 | |
|         }
 | |
|     }
 | |
|     _watchContainer(viewType, container, plugin, selector, filter_collapsible = false) {
 | |
|         let observer = new MutationObserver((records, _) => {
 | |
|             plugin.updateContainer(container, plugin, selector, filter_collapsible);
 | |
|         });
 | |
|         observer.observe(container, { subtree: true, childList: true, attributes: false });
 | |
|         if (viewType) {
 | |
|             plugin.observers.push([observer, viewType, selector]);
 | |
|         }
 | |
|     }
 | |
|     _watchContainerDynamic(viewType, container, plugin, selector, parent_class = 'tree-item') {
 | |
|         // Used for efficient updating of the backlinks panel
 | |
|         // Only loops through newly added DOM nodes instead of changing all of them
 | |
|         if (!plugin.settings.enableBacklinks)
 | |
|             return;
 | |
|         let observer = new MutationObserver((records, _) => {
 | |
|             records.forEach((mutation) => {
 | |
|                 if (mutation.type === 'childList') {
 | |
|                     mutation.addedNodes.forEach((n) => {
 | |
|                         if ('className' in n) {
 | |
|                             // @ts-ignore
 | |
|                             if (n.className.includes && typeof n.className.includes === 'function' && n.className.includes(parent_class)) {
 | |
|                                 const fileDivs = n.findAll(selector);
 | |
|                                 for (let i = 0; i < fileDivs.length; ++i) {
 | |
|                                     const link = fileDivs[i];
 | |
|                                     updateDivExtraAttributes(plugin.app, plugin.settings, link, "");
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     });
 | |
|                 }
 | |
|             });
 | |
|         });
 | |
|         observer.observe(container, { subtree: true, childList: true, attributes: false });
 | |
|         plugin.observers.push([observer, viewType, selector]);
 | |
|     }
 | |
|     onunload() {
 | |
|         this.observers.forEach(([observer, type, own_class]) => {
 | |
|             observer.disconnect();
 | |
|             const leaves = this.app.workspace.getLeavesOfType(type);
 | |
|             leaves.forEach(leaf => {
 | |
|                 this.removeFromContainer(leaf.view.containerEl, own_class);
 | |
|             });
 | |
|         });
 | |
|         for (const observer of this.modalObservers) {
 | |
|             observer.disconnect();
 | |
|         }
 | |
|         console.log('Supercharged links unloaded');
 | |
|     }
 | |
|     loadSettings() {
 | |
|         return __awaiter(this, void 0, void 0, function* () {
 | |
|             this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
 | |
|         });
 | |
|     }
 | |
|     saveSettings() {
 | |
|         return __awaiter(this, void 0, void 0, function* () {
 | |
|             yield this.saveData(this.settings);
 | |
|         });
 | |
|     }
 | |
| }
 | |
| 
 | |
| module.exports = SuperchargedLinks;
 | |
| 
 | |
| 
 | |
| /* nosourcemap */ |