@@ -303,17 +303,38 @@ const escapeJS = function (str) {
303
303
* @memberof IITC.utils
304
304
* @function escapeHtml
305
305
* @param {string } str - The string to escape.
306
+ * @param {string[] } [allowedTags] - Optional array of allowed HTML tags that should not be escaped.
306
307
* @returns {string } The escaped string.
307
308
*/
308
- const escapeHtml = function ( str ) {
309
+ const escapeHtml = function ( str , allowedTags = [ ] ) {
309
310
const escapeMap = {
310
311
'&' : '&' ,
311
312
'<' : '<' ,
312
313
'>' : '>' ,
313
314
'"' : '"' ,
314
315
"'" : ''' ,
315
316
} ;
316
- return str . replace ( / [ & < > " ' ] / g, ( char ) => escapeMap [ char ] ) ;
317
+
318
+ if ( allowedTags . length === 0 ) {
319
+ return str . replace ( / [ & < > " ' ] / g, ( char ) => escapeMap [ char ] ) ;
320
+ }
321
+
322
+ // Create pattern for allowed tags (self-closing and paired)
323
+ const allowedTagsPattern = new RegExp ( `(<\\/?(?:${ allowedTags . join ( '|' ) } )>)` , 'g' ) ;
324
+
325
+ // Split text by allowed tags to preserve them
326
+ const parts = str . split ( allowedTagsPattern ) ;
327
+
328
+ return parts
329
+ . map ( ( part ) => {
330
+ // If part matches allowed tags pattern, keep as is
331
+ if ( allowedTagsPattern . test ( part ) ) {
332
+ return part ;
333
+ }
334
+ // Otherwise, escape HTML
335
+ return part . replace ( / [ & < > " ' ] / g, ( char ) => escapeMap [ char ] ) ;
336
+ } )
337
+ . join ( '' ) ;
317
338
} ;
318
339
319
340
/**
@@ -387,7 +408,7 @@ const textToTable = function (text) {
387
408
for ( const row of rows ) {
388
409
let rowHtml = '<tr>' ;
389
410
for ( let k = 0 ; k < row . length ; k ++ ) {
390
- const cell = IITC . utils . escapeHtml ( row [ k ] ) ;
411
+ const cell = IITC . utils . escapeHtml ( row [ k ] , [ 'hr' , 'br' , 'b' , 'i' , 'strong' , 'em' ] ) ;
391
412
const colspan = k === 0 && row . length < columnCount ? ` colspan="${ columnCount - row . length + 1 } "` : '' ;
392
413
rowHtml += `<td${ colspan } >${ cell } </td>` ;
393
414
}
0 commit comments