@memberjunction/ng-artifacts 5.27.1 → 5.29.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 (65) hide show
  1. package/dist/lib/__tests__/artifact-snapshots.test.d.ts +2 -0
  2. package/dist/lib/__tests__/artifact-snapshots.test.d.ts.map +1 -0
  3. package/dist/lib/__tests__/artifact-snapshots.test.js +155 -0
  4. package/dist/lib/__tests__/artifact-snapshots.test.js.map +1 -0
  5. package/dist/lib/components/artifact-viewer-panel.component.d.ts +16 -2
  6. package/dist/lib/components/artifact-viewer-panel.component.d.ts.map +1 -1
  7. package/dist/lib/components/artifact-viewer-panel.component.js +128 -98
  8. package/dist/lib/components/artifact-viewer-panel.component.js.map +1 -1
  9. package/dist/lib/components/base-artifact-viewer.component.d.ts +24 -0
  10. package/dist/lib/components/base-artifact-viewer.component.d.ts.map +1 -1
  11. package/dist/lib/components/base-artifact-viewer.component.js +15 -1
  12. package/dist/lib/components/base-artifact-viewer.component.js.map +1 -1
  13. package/dist/lib/components/plugins/code-artifact-viewer.component.d.ts +2 -0
  14. package/dist/lib/components/plugins/code-artifact-viewer.component.d.ts.map +1 -1
  15. package/dist/lib/components/plugins/code-artifact-viewer.component.js +5 -1
  16. package/dist/lib/components/plugins/code-artifact-viewer.component.js.map +1 -1
  17. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts +2 -1
  18. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts.map +1 -1
  19. package/dist/lib/components/plugins/component-artifact-viewer.component.js +29 -0
  20. package/dist/lib/components/plugins/component-artifact-viewer.component.js.map +1 -1
  21. package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts +50 -43
  22. package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts.map +1 -1
  23. package/dist/lib/components/plugins/data-artifact-viewer.component.js +336 -137
  24. package/dist/lib/components/plugins/data-artifact-viewer.component.js.map +1 -1
  25. package/dist/lib/components/plugins/docx-artifact-viewer.component.d.ts +2 -0
  26. package/dist/lib/components/plugins/docx-artifact-viewer.component.d.ts.map +1 -1
  27. package/dist/lib/components/plugins/docx-artifact-viewer.component.js +21 -6
  28. package/dist/lib/components/plugins/docx-artifact-viewer.component.js.map +1 -1
  29. package/dist/lib/components/plugins/html-artifact-viewer.component.d.ts +2 -0
  30. package/dist/lib/components/plugins/html-artifact-viewer.component.d.ts.map +1 -1
  31. package/dist/lib/components/plugins/html-artifact-viewer.component.js +11 -1
  32. package/dist/lib/components/plugins/html-artifact-viewer.component.js.map +1 -1
  33. package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts +2 -0
  34. package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts.map +1 -1
  35. package/dist/lib/components/plugins/json-artifact-viewer.component.js +5 -1
  36. package/dist/lib/components/plugins/json-artifact-viewer.component.js.map +1 -1
  37. package/dist/lib/components/plugins/markdown-artifact-viewer.component.d.ts +2 -0
  38. package/dist/lib/components/plugins/markdown-artifact-viewer.component.d.ts.map +1 -1
  39. package/dist/lib/components/plugins/markdown-artifact-viewer.component.js +5 -1
  40. package/dist/lib/components/plugins/markdown-artifact-viewer.component.js.map +1 -1
  41. package/dist/lib/components/plugins/pdf-artifact-viewer.component.d.ts +2 -0
  42. package/dist/lib/components/plugins/pdf-artifact-viewer.component.d.ts.map +1 -1
  43. package/dist/lib/components/plugins/pdf-artifact-viewer.component.js +29 -10
  44. package/dist/lib/components/plugins/pdf-artifact-viewer.component.js.map +1 -1
  45. package/dist/lib/components/plugins/svg-artifact-viewer.component.d.ts +2 -0
  46. package/dist/lib/components/plugins/svg-artifact-viewer.component.d.ts.map +1 -1
  47. package/dist/lib/components/plugins/svg-artifact-viewer.component.js +11 -1
  48. package/dist/lib/components/plugins/svg-artifact-viewer.component.js.map +1 -1
  49. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.d.ts +2 -0
  50. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.d.ts.map +1 -1
  51. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.js +39 -13
  52. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.js.map +1 -1
  53. package/dist/lib/services/analyze-artifact.service.d.ts +77 -0
  54. package/dist/lib/services/analyze-artifact.service.d.ts.map +1 -0
  55. package/dist/lib/services/analyze-artifact.service.js +120 -0
  56. package/dist/lib/services/analyze-artifact.service.js.map +1 -0
  57. package/dist/lib/snapshot-helpers.d.ts +48 -0
  58. package/dist/lib/snapshot-helpers.d.ts.map +1 -0
  59. package/dist/lib/snapshot-helpers.js +79 -0
  60. package/dist/lib/snapshot-helpers.js.map +1 -0
  61. package/dist/public-api.d.ts +2 -0
  62. package/dist/public-api.d.ts.map +1 -1
  63. package/dist/public-api.js +3 -0
  64. package/dist/public-api.js.map +1 -1
  65. package/package.json +16 -16
@@ -1 +1 @@
1
- {"version":3,"file":"json-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/json-artifact-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAa,UAAU,EAAE,MAAM,eAAe,CAAC;AACvG,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;AAItF;;;;GAIG;AACH,qBAsHa,2BAA4B,SAAQ,iCAAkC,YAAW,MAAM,EAAE,SAAS;IAkB3G,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,SAAS;IAlBK,SAAS,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAE3D,WAAW,SAAM;IACjB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAQ;IACtC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAClC,WAAW,EAAE,eAAe,GAAG,IAAI,CAAQ;IAClD,OAAO,CAAC,iBAAiB,CAA0C;IACnE,OAAO,CAAC,aAAa,CAAuB;IAE5C;;OAEG;IACH,IAAoB,iBAAiB,IAAI,OAAO,CAE/C;gBAGS,GAAG,EAAE,iBAAiB,EACtB,SAAS,EAAE,YAAY;IAKjC,WAAW,IAAI,IAAI;IASb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAU/B;;;OAGG;IACH,IAAoB,wBAAwB,IAAI,OAAO,CAEtD;IAED;;;;OAIG;IACH,IAAoB,0BAA0B,IAAI,OAAO,CAExD;YAEa,qBAAqB;IA6DnC,OAAO,CAAC,mBAAmB;IAyB3B,YAAY,IAAI,IAAI;IA2DpB,OAAO,CAAC,qBAAqB;IAsB7B,eAAe,IAAI,IAAI;IAUvB,SAAS,IAAI,IAAI;IAWjB,MAAM,IAAI,IAAI;IAYd;;;OAGG;IACH,OAAO,CAAC,sBAAsB;yCAxQnB,2BAA2B;2CAA3B,2BAA2B;CA2RvC"}
1
+ {"version":3,"file":"json-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/json-artifact-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAa,UAAU,EAAE,MAAM,eAAe,CAAC;AACvG,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AACtF,OAAO,EAAE,YAAY,EAAW,MAAM,sBAAsB,CAAC;;AAI7D;;;;GAIG;AACH,qBAsHa,2BAA4B,SAAQ,iCAAkC,YAAW,MAAM,EAAE,SAAS;IAkB3G,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,SAAS;IAlBK,SAAS,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAE3D,WAAW,SAAM;IACjB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAQ;IACtC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAClC,WAAW,EAAE,eAAe,GAAG,IAAI,CAAQ;IAClD,OAAO,CAAC,iBAAiB,CAA0C;IACnE,OAAO,CAAC,aAAa,CAAuB;IAE5C;;OAEG;IACH,IAAoB,iBAAiB,IAAI,OAAO,CAE/C;gBAGS,GAAG,EAAE,iBAAiB,EACtB,SAAS,EAAE,YAAY;IAKjC,WAAW,IAAI,IAAI;IASb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAU/B;;;OAGG;IACH,IAAoB,wBAAwB,IAAI,OAAO,CAEtD;IAED;;;;OAIG;IACH,IAAoB,0BAA0B,IAAI,OAAO,CAExD;YAEa,qBAAqB;IA6DnC,OAAO,CAAC,mBAAmB;IAyB3B,YAAY,IAAI,IAAI;IA2DpB,OAAO,CAAC,qBAAqB;IAsB7B,eAAe,IAAI,IAAI;IAUvB,SAAS,IAAI,IAAI;IAWjB,MAAM,IAAI,IAAI;IAYE,uBAAuB,IAAI,YAAY,GAAG,IAAI;IAI9D;;;OAGG;IACH,OAAO,CAAC,sBAAsB;yCA5QnB,2BAA2B;2CAA3B,2BAA2B;CA+RvC"}
@@ -8,6 +8,7 @@ import { Component, ViewChild } from '@angular/core';
8
8
  import { RegisterClass } from '@memberjunction/global';
9
9
  import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
10
10
  import { RunView } from '@memberjunction/core';
11
+ import { createJsonSnapshot } from '../../snapshot-helpers';
11
12
  import * as i0 from "@angular/core";
12
13
  import * as i1 from "@angular/platform-browser";
13
14
  import * as i2 from "@angular/common";
@@ -283,6 +284,9 @@ let JsonArtifactViewerComponent = class JsonArtifactViewerComponent extends Base
283
284
  });
284
285
  }
285
286
  }
287
+ GetCurrentStateSnapshot() {
288
+ return createJsonSnapshot(this.getRawContent(), this.getDisplayTitle());
289
+ }
286
290
  /**
287
291
  * Clean up double-escaped characters that appear in LLM-generated HTML
288
292
  * Removes literal "\\n", "\\t", and "\\\"" which cause rendering issues
@@ -385,5 +389,5 @@ export { JsonArtifactViewerComponent };
385
389
  type: ViewChild,
386
390
  args: ['htmlFrame']
387
391
  }] }); })();
388
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(JsonArtifactViewerComponent, { className: "JsonArtifactViewerComponent", filePath: "src/lib/components/plugins/json-artifact-viewer.component.ts", lineNumber: 131 }); })();
392
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(JsonArtifactViewerComponent, { className: "JsonArtifactViewerComponent", filePath: "src/lib/components/plugins/json-artifact-viewer.component.ts", lineNumber: 132 }); })();
389
393
  //# sourceMappingURL=json-artifact-viewer.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"json-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/json-artifact-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef, ViewChild, ElementRef } from '@angular/core';\nimport { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { RunView } from '@memberjunction/core';\nimport { MJArtifactVersionAttributeEntity } from '@memberjunction/core-entities';\n\n/**\n * Viewer component for JSON artifacts.\n * Supports extract rules - shows displayMarkdown, displayHtml, or raw JSON editor (in that priority order).\n * All content is displayed in the parent's Display tab.\n */\n@Component({\n standalone: false,\n selector: 'mj-json-artifact-viewer',\n template: `\n <div class=\"json-artifact-viewer\" [ngClass]=\"cssClass\">\n <!-- Display toolbar -->\n <div class=\"display-toolbar\">\n <button class=\"btn-icon\" title=\"Copy Content\" (click)=\"onCopy()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n @if (displayHtml) {\n <button class=\"btn-icon\" title=\"Open in New Window\" (click)=\"openInNewWindow()\">\n <i class=\"fas fa-external-link-alt\"></i> New Window\n </button>\n <button class=\"btn-icon\" title=\"Print\" (click)=\"printHtml()\">\n <i class=\"fas fa-print\"></i> Print\n </button>\n }\n </div>\n\n <!-- Display content: priority order = displayHtml > displayMarkdown > JSON editor -->\n <div class=\"display-content\">\n @if (displayHtml && htmlBlobUrl) {\n <!-- Sandboxed iframe for rich HTML using blob URL -->\n <iframe\n #htmlFrame\n [src]=\"htmlBlobUrl\"\n sandbox=\"allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox allow-modals\"\n class=\"html-iframe\"\n (load)=\"onIframeLoad()\">\n </iframe>\n } @else if (displayMarkdown) {\n <div class=\"markdown-content\">\n <mj-markdown [data]=\"displayMarkdown\"\n [enableCollapsibleHeadings]=\"true\"\n [enableLineNumbers]=\"true\"\n [enableSmartypants]=\"true\"\n [enableHtml]=\"true\"></mj-markdown>\n </div>\n } @else {\n <div class=\"json-editor-container\">\n <mj-code-editor\n [(ngModel)]=\"jsonContent\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n </div>\n }\n </div>\n </div>\n `,\n styles: [`\n .json-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .display-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .btn-icon {\n padding: 6px 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n }\n\n .btn-icon:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-text-disabled);\n }\n\n .display-content {\n flex: 1;\n overflow: auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n }\n\n .html-iframe {\n width: 100%;\n border: none;\n background: var(--mj-bg-surface);\n display: block;\n }\n\n .markdown-content {\n flex: 1;\n padding: 20px;\n overflow: auto;\n min-height: 0;\n background: var(--mj-bg-surface);\n }\n\n .json-editor-container {\n flex: 1;\n overflow: auto;\n min-height: 0;\n }\n `]\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'JsonArtifactViewerPlugin')\nexport class JsonArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit, OnDestroy {\n @ViewChild('htmlFrame') htmlFrame?: ElementRef<HTMLIFrameElement>;\n\n public jsonContent = '';\n public displayMarkdown: string | null = null;\n public displayHtml: string | null = null;\n public htmlBlobUrl: SafeResourceUrl | null = null;\n private versionAttributes: MJArtifactVersionAttributeEntity[] = [];\n private unsafeBlobUrl: string | null = null; // Keep unsafe URL for cleanup\n\n /**\n * JSON artifacts always have content to display (JSON editor, displayHtml, or displayMarkdown)\n */\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n constructor(\n private cdr: ChangeDetectorRef,\n private sanitizer: DomSanitizer\n ) {\n super();\n }\n\n ngOnDestroy(): void {\n // Clean up blob URL to prevent memory leaks\n if (this.unsafeBlobUrl) {\n URL.revokeObjectURL(this.unsafeBlobUrl);\n this.unsafeBlobUrl = null;\n this.htmlBlobUrl = null;\n }\n }\n\n async ngOnInit(): Promise<void> {\n this.jsonContent = this.getContent();\n\n // Load version attributes to check for extract rules\n await this.loadVersionAttributes();\n\n // Trigger change detection after async load\n this.cdr.detectChanges();\n }\n\n /**\n * Override to return true when showing extracted displayHtml or displayMarkdown.\n * Returns false when showing raw JSON editor (no extract rules available).\n */\n public override get isShowingElevatedDisplay(): boolean {\n return !!(this.displayHtml || this.displayMarkdown);\n }\n\n /**\n * Override to tell parent whether to show raw JSON tab.\n * When showing elevated display (markdown/HTML), return true so parent shows JSON tab.\n * When showing raw JSON editor, return false (no need for duplicate JSON tab).\n */\n public override get parentShouldShowRawContent(): boolean {\n return this.isShowingElevatedDisplay;\n }\n\n private async loadVersionAttributes(): Promise<void> {\n if (!this.artifactVersion?.ID) {\n console.log('📦 JSON Plugin: No artifactVersion.ID, skipping attribute load');\n return;\n }\n\n console.log(`📦 JSON Plugin: Loading attributes for version ID: ${this.artifactVersion.ID}`);\n\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJArtifactVersionAttributeEntity>({\n EntityName: 'MJ: Artifact Version Attributes',\n ExtraFilter: `ArtifactVersionID='${this.artifactVersion.ID}'`,\n ResultType: 'entity_object'\n });\n\n console.log(`📦 JSON Plugin: RunView completed. Success=${result.Success}, Results count=${result.Results?.length || 0}`);\n\n if (result.Success && result.Results) {\n this.versionAttributes = result.Results;\n\n console.log(`📦 JSON Plugin: Loaded ${this.versionAttributes.length} attributes for version ${this.artifactVersion.ID}`);\n console.log(`📦 Attributes:`, this.versionAttributes.map(a => ({ name: a.Name, hasValue: !!a.Value })));\n\n // Check for displayHtml and displayMarkdown attributes (from extract rules)\n // Priority: displayHtml > displayMarkdown\n const displayHtmlAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'displayhtml');\n const displayMarkdownAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'displaymarkdown');\n\n console.log(`📦 displayHtmlAttr:`, displayHtmlAttr ? { name: displayHtmlAttr.Name, valueLength: displayHtmlAttr.Value?.length } : 'not found');\n console.log(`📦 displayMarkdownAttr:`, displayMarkdownAttr ? { name: displayMarkdownAttr.Name, valueLength: displayMarkdownAttr.Value?.length } : 'not found');\n\n // Parse attribute values - fix \"null\" string bug\n this.displayHtml = this.parseAttributeValue(displayHtmlAttr?.Value);\n this.displayMarkdown = this.parseAttributeValue(displayMarkdownAttr?.Value);\n\n // Clean up double-escaped characters in HTML (from LLM generation)\n if (this.displayHtml) {\n this.displayHtml = this.cleanEscapedCharacters(this.displayHtml);\n }\n\n // Create blob URL for HTML to avoid srcdoc sanitization issues\n if (this.displayHtml) {\n const blob = new Blob([this.displayHtml], { type: 'text/html' });\n this.unsafeBlobUrl = URL.createObjectURL(blob);\n // Sanitize the blob URL so Angular trusts it in the iframe\n this.htmlBlobUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.unsafeBlobUrl);\n }\n\n // Note: Markdown rendering is now handled by <mj-markdown> component in template\n\n console.log(`📦 JSON Plugin: displayHtml=${!!this.displayHtml} (${this.displayHtml?.length || 0} chars), displayMarkdown=${!!this.displayMarkdown} (${this.displayMarkdown?.length || 0} chars)`);\n console.log(`📦 isShowingElevatedDisplay=${this.isShowingElevatedDisplay}`);\n } else {\n console.log(`📦 JSON Plugin: No attributes found or query failed. Success=${result.Success}, ResultsLength=${result.Results?.length}`);\n }\n } catch (err) {\n console.error('📦 JSON Plugin: Error loading version attributes:', err);\n }\n }\n\n private parseAttributeValue(value: string | null | undefined): string | null {\n if (!value) return null;\n\n // Fix bug: Some extractors return string \"null\" instead of actual null\n if (value === 'null' || value.trim() === '') {\n return null;\n }\n\n try {\n // Try to parse as JSON first\n const parsed = JSON.parse(value);\n if (typeof parsed === 'string') {\n // Check if parsed string is also \"null\"\n if (parsed === 'null' || parsed.trim() === '') {\n return null;\n }\n return parsed;\n }\n return JSON.stringify(parsed, null, 2);\n } catch {\n // If not valid JSON, return as-is (unless it's \"null\")\n return value === 'null' ? null : value;\n }\n }\n\n onIframeLoad(): void {\n // Inject base styles if HTML doesn't have them\n if (this.htmlFrame) {\n const iframe = this.htmlFrame.nativeElement;\n const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;\n\n if (iframeDoc) {\n // Check if HTML already has styles\n const hasStyles = iframeDoc.querySelector('style') || iframeDoc.querySelector('link[rel=\"stylesheet\"]');\n\n if (!hasStyles) {\n // Inject minimal base styles for better defaults\n const style = iframeDoc.createElement('style');\n style.textContent = `\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n line-height: 1.6;\n color: #333;\n margin: 20px;\n padding: 0;\n }\n h1, h2, h3 { color: #2c3e50; margin-top: 1.5em; margin-bottom: 0.5em; }\n h1 { font-size: 2em; border-bottom: 2px solid #3498db; padding-bottom: 0.3em; }\n h2 { font-size: 1.5em; }\n table { border-collapse: collapse; width: 100%; margin: 1em 0; }\n th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }\n th { background-color: #f8f9fa; font-weight: 600; }\n pre { background: #f6f8fa; padding: 16px; border-radius: 6px; overflow-x: auto; }\n code { background: #f6f8fa; padding: 2px 6px; border-radius: 3px; font-family: monospace; }\n `;\n iframeDoc.head.appendChild(style);\n }\n\n // Inject width guardrails to prevent iframe content from causing horizontal overflow\n const widthOverride = iframeDoc.createElement('style');\n widthOverride.textContent = `\n html, body {\n max-width: 100% !important;\n overflow-x: hidden !important;\n }\n body {\n margin: 20px 10px 5px 20px !important; /* top right bottom left */\n padding: 0 !important;\n box-sizing: border-box !important;\n }\n img, svg, table, pre {\n max-width: 100% !important;\n }\n `;\n iframeDoc.head.appendChild(widthOverride);\n\n console.log('📦 Iframe loaded, hasStyles:', !!hasStyles);\n\n // Auto-resize iframe to fit content\n this.resizeIframeToContent();\n }\n }\n }\n\n private resizeIframeToContent(): void {\n if (this.htmlFrame) {\n const iframe = this.htmlFrame.nativeElement;\n const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;\n\n if (iframeDoc && iframeDoc.body) {\n // Get the actual content height\n const contentHeight = Math.max(\n iframeDoc.body.scrollHeight,\n iframeDoc.body.offsetHeight,\n iframeDoc.documentElement.scrollHeight,\n iframeDoc.documentElement.offsetHeight\n );\n\n // Set iframe height to match content (with a bit of padding)\n iframe.style.height = `${contentHeight + 20}px`;\n\n console.log('📦 Iframe resized - Height:', contentHeight + 20, 'px');\n }\n }\n }\n\n openInNewWindow(): void {\n if (this.displayHtml) {\n const newWindow = window.open('', '_blank');\n if (newWindow) {\n newWindow.document.write(this.displayHtml);\n newWindow.document.close();\n }\n }\n }\n\n printHtml(): void {\n if (this.htmlFrame) {\n const iframe = this.htmlFrame.nativeElement;\n const iframeWindow = iframe.contentWindow;\n if (iframeWindow) {\n iframeWindow.focus();\n iframeWindow.print();\n }\n }\n }\n\n onCopy(): void {\n // Copy based on what's being displayed - prioritize displayHtml\n const content = this.displayHtml || this.displayMarkdown || this.jsonContent;\n if (content) {\n navigator.clipboard.writeText(content).then(() => {\n console.log('✅ Copied content to clipboard');\n }).catch(err => {\n console.error('Failed to copy to clipboard:', err);\n });\n }\n }\n\n /**\n * Clean up double-escaped characters that appear in LLM-generated HTML\n * Removes literal \"\\\\n\", \"\\\\t\", and \"\\\\\\\"\" which cause rendering issues\n */\n private cleanEscapedCharacters(html: string): string {\n // Remove escaped quotes (\\\" becomes \")\n let cleaned = html.replace(/\\\\\"/g, '\"');\n\n // Remove escaped newlines (\\\\n becomes nothing)\n // HTML doesn't need whitespace for formatting, and these cause display issues\n cleaned = cleaned.replace(/\\\\n/g, '');\n\n // Remove escaped tabs\n cleaned = cleaned.replace(/\\\\t/g, '');\n\n // Remove double-escaped tabs\n cleaned = cleaned.replace(/\\\\\\\\t/g, '');\n\n // Remove double-escaped newlines\n cleaned = cleaned.replace(/\\\\\\\\n/g, '');\n\n return cleaned;\n }\n}\n"]}
1
+ {"version":3,"file":"json-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/json-artifact-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef, ViewChild, ElementRef } from '@angular/core';\nimport { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { DataSnapshot, RunView } from '@memberjunction/core';\nimport { MJArtifactVersionAttributeEntity } from '@memberjunction/core-entities';\nimport { createJsonSnapshot } from '../../snapshot-helpers';\n\n/**\n * Viewer component for JSON artifacts.\n * Supports extract rules - shows displayMarkdown, displayHtml, or raw JSON editor (in that priority order).\n * All content is displayed in the parent's Display tab.\n */\n@Component({\n standalone: false,\n selector: 'mj-json-artifact-viewer',\n template: `\n <div class=\"json-artifact-viewer\" [ngClass]=\"cssClass\">\n <!-- Display toolbar -->\n <div class=\"display-toolbar\">\n <button class=\"btn-icon\" title=\"Copy Content\" (click)=\"onCopy()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n @if (displayHtml) {\n <button class=\"btn-icon\" title=\"Open in New Window\" (click)=\"openInNewWindow()\">\n <i class=\"fas fa-external-link-alt\"></i> New Window\n </button>\n <button class=\"btn-icon\" title=\"Print\" (click)=\"printHtml()\">\n <i class=\"fas fa-print\"></i> Print\n </button>\n }\n </div>\n\n <!-- Display content: priority order = displayHtml > displayMarkdown > JSON editor -->\n <div class=\"display-content\">\n @if (displayHtml && htmlBlobUrl) {\n <!-- Sandboxed iframe for rich HTML using blob URL -->\n <iframe\n #htmlFrame\n [src]=\"htmlBlobUrl\"\n sandbox=\"allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox allow-modals\"\n class=\"html-iframe\"\n (load)=\"onIframeLoad()\">\n </iframe>\n } @else if (displayMarkdown) {\n <div class=\"markdown-content\">\n <mj-markdown [data]=\"displayMarkdown\"\n [enableCollapsibleHeadings]=\"true\"\n [enableLineNumbers]=\"true\"\n [enableSmartypants]=\"true\"\n [enableHtml]=\"true\"></mj-markdown>\n </div>\n } @else {\n <div class=\"json-editor-container\">\n <mj-code-editor\n [(ngModel)]=\"jsonContent\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n </div>\n }\n </div>\n </div>\n `,\n styles: [`\n .json-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .display-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .btn-icon {\n padding: 6px 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n }\n\n .btn-icon:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-text-disabled);\n }\n\n .display-content {\n flex: 1;\n overflow: auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n }\n\n .html-iframe {\n width: 100%;\n border: none;\n background: var(--mj-bg-surface);\n display: block;\n }\n\n .markdown-content {\n flex: 1;\n padding: 20px;\n overflow: auto;\n min-height: 0;\n background: var(--mj-bg-surface);\n }\n\n .json-editor-container {\n flex: 1;\n overflow: auto;\n min-height: 0;\n }\n `]\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'JsonArtifactViewerPlugin')\nexport class JsonArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit, OnDestroy {\n @ViewChild('htmlFrame') htmlFrame?: ElementRef<HTMLIFrameElement>;\n\n public jsonContent = '';\n public displayMarkdown: string | null = null;\n public displayHtml: string | null = null;\n public htmlBlobUrl: SafeResourceUrl | null = null;\n private versionAttributes: MJArtifactVersionAttributeEntity[] = [];\n private unsafeBlobUrl: string | null = null; // Keep unsafe URL for cleanup\n\n /**\n * JSON artifacts always have content to display (JSON editor, displayHtml, or displayMarkdown)\n */\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n constructor(\n private cdr: ChangeDetectorRef,\n private sanitizer: DomSanitizer\n ) {\n super();\n }\n\n ngOnDestroy(): void {\n // Clean up blob URL to prevent memory leaks\n if (this.unsafeBlobUrl) {\n URL.revokeObjectURL(this.unsafeBlobUrl);\n this.unsafeBlobUrl = null;\n this.htmlBlobUrl = null;\n }\n }\n\n async ngOnInit(): Promise<void> {\n this.jsonContent = this.getContent();\n\n // Load version attributes to check for extract rules\n await this.loadVersionAttributes();\n\n // Trigger change detection after async load\n this.cdr.detectChanges();\n }\n\n /**\n * Override to return true when showing extracted displayHtml or displayMarkdown.\n * Returns false when showing raw JSON editor (no extract rules available).\n */\n public override get isShowingElevatedDisplay(): boolean {\n return !!(this.displayHtml || this.displayMarkdown);\n }\n\n /**\n * Override to tell parent whether to show raw JSON tab.\n * When showing elevated display (markdown/HTML), return true so parent shows JSON tab.\n * When showing raw JSON editor, return false (no need for duplicate JSON tab).\n */\n public override get parentShouldShowRawContent(): boolean {\n return this.isShowingElevatedDisplay;\n }\n\n private async loadVersionAttributes(): Promise<void> {\n if (!this.artifactVersion?.ID) {\n console.log('📦 JSON Plugin: No artifactVersion.ID, skipping attribute load');\n return;\n }\n\n console.log(`📦 JSON Plugin: Loading attributes for version ID: ${this.artifactVersion.ID}`);\n\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJArtifactVersionAttributeEntity>({\n EntityName: 'MJ: Artifact Version Attributes',\n ExtraFilter: `ArtifactVersionID='${this.artifactVersion.ID}'`,\n ResultType: 'entity_object'\n });\n\n console.log(`📦 JSON Plugin: RunView completed. Success=${result.Success}, Results count=${result.Results?.length || 0}`);\n\n if (result.Success && result.Results) {\n this.versionAttributes = result.Results;\n\n console.log(`📦 JSON Plugin: Loaded ${this.versionAttributes.length} attributes for version ${this.artifactVersion.ID}`);\n console.log(`📦 Attributes:`, this.versionAttributes.map(a => ({ name: a.Name, hasValue: !!a.Value })));\n\n // Check for displayHtml and displayMarkdown attributes (from extract rules)\n // Priority: displayHtml > displayMarkdown\n const displayHtmlAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'displayhtml');\n const displayMarkdownAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'displaymarkdown');\n\n console.log(`📦 displayHtmlAttr:`, displayHtmlAttr ? { name: displayHtmlAttr.Name, valueLength: displayHtmlAttr.Value?.length } : 'not found');\n console.log(`📦 displayMarkdownAttr:`, displayMarkdownAttr ? { name: displayMarkdownAttr.Name, valueLength: displayMarkdownAttr.Value?.length } : 'not found');\n\n // Parse attribute values - fix \"null\" string bug\n this.displayHtml = this.parseAttributeValue(displayHtmlAttr?.Value);\n this.displayMarkdown = this.parseAttributeValue(displayMarkdownAttr?.Value);\n\n // Clean up double-escaped characters in HTML (from LLM generation)\n if (this.displayHtml) {\n this.displayHtml = this.cleanEscapedCharacters(this.displayHtml);\n }\n\n // Create blob URL for HTML to avoid srcdoc sanitization issues\n if (this.displayHtml) {\n const blob = new Blob([this.displayHtml], { type: 'text/html' });\n this.unsafeBlobUrl = URL.createObjectURL(blob);\n // Sanitize the blob URL so Angular trusts it in the iframe\n this.htmlBlobUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.unsafeBlobUrl);\n }\n\n // Note: Markdown rendering is now handled by <mj-markdown> component in template\n\n console.log(`📦 JSON Plugin: displayHtml=${!!this.displayHtml} (${this.displayHtml?.length || 0} chars), displayMarkdown=${!!this.displayMarkdown} (${this.displayMarkdown?.length || 0} chars)`);\n console.log(`📦 isShowingElevatedDisplay=${this.isShowingElevatedDisplay}`);\n } else {\n console.log(`📦 JSON Plugin: No attributes found or query failed. Success=${result.Success}, ResultsLength=${result.Results?.length}`);\n }\n } catch (err) {\n console.error('📦 JSON Plugin: Error loading version attributes:', err);\n }\n }\n\n private parseAttributeValue(value: string | null | undefined): string | null {\n if (!value) return null;\n\n // Fix bug: Some extractors return string \"null\" instead of actual null\n if (value === 'null' || value.trim() === '') {\n return null;\n }\n\n try {\n // Try to parse as JSON first\n const parsed = JSON.parse(value);\n if (typeof parsed === 'string') {\n // Check if parsed string is also \"null\"\n if (parsed === 'null' || parsed.trim() === '') {\n return null;\n }\n return parsed;\n }\n return JSON.stringify(parsed, null, 2);\n } catch {\n // If not valid JSON, return as-is (unless it's \"null\")\n return value === 'null' ? null : value;\n }\n }\n\n onIframeLoad(): void {\n // Inject base styles if HTML doesn't have them\n if (this.htmlFrame) {\n const iframe = this.htmlFrame.nativeElement;\n const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;\n\n if (iframeDoc) {\n // Check if HTML already has styles\n const hasStyles = iframeDoc.querySelector('style') || iframeDoc.querySelector('link[rel=\"stylesheet\"]');\n\n if (!hasStyles) {\n // Inject minimal base styles for better defaults\n const style = iframeDoc.createElement('style');\n style.textContent = `\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n line-height: 1.6;\n color: #333;\n margin: 20px;\n padding: 0;\n }\n h1, h2, h3 { color: #2c3e50; margin-top: 1.5em; margin-bottom: 0.5em; }\n h1 { font-size: 2em; border-bottom: 2px solid #3498db; padding-bottom: 0.3em; }\n h2 { font-size: 1.5em; }\n table { border-collapse: collapse; width: 100%; margin: 1em 0; }\n th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }\n th { background-color: #f8f9fa; font-weight: 600; }\n pre { background: #f6f8fa; padding: 16px; border-radius: 6px; overflow-x: auto; }\n code { background: #f6f8fa; padding: 2px 6px; border-radius: 3px; font-family: monospace; }\n `;\n iframeDoc.head.appendChild(style);\n }\n\n // Inject width guardrails to prevent iframe content from causing horizontal overflow\n const widthOverride = iframeDoc.createElement('style');\n widthOverride.textContent = `\n html, body {\n max-width: 100% !important;\n overflow-x: hidden !important;\n }\n body {\n margin: 20px 10px 5px 20px !important; /* top right bottom left */\n padding: 0 !important;\n box-sizing: border-box !important;\n }\n img, svg, table, pre {\n max-width: 100% !important;\n }\n `;\n iframeDoc.head.appendChild(widthOverride);\n\n console.log('📦 Iframe loaded, hasStyles:', !!hasStyles);\n\n // Auto-resize iframe to fit content\n this.resizeIframeToContent();\n }\n }\n }\n\n private resizeIframeToContent(): void {\n if (this.htmlFrame) {\n const iframe = this.htmlFrame.nativeElement;\n const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;\n\n if (iframeDoc && iframeDoc.body) {\n // Get the actual content height\n const contentHeight = Math.max(\n iframeDoc.body.scrollHeight,\n iframeDoc.body.offsetHeight,\n iframeDoc.documentElement.scrollHeight,\n iframeDoc.documentElement.offsetHeight\n );\n\n // Set iframe height to match content (with a bit of padding)\n iframe.style.height = `${contentHeight + 20}px`;\n\n console.log('📦 Iframe resized - Height:', contentHeight + 20, 'px');\n }\n }\n }\n\n openInNewWindow(): void {\n if (this.displayHtml) {\n const newWindow = window.open('', '_blank');\n if (newWindow) {\n newWindow.document.write(this.displayHtml);\n newWindow.document.close();\n }\n }\n }\n\n printHtml(): void {\n if (this.htmlFrame) {\n const iframe = this.htmlFrame.nativeElement;\n const iframeWindow = iframe.contentWindow;\n if (iframeWindow) {\n iframeWindow.focus();\n iframeWindow.print();\n }\n }\n }\n\n onCopy(): void {\n // Copy based on what's being displayed - prioritize displayHtml\n const content = this.displayHtml || this.displayMarkdown || this.jsonContent;\n if (content) {\n navigator.clipboard.writeText(content).then(() => {\n console.log('✅ Copied content to clipboard');\n }).catch(err => {\n console.error('Failed to copy to clipboard:', err);\n });\n }\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n return createJsonSnapshot(this.getRawContent(), this.getDisplayTitle());\n }\n\n /**\n * Clean up double-escaped characters that appear in LLM-generated HTML\n * Removes literal \"\\\\n\", \"\\\\t\", and \"\\\\\\\"\" which cause rendering issues\n */\n private cleanEscapedCharacters(html: string): string {\n // Remove escaped quotes (\\\" becomes \")\n let cleaned = html.replace(/\\\\\"/g, '\"');\n\n // Remove escaped newlines (\\\\n becomes nothing)\n // HTML doesn't need whitespace for formatting, and these cause display issues\n cleaned = cleaned.replace(/\\\\n/g, '');\n\n // Remove escaped tabs\n cleaned = cleaned.replace(/\\\\t/g, '');\n\n // Remove double-escaped tabs\n cleaned = cleaned.replace(/\\\\\\\\t/g, '');\n\n // Remove double-escaped newlines\n cleaned = cleaned.replace(/\\\\\\\\n/g, '');\n\n return cleaned;\n }\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { DataSnapshot } from '@memberjunction/core';
1
2
  import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
2
3
  import * as i0 from "@angular/core";
3
4
  /**
@@ -11,6 +12,7 @@ export declare class MarkdownArtifactViewerComponent extends BaseArtifactViewerP
11
12
  */
12
13
  get hasDisplayContent(): boolean;
13
14
  ngOnInit(): void;
15
+ GetCurrentStateSnapshot(): DataSnapshot | null;
14
16
  onCopy(): void;
15
17
  static ɵfac: i0.ɵɵFactoryDeclaration<MarkdownArtifactViewerComponent, never>;
16
18
  static ɵcmp: i0.ɵɵComponentDeclaration<MarkdownArtifactViewerComponent, "mj-markdown-artifact-viewer", never, {}, {}, never, never, false, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/markdown-artifact-viewer.component.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;AAEtF;;GAEG;AACH,qBAkJa,+BAAgC,SAAQ,iCAAiC;IAC7E,eAAe,SAAM;IACrB,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAa;IAElD;;OAEG;IACH,IAAoB,iBAAiB,IAAI,OAAO,CAE/C;IAED,QAAQ,IAAI,IAAI;IAIhB,MAAM,IAAI,IAAI;yCAfH,+BAA+B;2CAA/B,+BAA+B;CAwB3C"}
1
+ {"version":3,"file":"markdown-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/markdown-artifact-viewer.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;AAGtF;;GAEG;AACH,qBAkJa,+BAAgC,SAAQ,iCAAiC;IAC7E,eAAe,SAAM;IACrB,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAa;IAElD;;OAEG;IACH,IAAoB,iBAAiB,IAAI,OAAO,CAE/C;IAED,QAAQ,IAAI,IAAI;IAIA,uBAAuB,IAAI,YAAY,GAAG,IAAI;IAI9D,MAAM,IAAI,IAAI;yCAnBH,+BAA+B;2CAA/B,+BAA+B;CA4B3C"}
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { Component } from '@angular/core';
8
8
  import { RegisterClass } from '@memberjunction/global';
9
9
  import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
10
+ import { createMarkdownSnapshot } from '../../snapshot-helpers';
10
11
  import * as i0 from "@angular/core";
11
12
  import * as i1 from "@angular/common";
12
13
  import * as i2 from "@angular/forms";
@@ -46,6 +47,9 @@ let MarkdownArtifactViewerComponent = class MarkdownArtifactViewerComponent exte
46
47
  ngOnInit() {
47
48
  this.markdownContent = this.getContent();
48
49
  }
50
+ GetCurrentStateSnapshot() {
51
+ return createMarkdownSnapshot(this.getRawContent(), this.getDisplayTitle());
52
+ }
49
53
  onCopy() {
50
54
  if (this.markdownContent) {
51
55
  navigator.clipboard.writeText(this.markdownContent).then(() => {
@@ -127,5 +131,5 @@ export { MarkdownArtifactViewerComponent };
127
131
  </div>
128
132
  `, styles: ["\n .markdown-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .markdown-toolbar {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n padding: 8px;\n background: #f5f5f5;\n border-bottom: 1px solid #ddd;\n }\n\n .btn-icon {\n padding: 6px 12px;\n background: white;\n border: 1px solid #ccc;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .btn-icon:hover {\n background: #e9ecef;\n border-color: #999;\n }\n\n .btn-icon.active {\n background: #007acc;\n color: white;\n border-color: #007acc;\n }\n\n .markdown-content-container {\n flex: 1;\n overflow: auto;\n }\n\n .markdown-preview {\n padding: 20px;\n background: white;\n height: 100%;\n overflow: auto;\n }\n\n .markdown-preview ::ng-deep h1 {\n font-size: 2em;\n margin-top: 0.67em;\n margin-bottom: 0.67em;\n border-bottom: 1px solid #eaecef;\n padding-bottom: 0.3em;\n }\n\n .markdown-preview ::ng-deep h2 {\n font-size: 1.5em;\n margin-top: 0.83em;\n margin-bottom: 0.83em;\n border-bottom: 1px solid #eaecef;\n padding-bottom: 0.3em;\n }\n\n .markdown-preview ::ng-deep code {\n background: #f6f8fa;\n padding: 2px 6px;\n border-radius: 3px;\n font-family: monospace;\n }\n\n .markdown-preview ::ng-deep pre {\n background: #f6f8fa;\n padding: 16px;\n border-radius: 6px;\n overflow: auto;\n }\n\n .markdown-preview ::ng-deep blockquote {\n border-left: 4px solid #dfe2e5;\n padding-left: 16px;\n color: #6a737d;\n margin: 0;\n }\n\n .markdown-preview ::ng-deep table {\n border-collapse: collapse;\n width: 100%;\n margin: 16px 0;\n }\n\n .markdown-preview ::ng-deep th,\n .markdown-preview ::ng-deep td {\n border: 1px solid #dfe2e5;\n padding: 8px 16px;\n }\n\n .markdown-preview ::ng-deep th {\n background: #f6f8fa;\n font-weight: 600;\n }\n "] }]
129
133
  }], null, null); })();
130
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MarkdownArtifactViewerComponent, { className: "MarkdownArtifactViewerComponent", filePath: "src/lib/components/plugins/markdown-artifact-viewer.component.ts", lineNumber: 154 }); })();
134
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MarkdownArtifactViewerComponent, { className: "MarkdownArtifactViewerComponent", filePath: "src/lib/components/plugins/markdown-artifact-viewer.component.ts", lineNumber: 156 }); })();
131
135
  //# sourceMappingURL=markdown-artifact-viewer.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/markdown-artifact-viewer.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;;;;;;IAyB5E,8BAA8B;IAC5B,kCAI+C;IACjD,iBAAM;;;IALS,cAAwB;IAIxB,AADA,AADA,AADA,AADA,6CAAwB,mCACU,2BACR,2BACA,oBACP;;;;IAGlC,0CAIqC;IAHnC,+UAA6B;IAI/B,iBAAiB;;;IAJf,sDAA6B;IAE7B,AADA,qCAAuB,6BACF;;AAlCjC;;GAEG;AAmJI,IAAM,+BAA+B,GAArC,MAAM,+BAAgC,SAAQ,iCAAiC;IAC7E,eAAe,GAAG,EAAE,CAAC;IACrB,QAAQ,GAAyB,SAAS,CAAC;IAElD;;OAEG;IACH,IAAoB,iBAAiB;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC5D,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;YAChD,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;gBACb,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;ySAvBU,+BAA+B,yBAA/B,+BAA+B;6DAA/B,+BAA+B;YA5IpC,AADF,AADF,8BAA2D,aAC3B,gBAE2B;YAA/B,2HAAoB,SAAS,IAAC;YACpD,uBAA0B;YAAC,yBAC7B;YAAA,iBAAS;YACT,iCACqD;YAA9B,2HAAoB,QAAQ,IAAC;YAClD,uBAA2B;YAAC,wBAC9B;YAAA,iBAAS;YACT,iCAAkE;YAAnB,4GAAS,YAAQ,IAAC;YAC/D,uBAA2B;YAAC,uBAC9B;YACF,AADE,iBAAS,EACL;YACN,+BAAwC;YASpC,AARF,mGAA8B,yFAQrB;YASb,AADE,iBAAM,EACF;;YAhCgC,sCAAoB;YAE7B,eAAuC;YAAvC,oDAAuC;YAIvC,eAAsC;YAAtC,mDAAsC;YAS/D,eAeC;YAfD,sDAeC;;;AAgHI,+BAA+B;IAD3C,aAAa,CAAC,iCAAiC,EAAE,8BAA8B,CAAC;GACpE,+BAA+B,CAwB3C;;iFAxBY,+BAA+B;cAlJ3C,SAAS;6BACI,KAAK,YACP,6BAA6B,YAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCT;;kFA6GU,+BAA+B","sourcesContent":["import { Component } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\n\n/**\n * Viewer component for Markdown artifacts\n */\n@Component({\n standalone: false,\n selector: 'mj-markdown-artifact-viewer',\n template: `\n <div class=\"markdown-artifact-viewer\" [ngClass]=\"cssClass\">\n <div class=\"markdown-toolbar\">\n <button class=\"btn-icon\" [class.active]=\"viewMode === 'preview'\"\n title=\"Preview\" (click)=\"viewMode = 'preview'\">\n <i class=\"fas fa-eye\"></i> Preview\n </button>\n <button class=\"btn-icon\" [class.active]=\"viewMode === 'source'\"\n title=\"Source\" (click)=\"viewMode = 'source'\">\n <i class=\"fas fa-code\"></i> Source\n </button>\n <button class=\"btn-icon\" title=\"Copy Markdown\" (click)=\"onCopy()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"markdown-content-container\">\n @if (viewMode === 'preview') {\n <div class=\"markdown-preview\">\n <mj-markdown [data]=\"markdownContent\"\n [enableCollapsibleHeadings]=\"true\"\n [enableLineNumbers]=\"true\"\n [enableSmartypants]=\"true\"\n [enableHtml]=\"true\"></mj-markdown>\n </div>\n } @else {\n <mj-code-editor\n [(ngModel)]=\"markdownContent\"\n [language]=\"'markdown'\"\n [readonly]=\"readonly\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n }\n </div>\n </div>\n `,\n styles: [`\n .markdown-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .markdown-toolbar {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n padding: 8px;\n background: #f5f5f5;\n border-bottom: 1px solid #ddd;\n }\n\n .btn-icon {\n padding: 6px 12px;\n background: white;\n border: 1px solid #ccc;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .btn-icon:hover {\n background: #e9ecef;\n border-color: #999;\n }\n\n .btn-icon.active {\n background: #007acc;\n color: white;\n border-color: #007acc;\n }\n\n .markdown-content-container {\n flex: 1;\n overflow: auto;\n }\n\n .markdown-preview {\n padding: 20px;\n background: white;\n height: 100%;\n overflow: auto;\n }\n\n .markdown-preview ::ng-deep h1 {\n font-size: 2em;\n margin-top: 0.67em;\n margin-bottom: 0.67em;\n border-bottom: 1px solid #eaecef;\n padding-bottom: 0.3em;\n }\n\n .markdown-preview ::ng-deep h2 {\n font-size: 1.5em;\n margin-top: 0.83em;\n margin-bottom: 0.83em;\n border-bottom: 1px solid #eaecef;\n padding-bottom: 0.3em;\n }\n\n .markdown-preview ::ng-deep code {\n background: #f6f8fa;\n padding: 2px 6px;\n border-radius: 3px;\n font-family: monospace;\n }\n\n .markdown-preview ::ng-deep pre {\n background: #f6f8fa;\n padding: 16px;\n border-radius: 6px;\n overflow: auto;\n }\n\n .markdown-preview ::ng-deep blockquote {\n border-left: 4px solid #dfe2e5;\n padding-left: 16px;\n color: #6a737d;\n margin: 0;\n }\n\n .markdown-preview ::ng-deep table {\n border-collapse: collapse;\n width: 100%;\n margin: 16px 0;\n }\n\n .markdown-preview ::ng-deep th,\n .markdown-preview ::ng-deep td {\n border: 1px solid #dfe2e5;\n padding: 8px 16px;\n }\n\n .markdown-preview ::ng-deep th {\n background: #f6f8fa;\n font-weight: 600;\n }\n `]\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'MarkdownArtifactViewerPlugin')\nexport class MarkdownArtifactViewerComponent extends BaseArtifactViewerPluginComponent {\n public markdownContent = '';\n public viewMode: 'preview' | 'source' = 'preview';\n\n /**\n * Markdown artifacts always have content to display\n */\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n ngOnInit(): void {\n this.markdownContent = this.getContent();\n }\n\n onCopy(): void {\n if (this.markdownContent) {\n navigator.clipboard.writeText(this.markdownContent).then(() => {\n console.log('✅ Copied markdown to clipboard');\n }).catch(err => {\n console.error('Failed to copy to clipboard:', err);\n });\n }\n }\n}\n"]}
1
+ {"version":3,"file":"markdown-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/markdown-artifact-viewer.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AACtF,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;;;;;;;IAyBtD,8BAA8B;IAC5B,kCAI+C;IACjD,iBAAM;;;IALS,cAAwB;IAIxB,AADA,AADA,AADA,AADA,6CAAwB,mCACU,2BACR,2BACA,oBACP;;;;IAGlC,0CAIqC;IAHnC,+UAA6B;IAI/B,iBAAiB;;;IAJf,sDAA6B;IAE7B,AADA,qCAAuB,6BACF;;AAlCjC;;GAEG;AAmJI,IAAM,+BAA+B,GAArC,MAAM,+BAAgC,SAAQ,iCAAiC;IAC7E,eAAe,GAAG,EAAE,CAAC;IACrB,QAAQ,GAAyB,SAAS,CAAC;IAElD;;OAEG;IACH,IAAoB,iBAAiB;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IAC3C,CAAC;IAEe,uBAAuB;QACrC,OAAO,sBAAsB,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC5D,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;YAChD,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;gBACb,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;ySA3BU,+BAA+B,yBAA/B,+BAA+B;6DAA/B,+BAA+B;YA5IpC,AADF,AADF,8BAA2D,aAC3B,gBAE2B;YAA/B,2HAAoB,SAAS,IAAC;YACpD,uBAA0B;YAAC,yBAC7B;YAAA,iBAAS;YACT,iCACqD;YAA9B,2HAAoB,QAAQ,IAAC;YAClD,uBAA2B;YAAC,wBAC9B;YAAA,iBAAS;YACT,iCAAkE;YAAnB,4GAAS,YAAQ,IAAC;YAC/D,uBAA2B;YAAC,uBAC9B;YACF,AADE,iBAAS,EACL;YACN,+BAAwC;YASpC,AARF,mGAA8B,yFAQrB;YASb,AADE,iBAAM,EACF;;YAhCgC,sCAAoB;YAE7B,eAAuC;YAAvC,oDAAuC;YAIvC,eAAsC;YAAtC,mDAAsC;YAS/D,eAeC;YAfD,sDAeC;;;AAgHI,+BAA+B;IAD3C,aAAa,CAAC,iCAAiC,EAAE,8BAA8B,CAAC;GACpE,+BAA+B,CA4B3C;;iFA5BY,+BAA+B;cAlJ3C,SAAS;6BACI,KAAK,YACP,6BAA6B,YAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCT;;kFA6GU,+BAA+B","sourcesContent":["import { Component } from '@angular/core';\nimport { DataSnapshot } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { createMarkdownSnapshot } from '../../snapshot-helpers';\n\n/**\n * Viewer component for Markdown artifacts\n */\n@Component({\n standalone: false,\n selector: 'mj-markdown-artifact-viewer',\n template: `\n <div class=\"markdown-artifact-viewer\" [ngClass]=\"cssClass\">\n <div class=\"markdown-toolbar\">\n <button class=\"btn-icon\" [class.active]=\"viewMode === 'preview'\"\n title=\"Preview\" (click)=\"viewMode = 'preview'\">\n <i class=\"fas fa-eye\"></i> Preview\n </button>\n <button class=\"btn-icon\" [class.active]=\"viewMode === 'source'\"\n title=\"Source\" (click)=\"viewMode = 'source'\">\n <i class=\"fas fa-code\"></i> Source\n </button>\n <button class=\"btn-icon\" title=\"Copy Markdown\" (click)=\"onCopy()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"markdown-content-container\">\n @if (viewMode === 'preview') {\n <div class=\"markdown-preview\">\n <mj-markdown [data]=\"markdownContent\"\n [enableCollapsibleHeadings]=\"true\"\n [enableLineNumbers]=\"true\"\n [enableSmartypants]=\"true\"\n [enableHtml]=\"true\"></mj-markdown>\n </div>\n } @else {\n <mj-code-editor\n [(ngModel)]=\"markdownContent\"\n [language]=\"'markdown'\"\n [readonly]=\"readonly\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n }\n </div>\n </div>\n `,\n styles: [`\n .markdown-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .markdown-toolbar {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n padding: 8px;\n background: #f5f5f5;\n border-bottom: 1px solid #ddd;\n }\n\n .btn-icon {\n padding: 6px 12px;\n background: white;\n border: 1px solid #ccc;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .btn-icon:hover {\n background: #e9ecef;\n border-color: #999;\n }\n\n .btn-icon.active {\n background: #007acc;\n color: white;\n border-color: #007acc;\n }\n\n .markdown-content-container {\n flex: 1;\n overflow: auto;\n }\n\n .markdown-preview {\n padding: 20px;\n background: white;\n height: 100%;\n overflow: auto;\n }\n\n .markdown-preview ::ng-deep h1 {\n font-size: 2em;\n margin-top: 0.67em;\n margin-bottom: 0.67em;\n border-bottom: 1px solid #eaecef;\n padding-bottom: 0.3em;\n }\n\n .markdown-preview ::ng-deep h2 {\n font-size: 1.5em;\n margin-top: 0.83em;\n margin-bottom: 0.83em;\n border-bottom: 1px solid #eaecef;\n padding-bottom: 0.3em;\n }\n\n .markdown-preview ::ng-deep code {\n background: #f6f8fa;\n padding: 2px 6px;\n border-radius: 3px;\n font-family: monospace;\n }\n\n .markdown-preview ::ng-deep pre {\n background: #f6f8fa;\n padding: 16px;\n border-radius: 6px;\n overflow: auto;\n }\n\n .markdown-preview ::ng-deep blockquote {\n border-left: 4px solid #dfe2e5;\n padding-left: 16px;\n color: #6a737d;\n margin: 0;\n }\n\n .markdown-preview ::ng-deep table {\n border-collapse: collapse;\n width: 100%;\n margin: 16px 0;\n }\n\n .markdown-preview ::ng-deep th,\n .markdown-preview ::ng-deep td {\n border: 1px solid #dfe2e5;\n padding: 8px 16px;\n }\n\n .markdown-preview ::ng-deep th {\n background: #f6f8fa;\n font-weight: 600;\n }\n `]\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'MarkdownArtifactViewerPlugin')\nexport class MarkdownArtifactViewerComponent extends BaseArtifactViewerPluginComponent {\n public markdownContent = '';\n public viewMode: 'preview' | 'source' = 'preview';\n\n /**\n * Markdown artifacts always have content to display\n */\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n ngOnInit(): void {\n this.markdownContent = this.getContent();\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n return createMarkdownSnapshot(this.getRawContent(), this.getDisplayTitle());\n }\n\n onCopy(): void {\n if (this.markdownContent) {\n navigator.clipboard.writeText(this.markdownContent).then(() => {\n console.log('✅ Copied markdown to clipboard');\n }).catch(err => {\n console.error('Failed to copy to clipboard:', err);\n });\n }\n }\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { OnInit, OnDestroy, ElementRef, ChangeDetectorRef } from '@angular/core';
2
+ import { DataSnapshot } from '@memberjunction/core';
2
3
  import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
3
4
  import { ArtifactFileService } from '../../services/artifact-file.service';
4
5
  import * as i0 from "@angular/core";
@@ -62,6 +63,7 @@ export declare class PdfArtifactViewerComponent extends BaseArtifactViewerPlugin
62
63
  private renderPage;
63
64
  private cancelCurrentRender;
64
65
  private showError;
66
+ GetCurrentStateSnapshot(): DataSnapshot | null;
65
67
  static ɵfac: i0.ɵɵFactoryDeclaration<PdfArtifactViewerComponent, never>;
66
68
  static ɵcmp: i0.ɵɵComponentDeclaration<PdfArtifactViewerComponent, "mj-pdf-artifact-viewer", never, {}, {}, never, never, false, never>;
67
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pdf-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/pdf-artifact-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,SAAS,EAAa,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvG,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;;AAE3E;;;;;;;;;;;GAWG;AACH,qBA8Fa,0BAA2B,SAAQ,iCAAkC,YAAW,MAAM,EAAE,SAAS;IAsB1G,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,GAAG;IArBW,SAAS,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAE3D,SAAS,UAAQ;IACjB,aAAa,UAAS;IACtB,YAAY,SAAM;IAClB,WAAW,SAAK;IAChB,UAAU,SAAK;IACf,SAAS,SAAO;IAEvB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,SAAS,CAAyB;IAE1C,2CAA2C;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoD;IAC/E,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAO;gBAGxB,WAAW,EAAE,mBAAmB,EAChC,GAAG,EAAE,iBAAiB;IAKhC,IAAoB,iBAAiB,IAAI,OAAO,CAAiB;IAEjE,iEAAiE;IACjE,IAAW,WAAW,IAAI,MAAM,CAA6C;IAE7E,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,IAAW,UAAU,IAAI,OAAO,CAE/B;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,WAAW,IAAI,IAAI;IAQN,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQzB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAU1B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAcjC,OAAO,IAAI,IAAI;YAUR,OAAO;IA4CrB;;;;OAIG;YACW,eAAe;IAkB7B,wEAAwE;YAC1D,SAAS;YAQT,eAAe;YAMf,eAAe;YAMf,UAAU;IAwCxB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,SAAS;yCAjQN,0BAA0B;2CAA1B,0BAA0B;CAuQtC"}
1
+ {"version":3,"file":"pdf-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/pdf-artifact-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,SAAS,EAAa,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvG,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;;AAE3E;;;;;;;;;;;GAWG;AACH,qBAiGa,0BAA2B,SAAQ,iCAAkC,YAAW,MAAM,EAAE,SAAS;IAqB1G,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,GAAG;IArBW,SAAS,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAE3D,SAAS,UAAQ;IACjB,aAAa,UAAS;IACtB,YAAY,SAAM;IAClB,WAAW,SAAK;IAChB,UAAU,SAAK;IACf,SAAS,SAAO;IAEvB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,SAAS,CAAyB;IAE1C,2CAA2C;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoD;IAC/E,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAO;gBAGxB,WAAW,EAAE,mBAAmB,EAChC,GAAG,EAAE,iBAAiB;IAKhC,IAAoB,iBAAiB,IAAI,OAAO,CAE/C;IAED,iEAAiE;IACjE,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,IAAW,UAAU,IAAI,OAAO,CAE/B;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,WAAW,IAAI,IAAI;IAQN,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQzB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAU1B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAcjC,OAAO,IAAI,IAAI;YAUR,OAAO;IAyCrB;;;;OAIG;YACW,eAAe;IAe7B,wEAAwE;YAC1D,SAAS;YAQT,eAAe;YAMf,eAAe;YAMf,UAAU;IAwCxB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,SAAS;IAMD,uBAAuB,IAAI,YAAY,GAAG,IAAI;yCApQnD,0BAA0B;2CAA1B,0BAA0B;CAiRtC"}
@@ -6,6 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { Component, ViewChild } from '@angular/core';
8
8
  import { RegisterClass } from '@memberjunction/global';
9
+ import { DataSnapshot } from '@memberjunction/core';
9
10
  import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
10
11
  import * as i0 from "@angular/core";
11
12
  import * as i1 from "../../services/artifact-file.service";
@@ -69,9 +70,13 @@ let PdfArtifactViewerComponent = class PdfArtifactViewerComponent extends BaseAr
69
70
  this.fileService = fileService;
70
71
  this.cdr = cdr;
71
72
  }
72
- get hasDisplayContent() { return true; }
73
+ get hasDisplayContent() {
74
+ return true;
75
+ }
73
76
  /** Current zoom as an integer percentage for toolbar display. */
74
- get zoomPercent() { return Math.round(this.zoomLevel * 100); }
77
+ get zoomPercent() {
78
+ return Math.round(this.zoomLevel * 100);
79
+ }
75
80
  get canZoomIn() {
76
81
  return this.zoomLevel < this.ZOOM_STEPS[this.ZOOM_STEPS.length - 1];
77
82
  }
@@ -102,7 +107,7 @@ let PdfArtifactViewerComponent = class PdfArtifactViewerComponent extends BaseAr
102
107
  }
103
108
  // ─── Zoom ────────────────────────────────────────────────────────────────────
104
109
  async onZoomIn() {
105
- const next = this.ZOOM_STEPS.find(z => z > this.zoomLevel);
110
+ const next = this.ZOOM_STEPS.find((z) => z > this.zoomLevel);
106
111
  if (next !== undefined) {
107
112
  this.zoomLevel = next;
108
113
  await this.renderPage(this.currentPage);
@@ -194,7 +199,7 @@ let PdfArtifactViewerComponent = class PdfArtifactViewerComponent extends BaseAr
194
199
  if (!this.pdfDoc || !this.canvasRef?.nativeElement) {
195
200
  return;
196
201
  }
197
- const page = await this.pdfDoc.getPage(1);
202
+ const page = (await this.pdfDoc.getPage(1));
198
203
  // naturalViewport.width is the CSS pixel width of the page at zoom = 1.0
199
204
  const naturalViewport = page.getViewport({ scale: this.BASE_SCALE });
200
205
  const body = this.canvasRef.nativeElement.closest('.pdf-viewer__body');
@@ -206,7 +211,7 @@ let PdfArtifactViewerComponent = class PdfArtifactViewerComponent extends BaseAr
206
211
  }
207
212
  /** Dynamically import pdfjs-dist and point it at the bundled worker. */
208
213
  async initPdfJs() {
209
- const pdfjsLib = await import('pdfjs-dist');
214
+ const pdfjsLib = (await import('pdfjs-dist'));
210
215
  // pdfjs-dist v4 requires an explicit workerSrc. The worker file is copied to
211
216
  // /assets/pdf.worker.min.mjs via the angular.json assets config in MJExplorer.
212
217
  pdfjsLib.GlobalWorkerOptions.workerSrc = '/assets/pdf.worker.min.mjs';
@@ -227,7 +232,7 @@ let PdfArtifactViewerComponent = class PdfArtifactViewerComponent extends BaseAr
227
232
  return;
228
233
  }
229
234
  this.cancelCurrentRender();
230
- const page = await this.pdfDoc.getPage(pageNum);
235
+ const page = (await this.pdfDoc.getPage(pageNum));
231
236
  const canvas = this.canvasRef.nativeElement;
232
237
  const ctx = canvas.getContext('2d');
233
238
  if (!ctx) {
@@ -265,6 +270,19 @@ let PdfArtifactViewerComponent = class PdfArtifactViewerComponent extends BaseAr
265
270
  this.errorMessage = message;
266
271
  this.cdr.markForCheck();
267
272
  }
273
+ GetCurrentStateSnapshot() {
274
+ const snap = new DataSnapshot();
275
+ snap.title = this.getDisplayTitle() ?? undefined;
276
+ snap.interpretation = `PDF document, ${this.totalPages} page${this.totalPages !== 1 ? 's' : ''}. Currently viewing page ${this.currentPage}.`;
277
+ snap.custom = {
278
+ pageCount: this.totalPages,
279
+ currentPage: this.currentPage,
280
+ fileName: this.artifactVersion.FileName ?? undefined,
281
+ mimeType: this.artifactVersion.MimeType ?? 'application/pdf',
282
+ contentMode: this.artifactVersion.ContentMode,
283
+ };
284
+ return snap;
285
+ }
268
286
  static ɵfac = function PdfArtifactViewerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PdfArtifactViewerComponent)(i0.ɵɵdirectiveInject(i1.ArtifactFileService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
269
287
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PdfArtifactViewerComponent, selectors: [["mj-pdf-artifact-viewer"]], viewQuery: function PdfArtifactViewerComponent_Query(rf, ctx) { if (rf & 1) {
270
288
  i0.ɵɵviewQuery(_c0, 5);
@@ -283,7 +301,7 @@ let PdfArtifactViewerComponent = class PdfArtifactViewerComponent extends BaseAr
283
301
  i0.ɵɵproperty("fileName", (ctx.artifactVersion == null ? null : ctx.artifactVersion.FileName) || "document.pdf")("currentPage", ctx.currentPage)("totalPages", ctx.totalPages)("isDownloading", ctx.isDownloading)("showPrint", true)("showZoom", true)("zoomPercent", ctx.zoomPercent)("canZoomIn", ctx.canZoomIn)("canZoomOut", ctx.canZoomOut);
284
302
  i0.ɵɵadvance(2);
285
303
  i0.ɵɵconditional(ctx.isLoading ? 3 : ctx.errorMessage ? 4 : 5);
286
- } }, dependencies: [i2.FileArtifactToolbarComponent], styles: [".pdf-viewer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n }\n\n .pdf-viewer__body[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n\n .pdf-viewer__state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n height: 100%;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .pdf-viewer__state--error[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n }\n\n .pdf-viewer__canvas-wrap[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n padding: 16px;\n \n\n\n\n min-width: fit-content;\n }\n\n canvas[_ngcontent-%COMP%] {\n display: block;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n \n\n\n\n\n }"] });
304
+ } }, dependencies: [i2.FileArtifactToolbarComponent], styles: [".pdf-viewer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n }\n\n .pdf-viewer__body[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n\n .pdf-viewer__state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n height: 100%;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .pdf-viewer__state--error[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n }\n\n .pdf-viewer__canvas-wrap[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n padding: 16px;\n \n\n\n\n min-width: fit-content;\n }\n\n canvas[_ngcontent-%COMP%] {\n display: block;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n \n\n\n\n\n }"] });
287
305
  };
288
306
  PdfArtifactViewerComponent = __decorate([
289
307
  RegisterClass(BaseArtifactViewerPluginComponent, 'PdfArtifactViewerPlugin')
@@ -310,7 +328,8 @@ export { PdfArtifactViewerComponent };
310
328
  (pageChange)="onPageChange($event)"
311
329
  (zoomIn)="onZoomIn()"
312
330
  (zoomOut)="onZoomOut()"
313
- (zoomReset)="onZoomReset()">
331
+ (zoomReset)="onZoomReset()"
332
+ >
314
333
  </mj-file-artifact-toolbar>
315
334
 
316
335
  <div class="pdf-viewer__body">
@@ -331,10 +350,10 @@ export { PdfArtifactViewerComponent };
331
350
  }
332
351
  </div>
333
352
  </div>
334
- `, styles: ["\n .pdf-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n }\n\n .pdf-viewer__body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n\n .pdf-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n height: 100%;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .pdf-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n\n .pdf-viewer__canvas-wrap {\n display: flex;\n justify-content: center;\n padding: 16px;\n /* Prevent centered overflow from clipping the left side of zoomed pages.\n min-width: fit-content makes the wrap grow to fit the canvas so the\n parent overflow:auto container can scroll to both edges. */\n min-width: fit-content;\n }\n\n canvas {\n display: block;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n /* Natural size \u2014 do NOT add max-width:100% here.\n renderPage sets width/aspect-ratio/height inline so the canvas renders at\n exactly the zoomed logical size. The scroll area (overflow:auto on the body)\n handles pages wider than the panel, which is the correct UX for zoom. */\n }\n "] }]
353
+ `, styles: ["\n .pdf-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n }\n\n .pdf-viewer__body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n\n .pdf-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n height: 100%;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .pdf-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n\n .pdf-viewer__canvas-wrap {\n display: flex;\n justify-content: center;\n padding: 16px;\n /* Prevent centered overflow from clipping the left side of zoomed pages.\n min-width: fit-content makes the wrap grow to fit the canvas so the\n parent overflow:auto container can scroll to both edges. */\n min-width: fit-content;\n }\n\n canvas {\n display: block;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n /* Natural size \u2014 do NOT add max-width:100% here.\n renderPage sets width/aspect-ratio/height inline so the canvas renders at\n exactly the zoomed logical size. The scroll area (overflow:auto on the body)\n handles pages wider than the panel, which is the correct UX for zoom. */\n }\n "] }]
335
354
  }], () => [{ type: i1.ArtifactFileService }, { type: i0.ChangeDetectorRef }], { canvasRef: [{
336
355
  type: ViewChild,
337
356
  args: ['pdfCanvas']
338
357
  }] }); })();
339
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PdfArtifactViewerComponent, { className: "PdfArtifactViewerComponent", filePath: "src/lib/components/plugins/pdf-artifact-viewer.component.ts", lineNumber: 112 }); })();
358
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PdfArtifactViewerComponent, { className: "PdfArtifactViewerComponent", filePath: "src/lib/components/plugins/pdf-artifact-viewer.component.ts", lineNumber: 116 }); })();
340
359
  //# sourceMappingURL=pdf-artifact-viewer.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pdf-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/pdf-artifact-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { ArtifactFileService } from '../../services/artifact-file.service';\n\n/**\n * Viewer plugin for PDF artifact versions stored in MJStorage (ContentMode = 'File')\n * or as inline base64 content (ContentMode = 'Inline').\n *\n * Renders one page at a time using PDF.js. The toolbar provides page navigation\n * (including a direct page-jump input), zoom in/out, download, and print.\n *\n * Aspect-ratio preservation: the canvas backing buffer is sized at full HiDPI\n * resolution while the CSS size uses `aspect-ratio` + `height: auto` so both\n * dimensions scale proportionally. Pages wider than the panel scroll horizontally\n * inside the body — no max-width clamping, which is required for zoom to work.\n */\n@Component({\n standalone: false,\n selector: 'mj-pdf-artifact-viewer',\n template: `\n <div class=\"pdf-viewer\">\n <mj-file-artifact-toolbar\n [fileName]=\"artifactVersion?.FileName || 'document.pdf'\"\n [currentPage]=\"currentPage\"\n [totalPages]=\"totalPages\"\n [isDownloading]=\"isDownloading\"\n [showPrint]=\"true\"\n [showZoom]=\"true\"\n [zoomPercent]=\"zoomPercent\"\n [canZoomIn]=\"canZoomIn\"\n [canZoomOut]=\"canZoomOut\"\n (download)=\"onDownload()\"\n (print)=\"onPrint()\"\n (prevPage)=\"goToPrevPage()\"\n (nextPage)=\"goToNextPage()\"\n (pageChange)=\"onPageChange($event)\"\n (zoomIn)=\"onZoomIn()\"\n (zoomOut)=\"onZoomOut()\"\n (zoomReset)=\"onZoomReset()\">\n </mj-file-artifact-toolbar>\n\n <div class=\"pdf-viewer__body\">\n @if (isLoading) {\n <div class=\"pdf-viewer__state\">\n <i class=\"fas fa-spinner fa-spin\"></i>\n <span>Loading PDF…</span>\n </div>\n } @else if (errorMessage) {\n <div class=\"pdf-viewer__state pdf-viewer__state--error\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else {\n <div class=\"pdf-viewer__canvas-wrap\">\n <canvas #pdfCanvas></canvas>\n </div>\n }\n </div>\n </div>\n `,\n styles: [`\n .pdf-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n }\n\n .pdf-viewer__body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n\n .pdf-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n height: 100%;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .pdf-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n\n .pdf-viewer__canvas-wrap {\n display: flex;\n justify-content: center;\n padding: 16px;\n /* Prevent centered overflow from clipping the left side of zoomed pages.\n min-width: fit-content makes the wrap grow to fit the canvas so the\n parent overflow:auto container can scroll to both edges. */\n min-width: fit-content;\n }\n\n canvas {\n display: block;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n /* Natural size — do NOT add max-width:100% here.\n renderPage sets width/aspect-ratio/height inline so the canvas renders at\n exactly the zoomed logical size. The scroll area (overflow:auto on the body)\n handles pages wider than the panel, which is the correct UX for zoom. */\n }\n `]\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'PdfArtifactViewerPlugin')\nexport class PdfArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit, OnDestroy {\n\n @ViewChild('pdfCanvas') canvasRef?: ElementRef<HTMLCanvasElement>;\n\n public isLoading = true;\n public isDownloading = false;\n public errorMessage = '';\n public currentPage = 1;\n public totalPages = 1;\n public zoomLevel = 1.0;\n\n private pdfDoc: PdfDocumentProxy | null = null;\n private renderTask: PdfRenderTask | null = null;\n private downloadUrl = '';\n private _pdfjsLib: PdfJsLib | null = null;\n\n /** Discrete zoom steps — 50 % to 400 %. */\n private readonly ZOOM_STEPS = [0.5, 0.67, 0.75, 1.0, 1.25, 1.5, 2.0, 3.0, 4.0];\n /** Base render scale (logical pixels per PDF point at zoom 1.0). */\n private readonly BASE_SCALE = 1.5;\n\n constructor(\n private fileService: ArtifactFileService,\n private cdr: ChangeDetectorRef,\n ) {\n super();\n }\n\n public override get hasDisplayContent(): boolean { return true; }\n\n /** Current zoom as an integer percentage for toolbar display. */\n public get zoomPercent(): number { return Math.round(this.zoomLevel * 100); }\n\n public get canZoomIn(): boolean {\n return this.zoomLevel < this.ZOOM_STEPS[this.ZOOM_STEPS.length - 1];\n }\n\n public get canZoomOut(): boolean {\n return this.zoomLevel > this.ZOOM_STEPS[0];\n }\n\n async ngOnInit(): Promise<void> {\n await this.loadPdf();\n }\n\n ngOnDestroy(): void {\n this.cancelCurrentRender();\n this.pdfDoc?.destroy();\n this.pdfDoc = null;\n }\n\n // ─── Navigation ─────────────────────────────────────────────────────────────\n\n public async goToNextPage(): Promise<void> {\n await this.onPageChange(this.currentPage + 1);\n }\n\n public async goToPrevPage(): Promise<void> {\n await this.onPageChange(this.currentPage - 1);\n }\n\n public async onPageChange(page: number): Promise<void> {\n const clamped = Math.max(1, Math.min(page, this.totalPages));\n if (clamped !== this.currentPage) {\n this.currentPage = clamped;\n await this.renderPage(this.currentPage);\n }\n }\n\n // ─── Zoom ────────────────────────────────────────────────────────────────────\n\n public async onZoomIn(): Promise<void> {\n const next = this.ZOOM_STEPS.find(z => z > this.zoomLevel);\n if (next !== undefined) {\n this.zoomLevel = next;\n await this.renderPage(this.currentPage);\n }\n }\n\n public async onZoomOut(): Promise<void> {\n for (let i = this.ZOOM_STEPS.length - 1; i >= 0; i--) {\n if (this.ZOOM_STEPS[i] < this.zoomLevel) {\n this.zoomLevel = this.ZOOM_STEPS[i];\n await this.renderPage(this.currentPage);\n return;\n }\n }\n }\n\n public async onZoomReset(): Promise<void> {\n if (this.zoomLevel !== 1.0) {\n this.zoomLevel = 1.0;\n await this.renderPage(this.currentPage);\n }\n }\n\n // ─── Download / Print ───────────────────────────────────────────────────────\n\n public async onDownload(): Promise<void> {\n if (!this.downloadUrl || this.isDownloading) {\n return;\n }\n this.isDownloading = true;\n this.cdr.markForCheck();\n try {\n await this.triggerBrowserDownload(this.downloadUrl, this.artifactVersion?.FileName || 'document.pdf');\n } finally {\n this.isDownloading = false;\n this.cdr.markForCheck();\n }\n }\n\n public onPrint(): void {\n if (!this.downloadUrl) {\n return;\n }\n // Open the PDF in a new tab so the browser's native print dialog handles it\n window.open(this.downloadUrl, '_blank');\n }\n\n // ─── Private helpers ────────────────────────────────────────────────────────\n\n private async loadPdf(): Promise<void> {\n if (!this.artifactVersion?.ID) {\n this.showError('No artifact version provided.');\n return;\n }\n\n try {\n await this.initPdfJs();\n let pdfDoc: PdfDocumentProxy;\n\n if (this.artifactVersion.ContentMode === 'File') {\n // File-backed: download from storage via pre-auth URL\n this.downloadUrl = await this.fileService.getDownloadUrl(this.artifactVersion.ID);\n pdfDoc = await this.loadPdfDocument(this.downloadUrl);\n } else {\n // Inline: content is a base64 data URL stored in the artifact version\n const content = this.artifactVersion.Content;\n if (!content) {\n this.showError('Artifact has no content.');\n return;\n }\n const arrayBuffer = this.fileService.dataUrlToArrayBuffer(content);\n pdfDoc = await this.loadPdfFromData(new Uint8Array(arrayBuffer));\n // Create an object URL for download/print support\n this.downloadUrl = this.fileService.dataUrlToObjectUrl(\n content,\n this.artifactVersion.MimeType || 'application/pdf'\n );\n }\n\n this.pdfDoc = pdfDoc;\n this.totalPages = pdfDoc.numPages;\n this.currentPage = 1;\n this.isLoading = false;\n // detectChanges() forces a synchronous DOM update so the canvas element\n // exists before renderPage() tries to draw on it.\n this.cdr.detectChanges();\n await this.setFitWidthZoom();\n await this.renderPage(1);\n } catch (err) {\n this.showError(`Could not load PDF: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n /**\n * Set the initial zoom so the first page fills the available panel width.\n * Uses the exact ratio rather than snapping to a ZOOM_STEP so the page fits\n * pixel-perfectly. Subsequent +/- presses will snap to the nearest step.\n */\n private async setFitWidthZoom(): Promise<void> {\n if (!this.pdfDoc || !this.canvasRef?.nativeElement) {\n return;\n }\n const page = await this.pdfDoc.getPage(1) as PdfPageProxy;\n // naturalViewport.width is the CSS pixel width of the page at zoom = 1.0\n const naturalViewport = page.getViewport({ scale: this.BASE_SCALE });\n const body = this.canvasRef.nativeElement.closest('.pdf-viewer__body') as HTMLElement | null;\n const availableWidth = (body?.clientWidth ?? 0) - 32; // 16px padding each side\n if (availableWidth > 0 && naturalViewport.width > 0) {\n const fitZoom = availableWidth / naturalViewport.width;\n this.zoomLevel = Math.max(\n this.ZOOM_STEPS[0],\n Math.min(fitZoom, this.ZOOM_STEPS[this.ZOOM_STEPS.length - 1])\n );\n }\n }\n\n /** Dynamically import pdfjs-dist and point it at the bundled worker. */\n private async initPdfJs(): Promise<void> {\n const pdfjsLib = await import('pdfjs-dist') as unknown as PdfJsLib;\n // pdfjs-dist v4 requires an explicit workerSrc. The worker file is copied to\n // /assets/pdf.worker.min.mjs via the angular.json assets config in MJExplorer.\n pdfjsLib.GlobalWorkerOptions.workerSrc = '/assets/pdf.worker.min.mjs';\n this._pdfjsLib = pdfjsLib;\n }\n\n private async loadPdfDocument(url: string): Promise<PdfDocumentProxy> {\n const pdfjsLib = this._pdfjsLib!;\n const loadingTask = pdfjsLib.getDocument(url);\n return loadingTask.promise;\n }\n\n private async loadPdfFromData(data: Uint8Array): Promise<PdfDocumentProxy> {\n const pdfjsLib = this._pdfjsLib!;\n const loadingTask = pdfjsLib.getDocument({ data });\n return loadingTask.promise;\n }\n\n private async renderPage(pageNum: number): Promise<void> {\n if (!this.pdfDoc || !this.canvasRef?.nativeElement) {\n return;\n }\n\n this.cancelCurrentRender();\n\n const page = await this.pdfDoc.getPage(pageNum) as PdfPageProxy;\n const canvas = this.canvasRef.nativeElement;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return;\n }\n\n const pixelRatio = window.devicePixelRatio || 1;\n // Scale = base * zoom * devicePixelRatio so backing buffer is always HiDPI-sharp.\n const viewport = page.getViewport({ scale: this.BASE_SCALE * this.zoomLevel * pixelRatio });\n\n // Backing buffer: full HiDPI resolution.\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n\n // CSS logical pixel dimensions at the current zoom level.\n const cssWidth = viewport.width / pixelRatio;\n const cssHeight = viewport.height / pixelRatio;\n\n canvas.style.width = `${cssWidth}px`;\n // aspect-ratio + height:auto: when cssWidth is set explicitly and the page\n // renders at its natural size, the browser derives height proportionally.\n // Pages wider than the panel scroll horizontally — the body handles overflow.\n canvas.style.aspectRatio = `${cssWidth} / ${cssHeight}`;\n canvas.style.height = 'auto';\n\n const renderContext = { canvasContext: ctx, viewport };\n this.renderTask = page.render(renderContext) as PdfRenderTask;\n await this.renderTask.promise;\n this.renderTask = null;\n this.cdr.markForCheck();\n }\n\n private cancelCurrentRender(): void {\n if (this.renderTask) {\n this.renderTask.cancel();\n this.renderTask = null;\n }\n }\n\n private showError(message: string): void {\n this.isLoading = false;\n this.errorMessage = message;\n this.cdr.markForCheck();\n }\n\n}\n\n\n// ─── Minimal type shims for pdfjs-dist dynamic import ─────────────────────────\n// We avoid a hard build-time dependency on pdfjs-dist types by declaring only\n// the surface we actually use.\n\ninterface PdfDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageProxy>;\n destroy(): void;\n}\n\ninterface PdfPageProxy {\n getViewport(params: { scale: number }): { width: number; height: number };\n render(renderContext: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }): PdfRenderTask;\n}\n\ninterface PdfRenderTask {\n promise: Promise<void>;\n cancel(): void;\n}\n\ninterface PdfJsLib {\n GlobalWorkerOptions: { workerSrc: string };\n getDocument(source: string | { data: Uint8Array }): { promise: Promise<PdfDocumentProxy> };\n}\n"]}
1
+ {"version":3,"file":"pdf-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/pdf-artifact-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { DataSnapshot } from '@memberjunction/core';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { ArtifactFileService } from '../../services/artifact-file.service';\n\n/**\n * Viewer plugin for PDF artifact versions stored in MJStorage (ContentMode = 'File')\n * or as inline base64 content (ContentMode = 'Inline').\n *\n * Renders one page at a time using PDF.js. The toolbar provides page navigation\n * (including a direct page-jump input), zoom in/out, download, and print.\n *\n * Aspect-ratio preservation: the canvas backing buffer is sized at full HiDPI\n * resolution while the CSS size uses `aspect-ratio` + `height: auto` so both\n * dimensions scale proportionally. Pages wider than the panel scroll horizontally\n * inside the body — no max-width clamping, which is required for zoom to work.\n */\n@Component({\n standalone: false,\n selector: 'mj-pdf-artifact-viewer',\n template: `\n <div class=\"pdf-viewer\">\n <mj-file-artifact-toolbar\n [fileName]=\"artifactVersion?.FileName || 'document.pdf'\"\n [currentPage]=\"currentPage\"\n [totalPages]=\"totalPages\"\n [isDownloading]=\"isDownloading\"\n [showPrint]=\"true\"\n [showZoom]=\"true\"\n [zoomPercent]=\"zoomPercent\"\n [canZoomIn]=\"canZoomIn\"\n [canZoomOut]=\"canZoomOut\"\n (download)=\"onDownload()\"\n (print)=\"onPrint()\"\n (prevPage)=\"goToPrevPage()\"\n (nextPage)=\"goToNextPage()\"\n (pageChange)=\"onPageChange($event)\"\n (zoomIn)=\"onZoomIn()\"\n (zoomOut)=\"onZoomOut()\"\n (zoomReset)=\"onZoomReset()\"\n >\n </mj-file-artifact-toolbar>\n\n <div class=\"pdf-viewer__body\">\n @if (isLoading) {\n <div class=\"pdf-viewer__state\">\n <i class=\"fas fa-spinner fa-spin\"></i>\n <span>Loading PDF…</span>\n </div>\n } @else if (errorMessage) {\n <div class=\"pdf-viewer__state pdf-viewer__state--error\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else {\n <div class=\"pdf-viewer__canvas-wrap\">\n <canvas #pdfCanvas></canvas>\n </div>\n }\n </div>\n </div>\n `,\n styles: [\n `\n .pdf-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n }\n\n .pdf-viewer__body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n\n .pdf-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n height: 100%;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .pdf-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n\n .pdf-viewer__canvas-wrap {\n display: flex;\n justify-content: center;\n padding: 16px;\n /* Prevent centered overflow from clipping the left side of zoomed pages.\n min-width: fit-content makes the wrap grow to fit the canvas so the\n parent overflow:auto container can scroll to both edges. */\n min-width: fit-content;\n }\n\n canvas {\n display: block;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n /* Natural size — do NOT add max-width:100% here.\n renderPage sets width/aspect-ratio/height inline so the canvas renders at\n exactly the zoomed logical size. The scroll area (overflow:auto on the body)\n handles pages wider than the panel, which is the correct UX for zoom. */\n }\n `,\n ],\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'PdfArtifactViewerPlugin')\nexport class PdfArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit, OnDestroy {\n @ViewChild('pdfCanvas') canvasRef?: ElementRef<HTMLCanvasElement>;\n\n public isLoading = true;\n public isDownloading = false;\n public errorMessage = '';\n public currentPage = 1;\n public totalPages = 1;\n public zoomLevel = 1.0;\n\n private pdfDoc: PdfDocumentProxy | null = null;\n private renderTask: PdfRenderTask | null = null;\n private downloadUrl = '';\n private _pdfjsLib: PdfJsLib | null = null;\n\n /** Discrete zoom steps — 50 % to 400 %. */\n private readonly ZOOM_STEPS = [0.5, 0.67, 0.75, 1.0, 1.25, 1.5, 2.0, 3.0, 4.0];\n /** Base render scale (logical pixels per PDF point at zoom 1.0). */\n private readonly BASE_SCALE = 1.5;\n\n constructor(\n private fileService: ArtifactFileService,\n private cdr: ChangeDetectorRef,\n ) {\n super();\n }\n\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n /** Current zoom as an integer percentage for toolbar display. */\n public get zoomPercent(): number {\n return Math.round(this.zoomLevel * 100);\n }\n\n public get canZoomIn(): boolean {\n return this.zoomLevel < this.ZOOM_STEPS[this.ZOOM_STEPS.length - 1];\n }\n\n public get canZoomOut(): boolean {\n return this.zoomLevel > this.ZOOM_STEPS[0];\n }\n\n async ngOnInit(): Promise<void> {\n await this.loadPdf();\n }\n\n ngOnDestroy(): void {\n this.cancelCurrentRender();\n this.pdfDoc?.destroy();\n this.pdfDoc = null;\n }\n\n // ─── Navigation ─────────────────────────────────────────────────────────────\n\n public async goToNextPage(): Promise<void> {\n await this.onPageChange(this.currentPage + 1);\n }\n\n public async goToPrevPage(): Promise<void> {\n await this.onPageChange(this.currentPage - 1);\n }\n\n public async onPageChange(page: number): Promise<void> {\n const clamped = Math.max(1, Math.min(page, this.totalPages));\n if (clamped !== this.currentPage) {\n this.currentPage = clamped;\n await this.renderPage(this.currentPage);\n }\n }\n\n // ─── Zoom ────────────────────────────────────────────────────────────────────\n\n public async onZoomIn(): Promise<void> {\n const next = this.ZOOM_STEPS.find((z) => z > this.zoomLevel);\n if (next !== undefined) {\n this.zoomLevel = next;\n await this.renderPage(this.currentPage);\n }\n }\n\n public async onZoomOut(): Promise<void> {\n for (let i = this.ZOOM_STEPS.length - 1; i >= 0; i--) {\n if (this.ZOOM_STEPS[i] < this.zoomLevel) {\n this.zoomLevel = this.ZOOM_STEPS[i];\n await this.renderPage(this.currentPage);\n return;\n }\n }\n }\n\n public async onZoomReset(): Promise<void> {\n if (this.zoomLevel !== 1.0) {\n this.zoomLevel = 1.0;\n await this.renderPage(this.currentPage);\n }\n }\n\n // ─── Download / Print ───────────────────────────────────────────────────────\n\n public async onDownload(): Promise<void> {\n if (!this.downloadUrl || this.isDownloading) {\n return;\n }\n this.isDownloading = true;\n this.cdr.markForCheck();\n try {\n await this.triggerBrowserDownload(this.downloadUrl, this.artifactVersion?.FileName || 'document.pdf');\n } finally {\n this.isDownloading = false;\n this.cdr.markForCheck();\n }\n }\n\n public onPrint(): void {\n if (!this.downloadUrl) {\n return;\n }\n // Open the PDF in a new tab so the browser's native print dialog handles it\n window.open(this.downloadUrl, '_blank');\n }\n\n // ─── Private helpers ────────────────────────────────────────────────────────\n\n private async loadPdf(): Promise<void> {\n if (!this.artifactVersion?.ID) {\n this.showError('No artifact version provided.');\n return;\n }\n\n try {\n await this.initPdfJs();\n let pdfDoc: PdfDocumentProxy;\n\n if (this.artifactVersion.ContentMode === 'File') {\n // File-backed: download from storage via pre-auth URL\n this.downloadUrl = await this.fileService.getDownloadUrl(this.artifactVersion.ID);\n pdfDoc = await this.loadPdfDocument(this.downloadUrl);\n } else {\n // Inline: content is a base64 data URL stored in the artifact version\n const content = this.artifactVersion.Content;\n if (!content) {\n this.showError('Artifact has no content.');\n return;\n }\n const arrayBuffer = this.fileService.dataUrlToArrayBuffer(content);\n pdfDoc = await this.loadPdfFromData(new Uint8Array(arrayBuffer));\n // Create an object URL for download/print support\n this.downloadUrl = this.fileService.dataUrlToObjectUrl(content, this.artifactVersion.MimeType || 'application/pdf');\n }\n\n this.pdfDoc = pdfDoc;\n this.totalPages = pdfDoc.numPages;\n this.currentPage = 1;\n this.isLoading = false;\n // detectChanges() forces a synchronous DOM update so the canvas element\n // exists before renderPage() tries to draw on it.\n this.cdr.detectChanges();\n await this.setFitWidthZoom();\n await this.renderPage(1);\n } catch (err) {\n this.showError(`Could not load PDF: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n /**\n * Set the initial zoom so the first page fills the available panel width.\n * Uses the exact ratio rather than snapping to a ZOOM_STEP so the page fits\n * pixel-perfectly. Subsequent +/- presses will snap to the nearest step.\n */\n private async setFitWidthZoom(): Promise<void> {\n if (!this.pdfDoc || !this.canvasRef?.nativeElement) {\n return;\n }\n const page = (await this.pdfDoc.getPage(1)) as PdfPageProxy;\n // naturalViewport.width is the CSS pixel width of the page at zoom = 1.0\n const naturalViewport = page.getViewport({ scale: this.BASE_SCALE });\n const body = this.canvasRef.nativeElement.closest('.pdf-viewer__body') as HTMLElement | null;\n const availableWidth = (body?.clientWidth ?? 0) - 32; // 16px padding each side\n if (availableWidth > 0 && naturalViewport.width > 0) {\n const fitZoom = availableWidth / naturalViewport.width;\n this.zoomLevel = Math.max(this.ZOOM_STEPS[0], Math.min(fitZoom, this.ZOOM_STEPS[this.ZOOM_STEPS.length - 1]));\n }\n }\n\n /** Dynamically import pdfjs-dist and point it at the bundled worker. */\n private async initPdfJs(): Promise<void> {\n const pdfjsLib = (await import('pdfjs-dist')) as unknown as PdfJsLib;\n // pdfjs-dist v4 requires an explicit workerSrc. The worker file is copied to\n // /assets/pdf.worker.min.mjs via the angular.json assets config in MJExplorer.\n pdfjsLib.GlobalWorkerOptions.workerSrc = '/assets/pdf.worker.min.mjs';\n this._pdfjsLib = pdfjsLib;\n }\n\n private async loadPdfDocument(url: string): Promise<PdfDocumentProxy> {\n const pdfjsLib = this._pdfjsLib!;\n const loadingTask = pdfjsLib.getDocument(url);\n return loadingTask.promise;\n }\n\n private async loadPdfFromData(data: Uint8Array): Promise<PdfDocumentProxy> {\n const pdfjsLib = this._pdfjsLib!;\n const loadingTask = pdfjsLib.getDocument({ data });\n return loadingTask.promise;\n }\n\n private async renderPage(pageNum: number): Promise<void> {\n if (!this.pdfDoc || !this.canvasRef?.nativeElement) {\n return;\n }\n\n this.cancelCurrentRender();\n\n const page = (await this.pdfDoc.getPage(pageNum)) as PdfPageProxy;\n const canvas = this.canvasRef.nativeElement;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return;\n }\n\n const pixelRatio = window.devicePixelRatio || 1;\n // Scale = base * zoom * devicePixelRatio so backing buffer is always HiDPI-sharp.\n const viewport = page.getViewport({ scale: this.BASE_SCALE * this.zoomLevel * pixelRatio });\n\n // Backing buffer: full HiDPI resolution.\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n\n // CSS logical pixel dimensions at the current zoom level.\n const cssWidth = viewport.width / pixelRatio;\n const cssHeight = viewport.height / pixelRatio;\n\n canvas.style.width = `${cssWidth}px`;\n // aspect-ratio + height:auto: when cssWidth is set explicitly and the page\n // renders at its natural size, the browser derives height proportionally.\n // Pages wider than the panel scroll horizontally — the body handles overflow.\n canvas.style.aspectRatio = `${cssWidth} / ${cssHeight}`;\n canvas.style.height = 'auto';\n\n const renderContext = { canvasContext: ctx, viewport };\n this.renderTask = page.render(renderContext) as PdfRenderTask;\n await this.renderTask.promise;\n this.renderTask = null;\n this.cdr.markForCheck();\n }\n\n private cancelCurrentRender(): void {\n if (this.renderTask) {\n this.renderTask.cancel();\n this.renderTask = null;\n }\n }\n\n private showError(message: string): void {\n this.isLoading = false;\n this.errorMessage = message;\n this.cdr.markForCheck();\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n const snap = new DataSnapshot();\n snap.title = this.getDisplayTitle() ?? undefined;\n snap.interpretation = `PDF document, ${this.totalPages} page${this.totalPages !== 1 ? 's' : ''}. Currently viewing page ${this.currentPage}.`;\n snap.custom = {\n pageCount: this.totalPages,\n currentPage: this.currentPage,\n fileName: this.artifactVersion.FileName ?? undefined,\n mimeType: this.artifactVersion.MimeType ?? 'application/pdf',\n contentMode: this.artifactVersion.ContentMode,\n };\n return snap;\n }\n}\n\n// ─── Minimal type shims for pdfjs-dist dynamic import ─────────────────────────\n// We avoid a hard build-time dependency on pdfjs-dist types by declaring only\n// the surface we actually use.\n\ninterface PdfDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageProxy>;\n destroy(): void;\n}\n\ninterface PdfPageProxy {\n getViewport(params: { scale: number }): { width: number; height: number };\n render(renderContext: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }): PdfRenderTask;\n}\n\ninterface PdfRenderTask {\n promise: Promise<void>;\n cancel(): void;\n}\n\ninterface PdfJsLib {\n GlobalWorkerOptions: { workerSrc: string };\n getDocument(source: string | { data: Uint8Array }): { promise: Promise<PdfDocumentProxy> };\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
2
+ import { DataSnapshot } from '@memberjunction/core';
2
3
  import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
3
4
  import * as i0 from "@angular/core";
4
5
  /**
@@ -15,6 +16,7 @@ export declare class SvgArtifactViewerComponent extends BaseArtifactViewerPlugin
15
16
  get hasDisplayContent(): boolean;
16
17
  constructor(sanitizer: DomSanitizer);
17
18
  ngOnInit(): void;
19
+ GetCurrentStateSnapshot(): DataSnapshot | null;
18
20
  onCopy(): void;
19
21
  static ɵfac: i0.ɵɵFactoryDeclaration<SvgArtifactViewerComponent, never>;
20
22
  static ɵcmp: i0.ɵɵComponentDeclaration<SvgArtifactViewerComponent, "mj-svg-artifact-viewer", never, {}, {}, never, never, false, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"svg-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/svg-artifact-viewer.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;AAEtF;;GAEG;AACH,qBAsGa,0BAA2B,SAAQ,iCAAiC;IAYnE,OAAO,CAAC,SAAS;IAXtB,UAAU,SAAM;IAChB,cAAc,EAAE,QAAQ,CAAM;IAC9B,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAa;IAElD;;OAEG;IACH,IAAoB,iBAAiB,IAAI,OAAO,CAE/C;gBAEmB,SAAS,EAAE,YAAY;IAI3C,QAAQ,IAAI,IAAI;IAMhB,MAAM,IAAI,IAAI;yCAtBH,0BAA0B;2CAA1B,0BAA0B;CA+BtC"}
1
+ {"version":3,"file":"svg-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/svg-artifact-viewer.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;AAEtF;;GAEG;AACH,qBAsGa,0BAA2B,SAAQ,iCAAiC;IAYnE,OAAO,CAAC,SAAS;IAXtB,UAAU,SAAM;IAChB,cAAc,EAAE,QAAQ,CAAM;IAC9B,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAa;IAElD;;OAEG;IACH,IAAoB,iBAAiB,IAAI,OAAO,CAE/C;gBAEmB,SAAS,EAAE,YAAY;IAI3C,QAAQ,IAAI,IAAI;IAMA,uBAAuB,IAAI,YAAY,GAAG,IAAI;IAS9D,MAAM,IAAI,IAAI;yCA/BH,0BAA0B;2CAA1B,0BAA0B;CAwCtC"}
@@ -5,6 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { Component } from '@angular/core';
8
+ import { DataSnapshot } from '@memberjunction/core';
8
9
  import { RegisterClass } from '@memberjunction/global';
9
10
  import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
10
11
  import * as i0 from "@angular/core";
@@ -54,6 +55,15 @@ let SvgArtifactViewerComponent = class SvgArtifactViewerComponent extends BaseAr
54
55
  // For SVG, we use sanitize with SecurityContext.HTML (1) to allow safe rendering
55
56
  this.safeSvgContent = this.sanitizer.sanitize(1, this.svgContent) || '';
56
57
  }
58
+ GetCurrentStateSnapshot() {
59
+ const content = this.getRawContent();
60
+ if (!content)
61
+ return null;
62
+ const snap = new DataSnapshot();
63
+ snap.title = this.getDisplayTitle() ?? undefined;
64
+ snap.custom = { content };
65
+ return snap;
66
+ }
57
67
  onCopy() {
58
68
  if (this.svgContent) {
59
69
  navigator.clipboard.writeText(this.svgContent).then(() => {
@@ -131,5 +141,5 @@ export { SvgArtifactViewerComponent };
131
141
  </div>
132
142
  `, styles: ["\n .svg-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .svg-toolbar {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n padding: 8px;\n background: #f5f5f5;\n border-bottom: 1px solid #ddd;\n }\n\n .btn-icon {\n padding: 6px 12px;\n background: white;\n border: 1px solid #ccc;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .btn-icon:hover {\n background: #e9ecef;\n border-color: #999;\n }\n\n .btn-icon.active {\n background: #007acc;\n color: white;\n border-color: #007acc;\n }\n\n .svg-content-container {\n flex: 1;\n overflow: auto;\n }\n\n .svg-preview {\n padding: 20px;\n background: white;\n height: 100%;\n overflow: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .svg-wrapper {\n max-width: 100%;\n max-height: 100%;\n }\n\n .svg-wrapper ::ng-deep svg {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n }\n "] }]
133
143
  }], () => [{ type: i1.DomSanitizer }], null); })();
134
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SvgArtifactViewerComponent, { className: "SvgArtifactViewerComponent", filePath: "src/lib/components/plugins/svg-artifact-viewer.component.ts", lineNumber: 111 }); })();
144
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SvgArtifactViewerComponent, { className: "SvgArtifactViewerComponent", filePath: "src/lib/components/plugins/svg-artifact-viewer.component.ts", lineNumber: 112 }); })();
135
145
  //# sourceMappingURL=svg-artifact-viewer.component.js.map