| 
									
										
										
										
											2022-07-31 13:10:20 -08:00
										 |  |  | <template> | 
					
						
							| 
									
										
										
										
											2025-06-26 21:58:31 +02:00
										 |  |  | <!-- eslint-disable-next-line vue/no-v-html is safe here because all HTML is sanitized with DOMPurify in setup() --> | 
					
						
							|  |  |  | <div v-html="value" /> | 
					
						
							| 
									
										
										
										
											2022-07-31 13:10:20 -08:00
										 |  |  | </template> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <script lang="ts"> | 
					
						
							|  |  |  | import DOMPurify from "isomorphic-dompurify"; | 
					
						
							| 
									
										
										
										
											2025-06-26 21:58:31 +02:00
										 |  |  | import { marked } from "marked"; | 
					
						
							| 
									
										
										
										
											2022-07-31 13:10:20 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | export default defineNuxtComponent({ | 
					
						
							| 
									
										
										
										
											2022-07-31 13:10:20 -08:00
										 |  |  |   props: { | 
					
						
							|  |  |  |     source: { | 
					
						
							|  |  |  |       type: String, | 
					
						
							|  |  |  |       default: "", | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }, | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |   setup(props) { | 
					
						
							| 
									
										
										
										
											2022-07-31 13:10:20 -08:00
										 |  |  |     function sanitizeMarkdown(rawHtml: string | null | undefined): string { | 
					
						
							|  |  |  |       if (!rawHtml) { | 
					
						
							|  |  |  |         return ""; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const sanitized = DOMPurify.sanitize(rawHtml, { | 
					
						
							| 
									
										
										
										
											2023-03-21 14:49:41 -05:00
										 |  |  |         // List based on
 | 
					
						
							|  |  |  |         // https://support.zendesk.com/hc/en-us/articles/4408824584602-Allowing-unsafe-HTML-in-help-center-articles
 | 
					
						
							|  |  |  |         ALLOWED_TAGS: [ | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           "strong", "em", "b", "i", "u", "p", "code", "pre", "samp", "kbd", "var", "sub", "sup", "dfn", "cite", | 
					
						
							|  |  |  |           "small", "address", "hr", "br", "id", "div", "span", "h1", "h2", "h3", "h4", "h5", "h6", | 
					
						
							|  |  |  |           "ul", "ol", "li", "dl", "dt", "dd", "abbr", "a", "img", "blockquote", "iframe", | 
					
						
							|  |  |  |           "del", "ins", "table", "thead", "tbody", "tfoot", "tr", "th", "td", "colgroup", | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2023-03-21 14:49:41 -05:00
										 |  |  |         ADD_ATTR: [ | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           "href", "src", "alt", "height", "width", "class", "allow", "title", "allowfullscreen", "frameborder", | 
					
						
							|  |  |  |           "scrolling", "cite", "datetime", "name", "abbr", "target", "border", | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-07-31 13:10:20 -08:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return sanitized; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     const value = computed(() => { | 
					
						
							| 
									
										
										
										
											2025-06-26 21:58:31 +02:00
										 |  |  |       const rawHtml = marked.parse(props.source || "", { async: false }); | 
					
						
							|  |  |  |       return sanitizeMarkdown(rawHtml); | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-31 13:10:20 -08:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       value, | 
					
						
							| 
									
										
										
										
											2022-07-31 13:10:20 -08:00
										 |  |  |     }; | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | </script> | 
					
						
							| 
									
										
										
										
											2024-12-11 03:33:43 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | <style scoped> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | :deep(table) { | 
					
						
							| 
									
										
										
										
											2024-12-11 03:33:43 -06:00
										 |  |  |   border-collapse: collapse; | 
					
						
							|  |  |  |   width: 100%; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-26 21:58:31 +02:00
										 |  |  | :deep(th), | 
					
						
							|  |  |  | :deep(td) { | 
					
						
							| 
									
										
										
										
											2024-12-11 03:33:43 -06:00
										 |  |  |   border: 1px solid; | 
					
						
							|  |  |  |   padding: 8px; | 
					
						
							|  |  |  |   text-align: left; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | :deep(th) { | 
					
						
							| 
									
										
										
										
											2024-12-11 03:33:43 -06:00
										 |  |  |   font-weight: bold; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-06-26 21:58:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | :deep(ul), | 
					
						
							|  |  |  | :deep(ol) { | 
					
						
							|  |  |  |   margin: 8px 0; | 
					
						
							|  |  |  |   padding-left: 20px; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-12-11 03:33:43 -06:00
										 |  |  | </style> |