@@ -147,21 +147,28 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
147
147
renderedMarkdown = elements . map ( e => typeof e === 'string' ? e : e . outerHTML ) . join ( '' ) ;
148
148
}
149
149
150
- const htmlParser = new DOMParser ( ) ;
151
- const markdownHtmlDoc = htmlParser . parseFromString ( sanitizeRenderedMarkdown ( renderedMarkdown , markdown . isTrusted ?? false , options . sanitizerConfig ) as unknown as string , 'text/html' ) ;
150
+ const renderedContent = document . createElement ( 'div' ) ;
151
+ const sanitizerConfig = getDomSanitizerConfig ( markdown . isTrusted ?? false , options . sanitizerConfig ?? { } ) ;
152
+ domSanitize . safeSetInnerHtml ( renderedContent , renderedMarkdown , sanitizerConfig ) ;
152
153
153
- rewriteRenderedLinks ( markdown , options , markdownHtmlDoc . body ) ;
154
+ // Rewrite links and images before potentially inserting them into the real dom
155
+ rewriteRenderedLinks ( markdown , options , renderedContent ) ;
154
156
155
- const element = target ?? document . createElement ( 'div' ) ;
156
- element . innerHTML = sanitizeRenderedMarkdown ( markdownHtmlDoc . body . innerHTML , markdown . isTrusted ?? false , options . sanitizerConfig ) as unknown as string ;
157
+ let outElement : HTMLElement ;
158
+ if ( target ) {
159
+ outElement = target ;
160
+ DOM . reset ( target , ...renderedContent . children ) ;
161
+ } else {
162
+ outElement = renderedContent ;
163
+ }
157
164
158
165
if ( codeBlocks . length > 0 ) {
159
166
Promise . all ( codeBlocks ) . then ( ( tuples ) => {
160
167
if ( isDisposed ) {
161
168
return ;
162
169
}
163
170
const renderedElements = new Map ( tuples ) ;
164
- const placeholderElements = element . querySelectorAll < HTMLDivElement > ( `div[data-code]` ) ;
171
+ const placeholderElements = outElement . querySelectorAll < HTMLDivElement > ( `div[data-code]` ) ;
165
172
for ( const placeholderElement of placeholderElements ) {
166
173
const renderedElement = renderedElements . get ( placeholderElement . dataset [ 'code' ] ?? '' ) ;
167
174
if ( renderedElement ) {
@@ -172,7 +179,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
172
179
} ) ;
173
180
} else if ( syncCodeBlocks . length > 0 ) {
174
181
const renderedElements = new Map ( syncCodeBlocks ) ;
175
- const placeholderElements = element . querySelectorAll < HTMLDivElement > ( `div[data-code]` ) ;
182
+ const placeholderElements = outElement . querySelectorAll < HTMLDivElement > ( `div[data-code]` ) ;
176
183
for ( const placeholderElement of placeholderElements ) {
177
184
const renderedElement = renderedElements . get ( placeholderElement . dataset [ 'code' ] ?? '' ) ;
178
185
if ( renderedElement ) {
@@ -183,7 +190,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
183
190
184
191
// Signal size changes for image tags
185
192
if ( options . asyncRenderCallback ) {
186
- for ( const img of element . getElementsByTagName ( 'img' ) ) {
193
+ for ( const img of outElement . getElementsByTagName ( 'img' ) ) {
187
194
const listener = disposables . add ( DOM . addDisposableListener ( img , 'load' , ( ) => {
188
195
listener . dispose ( ) ;
189
196
options . asyncRenderCallback ! ( ) ;
@@ -193,17 +200,17 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
193
200
194
201
// Add event listeners for links
195
202
if ( options . actionHandler ) {
196
- const onClick = options . actionHandler . disposables . add ( new DomEmitter ( element , 'click' ) ) ;
197
- const onAuxClick = options . actionHandler . disposables . add ( new DomEmitter ( element , 'auxclick' ) ) ;
203
+ const onClick = options . actionHandler . disposables . add ( new DomEmitter ( outElement , 'click' ) ) ;
204
+ const onAuxClick = options . actionHandler . disposables . add ( new DomEmitter ( outElement , 'auxclick' ) ) ;
198
205
options . actionHandler . disposables . add ( Event . any ( onClick . event , onAuxClick . event ) ( e => {
199
- const mouseEvent = new StandardMouseEvent ( DOM . getWindow ( element ) , e ) ;
206
+ const mouseEvent = new StandardMouseEvent ( DOM . getWindow ( outElement ) , e ) ;
200
207
if ( ! mouseEvent . leftButton && ! mouseEvent . middleButton ) {
201
208
return ;
202
209
}
203
210
activateLink ( markdown , options , mouseEvent ) ;
204
211
} ) ) ;
205
212
206
- options . actionHandler . disposables . add ( DOM . addDisposableListener ( element , 'keydown' , ( e ) => {
213
+ options . actionHandler . disposables . add ( DOM . addDisposableListener ( outElement , 'keydown' , ( e ) => {
207
214
const keyboardEvent = new StandardKeyboardEvent ( e ) ;
208
215
if ( ! keyboardEvent . equals ( KeyCode . Space ) && ! keyboardEvent . equals ( KeyCode . Enter ) ) {
209
216
return ;
@@ -213,7 +220,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
213
220
}
214
221
215
222
// Remove/disable inputs
216
- for ( const input of [ ...element . getElementsByTagName ( 'input' ) ] ) {
223
+ for ( const input of [ ...outElement . getElementsByTagName ( 'input' ) ] ) {
217
224
if ( input . attributes . getNamedItem ( 'type' ) ?. value === 'checkbox' ) {
218
225
input . setAttribute ( 'disabled' , '' ) ;
219
226
} else {
@@ -227,7 +234,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
227
234
}
228
235
229
236
return {
230
- element,
237
+ element : outElement ,
231
238
dispose : ( ) => {
232
239
isDisposed = true ;
233
240
disposables . dispose ( ) ;
0 commit comments