12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283 |
- 'use strict';
- var obsidian = require('obsidian');
- var state = require('@codemirror/state');
- var view = require('@codemirror/view');
- var language = require('@codemirror/language');
- 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());
- });
- }
- 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);
- };
-
- 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 "<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}</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!`);
-
- 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");
-
- 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));
- });
- });
-
- 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));
- });
- });
-
- 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' });
-
- 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));
- });
- });
-
- 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();
- });
- });
-
- 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;
- }
- hash = Math.abs(hash);
- return hash;
- }
- function buildCSS(selectors, plugin) {
- var _a;
- return __awaiter(this, void 0, void 0, function* () {
- 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';
-
- }
- 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'));
-
- if (plugin.settings.activateSnippet) {
-
- const customCss = plugin.app.customCss;
- customCss.enabledSnippets.add('supercharged-links-gen');
- customCss.requestLoadSnippets();
- }
-
- 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;
-
- 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) {
-
- 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 name = "data-link-" + key;
- const newValue = new_props[key];
- const curValue = link.getAttribute(name);
-
- if (!newValue || curValue != newValue) {
- link.setAttribute("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) {
- const linkHref = link.getAttribute('href').split('#')[0];
- 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 (!linkName) {
- linkName = link.textContent;
- }
- 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 updateVisibleLinks(app, plugin) {
- const settings = plugin.settings;
- app.workspace.iterateRootLeaves((leaf) => {
- if (leaf.view instanceof obsidian.MarkdownView && leaf.view.file) {
- const file = leaf.view.file;
- const cachedFile = app.metadataCache.getFileCache(file);
-
- const tabHeader = leaf.tabHeaderInnerTitleEl;
- if (settings.enableTabHeader) {
-
- updateDivExtraAttributes(app, settings, tabHeader, "");
- }
- else {
- clearExtraAttributes(tabHeader);
- }
- if (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);
- }
- display() {
- let { containerEl } = this;
- containerEl.empty();
-
- 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.
- <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(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(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 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' });
-
- 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();
- }));
- });
-
- 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();
- }));
- });
-
- 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();
- }));
- });
-
-
- 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);
-
- });
- }
- 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);
-
- });
- formModal.open();
- });
- button.setButtonText("New");
- });
- }
- }
- const DEFAULT_SETTINGS = {
- targetAttributes: [],
- targetTags: true,
- getFromInlineField: true,
- enableTabHeader: true,
- activateSnippet: true,
- enableEditor: true,
- enableFileList: true,
- enableBacklinks: true,
- enableQuickSwitcher: true,
- enableSuggestor: true,
- selectors: []
- };
- function buildCMViewPlugin(app, _settings) {
-
-
-
- class HeaderWidget extends view.WidgetType {
- constructor(attributes, after) {
- super();
- this.attributes = attributes;
- this.after = after;
- }
- toDOM() {
- let headerEl = document.createElement("span");
- headerEl.setAttrs(this.attributes);
- if (this.after) {
- headerEl.addClass('data-link-icon-after');
- }
- else {
- headerEl.addClass('data-link-icon');
- }
-
- 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 || update.viewportChanged) {
- this.decorations = this.buildDecorations(update.view);
- }
- }
- destroy() {
- }
- buildDecorations(view$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) {
- language.syntaxTree(view$1.state).iterate({
- from,
- to,
- enter: (node) => {
- const tokenProps = node.type.prop(language.tokenClassNodeProp);
- if (tokenProps) {
- const props = new Set(tokenProps.split(" "));
- const isLink = props.has("hmd-internal-link");
- const isAlias = props.has("link-alias");
- const isPipe = props.has("link-alias-pipe");
-
- const isMDLink = props.has('link');
-
- const isMDUrl = props.has('url');
- const isMDFormatting = props.has('formatting-link');
- if (isMDLink && !isMDFormatting) {
-
-
- 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) {
-
- 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);
- });
- });
- };
-
- 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);
- });
-
- this.registerEvent(this.app.workspace.on("window-open", (window, win) => this.initModalObservers(this, window.getContainer().doc)));
-
-
- this.registerEvent(this.app.metadataCache.on('changed', obsidian.debounce(updateLinks, 500, true)));
-
-
- this.registerEvent(this.app.workspace.on("layout-change", obsidian.debounce(updateLinks, 10, true)));
-
-
- this.registerEvent(this.app.workspace.on("layout-change", () => this.initViewObservers(this)));
- });
- }
- initViewObservers(plugin) {
- var _a, _b, _c, _d, _e, _f;
-
- plugin.observers.forEach(([observer, type]) => {
- observer.disconnect();
- });
- plugin.observers = [];
-
- plugin.registerViewType('backlink', plugin, ".tree-item-inner", true);
- plugin.registerViewType('outgoing-link', plugin, ".tree-item-inner", true);
- plugin.registerViewType('search', plugin, ".tree-item-inner");
- plugin.registerViewType('BC-matrix', plugin, '.BC-Link');
- plugin.registerViewType('BC-ducks', plugin, '.internal-link');
- plugin.registerViewType('BC-tree', plugin, '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');
- plugin.registerViewType('recent-files', plugin, '.nav-file-title-content');
-
-
- if ((_f = (_e = (_d = (_c = (_b = (_a = plugin.app) === null || _a === void 0 ? void 0 : _a.internalPlugins) === null || _b === void 0 ? void 0 : _b.plugins) === null || _c === void 0 ? void 0 : _c.backlink) === null || _d === void 0 ? void 0 : _d.instance) === null || _e === void 0 ? void 0 : _e.options) === null || _f === void 0 ? void 0 : _f.backlinkInDocument) {
- plugin.registerViewType('markdown', plugin, '.tree-item-inner', true);
- }
- }
- 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 &&
-
- (n.className.includes('modal-container') && plugin.settings.enableQuickSwitcher
-
- || n.className.includes('suggestion-container') && plugin.settings.enableSuggestor)) {
- let selector = ".suggestion-title, .suggestion-note, .another-quick-switcher__item__title, .omnisearch-result__title";
-
- 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) {
- 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);
- }
- }
- }
- 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) {
- if (!plugin.settings.enableBacklinks)
- return;
- const nodes = container.findAll(selector);
- for (let i = 0; i < nodes.length; ++i) {
- const el = nodes[i];
- updateDivExtraAttributes(plugin.app, plugin.settings, el, "");
- }
- }
- 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) {
- let observer = new MutationObserver((records, _) => {
- plugin.updateContainer(container, plugin, selector);
- });
- observer.observe(container, { subtree: true, childList: true, attributes: false });
- if (viewType) {
- plugin.observers.push([observer, viewType, selector]);
- }
- }
- _watchContainerDynamic(viewType, container, plugin, selector, own_class = 'tree-item-inner', parent_class = 'tree-item') {
-
-
- let observer = new MutationObserver((records, _) => {
- records.forEach((mutation) => {
- if (mutation.type === 'childList') {
- mutation.addedNodes.forEach((n) => {
- if ('className' in n) {
-
- if (n.className.includes && typeof n.className.includes === 'function' && n.className.includes(parent_class)) {
- const fileDivs = n.getElementsByClassName(own_class);
- 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;
|