@memberjunction/ng-markdown 5.43.0 → 5.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/__tests__/markdown.service.dom.test.d.ts +2 -0
  2. package/dist/__tests__/markdown.service.dom.test.d.ts.map +1 -0
  3. package/dist/__tests__/markdown.service.dom.test.js +86 -0
  4. package/dist/__tests__/markdown.service.dom.test.js.map +1 -0
  5. package/dist/__tests__/web-dom-utils.test.d.ts +2 -0
  6. package/dist/__tests__/web-dom-utils.test.d.ts.map +1 -0
  7. package/dist/__tests__/web-dom-utils.test.js +160 -0
  8. package/dist/__tests__/web-dom-utils.test.js.map +1 -0
  9. package/dist/lib/components/markdown.component.d.ts +1 -1
  10. package/dist/lib/components/markdown.component.d.ts.map +1 -1
  11. package/dist/lib/components/markdown.component.dom.test.d.ts +2 -0
  12. package/dist/lib/components/markdown.component.dom.test.d.ts.map +1 -0
  13. package/dist/lib/components/markdown.component.dom.test.js +81 -0
  14. package/dist/lib/components/markdown.component.dom.test.js.map +1 -0
  15. package/dist/lib/components/markdown.component.js +1 -1
  16. package/dist/lib/components/markdown.component.js.map +1 -1
  17. package/dist/lib/extensions/code-copy.extension.d.ts +0 -7
  18. package/dist/lib/extensions/code-copy.extension.d.ts.map +1 -1
  19. package/dist/lib/extensions/code-copy.extension.js +1 -58
  20. package/dist/lib/extensions/code-copy.extension.js.map +1 -1
  21. package/dist/lib/extensions/collapsible-headings.extension.d.ts +5 -67
  22. package/dist/lib/extensions/collapsible-headings.extension.d.ts.map +1 -1
  23. package/dist/lib/extensions/collapsible-headings.extension.js +5 -179
  24. package/dist/lib/extensions/collapsible-headings.extension.js.map +1 -1
  25. package/dist/lib/extensions/svg-renderer.extension.d.ts +5 -28
  26. package/dist/lib/extensions/svg-renderer.extension.d.ts.map +1 -1
  27. package/dist/lib/extensions/svg-renderer.extension.js +5 -72
  28. package/dist/lib/extensions/svg-renderer.extension.js.map +1 -1
  29. package/dist/lib/services/markdown.service.d.ts +27 -43
  30. package/dist/lib/services/markdown.service.d.ts.map +1 -1
  31. package/dist/lib/services/markdown.service.js +56 -235
  32. package/dist/lib/services/markdown.service.js.map +1 -1
  33. package/dist/public-api.d.ts +0 -1
  34. package/dist/public-api.d.ts.map +1 -1
  35. package/dist/public-api.js +6 -3
  36. package/dist/public-api.js.map +1 -1
  37. package/package.json +4 -6
  38. package/dist/__tests__/markdown-types.test.d.ts +0 -2
  39. package/dist/__tests__/markdown-types.test.d.ts.map +0 -1
  40. package/dist/__tests__/markdown-types.test.js +0 -78
  41. package/dist/__tests__/markdown-types.test.js.map +0 -1
  42. package/dist/lib/extensions/html-block-repair.extension.d.ts +0 -20
  43. package/dist/lib/extensions/html-block-repair.extension.d.ts.map +0 -1
  44. package/dist/lib/extensions/html-block-repair.extension.js +0 -43
  45. package/dist/lib/extensions/html-block-repair.extension.js.map +0 -1
  46. package/dist/lib/types/markdown.types.d.ts +0 -194
  47. package/dist/lib/types/markdown.types.d.ts.map +0 -1
  48. package/dist/lib/types/markdown.types.js +0 -25
  49. package/dist/lib/types/markdown.types.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.component.js","sourceRoot":"","sources":["../../../src/lib/components/markdown.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n ElementRef,\n OnChanges,\n OnDestroy,\n SimpleChanges,\n SecurityContext,\n ViewEncapsulation,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n AfterViewInit,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { MarkdownService } from '../services/markdown.service';\nimport { MarkdownConfig, DEFAULT_MARKDOWN_CONFIG, MarkdownRenderEvent, HeadingInfo } from '../types/markdown.types';\n// Collapsible section toggle is handled inline in setupCollapsibleListeners\n\n/**\n * Angular component for rendering markdown content.\n *\n * Features:\n * - Prism.js syntax highlighting for code blocks\n * - Mermaid diagram rendering\n * - Copy-to-clipboard for code blocks\n * - Collapsible heading sections\n * - GitHub-style alerts and heading IDs\n *\n * Usage:\n * ```html\n * <mj-markdown [data]=\"markdownContent\"></mj-markdown>\n *\n * <mj-markdown\n * [data]=\"content\"\n * [enableMermaid]=\"true\"\n * [enableCollapsibleHeadings]=\"true\"\n * (rendered)=\"onRendered($event)\">\n * </mj-markdown>\n * ```\n */\n@Component({\n selector: 'mj-markdown',\n standalone: false,\n template: ` <div class=\"mj-markdown-container\" [class]=\"containerClass\" [innerHTML]=\"renderedContent\"></div> `,\n styleUrls: ['./markdown.component.css'],\n encapsulation: ViewEncapsulation.None, // Allow styles to penetrate into rendered content\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy {\n /**\n * The markdown content to render\n */\n @Input() data: string = '';\n\n /**\n * Enable syntax highlighting\n */\n @Input() enableHighlight: boolean = DEFAULT_MARKDOWN_CONFIG.enableHighlight;\n\n /**\n * Enable Mermaid diagram rendering\n */\n @Input() enableMermaid: boolean = DEFAULT_MARKDOWN_CONFIG.enableMermaid;\n\n /**\n * Enable copy button on code blocks\n */\n @Input() enableCodeCopy: boolean = DEFAULT_MARKDOWN_CONFIG.enableCodeCopy;\n\n /**\n * Enable collapsible heading sections\n */\n @Input() enableCollapsibleHeadings: boolean = DEFAULT_MARKDOWN_CONFIG.enableCollapsibleHeadings;\n\n /**\n * Heading level at which to start collapsing\n */\n @Input() collapsibleHeadingLevel: 1 | 2 | 3 | 4 | 5 | 6 = DEFAULT_MARKDOWN_CONFIG.collapsibleHeadingLevel;\n\n /**\n * Whether collapsible sections should be expanded by default\n */\n @Input() collapsibleDefaultExpanded: boolean = DEFAULT_MARKDOWN_CONFIG.collapsibleDefaultExpanded;\n\n /**\n * Specify which heading levels should start expanded.\n * Array of heading levels (2-6) that should be expanded by default.\n * Takes precedence over collapsibleDefaultExpanded for specified levels.\n *\n * Examples:\n * - [2] = Only h2 expanded, h3-h6 collapsed\n * - [2, 3] = h2 and h3 expanded, h4-h6 collapsed\n * - [] = All collapsed\n * - undefined = Uses collapsibleDefaultExpanded for all levels\n */\n @Input() autoExpandLevels?: number[];\n\n /**\n * Enable GitHub-style alerts\n */\n @Input() enableAlerts: boolean = DEFAULT_MARKDOWN_CONFIG.enableAlerts;\n\n /**\n * Enable smartypants for typography (curly quotes, em/en dashes, ellipses)\n */\n @Input() enableSmartypants: boolean = DEFAULT_MARKDOWN_CONFIG.enableSmartypants;\n\n /**\n * Enable SVG code block rendering\n * When enabled, ```svg code blocks are rendered as actual SVG images\n */\n @Input() enableSvgRenderer: boolean = DEFAULT_MARKDOWN_CONFIG.enableSvgRenderer;\n\n /**\n * Enable raw HTML passthrough in markdown content.\n * Scripts and event handlers are still stripped unless enableJavaScript is true.\n */\n @Input() enableHtml: boolean = DEFAULT_MARKDOWN_CONFIG.enableHtml;\n\n /**\n * Enable JavaScript in HTML content (<script> tags and on* handlers).\n * WARNING: Major security risk - only enable for fully trusted content.\n */\n @Input() enableJavaScript: boolean = DEFAULT_MARKDOWN_CONFIG.enableJavaScript;\n\n /**\n * Enable heading IDs for anchor links\n */\n @Input() enableHeadingIds: boolean = DEFAULT_MARKDOWN_CONFIG.enableHeadingIds;\n\n /**\n * Prefix for heading IDs\n */\n @Input() headingIdPrefix: string = DEFAULT_MARKDOWN_CONFIG.headingIdPrefix;\n\n /**\n * Enable line numbers in code blocks\n */\n @Input() enableLineNumbers: boolean = DEFAULT_MARKDOWN_CONFIG.enableLineNumbers;\n\n /**\n * Custom CSS class for the container\n */\n @Input() containerClass: string = '';\n\n /**\n * Mermaid theme.\n * 'auto' (default) detects light/dark from the document's data-theme attribute.\n */\n @Input() mermaidTheme: 'auto' | 'default' | 'dark' | 'forest' | 'neutral' | 'base' = DEFAULT_MARKDOWN_CONFIG.mermaidTheme;\n\n /**\n * Whether to sanitize HTML output\n */\n @Input() sanitize: boolean = DEFAULT_MARKDOWN_CONFIG.sanitize;\n\n /**\n * Emitted when rendering is complete\n */\n @Output() rendered = new EventEmitter<MarkdownRenderEvent>();\n\n /**\n * Emitted when a heading anchor is clicked\n */\n @Output() headingClick = new EventEmitter<HeadingInfo>();\n\n /**\n * Emitted when code is copied to clipboard\n */\n @Output() codeCopied = new EventEmitter<string>();\n\n /**\n * The sanitized HTML content to display\n */\n public renderedContent: SafeHtml = '';\n\n /**\n * Public accessor for the component's element reference.\n * Provided for backward compatibility with ngx-markdown API.\n */\n public get element(): ElementRef<HTMLElement> {\n return this.elementRef;\n }\n\n private renderStartTime: number = 0;\n private hasMermaid: boolean = false;\n private hasCodeBlocks: boolean = false;\n private themeObserver: MutationObserver | null = null;\n\n constructor(\n private elementRef: ElementRef<HTMLElement>,\n private sanitizer: DomSanitizer,\n private markdownService: MarkdownService,\n private cdr: ChangeDetectorRef,\n ) {}\n\n ngOnChanges(changes: SimpleChanges): void {\n // Check if any relevant input changed\n const needsRerender =\n changes['data'] ||\n changes['enableHighlight'] ||\n changes['enableMermaid'] ||\n changes['enableCodeCopy'] ||\n changes['enableCollapsibleHeadings'] ||\n changes['collapsibleHeadingLevel'] ||\n changes['collapsibleDefaultExpanded'] ||\n changes['autoExpandLevels'] ||\n changes['enableAlerts'] ||\n changes['enableSmartypants'] ||\n changes['enableSvgRenderer'] ||\n changes['enableHtml'] ||\n changes['enableJavaScript'] ||\n changes['enableHeadingIds'] ||\n changes['headingIdPrefix'] ||\n changes['mermaidTheme'] ||\n changes['sanitize'];\n\n if (needsRerender) {\n this.render();\n }\n }\n\n ngAfterViewInit(): void {\n // Initial render if data was provided\n if (this.data) {\n this.postRenderProcessing();\n }\n\n this.setupThemeObserver();\n }\n\n ngOnDestroy(): void {\n this.themeObserver?.disconnect();\n this.themeObserver = null;\n this.cleanupEventListeners();\n }\n\n /**\n * Render the markdown content\n */\n private render(): void {\n if (!this.data) {\n this.renderedContent = '';\n this.cdr.markForCheck();\n return;\n }\n\n this.renderStartTime = performance.now();\n\n // Build config from inputs\n const config: MarkdownConfig = {\n enableHighlight: this.enableHighlight,\n enableMermaid: this.enableMermaid,\n enableCodeCopy: this.enableCodeCopy,\n enableCollapsibleHeadings: this.enableCollapsibleHeadings,\n collapsibleHeadingLevel: this.collapsibleHeadingLevel,\n collapsibleDefaultExpanded: this.collapsibleDefaultExpanded,\n autoExpandLevels: this.autoExpandLevels,\n enableAlerts: this.enableAlerts,\n enableSmartypants: this.enableSmartypants,\n enableSvgRenderer: this.enableSvgRenderer,\n enableHtml: this.enableHtml,\n enableJavaScript: this.enableJavaScript,\n enableHeadingIds: this.enableHeadingIds,\n headingIdPrefix: this.headingIdPrefix,\n mermaidTheme: this.mermaidTheme,\n sanitize: this.sanitize,\n };\n\n // Configure service and parse\n this.markdownService.configureMarked(config);\n let html = this.markdownService.parse(this.data);\n\n // Check for mermaid and code blocks\n this.hasMermaid = html.includes('language-mermaid') || html.includes('class=\"mermaid\"');\n this.hasCodeBlocks = html.includes('<pre>') && html.includes('<code');\n\n // Sanitize if enabled\n // Note: We bypass Angular's sanitizer when SVG renderer or HTML passthrough is enabled\n // because it strips SVG elements and most HTML layout tags.\n const bypassAngularSanitizer = this.enableSvgRenderer || this.enableHtml;\n if (this.sanitize && !bypassAngularSanitizer) {\n const sanitized = this.sanitizer.sanitize(SecurityContext.HTML, html);\n html = sanitized || '';\n }\n\n // Strip JavaScript unless explicitly enabled\n // This removes <script> tags and on* event handlers while keeping layout HTML\n if (bypassAngularSanitizer && !this.enableJavaScript) {\n html = this.stripJavaScript(html);\n }\n\n // Trust the HTML for display\n this.renderedContent = this.sanitizer.bypassSecurityTrustHtml(html);\n this.cdr.markForCheck();\n\n // Schedule post-render processing for next tick (after DOM update)\n Promise.resolve().then(() => this.postRenderProcessing());\n }\n\n /**\n * Process rendered content after DOM update\n * Handles syntax highlighting, mermaid rendering, copy buttons, etc.\n */\n private async postRenderProcessing(): Promise<void> {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n // Add copy buttons to code blocks\n if (this.enableCodeCopy && this.hasCodeBlocks) {\n this.markdownService.addCodeCopyButtons(container as HTMLElement);\n }\n\n // Initialize collapsible headings\n if (this.enableCollapsibleHeadings) {\n this.markdownService.initializeCollapsibleHeadings(container as HTMLElement);\n this.setupCollapsibleListeners(container as HTMLElement);\n }\n\n // Render mermaid diagrams (async)\n if (this.enableMermaid && this.hasMermaid) {\n await this.markdownService.renderMermaid(container as HTMLElement);\n }\n\n // Setup heading click listeners\n if (this.enableHeadingIds) {\n this.setupHeadingClickListeners(container as HTMLElement);\n }\n\n // Setup code copy listeners for custom event emission\n if (this.enableCodeCopy) {\n this.setupCodeCopyListeners(container as HTMLElement);\n }\n\n // Emit rendered event\n const renderTime = performance.now() - this.renderStartTime;\n const headingIds = this.markdownService.getHeadingList();\n\n this.rendered.emit({\n html: (container as HTMLElement).innerHTML,\n renderTime,\n hasMermaid: this.hasMermaid,\n hasCodeBlocks: this.hasCodeBlocks,\n headingIds,\n });\n }\n\n /**\n * Setup collapsible sections by adding toggle buttons and click listeners\n */\n private setupCollapsibleListeners(container: HTMLElement): void {\n const sections = container.querySelectorAll('.collapsible-section');\n\n sections.forEach((section) => {\n const wrapper = section.querySelector(':scope > .collapsible-heading-wrapper') as HTMLElement | null;\n if (!wrapper) return;\n\n // Check if toggle already exists\n if (wrapper.querySelector('.collapsible-toggle')) return;\n\n const isExpanded = !section.classList.contains('collapsed');\n const hasChildren = section.querySelector('.collapsible-section') !== null;\n\n // Create toggle button (chevron)\n const toggle = document.createElement('span');\n toggle.className = 'collapsible-toggle';\n toggle.setAttribute('role', 'button');\n toggle.setAttribute('tabindex', '0');\n toggle.setAttribute('aria-expanded', String(isExpanded));\n toggle.innerHTML = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M6 12l4-4-4-4\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n // Insert toggle before heading\n wrapper.insertBefore(toggle, wrapper.firstChild);\n\n // Add action buttons container (only if has children)\n if (hasChildren) {\n const actions = this.createActionButtons(section as HTMLElement);\n wrapper.appendChild(actions);\n }\n\n // Make the whole wrapper clickable\n wrapper.style.cursor = 'pointer';\n\n // Add click listener to wrapper (but not on action buttons)\n wrapper.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLElement;\n // Don't toggle if clicking on action buttons\n if (target.closest('.collapsible-actions')) return;\n\n e.preventDefault();\n e.stopPropagation();\n this.toggleSection(section as HTMLElement, toggle);\n });\n\n // Add keyboard support\n wrapper.addEventListener('keydown', (e: Event) => {\n const target = e.target as HTMLElement;\n if (target.closest('.collapsible-actions')) return;\n\n const keyEvent = e as KeyboardEvent;\n if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {\n e.preventDefault();\n this.toggleSection(section as HTMLElement, toggle);\n }\n });\n });\n }\n\n /**\n * Create the expand/collapse all action buttons for sections with children\n */\n private createActionButtons(section: HTMLElement): HTMLElement {\n const container = document.createElement('span');\n container.className = 'collapsible-actions';\n\n // Expand all button\n const expandBtn = document.createElement('button');\n expandBtn.className = 'collapsible-action-btn expand-all';\n expandBtn.setAttribute('type', 'button');\n expandBtn.setAttribute('title', 'Expand all');\n expandBtn.innerHTML = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 6l4 4 4-4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4 10l4 4 4-4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n expandBtn.addEventListener('click', (e: Event) => {\n e.preventDefault();\n e.stopPropagation();\n this.expandDescendants(section);\n // Also expand the section itself if collapsed\n if (section.classList.contains('collapsed')) {\n section.classList.remove('collapsed');\n const toggle = section.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) toggle.setAttribute('aria-expanded', 'true');\n }\n });\n\n // Collapse all button\n const collapseBtn = document.createElement('button');\n collapseBtn.className = 'collapsible-action-btn collapse-all';\n collapseBtn.setAttribute('type', 'button');\n collapseBtn.setAttribute('title', 'Collapse all');\n collapseBtn.innerHTML = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 10l4-4 4 4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4 14l4-4 4 4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n collapseBtn.addEventListener('click', (e: Event) => {\n e.preventDefault();\n e.stopPropagation();\n this.collapseDescendants(section);\n });\n\n container.appendChild(expandBtn);\n container.appendChild(collapseBtn);\n\n return container;\n }\n\n /**\n * Toggle a collapsible section\n * @param section The section element to toggle\n * @param toggle The toggle button element\n */\n private toggleSection(section: HTMLElement, toggle: HTMLElement): void {\n const isCollapsed = section.classList.contains('collapsed');\n\n // Toggle the section\n section.classList.toggle('collapsed');\n toggle.setAttribute('aria-expanded', String(isCollapsed));\n // Children retain their state - CSS handles visibility via parent collapse\n }\n\n /**\n * Collapse all descendant sections (used by action button)\n */\n private collapseDescendants(section: HTMLElement): void {\n const descendants = section.querySelectorAll('.collapsible-section');\n descendants.forEach((desc) => {\n desc.classList.add('collapsed');\n const toggle = desc.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) {\n toggle.setAttribute('aria-expanded', 'false');\n }\n });\n }\n\n /**\n * Expand all descendant sections (used by action button)\n */\n private expandDescendants(section: HTMLElement): void {\n const descendants = section.querySelectorAll('.collapsible-section');\n descendants.forEach((desc) => {\n desc.classList.remove('collapsed');\n const toggle = desc.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) {\n toggle.setAttribute('aria-expanded', 'true');\n }\n });\n }\n\n /**\n * Setup click listeners for heading anchors\n */\n private setupHeadingClickListeners(container: HTMLElement): void {\n const headings = container.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]');\n\n headings.forEach((heading) => {\n heading.addEventListener('click', () => {\n const id = heading.getAttribute('id') || '';\n const text = heading.textContent || '';\n const level = parseInt(heading.tagName.charAt(1), 10);\n\n this.headingClick.emit({\n id,\n text,\n level,\n raw: text,\n });\n });\n });\n }\n\n /**\n * Setup listeners to emit code copy events\n */\n private setupCodeCopyListeners(container: HTMLElement): void {\n const copyButtons = container.querySelectorAll('.code-copy-btn');\n\n copyButtons.forEach((button) => {\n button.addEventListener('click', () => {\n const pre = button.closest('pre');\n const code = pre?.querySelector('code');\n if (code) {\n this.codeCopied.emit(code.textContent || '');\n }\n });\n });\n }\n\n /**\n * Watch the document's data-theme attribute for changes.\n * When the app theme switches (light ↔ dark) and mermaidTheme is 'auto',\n * re-render so mermaid diagrams pick up the new theme.\n */\n private setupThemeObserver(): void {\n if (typeof MutationObserver === 'undefined') return;\n\n this.themeObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'attributes' && mutation.attributeName === 'data-theme') {\n this.onThemeAttributeChanged();\n break;\n }\n }\n });\n\n this.themeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-theme'],\n });\n }\n\n /**\n * Called when data-theme changes on the document root.\n * Triggers a full re-render when mermaid auto-theming is active.\n */\n private onThemeAttributeChanged(): void {\n if (this.mermaidTheme === 'auto' && this.enableMermaid && this.hasMermaid && this.data) {\n this.render();\n }\n }\n\n /**\n * Cleanup event listeners\n */\n private cleanupEventListeners(): void {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n // Clone and replace to remove all listeners\n const clone = container.cloneNode(true);\n container.parentNode?.replaceChild(clone, container);\n }\n\n /**\n * Force a re-render of the markdown content\n */\n public refresh(): void {\n this.render();\n }\n\n /**\n * Get the current heading list (for TOC building)\n */\n public getHeadings(): HeadingInfo[] {\n return this.markdownService.getHeadingList();\n }\n\n /**\n * Scroll to a heading by ID\n */\n public scrollToHeading(headingId: string): void {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n const heading = container.querySelector(`#${headingId}`);\n if (heading) {\n heading.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n }\n\n /**\n * Strip JavaScript from HTML content while preserving layout HTML.\n * Removes <script> tags, on* event handlers, and javascript: URLs.\n */\n private stripJavaScript(html: string): string {\n if (typeof DOMParser === 'undefined') {\n // Fallback for environments without DOMParser\n return this.fallbackStripJavaScript(html);\n }\n\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString('<body>' + html + '</body>', 'text/html');\n\n const cleanNode = (node: Element) => {\n const tagName = node.tagName.toLowerCase();\n\n // Remove unsafe elements completely\n if (tagName === 'script' || tagName === 'iframe' || tagName === 'object' || tagName === 'embed' || tagName === 'base') {\n node.parentNode?.removeChild(node);\n return;\n }\n\n if (node.attributes) {\n const attrs = Array.from(node.attributes);\n for (const attr of attrs) {\n const name = attr.name.toLowerCase();\n // Remove whitespace and control chars from value to prevent bypasses like \"java\\nscript:\"\n // eslint-disable-next-line no-control-regex\n const valueStr = attr.value.toLowerCase().replace(/[\\s\\x00-\\x20]/g, '');\n\n if (\n name.startsWith('on') ||\n ((name === 'href' || name === 'xlink:href' || name === 'src' || name === 'action' || name === 'formaction') &&\n (valueStr.startsWith('javascript:') || valueStr.startsWith('vbscript:') || valueStr.startsWith('data:text/html')))\n ) {\n node.removeAttribute(attr.name);\n }\n }\n }\n\n // Recursively clean children (Array.from prevents issues with live collections when removing nodes)\n Array.from(node.children).forEach(cleanNode);\n };\n\n Array.from(doc.body.children).forEach(cleanNode);\n return doc.body.innerHTML;\n } catch (e) {\n // If parsing fails completely, fall back to aggressive regex\n return this.fallbackStripJavaScript(html);\n }\n }\n\n /**\n * Fallback regex-based sanitization when DOMParser is unavailable.\n * Note: This is less robust than DOM parsing and should only be a fallback.\n */\n private fallbackStripJavaScript(html: string): string {\n // Remove <script> tags and their content\n html = html.replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '');\n\n // Remove on* event handlers (onclick, onload, onerror, etc.)\n html = html.replace(/\\s+on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi, '');\n html = html.replace(/\\s+on\\w+\\s*=\\s*[^\\s>]+/gi, '');\n\n // Remove javascript: URLs from href and src attributes\n html = html.replace(/\\s+href\\s*=\\s*[\"']?javascript:[^\"'>\\s]*[\"']?/gi, '');\n html = html.replace(/\\s+src\\s*=\\s*[\"']?javascript:[^\"'>\\s]*[\"']?/gi, '');\n\n // Remove data: URLs that could contain scripts (data:text/html, etc.)\n html = html.replace(/\\s+src\\s*=\\s*[\"']?data:text\\/html[^\"'>\\s]*[\"']?/gi, '');\n\n return html;\n }\n}\n"]}
1
+ {"version":3,"file":"markdown.component.js","sourceRoot":"","sources":["../../../src/lib/components/markdown.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n ElementRef,\n OnChanges,\n OnDestroy,\n SimpleChanges,\n SecurityContext,\n ViewEncapsulation,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n AfterViewInit,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { MarkdownService } from '../services/markdown.service';\nimport { MarkdownConfig, DEFAULT_MARKDOWN_CONFIG, MarkdownRenderEvent, HeadingInfo } from '@memberjunction/markdown-core';\n// Collapsible section toggle is handled inline in setupCollapsibleListeners\n\n/**\n * Angular component for rendering markdown content.\n *\n * Features:\n * - Prism.js syntax highlighting for code blocks\n * - Mermaid diagram rendering\n * - Copy-to-clipboard for code blocks\n * - Collapsible heading sections\n * - GitHub-style alerts and heading IDs\n *\n * Usage:\n * ```html\n * <mj-markdown [data]=\"markdownContent\"></mj-markdown>\n *\n * <mj-markdown\n * [data]=\"content\"\n * [enableMermaid]=\"true\"\n * [enableCollapsibleHeadings]=\"true\"\n * (rendered)=\"onRendered($event)\">\n * </mj-markdown>\n * ```\n */\n@Component({\n selector: 'mj-markdown',\n standalone: false,\n template: ` <div class=\"mj-markdown-container\" [class]=\"containerClass\" [innerHTML]=\"renderedContent\"></div> `,\n styleUrls: ['./markdown.component.css'],\n encapsulation: ViewEncapsulation.None, // Allow styles to penetrate into rendered content\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy {\n /**\n * The markdown content to render\n */\n @Input() data: string = '';\n\n /**\n * Enable syntax highlighting\n */\n @Input() enableHighlight: boolean = DEFAULT_MARKDOWN_CONFIG.enableHighlight;\n\n /**\n * Enable Mermaid diagram rendering\n */\n @Input() enableMermaid: boolean = DEFAULT_MARKDOWN_CONFIG.enableMermaid;\n\n /**\n * Enable copy button on code blocks\n */\n @Input() enableCodeCopy: boolean = DEFAULT_MARKDOWN_CONFIG.enableCodeCopy;\n\n /**\n * Enable collapsible heading sections\n */\n @Input() enableCollapsibleHeadings: boolean = DEFAULT_MARKDOWN_CONFIG.enableCollapsibleHeadings;\n\n /**\n * Heading level at which to start collapsing\n */\n @Input() collapsibleHeadingLevel: 1 | 2 | 3 | 4 | 5 | 6 = DEFAULT_MARKDOWN_CONFIG.collapsibleHeadingLevel;\n\n /**\n * Whether collapsible sections should be expanded by default\n */\n @Input() collapsibleDefaultExpanded: boolean = DEFAULT_MARKDOWN_CONFIG.collapsibleDefaultExpanded;\n\n /**\n * Specify which heading levels should start expanded.\n * Array of heading levels (2-6) that should be expanded by default.\n * Takes precedence over collapsibleDefaultExpanded for specified levels.\n *\n * Examples:\n * - [2] = Only h2 expanded, h3-h6 collapsed\n * - [2, 3] = h2 and h3 expanded, h4-h6 collapsed\n * - [] = All collapsed\n * - undefined = Uses collapsibleDefaultExpanded for all levels\n */\n @Input() autoExpandLevels?: number[];\n\n /**\n * Enable GitHub-style alerts\n */\n @Input() enableAlerts: boolean = DEFAULT_MARKDOWN_CONFIG.enableAlerts;\n\n /**\n * Enable smartypants for typography (curly quotes, em/en dashes, ellipses)\n */\n @Input() enableSmartypants: boolean = DEFAULT_MARKDOWN_CONFIG.enableSmartypants;\n\n /**\n * Enable SVG code block rendering\n * When enabled, ```svg code blocks are rendered as actual SVG images\n */\n @Input() enableSvgRenderer: boolean = DEFAULT_MARKDOWN_CONFIG.enableSvgRenderer;\n\n /**\n * Enable raw HTML passthrough in markdown content.\n * Scripts and event handlers are still stripped unless enableJavaScript is true.\n */\n @Input() enableHtml: boolean = DEFAULT_MARKDOWN_CONFIG.enableHtml;\n\n /**\n * Enable JavaScript in HTML content (<script> tags and on* handlers).\n * WARNING: Major security risk - only enable for fully trusted content.\n */\n @Input() enableJavaScript: boolean = DEFAULT_MARKDOWN_CONFIG.enableJavaScript;\n\n /**\n * Enable heading IDs for anchor links\n */\n @Input() enableHeadingIds: boolean = DEFAULT_MARKDOWN_CONFIG.enableHeadingIds;\n\n /**\n * Prefix for heading IDs\n */\n @Input() headingIdPrefix: string = DEFAULT_MARKDOWN_CONFIG.headingIdPrefix;\n\n /**\n * Enable line numbers in code blocks\n */\n @Input() enableLineNumbers: boolean = DEFAULT_MARKDOWN_CONFIG.enableLineNumbers;\n\n /**\n * Custom CSS class for the container\n */\n @Input() containerClass: string = '';\n\n /**\n * Mermaid theme.\n * 'auto' (default) detects light/dark from the document's data-theme attribute.\n */\n @Input() mermaidTheme: 'auto' | 'default' | 'dark' | 'forest' | 'neutral' | 'base' = DEFAULT_MARKDOWN_CONFIG.mermaidTheme;\n\n /**\n * Whether to sanitize HTML output\n */\n @Input() sanitize: boolean = DEFAULT_MARKDOWN_CONFIG.sanitize;\n\n /**\n * Emitted when rendering is complete\n */\n @Output() rendered = new EventEmitter<MarkdownRenderEvent>();\n\n /**\n * Emitted when a heading anchor is clicked\n */\n @Output() headingClick = new EventEmitter<HeadingInfo>();\n\n /**\n * Emitted when code is copied to clipboard\n */\n @Output() codeCopied = new EventEmitter<string>();\n\n /**\n * The sanitized HTML content to display\n */\n public renderedContent: SafeHtml = '';\n\n /**\n * Public accessor for the component's element reference.\n * Provided for backward compatibility with ngx-markdown API.\n */\n public get element(): ElementRef<HTMLElement> {\n return this.elementRef;\n }\n\n private renderStartTime: number = 0;\n private hasMermaid: boolean = false;\n private hasCodeBlocks: boolean = false;\n private themeObserver: MutationObserver | null = null;\n\n constructor(\n private elementRef: ElementRef<HTMLElement>,\n private sanitizer: DomSanitizer,\n private markdownService: MarkdownService,\n private cdr: ChangeDetectorRef,\n ) {}\n\n ngOnChanges(changes: SimpleChanges): void {\n // Check if any relevant input changed\n const needsRerender =\n changes['data'] ||\n changes['enableHighlight'] ||\n changes['enableMermaid'] ||\n changes['enableCodeCopy'] ||\n changes['enableCollapsibleHeadings'] ||\n changes['collapsibleHeadingLevel'] ||\n changes['collapsibleDefaultExpanded'] ||\n changes['autoExpandLevels'] ||\n changes['enableAlerts'] ||\n changes['enableSmartypants'] ||\n changes['enableSvgRenderer'] ||\n changes['enableHtml'] ||\n changes['enableJavaScript'] ||\n changes['enableHeadingIds'] ||\n changes['headingIdPrefix'] ||\n changes['mermaidTheme'] ||\n changes['sanitize'];\n\n if (needsRerender) {\n this.render();\n }\n }\n\n ngAfterViewInit(): void {\n // Initial render if data was provided\n if (this.data) {\n this.postRenderProcessing();\n }\n\n this.setupThemeObserver();\n }\n\n ngOnDestroy(): void {\n this.themeObserver?.disconnect();\n this.themeObserver = null;\n this.cleanupEventListeners();\n }\n\n /**\n * Render the markdown content\n */\n private render(): void {\n if (!this.data) {\n this.renderedContent = '';\n this.cdr.markForCheck();\n return;\n }\n\n this.renderStartTime = performance.now();\n\n // Build config from inputs\n const config: MarkdownConfig = {\n enableHighlight: this.enableHighlight,\n enableMermaid: this.enableMermaid,\n enableCodeCopy: this.enableCodeCopy,\n enableCollapsibleHeadings: this.enableCollapsibleHeadings,\n collapsibleHeadingLevel: this.collapsibleHeadingLevel,\n collapsibleDefaultExpanded: this.collapsibleDefaultExpanded,\n autoExpandLevels: this.autoExpandLevels,\n enableAlerts: this.enableAlerts,\n enableSmartypants: this.enableSmartypants,\n enableSvgRenderer: this.enableSvgRenderer,\n enableHtml: this.enableHtml,\n enableJavaScript: this.enableJavaScript,\n enableHeadingIds: this.enableHeadingIds,\n headingIdPrefix: this.headingIdPrefix,\n mermaidTheme: this.mermaidTheme,\n sanitize: this.sanitize,\n };\n\n // Configure service and parse\n this.markdownService.configureMarked(config);\n let html = this.markdownService.parse(this.data);\n\n // Check for mermaid and code blocks\n this.hasMermaid = html.includes('language-mermaid') || html.includes('class=\"mermaid\"');\n this.hasCodeBlocks = html.includes('<pre>') && html.includes('<code');\n\n // Sanitize if enabled\n // Note: We bypass Angular's sanitizer when SVG renderer or HTML passthrough is enabled\n // because it strips SVG elements and most HTML layout tags.\n const bypassAngularSanitizer = this.enableSvgRenderer || this.enableHtml;\n if (this.sanitize && !bypassAngularSanitizer) {\n const sanitized = this.sanitizer.sanitize(SecurityContext.HTML, html);\n html = sanitized || '';\n }\n\n // Strip JavaScript unless explicitly enabled\n // This removes <script> tags and on* event handlers while keeping layout HTML\n if (bypassAngularSanitizer && !this.enableJavaScript) {\n html = this.stripJavaScript(html);\n }\n\n // Trust the HTML for display\n this.renderedContent = this.sanitizer.bypassSecurityTrustHtml(html);\n this.cdr.markForCheck();\n\n // Schedule post-render processing for next tick (after DOM update)\n Promise.resolve().then(() => this.postRenderProcessing());\n }\n\n /**\n * Process rendered content after DOM update\n * Handles syntax highlighting, mermaid rendering, copy buttons, etc.\n */\n private async postRenderProcessing(): Promise<void> {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n // Add copy buttons to code blocks\n if (this.enableCodeCopy && this.hasCodeBlocks) {\n this.markdownService.addCodeCopyButtons(container as HTMLElement);\n }\n\n // Initialize collapsible headings\n if (this.enableCollapsibleHeadings) {\n this.markdownService.initializeCollapsibleHeadings(container as HTMLElement);\n this.setupCollapsibleListeners(container as HTMLElement);\n }\n\n // Render mermaid diagrams (async)\n if (this.enableMermaid && this.hasMermaid) {\n await this.markdownService.renderMermaid(container as HTMLElement);\n }\n\n // Setup heading click listeners\n if (this.enableHeadingIds) {\n this.setupHeadingClickListeners(container as HTMLElement);\n }\n\n // Setup code copy listeners for custom event emission\n if (this.enableCodeCopy) {\n this.setupCodeCopyListeners(container as HTMLElement);\n }\n\n // Emit rendered event\n const renderTime = performance.now() - this.renderStartTime;\n const headingIds = this.markdownService.getHeadingList();\n\n this.rendered.emit({\n html: (container as HTMLElement).innerHTML,\n renderTime,\n hasMermaid: this.hasMermaid,\n hasCodeBlocks: this.hasCodeBlocks,\n headingIds,\n });\n }\n\n /**\n * Setup collapsible sections by adding toggle buttons and click listeners\n */\n private setupCollapsibleListeners(container: HTMLElement): void {\n const sections = container.querySelectorAll('.collapsible-section');\n\n sections.forEach((section) => {\n const wrapper = section.querySelector(':scope > .collapsible-heading-wrapper') as HTMLElement | null;\n if (!wrapper) return;\n\n // Check if toggle already exists\n if (wrapper.querySelector('.collapsible-toggle')) return;\n\n const isExpanded = !section.classList.contains('collapsed');\n const hasChildren = section.querySelector('.collapsible-section') !== null;\n\n // Create toggle button (chevron)\n const toggle = document.createElement('span');\n toggle.className = 'collapsible-toggle';\n toggle.setAttribute('role', 'button');\n toggle.setAttribute('tabindex', '0');\n toggle.setAttribute('aria-expanded', String(isExpanded));\n toggle.innerHTML = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M6 12l4-4-4-4\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n // Insert toggle before heading\n wrapper.insertBefore(toggle, wrapper.firstChild);\n\n // Add action buttons container (only if has children)\n if (hasChildren) {\n const actions = this.createActionButtons(section as HTMLElement);\n wrapper.appendChild(actions);\n }\n\n // Make the whole wrapper clickable\n wrapper.style.cursor = 'pointer';\n\n // Add click listener to wrapper (but not on action buttons)\n wrapper.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLElement;\n // Don't toggle if clicking on action buttons\n if (target.closest('.collapsible-actions')) return;\n\n e.preventDefault();\n e.stopPropagation();\n this.toggleSection(section as HTMLElement, toggle);\n });\n\n // Add keyboard support\n wrapper.addEventListener('keydown', (e: Event) => {\n const target = e.target as HTMLElement;\n if (target.closest('.collapsible-actions')) return;\n\n const keyEvent = e as KeyboardEvent;\n if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {\n e.preventDefault();\n this.toggleSection(section as HTMLElement, toggle);\n }\n });\n });\n }\n\n /**\n * Create the expand/collapse all action buttons for sections with children\n */\n private createActionButtons(section: HTMLElement): HTMLElement {\n const container = document.createElement('span');\n container.className = 'collapsible-actions';\n\n // Expand all button\n const expandBtn = document.createElement('button');\n expandBtn.className = 'collapsible-action-btn expand-all';\n expandBtn.setAttribute('type', 'button');\n expandBtn.setAttribute('title', 'Expand all');\n expandBtn.innerHTML = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 6l4 4 4-4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4 10l4 4 4-4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n expandBtn.addEventListener('click', (e: Event) => {\n e.preventDefault();\n e.stopPropagation();\n this.expandDescendants(section);\n // Also expand the section itself if collapsed\n if (section.classList.contains('collapsed')) {\n section.classList.remove('collapsed');\n const toggle = section.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) toggle.setAttribute('aria-expanded', 'true');\n }\n });\n\n // Collapse all button\n const collapseBtn = document.createElement('button');\n collapseBtn.className = 'collapsible-action-btn collapse-all';\n collapseBtn.setAttribute('type', 'button');\n collapseBtn.setAttribute('title', 'Collapse all');\n collapseBtn.innerHTML = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 10l4-4 4 4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4 14l4-4 4 4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n collapseBtn.addEventListener('click', (e: Event) => {\n e.preventDefault();\n e.stopPropagation();\n this.collapseDescendants(section);\n });\n\n container.appendChild(expandBtn);\n container.appendChild(collapseBtn);\n\n return container;\n }\n\n /**\n * Toggle a collapsible section\n * @param section The section element to toggle\n * @param toggle The toggle button element\n */\n private toggleSection(section: HTMLElement, toggle: HTMLElement): void {\n const isCollapsed = section.classList.contains('collapsed');\n\n // Toggle the section\n section.classList.toggle('collapsed');\n toggle.setAttribute('aria-expanded', String(isCollapsed));\n // Children retain their state - CSS handles visibility via parent collapse\n }\n\n /**\n * Collapse all descendant sections (used by action button)\n */\n private collapseDescendants(section: HTMLElement): void {\n const descendants = section.querySelectorAll('.collapsible-section');\n descendants.forEach((desc) => {\n desc.classList.add('collapsed');\n const toggle = desc.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) {\n toggle.setAttribute('aria-expanded', 'false');\n }\n });\n }\n\n /**\n * Expand all descendant sections (used by action button)\n */\n private expandDescendants(section: HTMLElement): void {\n const descendants = section.querySelectorAll('.collapsible-section');\n descendants.forEach((desc) => {\n desc.classList.remove('collapsed');\n const toggle = desc.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) {\n toggle.setAttribute('aria-expanded', 'true');\n }\n });\n }\n\n /**\n * Setup click listeners for heading anchors\n */\n private setupHeadingClickListeners(container: HTMLElement): void {\n const headings = container.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]');\n\n headings.forEach((heading) => {\n heading.addEventListener('click', () => {\n const id = heading.getAttribute('id') || '';\n const text = heading.textContent || '';\n const level = parseInt(heading.tagName.charAt(1), 10);\n\n this.headingClick.emit({\n id,\n text,\n level,\n raw: text,\n });\n });\n });\n }\n\n /**\n * Setup listeners to emit code copy events\n */\n private setupCodeCopyListeners(container: HTMLElement): void {\n const copyButtons = container.querySelectorAll('.code-copy-btn');\n\n copyButtons.forEach((button) => {\n button.addEventListener('click', () => {\n const pre = button.closest('pre');\n const code = pre?.querySelector('code');\n if (code) {\n this.codeCopied.emit(code.textContent || '');\n }\n });\n });\n }\n\n /**\n * Watch the document's data-theme attribute for changes.\n * When the app theme switches (light ↔ dark) and mermaidTheme is 'auto',\n * re-render so mermaid diagrams pick up the new theme.\n */\n private setupThemeObserver(): void {\n if (typeof MutationObserver === 'undefined') return;\n\n this.themeObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'attributes' && mutation.attributeName === 'data-theme') {\n this.onThemeAttributeChanged();\n break;\n }\n }\n });\n\n this.themeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-theme'],\n });\n }\n\n /**\n * Called when data-theme changes on the document root.\n * Triggers a full re-render when mermaid auto-theming is active.\n */\n private onThemeAttributeChanged(): void {\n if (this.mermaidTheme === 'auto' && this.enableMermaid && this.hasMermaid && this.data) {\n this.render();\n }\n }\n\n /**\n * Cleanup event listeners\n */\n private cleanupEventListeners(): void {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n // Clone and replace to remove all listeners\n const clone = container.cloneNode(true);\n container.parentNode?.replaceChild(clone, container);\n }\n\n /**\n * Force a re-render of the markdown content\n */\n public refresh(): void {\n this.render();\n }\n\n /**\n * Get the current heading list (for TOC building)\n */\n public getHeadings(): HeadingInfo[] {\n return this.markdownService.getHeadingList();\n }\n\n /**\n * Scroll to a heading by ID\n */\n public scrollToHeading(headingId: string): void {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n const heading = container.querySelector(`#${headingId}`);\n if (heading) {\n heading.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n }\n\n /**\n * Strip JavaScript from HTML content while preserving layout HTML.\n * Removes <script> tags, on* event handlers, and javascript: URLs.\n */\n private stripJavaScript(html: string): string {\n if (typeof DOMParser === 'undefined') {\n // Fallback for environments without DOMParser\n return this.fallbackStripJavaScript(html);\n }\n\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString('<body>' + html + '</body>', 'text/html');\n\n const cleanNode = (node: Element) => {\n const tagName = node.tagName.toLowerCase();\n\n // Remove unsafe elements completely\n if (tagName === 'script' || tagName === 'iframe' || tagName === 'object' || tagName === 'embed' || tagName === 'base') {\n node.parentNode?.removeChild(node);\n return;\n }\n\n if (node.attributes) {\n const attrs = Array.from(node.attributes);\n for (const attr of attrs) {\n const name = attr.name.toLowerCase();\n // Remove whitespace and control chars from value to prevent bypasses like \"java\\nscript:\"\n // eslint-disable-next-line no-control-regex\n const valueStr = attr.value.toLowerCase().replace(/[\\s\\x00-\\x20]/g, '');\n\n if (\n name.startsWith('on') ||\n ((name === 'href' || name === 'xlink:href' || name === 'src' || name === 'action' || name === 'formaction') &&\n (valueStr.startsWith('javascript:') || valueStr.startsWith('vbscript:') || valueStr.startsWith('data:text/html')))\n ) {\n node.removeAttribute(attr.name);\n }\n }\n }\n\n // Recursively clean children (Array.from prevents issues with live collections when removing nodes)\n Array.from(node.children).forEach(cleanNode);\n };\n\n Array.from(doc.body.children).forEach(cleanNode);\n return doc.body.innerHTML;\n } catch (e) {\n // If parsing fails completely, fall back to aggressive regex\n return this.fallbackStripJavaScript(html);\n }\n }\n\n /**\n * Fallback regex-based sanitization when DOMParser is unavailable.\n * Note: This is less robust than DOM parsing and should only be a fallback.\n */\n private fallbackStripJavaScript(html: string): string {\n // Remove <script> tags and their content\n html = html.replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '');\n\n // Remove on* event handlers (onclick, onload, onerror, etc.)\n html = html.replace(/\\s+on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi, '');\n html = html.replace(/\\s+on\\w+\\s*=\\s*[^\\s>]+/gi, '');\n\n // Remove javascript: URLs from href and src attributes\n html = html.replace(/\\s+href\\s*=\\s*[\"']?javascript:[^\"'>\\s]*[\"']?/gi, '');\n html = html.replace(/\\s+src\\s*=\\s*[\"']?javascript:[^\"'>\\s]*[\"']?/gi, '');\n\n // Remove data: URLs that could contain scripts (data:text/html, etc.)\n html = html.replace(/\\s+src\\s*=\\s*[\"']?data:text\\/html[^\"'>\\s]*[\"']?/gi, '');\n\n return html;\n }\n}\n"]}
@@ -1,10 +1,3 @@
1
- /**
2
- * Code copy extension utilities
3
- *
4
- * This module provides utilities for adding copy-to-clipboard functionality
5
- * to code blocks. Unlike other marked extensions, this operates on the DOM
6
- * after rendering since it requires adding interactive elements.
7
- */
8
1
  /**
9
2
  * Options for the code copy functionality
10
3
  */
@@ -1 +1 @@
1
- {"version":3,"file":"code-copy.extension.d.ts","sourceRoot":"","sources":["../../../src/lib/extensions/code-copy.extension.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAEhC;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAeD;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,WAAW,EACtB,OAAO,CAAC,EAAE,eAAe,GACxB,IAAI,CA8EN;AA6ED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,WAAW,EACtB,YAAY,GAAE,MAAuB,GACpC,IAAI,CAGN"}
1
+ {"version":3,"file":"code-copy.extension.d.ts","sourceRoot":"","sources":["../../../src/lib/extensions/code-copy.extension.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAEhC;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAeD;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,WAAW,EACtB,OAAO,CAAC,EAAE,eAAe,GACxB,IAAI,CA8EN;AAiBD;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,WAAW,EACtB,YAAY,GAAE,MAAuB,GACpC,IAAI,CAGN"}
@@ -5,6 +5,7 @@
5
5
  * to code blocks. Unlike other marked extensions, this operates on the DOM
6
6
  * after rendering since it requires adding interactive elements.
7
7
  */
8
+ import { formatLanguageName } from '@memberjunction/markdown-core';
8
9
  const DEFAULT_OPTIONS = {
9
10
  buttonClass: 'code-copy-btn',
10
11
  toolbarClass: 'code-toolbar',
@@ -100,64 +101,6 @@ function extractLanguageFromCode(codeElement) {
100
101
  }
101
102
  return null;
102
103
  }
103
- /**
104
- * Format a language identifier for display
105
- */
106
- function formatLanguageName(language) {
107
- const languageMap = {
108
- js: 'JavaScript',
109
- ts: 'TypeScript',
110
- javascript: 'JavaScript',
111
- typescript: 'TypeScript',
112
- py: 'Python',
113
- python: 'Python',
114
- rb: 'Ruby',
115
- ruby: 'Ruby',
116
- cs: 'C#',
117
- csharp: 'C#',
118
- cpp: 'C++',
119
- 'c++': 'C++',
120
- html: 'HTML',
121
- css: 'CSS',
122
- scss: 'SCSS',
123
- sass: 'Sass',
124
- less: 'Less',
125
- json: 'JSON',
126
- yaml: 'YAML',
127
- yml: 'YAML',
128
- xml: 'XML',
129
- sql: 'SQL',
130
- bash: 'Bash',
131
- shell: 'Shell',
132
- sh: 'Shell',
133
- zsh: 'Zsh',
134
- powershell: 'PowerShell',
135
- ps1: 'PowerShell',
136
- md: 'Markdown',
137
- markdown: 'Markdown',
138
- graphql: 'GraphQL',
139
- gql: 'GraphQL',
140
- java: 'Java',
141
- kotlin: 'Kotlin',
142
- swift: 'Swift',
143
- go: 'Go',
144
- rust: 'Rust',
145
- php: 'PHP',
146
- r: 'R',
147
- dockerfile: 'Dockerfile',
148
- docker: 'Docker',
149
- nginx: 'Nginx',
150
- apache: 'Apache',
151
- ini: 'INI',
152
- toml: 'TOML',
153
- makefile: 'Makefile',
154
- diff: 'Diff',
155
- plaintext: 'Plain Text',
156
- text: 'Plain Text',
157
- mermaid: 'Mermaid'
158
- };
159
- return languageMap[language.toLowerCase()] || language.toUpperCase();
160
- }
161
104
  /**
162
105
  * Remove all copy buttons from code blocks in a container
163
106
  * Useful for cleanup when component is destroyed
@@ -1 +1 @@
1
- {"version":3,"file":"code-copy.extension.js","sourceRoot":"","sources":["../../../src/lib/extensions/code-copy.extension.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiEH,MAAM,eAAe,GAAwG;IAC3H,WAAW,EAAE,eAAe;IAC5B,YAAY,EAAE,cAAc;IAC5B,QAAQ,EAAE,6BAA6B;IACvC,WAAW,EAAE,8BAA8B;IAC3C,SAAS,EAAE,8BAA8B;IACzC,WAAW,EAAE,WAAW;IACxB,gBAAgB,EAAE,IAAI;IACtB,iBAAiB,EAAE,IAAI;IACvB,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,SAAS;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,SAAsB,EACtB,OAAyB;IAEzB,MAAM,IAAI,GAAG,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,EAAE,CAAC;IAEhD,MAAM,UAAU,GAAG,SAAS,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAE5D,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;QAC/B,MAAM,GAAG,GAAG,SAAS,CAAC,aAAa,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,8BAA8B;QAC9B,IAAI,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YAAE,OAAO;QAEvD,iBAAiB;QACjB,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC9C,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC;QAEtC,gCAAgC;QAChC,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;YACpD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;gBAC7C,KAAK,CAAC,SAAS,GAAG,qBAAqB,CAAC;gBACxC,KAAK,CAAC,WAAW,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;gBACjD,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,qBAAqB;QACrB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;QACjC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC;QAChC,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC;QACvB,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAEpD,oBAAoB;QACpB,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,WAAW,IAAI,EAAE,CAAC;YAEzC,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBAE1C,qBAAqB;gBACrB,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC;gBACpC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAE/B,wBAAwB;gBACxB,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;gBAEpB,oBAAoB;gBACpB,UAAU,CAAC,GAAG,EAAE;oBACd,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;oBACjC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACpC,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;gBAE3C,mBAAmB;gBACnB,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;gBAClC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAE9B,sBAAsB;gBACtB,IAAI,CAAC,OAAO,EAAE,CAAC,GAAY,CAAC,CAAC;gBAE7B,oBAAoB;gBACpB,UAAU,CAAC,GAAG,EAAE;oBACd,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;oBACjC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACnC,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAE5B,+DAA+D;QAC/D,GAAG,CAAC,KAAK,CAAC,QAAQ,GAAG,UAAU,CAAC;QAChC,GAAG,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB,CAAC,WAAoB;IACnD,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAEjD,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,OAAO,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,MAAM,WAAW,GAA2B;QAC1C,EAAE,EAAE,YAAY;QAChB,EAAE,EAAE,YAAY;QAChB,UAAU,EAAE,YAAY;QACxB,UAAU,EAAE,YAAY;QACxB,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,QAAQ;QAChB,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,MAAM;QACZ,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,KAAK;QACV,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,KAAK;QACV,GAAG,EAAE,KAAK;QACV,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,OAAO;QACd,EAAE,EAAE,OAAO;QACX,GAAG,EAAE,KAAK;QACV,UAAU,EAAE,YAAY;QACxB,GAAG,EAAE,YAAY;QACjB,EAAE,EAAE,UAAU;QACd,QAAQ,EAAE,UAAU;QACpB,OAAO,EAAE,SAAS;QAClB,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,OAAO;QACd,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,KAAK;QACV,CAAC,EAAE,GAAG;QACN,UAAU,EAAE,YAAY;QACxB,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,QAAQ;QAChB,GAAG,EAAE,KAAK;QACV,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,YAAY;QACvB,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,SAAS;KACnB,CAAC;IAEF,OAAO,WAAW,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;AACvE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAC7C,SAAsB,EACtB,eAAuB,cAAc;IAErC,MAAM,QAAQ,GAAG,SAAS,CAAC,gBAAgB,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC;IAChE,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAClD,CAAC","sourcesContent":["/**\n * Code copy extension utilities\n *\n * This module provides utilities for adding copy-to-clipboard functionality\n * to code blocks. Unlike other marked extensions, this operates on the DOM\n * after rendering since it requires adding interactive elements.\n */\n\n/**\n * Options for the code copy functionality\n */\nexport interface CodeCopyOptions {\n /**\n * CSS class for the copy button\n * @default 'code-copy-btn'\n */\n buttonClass?: string;\n\n /**\n * CSS class for the toolbar container\n * @default 'code-toolbar'\n */\n toolbarClass?: string;\n\n /**\n * Icon HTML for the copy button\n * @default '<i class=\"fas fa-copy\"></i>'\n */\n copyIcon?: string;\n\n /**\n * Icon HTML for successful copy\n * @default '<i class=\"fas fa-check\"></i>'\n */\n successIcon?: string;\n\n /**\n * Icon HTML for failed copy\n * @default '<i class=\"fas fa-times\"></i>'\n */\n errorIcon?: string;\n\n /**\n * Tooltip text for the copy button\n * @default 'Copy code'\n */\n tooltipText?: string;\n\n /**\n * Duration in ms to show success/error state\n * @default 2000\n */\n feedbackDuration?: number;\n\n /**\n * Callback when code is successfully copied\n */\n onCopy?: (code: string) => void;\n\n /**\n * Callback when copy fails\n */\n onError?: (error: Error) => void;\n\n /**\n * Whether to show the language label in the toolbar\n * @default true\n */\n showLanguageLabel?: boolean;\n}\n\nconst DEFAULT_OPTIONS: Required<Omit<CodeCopyOptions, 'onCopy' | 'onError'>> & Pick<CodeCopyOptions, 'onCopy' | 'onError'> = {\n buttonClass: 'code-copy-btn',\n toolbarClass: 'code-toolbar',\n copyIcon: '<i class=\"fas fa-copy\"></i>',\n successIcon: '<i class=\"fas fa-check\"></i>',\n errorIcon: '<i class=\"fas fa-times\"></i>',\n tooltipText: 'Copy code',\n feedbackDuration: 2000,\n showLanguageLabel: true,\n onCopy: undefined,\n onError: undefined\n};\n\n/**\n * Add copy buttons to all code blocks within a container\n * @param container The DOM element containing code blocks\n * @param options Configuration options\n */\nexport function addCopyButtonsToCodeBlocks(\n container: HTMLElement,\n options?: CodeCopyOptions\n): void {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n\n const codeBlocks = container.querySelectorAll('pre > code');\n\n codeBlocks.forEach((codeBlock) => {\n const pre = codeBlock.parentElement;\n if (!pre) return;\n\n // Skip if already has toolbar\n if (pre.querySelector(`.${opts.toolbarClass}`)) return;\n\n // Create toolbar\n const toolbar = document.createElement('div');\n toolbar.className = opts.toolbarClass;\n\n // Add language label if enabled\n if (opts.showLanguageLabel) {\n const language = extractLanguageFromCode(codeBlock);\n if (language) {\n const label = document.createElement('span');\n label.className = 'code-language-label';\n label.textContent = formatLanguageName(language);\n toolbar.appendChild(label);\n }\n }\n\n // Create copy button\n const button = document.createElement('button');\n button.className = opts.buttonClass;\n button.innerHTML = opts.copyIcon;\n button.title = opts.tooltipText;\n button.type = 'button';\n button.setAttribute('aria-label', opts.tooltipText);\n\n // Add click handler\n button.addEventListener('click', async () => {\n const code = codeBlock.textContent || '';\n\n try {\n await navigator.clipboard.writeText(code);\n\n // Show success state\n button.innerHTML = opts.successIcon;\n button.classList.add('copied');\n\n // Call success callback\n opts.onCopy?.(code);\n\n // Reset after delay\n setTimeout(() => {\n button.innerHTML = opts.copyIcon;\n button.classList.remove('copied');\n }, opts.feedbackDuration);\n } catch (err) {\n console.error('Failed to copy code:', err);\n\n // Show error state\n button.innerHTML = opts.errorIcon;\n button.classList.add('error');\n\n // Call error callback\n opts.onError?.(err as Error);\n\n // Reset after delay\n setTimeout(() => {\n button.innerHTML = opts.copyIcon;\n button.classList.remove('error');\n }, opts.feedbackDuration);\n }\n });\n\n toolbar.appendChild(button);\n\n // Position the pre element for absolute positioning of toolbar\n pre.style.position = 'relative';\n pre.insertBefore(toolbar, pre.firstChild);\n });\n}\n\n/**\n * Extract the language class from a code element\n */\nfunction extractLanguageFromCode(codeElement: Element): string | null {\n const classes = codeElement.className.split(' ');\n\n for (const cls of classes) {\n if (cls.startsWith('language-')) {\n return cls.replace('language-', '');\n }\n }\n\n return null;\n}\n\n/**\n * Format a language identifier for display\n */\nfunction formatLanguageName(language: string): string {\n const languageMap: Record<string, string> = {\n js: 'JavaScript',\n ts: 'TypeScript',\n javascript: 'JavaScript',\n typescript: 'TypeScript',\n py: 'Python',\n python: 'Python',\n rb: 'Ruby',\n ruby: 'Ruby',\n cs: 'C#',\n csharp: 'C#',\n cpp: 'C++',\n 'c++': 'C++',\n html: 'HTML',\n css: 'CSS',\n scss: 'SCSS',\n sass: 'Sass',\n less: 'Less',\n json: 'JSON',\n yaml: 'YAML',\n yml: 'YAML',\n xml: 'XML',\n sql: 'SQL',\n bash: 'Bash',\n shell: 'Shell',\n sh: 'Shell',\n zsh: 'Zsh',\n powershell: 'PowerShell',\n ps1: 'PowerShell',\n md: 'Markdown',\n markdown: 'Markdown',\n graphql: 'GraphQL',\n gql: 'GraphQL',\n java: 'Java',\n kotlin: 'Kotlin',\n swift: 'Swift',\n go: 'Go',\n rust: 'Rust',\n php: 'PHP',\n r: 'R',\n dockerfile: 'Dockerfile',\n docker: 'Docker',\n nginx: 'Nginx',\n apache: 'Apache',\n ini: 'INI',\n toml: 'TOML',\n makefile: 'Makefile',\n diff: 'Diff',\n plaintext: 'Plain Text',\n text: 'Plain Text',\n mermaid: 'Mermaid'\n };\n\n return languageMap[language.toLowerCase()] || language.toUpperCase();\n}\n\n/**\n * Remove all copy buttons from code blocks in a container\n * Useful for cleanup when component is destroyed\n */\nexport function removeCopyButtonsFromCodeBlocks(\n container: HTMLElement,\n toolbarClass: string = 'code-toolbar'\n): void {\n const toolbars = container.querySelectorAll(`.${toolbarClass}`);\n toolbars.forEach((toolbar) => toolbar.remove());\n}\n"]}
1
+ {"version":3,"file":"code-copy.extension.js","sourceRoot":"","sources":["../../../src/lib/extensions/code-copy.extension.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Code copy extension utilities\n *\n * This module provides utilities for adding copy-to-clipboard functionality\n * to code blocks. Unlike other marked extensions, this operates on the DOM\n * after rendering since it requires adding interactive elements.\n */\nimport { formatLanguageName } from '@memberjunction/markdown-core';\n\n/**\n * Options for the code copy functionality\n */\nexport interface CodeCopyOptions {\n /**\n * CSS class for the copy button\n * @default 'code-copy-btn'\n */\n buttonClass?: string;\n\n /**\n * CSS class for the toolbar container\n * @default 'code-toolbar'\n */\n toolbarClass?: string;\n\n /**\n * Icon HTML for the copy button\n * @default '<i class=\"fas fa-copy\"></i>'\n */\n copyIcon?: string;\n\n /**\n * Icon HTML for successful copy\n * @default '<i class=\"fas fa-check\"></i>'\n */\n successIcon?: string;\n\n /**\n * Icon HTML for failed copy\n * @default '<i class=\"fas fa-times\"></i>'\n */\n errorIcon?: string;\n\n /**\n * Tooltip text for the copy button\n * @default 'Copy code'\n */\n tooltipText?: string;\n\n /**\n * Duration in ms to show success/error state\n * @default 2000\n */\n feedbackDuration?: number;\n\n /**\n * Callback when code is successfully copied\n */\n onCopy?: (code: string) => void;\n\n /**\n * Callback when copy fails\n */\n onError?: (error: Error) => void;\n\n /**\n * Whether to show the language label in the toolbar\n * @default true\n */\n showLanguageLabel?: boolean;\n}\n\nconst DEFAULT_OPTIONS: Required<Omit<CodeCopyOptions, 'onCopy' | 'onError'>> & Pick<CodeCopyOptions, 'onCopy' | 'onError'> = {\n buttonClass: 'code-copy-btn',\n toolbarClass: 'code-toolbar',\n copyIcon: '<i class=\"fas fa-copy\"></i>',\n successIcon: '<i class=\"fas fa-check\"></i>',\n errorIcon: '<i class=\"fas fa-times\"></i>',\n tooltipText: 'Copy code',\n feedbackDuration: 2000,\n showLanguageLabel: true,\n onCopy: undefined,\n onError: undefined\n};\n\n/**\n * Add copy buttons to all code blocks within a container\n * @param container The DOM element containing code blocks\n * @param options Configuration options\n */\nexport function addCopyButtonsToCodeBlocks(\n container: HTMLElement,\n options?: CodeCopyOptions\n): void {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n\n const codeBlocks = container.querySelectorAll('pre > code');\n\n codeBlocks.forEach((codeBlock) => {\n const pre = codeBlock.parentElement;\n if (!pre) return;\n\n // Skip if already has toolbar\n if (pre.querySelector(`.${opts.toolbarClass}`)) return;\n\n // Create toolbar\n const toolbar = document.createElement('div');\n toolbar.className = opts.toolbarClass;\n\n // Add language label if enabled\n if (opts.showLanguageLabel) {\n const language = extractLanguageFromCode(codeBlock);\n if (language) {\n const label = document.createElement('span');\n label.className = 'code-language-label';\n label.textContent = formatLanguageName(language);\n toolbar.appendChild(label);\n }\n }\n\n // Create copy button\n const button = document.createElement('button');\n button.className = opts.buttonClass;\n button.innerHTML = opts.copyIcon;\n button.title = opts.tooltipText;\n button.type = 'button';\n button.setAttribute('aria-label', opts.tooltipText);\n\n // Add click handler\n button.addEventListener('click', async () => {\n const code = codeBlock.textContent || '';\n\n try {\n await navigator.clipboard.writeText(code);\n\n // Show success state\n button.innerHTML = opts.successIcon;\n button.classList.add('copied');\n\n // Call success callback\n opts.onCopy?.(code);\n\n // Reset after delay\n setTimeout(() => {\n button.innerHTML = opts.copyIcon;\n button.classList.remove('copied');\n }, opts.feedbackDuration);\n } catch (err) {\n console.error('Failed to copy code:', err);\n\n // Show error state\n button.innerHTML = opts.errorIcon;\n button.classList.add('error');\n\n // Call error callback\n opts.onError?.(err as Error);\n\n // Reset after delay\n setTimeout(() => {\n button.innerHTML = opts.copyIcon;\n button.classList.remove('error');\n }, opts.feedbackDuration);\n }\n });\n\n toolbar.appendChild(button);\n\n // Position the pre element for absolute positioning of toolbar\n pre.style.position = 'relative';\n pre.insertBefore(toolbar, pre.firstChild);\n });\n}\n\n/**\n * Extract the language class from a code element\n */\nfunction extractLanguageFromCode(codeElement: Element): string | null {\n const classes = codeElement.className.split(' ');\n\n for (const cls of classes) {\n if (cls.startsWith('language-')) {\n return cls.replace('language-', '');\n }\n }\n\n return null;\n}\n\n/**\n * Remove all copy buttons from code blocks in a container\n * Useful for cleanup when component is destroyed\n */\nexport function removeCopyButtonsFromCodeBlocks(\n container: HTMLElement,\n toolbarClass: string = 'code-toolbar'\n): void {\n const toolbars = container.querySelectorAll(`.${toolbarClass}`);\n toolbars.forEach((toolbar) => toolbar.remove());\n}\n"]}
@@ -1,73 +1,11 @@
1
- import { MarkedExtension } from 'marked';
2
1
  /**
3
- * Options for the collapsible headings extension
4
- */
5
- export interface CollapsibleHeadingsOptions {
6
- /**
7
- * The minimum heading level to make collapsible (1-6)
8
- * Headings at this level and below will be collapsible
9
- * @default 2
10
- */
11
- startLevel?: 1 | 2 | 3 | 4 | 5 | 6;
12
- /**
13
- * Whether sections should be expanded by default
14
- * @default true
15
- */
16
- defaultExpanded?: boolean;
17
- /**
18
- * Specify which heading levels should start expanded.
19
- * Takes precedence over defaultExpanded for specified levels.
20
- * @default undefined (uses defaultExpanded for all levels)
21
- */
22
- autoExpandLevels?: number[];
23
- /**
24
- * CSS class prefix for generated elements
25
- * @default 'collapsible'
26
- */
27
- classPrefix?: string;
28
- }
29
- /**
30
- * Creates a marked extension that wraps heading sections in collapsible containers.
31
- *
32
- * This extension transforms headings into clickable toggles that can expand/collapse
33
- * the content that follows them (until the next heading of equal or higher level).
34
- *
35
- * The key innovation is that child sections are properly NESTED inside parent sections,
36
- * so collapsing a parent will hide all its children.
37
- *
38
- * Usage:
39
- * ```typescript
40
- * import { Marked } from 'marked';
41
- * import { createCollapsibleHeadingsExtension } from './collapsible-headings.extension';
42
- *
43
- * const marked = new Marked();
44
- * marked.use(createCollapsibleHeadingsExtension({ startLevel: 2 }));
45
- * ```
46
- *
47
- * The generated HTML structure (properly nested):
48
- * ```html
49
- * <div class="collapsible-section" data-level="2">
50
- * <div class="collapsible-heading-wrapper">
51
- * <h2 class="collapsible-heading" id="...">Parent Heading</h2>
52
- * </div>
53
- * <div class="collapsible-content">
54
- * <p>Content under parent...</p>
55
- * <div class="collapsible-section" data-level="3">
56
- * <div class="collapsible-heading-wrapper">
57
- * <h3 class="collapsible-heading" id="...">Child Heading</h3>
58
- * </div>
59
- * <div class="collapsible-content">
60
- * <p>Content under child...</p>
61
- * </div>
62
- * </div>
63
- * </div>
64
- * </div>
65
- * ```
2
+ * Web-only DOM helpers for collapsible heading sections.
66
3
  *
67
- * Note: The toggle button is added dynamically by the component after rendering
68
- * to avoid issues with Angular's HTML sanitizer.
4
+ * The framework-agnostic marked extension that produces the nested
5
+ * `<div class="collapsible-section">` HTML (`createCollapsibleHeadingsExtension`)
6
+ * now lives in `@memberjunction/markdown-core`. This file keeps the browser-only
7
+ * helpers that toggle the rendered sections in a live DOM.
69
8
  */
70
- export declare function createCollapsibleHeadingsExtension(options?: CollapsibleHeadingsOptions): MarkedExtension;
71
9
  /**
72
10
  * Helper function to toggle a collapsible section programmatically
73
11
  */
@@ -1 +1 @@
1
- {"version":3,"file":"collapsible-headings.extension.d.ts","sourceRoot":"","sources":["../../../src/lib/extensions/collapsible-headings.extension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAU,MAAM,QAAQ,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEnC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,kCAAkC,CAChD,OAAO,CAAC,EAAE,0BAA0B,GACnC,eAAe,CA8BjB;AAuID;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,WAAW,GAAG,IAAI,CAS1E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAS9D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAShE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAgB/E"}
1
+ {"version":3,"file":"collapsible-headings.extension.d.ts","sourceRoot":"","sources":["../../../src/lib/extensions/collapsible-headings.extension.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,WAAW,GAAG,IAAI,CAS1E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAS9D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAShE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAgB/E"}
@@ -1,185 +1,11 @@
1
- const DEFAULT_OPTIONS = {
2
- startLevel: 2,
3
- defaultExpanded: true,
4
- autoExpandLevels: undefined,
5
- classPrefix: 'collapsible'
6
- };
7
1
  /**
8
- * Creates a marked extension that wraps heading sections in collapsible containers.
2
+ * Web-only DOM helpers for collapsible heading sections.
9
3
  *
10
- * This extension transforms headings into clickable toggles that can expand/collapse
11
- * the content that follows them (until the next heading of equal or higher level).
12
- *
13
- * The key innovation is that child sections are properly NESTED inside parent sections,
14
- * so collapsing a parent will hide all its children.
15
- *
16
- * Usage:
17
- * ```typescript
18
- * import { Marked } from 'marked';
19
- * import { createCollapsibleHeadingsExtension } from './collapsible-headings.extension';
20
- *
21
- * const marked = new Marked();
22
- * marked.use(createCollapsibleHeadingsExtension({ startLevel: 2 }));
23
- * ```
24
- *
25
- * The generated HTML structure (properly nested):
26
- * ```html
27
- * <div class="collapsible-section" data-level="2">
28
- * <div class="collapsible-heading-wrapper">
29
- * <h2 class="collapsible-heading" id="...">Parent Heading</h2>
30
- * </div>
31
- * <div class="collapsible-content">
32
- * <p>Content under parent...</p>
33
- * <div class="collapsible-section" data-level="3">
34
- * <div class="collapsible-heading-wrapper">
35
- * <h3 class="collapsible-heading" id="...">Child Heading</h3>
36
- * </div>
37
- * <div class="collapsible-content">
38
- * <p>Content under child...</p>
39
- * </div>
40
- * </div>
41
- * </div>
42
- * </div>
43
- * ```
44
- *
45
- * Note: The toggle button is added dynamically by the component after rendering
46
- * to avoid issues with Angular's HTML sanitizer.
47
- */
48
- export function createCollapsibleHeadingsExtension(options) {
49
- const opts = { ...DEFAULT_OPTIONS, ...options };
50
- return {
51
- renderer: {
52
- // Mark headings with a special marker that we'll process in postprocess
53
- heading(token) {
54
- const { depth, text } = token;
55
- const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-');
56
- const id = `heading-${escapedText}`;
57
- // Only make headings collapsible at or below the start level
58
- if (depth >= opts.startLevel) {
59
- // Use a marker format that we'll parse in postprocess
60
- // Format: <!--COLLAPSIBLE_HEADING:level:id:text-->
61
- const marker = `<!--COLLAPSIBLE_HEADING:${depth}:${id}:${encodeURIComponent(text)}-->`;
62
- return `${marker}<h${depth} id="${id}">${text}</h${depth}>\n`;
63
- }
64
- // Regular heading rendering for levels above startLevel
65
- return `<h${depth} id="${id}">${text}</h${depth}>\n`;
66
- }
67
- },
68
- hooks: {
69
- postprocess(html) {
70
- return restructureToNestedSections(html, opts);
71
- }
72
- }
73
- };
74
- }
75
- /**
76
- * Restructures flat HTML with heading markers into properly nested collapsible sections.
77
- * This is the key function that creates the hierarchical structure needed for
78
- * parent collapse to affect children.
4
+ * The framework-agnostic marked extension that produces the nested
5
+ * `<div class="collapsible-section">` HTML (`createCollapsibleHeadingsExtension`)
6
+ * now lives in `@memberjunction/markdown-core`. This file keeps the browser-only
7
+ * helpers that toggle the rendered sections in a live DOM.
79
8
  */
80
- function restructureToNestedSections(html, opts) {
81
- // Parse the HTML to find all content chunks and headings
82
- const markerRegex = /<!--COLLAPSIBLE_HEADING:(\d):([^:]+):([^>]+)-->/g;
83
- // Split HTML by markers while capturing the markers
84
- const parts = [];
85
- let lastIndex = 0;
86
- let match;
87
- while ((match = markerRegex.exec(html)) !== null) {
88
- // Add content before this marker
89
- if (match.index > lastIndex) {
90
- const content = html.slice(lastIndex, match.index);
91
- if (content.trim()) {
92
- parts.push({ type: 'content', content });
93
- }
94
- }
95
- // Add the heading marker info
96
- parts.push({
97
- type: 'heading',
98
- content: '', // Will be filled with the actual h tag
99
- level: parseInt(match[1], 10),
100
- id: match[2],
101
- text: decodeURIComponent(match[3])
102
- });
103
- lastIndex = match.index + match[0].length;
104
- }
105
- // Add remaining content after last marker
106
- if (lastIndex < html.length) {
107
- const content = html.slice(lastIndex);
108
- if (content.trim()) {
109
- parts.push({ type: 'content', content });
110
- }
111
- }
112
- // If no collapsible headings, return original HTML
113
- if (!parts.some(p => p.type === 'heading')) {
114
- return html;
115
- }
116
- // Now build the nested structure
117
- return buildNestedStructure(parts, opts);
118
- }
119
- /**
120
- * Determine if a heading level should start expanded based on options
121
- */
122
- function shouldLevelBeExpanded(level, opts) {
123
- // If autoExpandLevels is specified, use it
124
- if (opts.autoExpandLevels !== undefined) {
125
- return opts.autoExpandLevels.includes(level);
126
- }
127
- // Otherwise fall back to defaultExpanded
128
- return opts.defaultExpanded;
129
- }
130
- /**
131
- * Builds the nested HTML structure from the parsed parts.
132
- */
133
- function buildNestedStructure(parts, opts) {
134
- const result = [];
135
- // Stack tracks open sections: { level, hasContent }
136
- const sectionStack = [];
137
- for (let i = 0; i < parts.length; i++) {
138
- const part = parts[i];
139
- if (part.type === 'content') {
140
- // Regular content - just add it
141
- result.push(part.content);
142
- }
143
- else if (part.type === 'heading' && part.level !== undefined) {
144
- const level = part.level;
145
- // Close any sections at same or higher level (lower number = higher level)
146
- while (sectionStack.length > 0 && sectionStack[sectionStack.length - 1].level >= level) {
147
- // Close the content div and section div
148
- result.push('</div></div>');
149
- sectionStack.pop();
150
- }
151
- // Determine expanded state for this specific level
152
- const isExpanded = shouldLevelBeExpanded(level, opts);
153
- const expandedClass = isExpanded ? '' : ' collapsed';
154
- // Extract the actual h tag from the next content piece if it starts with it
155
- let headingHtml = `<h${level} class="${opts.classPrefix}-heading" id="${part.id}">${part.text}</h${level}>`;
156
- // Look ahead to find and remove the actual h tag from content
157
- if (i + 1 < parts.length && parts[i + 1].type === 'content') {
158
- const nextContent = parts[i + 1].content;
159
- const hTagRegex = new RegExp(`<h${level}[^>]*id="${part.id}"[^>]*>[^<]*</h${level}>\\s*`);
160
- const hTagMatch = nextContent.match(hTagRegex);
161
- if (hTagMatch) {
162
- // Use the actual h tag and remove it from content
163
- headingHtml = hTagMatch[0].replace(`<h${level}`, `<h${level} class="${opts.classPrefix}-heading"`);
164
- parts[i + 1].content = nextContent.replace(hTagRegex, '');
165
- }
166
- }
167
- // Open new section
168
- result.push(`<div class="${opts.classPrefix}-section${expandedClass}" data-level="${level}">`);
169
- result.push(`<div class="${opts.classPrefix}-heading-wrapper">`);
170
- result.push(headingHtml);
171
- result.push('</div>');
172
- result.push(`<div class="${opts.classPrefix}-content">`);
173
- sectionStack.push({ level });
174
- }
175
- }
176
- // Close any remaining open sections
177
- while (sectionStack.length > 0) {
178
- result.push('</div></div>');
179
- sectionStack.pop();
180
- }
181
- return result.join('');
182
- }
183
9
  /**
184
10
  * Helper function to toggle a collapsible section programmatically
185
11
  */