Skip to content

Commit f506641

Browse files
committed
0.1.0
Removed admonition.ts Added fastIntersection function Updated documentation
1 parent 53c0515 commit f506641

File tree

6 files changed

+127
-124
lines changed

6 files changed

+127
-124
lines changed

README.md

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Obsidian Admonition
22

3-
Adds admonition block-styled content to Obsidian.md
3+
Adds admonition block-styled content to Obsidian.md, styled after [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/reference/admonitions/)
4+
5+
![](https://raw.githubusercontent.com/valentine195/obsidian-admonition/master/images/all.gif)
46

57
## Usage
68

@@ -12,9 +14,19 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla.
1214
```
1315
````
1416

15-
This will then render as the admonition:
17+
Becomes:
18+
19+
![](https://raw.githubusercontent.com/valentine195/obsidian-admonition/master/images/default.png)
1620

17-
<img src="https://i.imgur.com/295CZkD.png">
21+
## Options
22+
23+
````markdown
24+
```<type> # Admonition type. See below for a list of available types.
25+
title: # Admonition title. Leave blank to remove the title element and display only the content.
26+
collapse: # Create a collapsible admonition. Use "open" to initially render the admonition open.
27+
content: # Actual text of admonition. Only required if "title" or "collapse" is used.
28+
```
29+
````
1830

1931
### Titles
2032

@@ -27,27 +39,32 @@ content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euism
2739
```
2840
````
2941

30-
<img src="https://i.imgur.com/pBTJAFa.png">
42+
![](https://raw.githubusercontent.com/valentine195/obsidian-admonition/master/images/title.png)
3143

3244
Leave the title field blank to only display the admonition.
45+
3346
````markdown
3447
```note
3548
title:
3649
content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla.
3750
```
3851
````
3952

40-
<img src="https://i.imgur.com/pNU2MB7.png">
53+
![](https://raw.githubusercontent.com/valentine195/obsidian-admonition/master/images/no-title.png)
4154

42-
**Please note that when the title is included, you _must_ specificy the content as well.**
55+
**Please note that when the title is included, you _must_ specify the content as well.**
4356

4457
### Collapsible
4558

46-
Use `collapse: open` or `collapse: closed` to create a collapsible admonition.
59+
Use the `collapse` parameter to create a collapsible admonition.
60+
61+
`collapse: open` will start the admonition opened on render, but allow collapse on click.
62+
63+
If a blank title is provided, the collapse parameter will not do anything.
4764

48-
`collapse: open` will startthe admonition opened on render.
65+
![](https://raw.githubusercontent.com/valentine195/obsidian-admonition/master/images/collapse.gif)
4966

50-
<img width='640px' src="https://thumbs.gfycat.com/UniqueVillainousHarpseal-size_restricted.gif">
67+
**Please note that when the title is included, you _must_ specify the content as well.**
5168

5269
## Admonition Types
5370

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "obsidian-admonition",
33
"name": "Admonition",
4-
"version": "0.0.5",
4+
"version": "0.1.0",
55
"minAppVersion": "0.11.0",
66
"description": "Admonition block-styled content for Obsidian.md",
77
"author": "Jeremy Valentine",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-admonition",
3-
"version": "0.0.5",
3+
"version": "0.1.0",
44
"description": "Admonition block-styled content for Obsidian.md",
55
"main": "main.js",
66
"scripts": {

src/admonitions.ts

Lines changed: 0 additions & 63 deletions
This file was deleted.

src/main.ts

Lines changed: 98 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,112 @@
1-
import { MarkdownPostProcessorContext, Plugin } from "obsidian";
1+
import { MarkdownPostProcessorContext, Notice, Plugin } from "obsidian";
22

33
import "./main.css";
4-
import ADMONITION_MAP from "./admonitions";
54

6-
export default class Admonition extends Plugin {
5+
const ADMONITION_MAP: {
6+
[admonitionType: string]: string;
7+
} = {
8+
note: "note",
9+
seealso: "note",
10+
abstract: "abstract",
11+
summary: "abstract",
12+
info: "info",
13+
todo: "todo",
14+
tip: "tip",
15+
hint: "tip",
16+
important: "tip",
17+
success: "success",
18+
check: "check",
19+
done: "done",
20+
question: "question",
21+
help: "question",
22+
faq: "question",
23+
warning: "warning",
24+
caution: "warning",
25+
attention: "warning",
26+
failure: "failure",
27+
fail: "failure",
28+
missing: "failure",
29+
danger: "danger",
30+
error: "danger",
31+
bug: "bug",
32+
example: "example",
33+
quote: "quote",
34+
cite: "quote"
35+
};
36+
const classMap = Object.keys(ADMONITION_MAP).map((k) => `language-${k}`);
37+
38+
/** Fast Intersection taken from
39+
* https://codeburst.io/optimizing-array-analytics-in-javascript-part-two-search-intersection-and-cross-products-79b4a6d68da0
40+
*/
41+
const fastIntersection = (...arrays: any[]) => {
42+
// if we process the arrays from shortest to longest
43+
// then we will identify failure points faster, i.e. when
44+
// one item is not in all arrays
45+
const ordered =
46+
arrays.length === 1
47+
? arrays
48+
: arrays.sort((a1, a2) => a1.length - a2.length),
49+
shortest = ordered[0],
50+
set = new Set(), // used for bookeeping, Sets are faster
51+
result = []; // the intersection, conversion from Set is slow
52+
// for each item in the shortest array
53+
for (let i = 0; i < shortest.length; i++) {
54+
const item = shortest[i];
55+
// see if item is in every subsequent array
56+
let every = true; // don't use ordered.every ... it is slow
57+
for (let j = 1; j < ordered.length; j++) {
58+
if (ordered[j].includes(item)) continue;
59+
every = false;
60+
break;
61+
}
62+
// ignore if not in every other array, or if already captured
63+
if (!every || set.has(item)) continue;
64+
// otherwise, add to bookeeping set and the result
65+
set.add(item);
66+
result[result.length] = item;
67+
}
68+
return result;
69+
};
70+
export default class ObsidianAdmonition extends Plugin {
771
async onload(): Promise<void> {
872
console.log("Obsidian Admonition loaded");
973

1074
this.registerMarkdownPostProcessor(this.postprocessor.bind(this));
1175
}
1276
postprocessor(el: HTMLElement, ctx: MarkdownPostProcessorContext) {
13-
/* */
77+
//don't process if no code elements in element;
1478
let codeBlocks = el.querySelectorAll("code");
1579
if (!codeBlocks.length) return;
16-
const classMap = Object.keys(ADMONITION_MAP).map(
17-
(k) => `language-${k}`
18-
);
1980

20-
codeBlocks = Array.prototype.map
21-
.call(
22-
codeBlocks,
23-
(element: HTMLElement): HTMLElement => {
24-
if (element) {
25-
const classList = Array.prototype.filter.call(
26-
element.classList,
27-
(cls: string) => classMap.includes(cls)
28-
);
29-
if (classList.length) return element;
30-
}
31-
}
32-
)
33-
.filter((b: HTMLElement) => b);
81+
//don't process if the code block is not an admonition type
82+
codeBlocks = Array.prototype.filter.call(
83+
codeBlocks,
84+
(element: HTMLElement) =>
85+
element &&
86+
fastIntersection(
87+
Array.prototype.slice.call(element.classList),
88+
classMap
89+
).length > 0
90+
);
3491
if (!codeBlocks.length) return;
3592

93+
//render admonition element
3694
codeBlocks.forEach((block) => {
3795
if (block) {
38-
let classType = Array.prototype.find.call(
39-
block.classList,
40-
(cls: string) => classMap.includes(cls)
41-
);
42-
if (!classType) return;
4396
let type =
44-
ADMONITION_MAP[classType.split("language-").pop().trim()];
45-
if (!type) return;
97+
ADMONITION_MAP[
98+
Array.prototype.find
99+
.call(block.classList, (cls: string) =>
100+
classMap.includes(cls)
101+
)
102+
.split("language-")
103+
.pop()
104+
.trim()
105+
];
106+
if (!type) {
107+
new Notice("There was an error rendering the admonition.");
108+
return;
109+
}
46110
let params = Object.fromEntries(
47111
block.innerText
48112
.split("\n")
@@ -53,13 +117,6 @@ export default class Admonition extends Plugin {
53117
content = block.innerText,
54118
collapse
55119
} = params;
56-
console.log(
57-
"🚀 ~ file: main.ts ~ line 56 ~ Admonition ~ codeBlocks.forEach ~ params",
58-
params,
59-
block.innerText
60-
.split("\n")
61-
.map((l) => l.split(":").map((s) => s.trim()))
62-
);
63120

64121
if (
65122
Object.prototype.hasOwnProperty.call(params, "title") &&
@@ -71,14 +128,12 @@ export default class Admonition extends Plugin {
71128
if (
72129
Object.prototype.hasOwnProperty.call(params, "collapse") &&
73130
(params.collapse.length == 0 ||
74-
params.collapse === undefined)
131+
params.collapse === undefined ||
132+
collapse !== "open")
75133
) {
76134
collapse = "closed";
77135
}
78-
console.log(
79-
"🚀 ~ file: main.ts ~ line 69 ~ Admonition ~ codeBlocks.forEach ~ params.collapse",
80-
collapse
81-
);
136+
82137
this.buildAdmonition(
83138
block.parentElement,
84139
type,
@@ -97,15 +152,9 @@ export default class Admonition extends Plugin {
97152
collapse?: string
98153
) {
99154
let attrs,
100-
els = [
101-
"div" as keyof HTMLElementTagNameMap,
102-
"div" as keyof HTMLElementTagNameMap
103-
];
104-
if (collapse && ["open", "closed"].includes(collapse)) {
105-
els = [
106-
"details" as keyof HTMLElementTagNameMap,
107-
"summary" as keyof HTMLElementTagNameMap
108-
];
155+
els: Array<keyof HTMLElementTagNameMap> = ["div", "div"];
156+
if (collapse) {
157+
els = ["details", "summary"];
109158
attrs = {
110159
[collapse]: true
111160
};

versions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"0.0.5": "0.11.0"
2+
"0.1.0": "0.11.0"
33
}

0 commit comments

Comments
 (0)