@@ -124,62 +124,8 @@ export function generateHtml(context: Context, mdRelPath: string, mdPage: Markdo
124
124
// Add the Markdown content to the search index
125
125
context . searchIndex . addMarkdownPage ( md , htmlRelPath )
126
126
127
- // Customize HTML generation
128
- marked . use ( {
129
- renderer : {
130
- // Transform special `glossary:` definition links to include a tooltip
131
- // and a link to the glossary page/definition
132
- link : ( href , title , text ) => {
133
- let classPart : string
134
- let textPart : string
135
- let hrefPart : string
136
- const m = href . match ( / g l o s s a r y : ( \w + ) / )
137
- if ( m ) {
138
- // This is a glossary link; insert a tooltip element
139
- const termKey = m [ 1 ]
140
- const tooltipText = context . getBlockText ( `glossary__${ termKey } __def` )
141
- if ( tooltipText === undefined ) {
142
- throw new Error (
143
- context . getScopedMessage ( `No glossary definition found for key=${ termKey } ` )
144
- )
145
- }
146
- const tooltipHtml = marked . parseInline ( tooltipText ) . replace ( / \n / g, '<br/>' )
147
- classPart = ' class="glossary-link"'
148
- textPart = `${ text } <span class="tooltip"><span class="tooltip-arrow"> </span>${ tooltipHtml } </span>`
149
- // TODO: This path assumes the page is in the `guide` directory; need to fix
150
- // this if we include glossary links on the index page
151
- hrefPart = ` href="./glossary.html#glossary__${ termKey } "`
152
- } else {
153
- // This is a normal link
154
- classPart = ''
155
- textPart = text
156
- hrefPart = href ? ` href="${ href } "` : ''
157
- }
158
-
159
- const titlePart = title ? ` title="${ title } "` : ''
160
- return `<a${ classPart } ${ hrefPart } ${ titlePart } >${ subscriptify ( textPart ) } </a>`
161
- } ,
162
-
163
- // Wrap tables in a div to allow for responsive scrolling behavior
164
- table : ( header , body ) => {
165
- let classes = 'table-container'
166
- if ( mdRelPath . includes ( 'tech_removal' ) ) {
167
- // XXX: Include a special class for the "CDR Methods" table on the Tech CDR page
168
- // in the En-ROADS User Guide so that we can target it in CSS. Currently we
169
- // check the number of rows to differentiate it from the other slider settings
170
- // table on that page.
171
- const rowTags = [ ...body . matchAll ( / < t r > / g) ]
172
- if ( rowTags . length > 1 ) {
173
- classes += ' removal_methods'
174
- }
175
- }
176
- return `<div class="${ classes } "><table><thead>${ header } </thead><tbody>${ body } </tbody></table></div>`
177
- }
178
- }
179
- } )
180
-
181
- // Parse the Markdown into HTML
182
- const body = marked . parse ( md )
127
+ // Convert the Markdown content to HTML
128
+ const body = convertMarkdownToHtml ( context , md )
183
129
184
130
// Clear the current page
185
131
context . setCurrentPage ( undefined )
@@ -237,9 +183,6 @@ export function writeHtmlFile(
237
183
// in a separate tab automatically
238
184
body = body . replace ( / ( h r e f = " h t t p ( .* ?) " ) / g, 'target="_blank" rel="noopener noreferrer" $1' )
239
185
240
- // Convert substrings like "CO2" to subscripted form ("CO<sub>2</sub>")
241
- body = subscriptify ( body )
242
-
243
186
// Get the path to the logo image
244
187
let logoPath : string
245
188
if ( context . config . logoPath ?. length > 0 && templateName !== 'simple' ) {
@@ -559,6 +502,80 @@ const subscriptMap = new Map([
559
502
[ 'SF6' , 'SF<sub>6</sub>' ]
560
503
] )
561
504
505
+ /**
506
+ * Convert the given Markdown content to HTML, applying custom conversions.
507
+ *
508
+ * @param context The language-specific context.
509
+ * @param md The Markdown content.
510
+ * @return The resulting HTML content.
511
+ */
512
+ export function convertMarkdownToHtml ( context : Context , md : string ) : string {
513
+ // Customize HTML generation
514
+ marked . use ( {
515
+ renderer : {
516
+ // Convert substrings like "CO2" to subscripted form ("CO<sub>2</sub>").
517
+ // Performing this conversion on text elements only ensures that we don't
518
+ // affect other things like URLs or image paths.
519
+ text : text => {
520
+ return subscriptify ( text )
521
+ } ,
522
+
523
+ // Transform special `glossary:` definition links to include a tooltip
524
+ // and a link to the glossary page/definition
525
+ link : ( href , title , text ) => {
526
+ let classPart : string
527
+ let textPart : string
528
+ let hrefPart : string
529
+ const m = href . match ( / g l o s s a r y : ( \w + ) / )
530
+ if ( m ) {
531
+ // This is a glossary link; insert a tooltip element
532
+ const termKey = m [ 1 ]
533
+ const tooltipText = context . getBlockText ( `glossary__${ termKey } __def` )
534
+ if ( tooltipText === undefined ) {
535
+ throw new Error (
536
+ context . getScopedMessage ( `No glossary definition found for key=${ termKey } ` )
537
+ )
538
+ }
539
+ const tooltipHtml = marked . parseInline ( tooltipText ) . replace ( / \n / g, '<br/>' )
540
+ classPart = ' class="glossary-link"'
541
+ textPart = `${ text } <span class="tooltip"><span class="tooltip-arrow"> </span>${ tooltipHtml } </span>`
542
+ // TODO: This path assumes the page is in the `guide` directory; need to fix
543
+ // this if we include glossary links on the index page
544
+ hrefPart = ` href="./glossary.html#glossary__${ termKey } "`
545
+ } else {
546
+ // This is a normal link
547
+ classPart = ''
548
+ textPart = text
549
+ hrefPart = href ? ` href="${ href } "` : ''
550
+ }
551
+
552
+ const titlePart = title ? ` title="${ title } "` : ''
553
+ return `<a${ classPart } ${ hrefPart } ${ titlePart } >${ subscriptify ( textPart ) } </a>`
554
+ } ,
555
+
556
+ // Wrap tables in a div to allow for responsive scrolling behavior
557
+ table : ( header , body ) => {
558
+ const mdRelPath = context . getCurrentPage ( )
559
+ let classes = 'table-container'
560
+ if ( mdRelPath . includes ( 'tech_removal' ) ) {
561
+ // XXX: Include a special class for the "CDR Methods" table on the Tech CDR page
562
+ // in the En-ROADS User Guide so that we can target it in CSS. Currently we
563
+ // check the number of rows to differentiate it from the other slider settings
564
+ // table on that page.
565
+ const rowTags = [ ...body . matchAll ( / < t r > / g) ]
566
+ if ( rowTags . length > 1 ) {
567
+ classes += ' removal_methods'
568
+ }
569
+ }
570
+ return `<div class="${ classes } "><table><thead>${ header } </thead><tbody>${ body } </tbody></table></div>`
571
+ }
572
+ }
573
+ } )
574
+
575
+ // Parse the Markdown into HTML
576
+ return marked . parse ( md )
577
+ }
578
+
562
579
/**
563
580
* Replace non-subscript forms of common chemicals with their subscripted equivalent.
564
581
* For example, "CO2" will be converted to "CO<sub>2</sub>". This only handles
@@ -576,15 +593,8 @@ const subscriptMap = new Map([
576
593
* @param s The input string.
577
594
* @return A new string containing subscripted chemical names.
578
595
*/
579
- function subscriptify ( s : string ) : string {
580
- // XXX: Some historical graph images in the En-ROADS User Guide have
581
- // {CO2,CH4,N2O} in the file name, so this regex is set up to avoid
582
- // converting those filenames
583
- return s . replace ( / ( H i s t _ ) ? ( C O 2 | C F 4 | C H 4 | H 2 O | N 2 O | N F 3 | O 2 | O 3 | S F 6 ) / g, ( m , m1 , m2 ) => {
584
- if ( m1 ) {
585
- return m
586
- } else {
587
- return subscriptMap . get ( m2 )
588
- }
596
+ export function subscriptify ( s : string ) : string {
597
+ return s . replace ( / ( C O 2 | C F 4 | C H 4 | H 2 O | N 2 O | N F 3 | O 2 | O 3 | S F 6 ) / g, ( _m , m1 ) => {
598
+ return subscriptMap . get ( m1 )
589
599
} )
590
600
}
0 commit comments