Skip to content

Commit 10da75e

Browse files
committed
Revert to a previous version
1 parent 34132e9 commit 10da75e

File tree

3 files changed

+175
-128
lines changed

3 files changed

+175
-128
lines changed

Diff for: manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "obsidian-basetag",
33
"name": "Base Tag Renderer",
4-
"version": "1.1.1",
4+
"version": "1.1.2",
55
"minAppVersion": "0.15.0",
66
"description": "This plugin renders the basename of tags in preview mode.",
77
"author": "Darren Kuro",

Diff for: src/main.ts

+36-127
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,47 @@
11
import { Plugin } from "obsidian";
2-
import { syntaxTree } from "@codemirror/language";
3-
import { RangeSetBuilder } from "@codemirror/state";
4-
import {
5-
Decoration,
6-
DecorationSet,
7-
EditorView,
8-
PluginValue,
9-
ViewPlugin,
10-
ViewUpdate,
11-
WidgetType,
12-
} from "@codemirror/view";
13-
import { livePreviewState } from "obsidian";
142

153
const BASETAG = "basename-tag";
164

17-
/** Get the current vault name. */
18-
const getVaultName = () => window.app.vault.getName();
19-
20-
/** Create a custom tag node from text content (can include #). */
21-
const createTagNode = (text: string | null) => {
22-
const node = document.createElement("a");
23-
if (!text) return node;
24-
25-
// Keep the 'tag' class for consistent css styles.
26-
node.className = `tag ${BASETAG}`;
27-
node.target = "_blank";
28-
node.rel = "noopener";
29-
node.href = text;
30-
31-
const vaultStr = encodeURIComponent(getVaultName());
32-
const queryStr = `tag:${encodeURIComponent(text)}`;
33-
node.dataset.uri = `obsidian://search?vault=${vaultStr}&query=${queryStr}`;
34-
35-
// Remove the hash tags to conform to the same style.
36-
node.textContent = text.slice(text.lastIndexOf("/") + 1).replaceAll("#", "");
37-
38-
node.onclick = () => window.open(node.dataset.uri);
39-
40-
return node;
41-
};
42-
43-
/** Create a tag node in the type of widget from text content. */
44-
class TagWidget extends WidgetType {
45-
constructor(private text: string) {
46-
super();
47-
}
48-
49-
toDOM(view: EditorView): HTMLElement {
50-
return createTagNode(this.text);
51-
}
52-
}
53-
54-
class editorPlugin implements PluginValue {
55-
decorations: DecorationSet;
56-
57-
constructor(view: EditorView) {
58-
this.decorations = this.buildDecorations(view);
59-
}
60-
61-
update(update: ViewUpdate): void {
62-
if (
63-
update.view.composing ||
64-
update.view.plugin(livePreviewState)?.mousedown
65-
) {
66-
this.decorations = this.decorations.map(update.changes);
67-
} else if (update.selectionSet || update.viewportChanged) {
68-
this.decorations = this.buildDecorations(update.view);
69-
}
70-
}
71-
72-
private buildDecorations(view: EditorView): DecorationSet {
73-
const builder = new RangeSetBuilder<Decoration>();
74-
75-
for (const { from, to } of view.visibleRanges) {
76-
syntaxTree(view.state).iterate({
77-
from,
78-
to,
79-
enter: (node) => {
80-
// Known issues: do not support live preview in some cases (i.e. under callout list)
81-
// Do not support frontmatter (fixable)
82-
83-
// Handle tags that's in the main content.
84-
if (node.name.contains("hashtag-end")) {
85-
// Do not render if falls under selection (cursor) range.
86-
const extendedFrom = node.from - 1;
87-
const extendedTo = node.to + 1;
88-
89-
for (const range of view.state.selection.ranges) {
90-
if (extendedFrom <= range.to && range.from < extendedTo) {
91-
return;
92-
}
93-
}
94-
95-
const text = view.state.sliceDoc(node.from, node.to);
96-
const lastIndex = text.lastIndexOf("/");
97-
if (lastIndex < 0) {
98-
return;
99-
}
100-
101-
builder.add(
102-
node.from - 1,
103-
node.to,
104-
Decoration.replace({
105-
widget: new TagWidget(text),
106-
}),
107-
);
108-
}
109-
},
110-
});
111-
}
112-
113-
return builder.finish();
114-
}
115-
}
116-
1175
export default class TagRenderer extends Plugin {
1186
async onload() {
119-
this.registerEditorExtension(
120-
ViewPlugin.fromClass(editorPlugin, {
121-
decorations: (value) => value.decorations,
122-
}),
123-
);
124-
1257
this.registerMarkdownPostProcessor((el: HTMLElement) => {
1268
// Find the original tags to render.
127-
el.querySelectorAll(`a.tag:not(.${BASETAG})`).forEach(
128-
(node: HTMLAnchorElement) => {
129-
// Remove class 'tag' so it doesn't get rendered again.
130-
node.removeAttribute("class");
131-
// Hide this node and append the custom tag node in its place.
132-
node.style.display = "none";
133-
node.parentNode?.insertBefore(createTagNode(node.textContent), node);
134-
},
135-
);
9+
el.querySelectorAll(`a.tag:not(.${BASETAG})`).forEach((a) => {
10+
this.formatTag(a as HTMLAnchorElement);
11+
});
13612
});
13713
}
14+
15+
private formatTag(el: HTMLAnchorElement) {
16+
/** Create a custom tag node. */
17+
const createTagNode = (text: string | null) => {
18+
const node = document.createElement("a");
19+
if (!text) return node;
20+
21+
// Keep the 'tag' class for consistent css styles.
22+
node.className = `tag ${BASETAG}`;
23+
node.target = "_blank";
24+
node.rel = "noopener";
25+
node.href = text;
26+
27+
const vaultStr = encodeURIComponent(this.app.vault.getName());
28+
const queryStr = `tag:${encodeURIComponent(text)}`;
29+
node.dataset.uri = `obsidian://search?vault=${vaultStr}&query=${queryStr}`;
30+
31+
// Remove the hash tags to conform to the same style.
32+
node.textContent = text
33+
.slice(text.lastIndexOf("/") + 1)
34+
.replaceAll("#", "");
35+
36+
node.onclick = () => window.open(node.dataset.uri);
37+
38+
return node;
39+
};
40+
41+
// Remove class 'tag' so it doesn't get rendered again.
42+
el.removeAttribute("class");
43+
// Hide this node and append the custom tag node in its place.
44+
el.style.display = "none";
45+
el.parentNode?.insertBefore(createTagNode(el.textContent), el);
46+
}
13847
}

Diff for: src/mainnew.ts

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { Plugin } from "obsidian";
2+
import { syntaxTree } from "@codemirror/language";
3+
import { RangeSetBuilder } from "@codemirror/state";
4+
import {
5+
Decoration,
6+
DecorationSet,
7+
EditorView,
8+
PluginValue,
9+
ViewPlugin,
10+
ViewUpdate,
11+
WidgetType,
12+
} from "@codemirror/view";
13+
import { livePreviewState } from "obsidian";
14+
15+
const BASETAG = "basename-tag";
16+
17+
/** Get the current vault name. */
18+
const getVaultName = () => window.app.vault.getName();
19+
20+
/** Create a custom tag node from text content (can include #). */
21+
const createTagNode = (text: string | null) => {
22+
const node = document.createElement("a");
23+
if (!text) return node;
24+
25+
// Keep the 'tag' class for consistent css styles.
26+
node.className = `tag ${BASETAG}`;
27+
node.target = "_blank";
28+
node.rel = "noopener";
29+
node.href = text;
30+
31+
const vaultStr = encodeURIComponent(getVaultName());
32+
const queryStr = `tag:${encodeURIComponent(text)}`;
33+
node.dataset.uri = `obsidian://search?vault=${vaultStr}&query=${queryStr}`;
34+
35+
// Remove the hash tags to conform to the same style.
36+
node.textContent = text.slice(text.lastIndexOf("/") + 1).replaceAll("#", "");
37+
38+
node.onclick = () => window.open(node.dataset.uri);
39+
40+
return node;
41+
};
42+
43+
/** Create a tag node in the type of widget from text content. */
44+
class TagWidget extends WidgetType {
45+
constructor(private text: string) {
46+
super();
47+
}
48+
49+
toDOM(view: EditorView): HTMLElement {
50+
return createTagNode(this.text);
51+
}
52+
}
53+
54+
class editorPlugin implements PluginValue {
55+
decorations: DecorationSet;
56+
57+
constructor(view: EditorView) {
58+
this.decorations = this.buildDecorations(view);
59+
}
60+
61+
update(update: ViewUpdate): void {
62+
if (
63+
update.view.composing ||
64+
update.view.plugin(livePreviewState)?.mousedown
65+
) {
66+
this.decorations = this.decorations.map(update.changes);
67+
} else if (update.selectionSet || update.viewportChanged) {
68+
this.decorations = this.buildDecorations(update.view);
69+
}
70+
}
71+
72+
private buildDecorations(view: EditorView): DecorationSet {
73+
const builder = new RangeSetBuilder<Decoration>();
74+
75+
for (const { from, to } of view.visibleRanges) {
76+
syntaxTree(view.state).iterate({
77+
from,
78+
to,
79+
enter: (node) => {
80+
// Known issues: do not support live preview in some cases (i.e. under callout list)
81+
// Do not support frontmatter (fixable)
82+
83+
// Handle tags that's in the main content.
84+
if (node.name.contains("hashtag-end")) {
85+
// Do not render if falls under selection (cursor) range.
86+
const extendedFrom = node.from - 1;
87+
const extendedTo = node.to + 1;
88+
89+
for (const range of view.state.selection.ranges) {
90+
if (extendedFrom <= range.to && range.from < extendedTo) {
91+
return;
92+
}
93+
}
94+
95+
const text = view.state.sliceDoc(node.from, node.to);
96+
const lastIndex = text.lastIndexOf("/");
97+
if (lastIndex < 0) {
98+
return;
99+
}
100+
101+
builder.add(
102+
node.from - 1,
103+
node.to,
104+
Decoration.replace({
105+
widget: new TagWidget(text),
106+
}),
107+
);
108+
}
109+
},
110+
});
111+
}
112+
113+
return builder.finish();
114+
}
115+
}
116+
117+
export default class TagRenderer2 extends Plugin {
118+
async onload() {
119+
this.registerEditorExtension(
120+
ViewPlugin.fromClass(editorPlugin, {
121+
decorations: (value) => value.decorations,
122+
}),
123+
);
124+
125+
this.registerMarkdownPostProcessor((el: HTMLElement) => {
126+
// Find the original tags to render.
127+
el.querySelectorAll(`a.tag:not(.${BASETAG})`).forEach(
128+
(node: HTMLAnchorElement) => {
129+
// Remove class 'tag' so it doesn't get rendered again.
130+
node.removeAttribute("class");
131+
// Hide this node and append the custom tag node in its place.
132+
node.style.display = "none";
133+
node.parentNode?.insertBefore(createTagNode(node.textContent), node);
134+
},
135+
);
136+
});
137+
}
138+
}

0 commit comments

Comments
 (0)