1- import { MarkdownPostProcessorContext , Plugin } from "obsidian" ;
1+ import { MarkdownPostProcessorContext , Notice , Plugin } from "obsidian" ;
22
33import "./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 } ;
0 commit comments