@lionrapid/core 0.1.4-beta.0 → 0.2.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 (41) hide show
  1. package/dist/base/event-emitter.d.ts.map +1 -1
  2. package/dist/base/event-emitter.js +4 -1
  3. package/dist/base/event-emitter.js.map +1 -1
  4. package/dist/browser/lionrapid.auto.dev.js +45 -10
  5. package/dist/browser/lionrapid.auto.dev.js.map +3 -3
  6. package/dist/browser/lionrapid.auto.js +45 -10
  7. package/dist/browser/lionrapid.auto.js.map +3 -3
  8. package/dist/browser/lionrapid.auto.min.js +3 -3
  9. package/dist/browser/lionrapid.auto.min.js.map +4 -4
  10. package/dist/browser/lionrapid.editor.js +22 -1
  11. package/dist/browser/lionrapid.editor.js.map +3 -3
  12. package/dist/browser/lionrapid.editor.min.js +3 -3
  13. package/dist/browser/lionrapid.editor.min.js.map +4 -4
  14. package/dist/browser/lionrapid.esm.js +45 -10
  15. package/dist/browser/lionrapid.esm.js.map +3 -3
  16. package/dist/browser/lionrapid.esm.min.js +2 -2
  17. package/dist/browser/lionrapid.esm.min.js.map +4 -4
  18. package/dist/browser/lionrapid.iife.dev.js +45 -10
  19. package/dist/browser/lionrapid.iife.dev.js.map +3 -3
  20. package/dist/browser/lionrapid.iife.js +45 -10
  21. package/dist/browser/lionrapid.iife.js.map +3 -3
  22. package/dist/browser/lionrapid.iife.min.js +2 -2
  23. package/dist/browser/lionrapid.iife.min.js.map +4 -4
  24. package/dist/browser/lionrapid.umd.js +45 -10
  25. package/dist/browser/lionrapid.umd.js.map +3 -3
  26. package/dist/browser/lionrapid.umd.min.js +2 -2
  27. package/dist/browser/lionrapid.umd.min.js.map +4 -4
  28. package/dist/content/safe-href.d.ts +22 -0
  29. package/dist/content/safe-href.d.ts.map +1 -0
  30. package/dist/content/safe-href.js +48 -0
  31. package/dist/content/safe-href.js.map +1 -0
  32. package/dist/content/style-mapper/DefaultStyleMapper.d.ts.map +1 -1
  33. package/dist/content/style-mapper/DefaultStyleMapper.js +5 -1
  34. package/dist/content/style-mapper/DefaultStyleMapper.js.map +1 -1
  35. package/dist/utils/logger.d.ts.map +1 -1
  36. package/dist/utils/logger.js +43 -8
  37. package/dist/utils/logger.js.map +1 -1
  38. package/dist/utils/translation-flow.d.ts.map +1 -1
  39. package/dist/utils/translation-flow.js +7 -2
  40. package/dist/utils/translation-flow.js.map +1 -1
  41. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../src/browser/editor/editor-styles.ts", "../../src/content/style-mapper/DefaultStyleMapper.ts", "../../src/browser/markup-parser.ts", "../../src/browser/md5.ts", "../../src/browser/editor/key-resolver.ts", "../../src/browser/editor/inspector.ts", "../../src/browser/editor/toolbar.ts", "../../src/content/serializer/HTMLSerializer.ts", "../../src/browser/editor/live-preview.ts", "../../src/browser/exclude-filter.ts", "../../src/browser/block-extractor.ts", "../../src/browser/editor/sidebar.ts", "../../src/browser/editor/editor-api.ts", "../../src/browser/editor/pii-redactor.ts", "../../src/browser/editor/snapshot-capture.ts", "../../src/browser/editor/snapshot-viewer.ts", "../../src/browser/editor/editor-init.ts"],
4
- "sourcesContent": ["/**\n * Editor CSS Styles\n * All styles are injected into Shadow DOM \u2014 no leakage to host page.\n */\n\nexport const EDITOR_CSS = `\n/* Reset inside shadow DOM */\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #1a1a2e;\n line-height: 1.5;\n box-sizing: border-box;\n}\n\n*, *::before, *::after {\n box-sizing: border-box;\n}\n\n/* \u2500\u2500 FAB (replaces fixed toolbar) \u2500\u2500 */\n.lr-fab {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n gap: 0;\n user-select: none;\n}\n\n.lr-fab-btn {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #2d7f7f;\n color: #fff;\n border: none;\n font-weight: 700;\n font-size: 16px;\n cursor: grab;\n box-shadow: 0 4px 12px rgba(0,0,0,0.25);\n transition: box-shadow 0.15s;\n flex-shrink: 0;\n z-index: 1;\n}\n\n.lr-fab-btn:hover {\n box-shadow: 0 6px 20px rgba(0,0,0,0.3);\n}\n\n.lr-fab-btn:active {\n cursor: grabbing;\n}\n\n.lr-fab-panel {\n display: none;\n align-items: center;\n gap: 8px;\n background: #1a1a2e;\n color: #fff;\n padding: 8px 12px;\n border-radius: 8px;\n margin-right: 8px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.25);\n white-space: nowrap;\n}\n\n.lr-fab.expanded .lr-fab-panel {\n display: flex;\n}\n\n.lr-lang-dropdown {\n position: relative;\n}\n\n.lr-lang-btn {\n background: rgba(255,255,255,0.1);\n color: #fff;\n border: 1px solid rgba(255,255,255,0.2);\n border-radius: 4px;\n padding: 4px 10px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n outline: none;\n}\n\n.lr-lang-btn:hover {\n background: rgba(255,255,255,0.2);\n}\n\n.lr-lang-menu {\n display: none;\n position: absolute;\n bottom: calc(100% + 6px);\n left: 0;\n background: #1a1a2e;\n border: 1px solid rgba(255,255,255,0.15);\n border-radius: 6px;\n padding: 4px;\n min-width: 60px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n}\n\n.lr-lang-menu.open {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.lr-lang-item {\n background: none;\n color: #ccc;\n border: none;\n padding: 6px 10px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n border-radius: 4px;\n text-align: left;\n}\n\n.lr-lang-item:hover {\n background: rgba(255,255,255,0.1);\n color: #fff;\n}\n\n.lr-lang-item.active {\n background: #2d7f7f;\n color: #fff;\n}\n\n.lr-fab-progress {\n font-size: 13px;\n color: rgba(255,255,255,0.7);\n}\n\n.lr-fab-exit {\n background: none;\n border: 1px solid rgba(255,255,255,0.3);\n color: #fff;\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n}\n\n.lr-fab-exit:hover {\n background: rgba(255,255,255,0.1);\n}\n\n.lr-fab-snapshot {\n background: #2d7f7f;\n border: 1px solid #2d7f7f;\n color: #fff;\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 600;\n}\n\n.lr-fab-snapshot:hover {\n background: #3a9999;\n border-color: #3a9999;\n}\n\n.lr-fab-snapshot:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Workflow action buttons (Phase 3) */\n.lr-workflow-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin: 12px 0 4px;\n padding: 8px 0 0;\n border-top: 1px solid #e5e7eb;\n}\n\n.lr-wf-btn {\n font-size: 12px;\n font-weight: 500;\n padding: 5px 10px;\n border-radius: 4px;\n border: 1px solid transparent;\n cursor: pointer;\n transition: background-color 0.1s;\n}\n\n.lr-wf-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.lr-wf-primary {\n background: #2563eb;\n color: white;\n border-color: #2563eb;\n}\n.lr-wf-primary:hover:not(:disabled) {\n background: #1d4ed8;\n}\n\n.lr-wf-secondary {\n background: white;\n color: #374151;\n border-color: #d1d5db;\n}\n.lr-wf-secondary:hover:not(:disabled) {\n background: #f3f4f6;\n}\n\n.lr-wf-danger {\n background: white;\n color: #b91c1c;\n border-color: #fca5a5;\n}\n.lr-wf-danger:hover:not(:disabled) {\n background: #fef2f2;\n}\n\n/* Snapshot viewer sandbox wrapper */\n#__lr_snapshot_root {\n isolation: isolate;\n position: relative;\n width: 100%;\n min-height: 100vh;\n}\n\n/* \u2500\u2500 Overlay \u2500\u2500 */\n.lr-overlay {\n position: fixed;\n pointer-events: none;\n border: 2px solid #2d7f7f;\n border-radius: 3px;\n background: rgba(45, 127, 127, 0.06);\n transition: all 0.1s ease;\n z-index: 2147483646;\n display: none;\n}\n\n.lr-overlay.active {\n display: block;\n}\n\n/* \u2500\u2500 Sidebar \u2500\u2500 */\n.lr-sidebar {\n position: fixed;\n top: 0;\n right: 0;\n width: 360px;\n min-width: 280px;\n max-width: 600px;\n bottom: 0;\n background: #fff;\n border-left: 1px solid #e0e0e0;\n z-index: 2147483647;\n overflow-y: auto;\n transform: translateX(100%);\n transition: transform 0.2s ease;\n}\n\n.lr-sidebar.open {\n transform: translateX(0);\n}\n\n/* Resize handle on left edge */\n.lr-sidebar-resize {\n position: absolute;\n top: 0;\n left: -4px;\n width: 8px;\n bottom: 0;\n cursor: col-resize;\n z-index: 1;\n}\n\n.lr-sidebar-resize:hover,\n.lr-sidebar-resize.active {\n background: rgba(45, 127, 127, 0.3);\n}\n\n.lr-sidebar-header {\n padding: 16px;\n border-bottom: 1px solid #e0e0e0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.lr-sidebar-title {\n font-weight: 600;\n font-size: 15px;\n}\n\n.lr-sidebar-close {\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n color: #666;\n padding: 4px 8px;\n line-height: 1;\n}\n\n.lr-sidebar-close:hover {\n color: #1a1a2e;\n}\n\n.lr-sidebar-body {\n padding: 16px;\n}\n\n.lr-field {\n margin-bottom: 16px;\n}\n\n.lr-field-label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n}\n\n.lr-field-key {\n font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;\n font-size: 12px;\n color: #2d7f7f;\n background: #f0f7f7;\n padding: 4px 8px;\n border-radius: 4px;\n word-break: break-all;\n}\n\n.lr-field-original {\n font-size: 13px;\n color: #333;\n background: #f8f8f8;\n padding: 10px 12px;\n border-radius: 6px;\n border: 1px solid #eee;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.lr-field-tag {\n display: inline;\n background: #d9eded;\n color: #2d7f7f;\n padding: 0 3px;\n border-radius: 2px;\n font-family: monospace;\n font-size: 12px;\n}\n\n.lr-textarea {\n width: 100%;\n min-height: 100px;\n padding: 10px 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-family: inherit;\n font-size: 14px;\n line-height: 1.5;\n resize: vertical;\n outline: none;\n transition: border-color 0.15s;\n}\n\n.lr-textarea:focus {\n border-color: #2d7f7f;\n box-shadow: 0 0 0 3px rgba(45, 127, 127, 0.1);\n}\n\n.lr-preview {\n padding: 10px 12px;\n background: #f8f8f8;\n border: 1px solid #eee;\n border-radius: 6px;\n font-size: 13px;\n min-height: 40px;\n}\n\n.lr-status {\n padding: 10px 16px;\n font-size: 12px;\n color: #666;\n text-align: center;\n border-top: 1px solid #eee;\n background: #fafafa;\n}\n\n.lr-status.saved {\n color: #22c55e;\n}\n\n.lr-status.error {\n color: #ef4444;\n}\n\n.lr-status.unsaved {\n color: #f59e0b;\n}\n\n/* \u2500\u2500 Page blocks list \u2500\u2500 */\n.lr-blocks-section {\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid #eee;\n}\n\n.lr-blocks-title {\n font-size: 12px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n\n.lr-block-item {\n padding: 8px 10px;\n border: 1px solid #eee;\n border-radius: 4px;\n margin-bottom: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n overflow: hidden;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n.lr-block-item:hover {\n background: #f0f7f7;\n border-color: #2d7f7f;\n}\n\n.lr-block-item.active {\n background: #e5f2f2;\n border-color: #2d7f7f;\n}\n\n/* \u2500\u2500 Status dots \u2500\u2500 */\n.lr-status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n margin-top: 5px;\n background: #d1d5db;\n}\n\n.lr-status-dot.missing { background: #d1d5db; }\n.lr-status-dot.mt { background: #60a5fa; }\n.lr-status-dot.edited { background: #f97316; }\n.lr-status-dot.confirmed { background: #22c55e; }\n.lr-status-dot.ready { background: #22c55e; }\n.lr-status-dot.locked { background: #a855f7; }\n.lr-status-dot.unsaved { background: #f59e0b; }\n\n/* \u2500\u2500 Locked textarea \u2500\u2500 */\n.lr-textarea-locked {\n background: #f3f4f6;\n color: #6b7280;\n cursor: not-allowed;\n border-color: #e5e7eb;\n}\n\n/* \u2500\u2500 Block text layout \u2500\u2500 */\n.lr-block-text {\n overflow: hidden;\n min-width: 0;\n}\n\n.lr-block-source {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.lr-block-preview {\n font-size: 11px;\n color: #888;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-top: 2px;\n}\n`;\n", "/**\n * Default style mapper for bidirectional HTML element \u2194 style property mapping\n * @module content/style-mapper/DefaultStyleMapper\n */\n\nimport type { IStyleMapper, ElementMapping } from './IStyleMapper.js';\n\n/**\n * Default implementation of style mapping\n *\n * Provides bidirectional conversion between HTML elements and style properties:\n * - mapElementToStyles: `<b>` \u2192 `[\"bold\"]`\n * - mapStylesToElement: `[\"bold\"]` \u2192 `<b>`\n *\n * @example\n * ```typescript\n * const mapper = new DefaultStyleMapper();\n *\n * // Parsing: HTML \u2192 styles\n * mapper.mapElementToStyles('a', { href: '/terms' });\n * // \u2192 [\"hyperlink:/terms\"]\n *\n * // Serializing: styles \u2192 HTML\n * mapper.mapStylesToElement(['bold', 'hyperlink:/terms']);\n * // \u2192 { element: 'a', attrs: { href: '/terms' } }\n * ```\n */\nexport class DefaultStyleMapper implements IStyleMapper {\n /**\n * Element \u2192 Style mapping\n * Maps HTML element names to their style property\n */\n private readonly elementToStyles: Record<string, string> = {\n b: 'bold',\n strong: 'bold',\n i: 'italic',\n em: 'italic',\n u: 'underline',\n s: 'strikethrough',\n del: 'strikethrough',\n strike: 'strikethrough',\n code: 'code',\n mark: 'highlight',\n sub: 'subscript',\n sup: 'superscript',\n };\n\n /**\n * Style \u2192 Element mapping (reverse)\n * Uses simple, familiar elements for developer convenience\n * Also accepts element names directly (strong, em, etc.)\n */\n private readonly styleToElement: Record<string, string> = {\n // Semantic style names \u2192 simple elements\n bold: 'b',\n italic: 'i',\n underline: 'u',\n strikethrough: 's',\n code: 'code',\n highlight: 'mark',\n subscript: 'sub',\n superscript: 'sup',\n // Element names (for servers that store styles as element names)\n strong: 'b',\n b: 'b',\n em: 'i',\n i: 'i',\n u: 'u',\n s: 's',\n del: 's',\n strike: 's',\n mark: 'mark',\n sub: 'sub',\n sup: 'sup',\n };\n\n /**\n * Convert HTML element to style properties\n *\n * @param element - Tag name (e.g., \"b\", \"a\", \"strong\")\n * @param attrs - Element attributes (e.g., { href: \"/url\" })\n * @returns Array of style strings\n */\n mapElementToStyles(element: string, attrs: Record<string, string>): string[] {\n const styles: string[] = [];\n const tag = element.toLowerCase();\n\n // Basic element mapping\n const mappedStyle = this.elementToStyles[tag];\n if (mappedStyle) {\n styles.push(mappedStyle);\n }\n\n // Special: <a href=\"...\"> \u2192 hyperlink:url\n if (tag === 'a' && attrs.href) {\n styles.push(`hyperlink:${attrs.href}`);\n }\n\n return styles;\n }\n\n /**\n * Convert style properties to HTML element\n *\n * Priority order:\n * 1. Hyperlink (becomes wrapper element with href)\n * 2. First recognized style property\n * 3. Fallback to span\n *\n * @param styles - Array of style strings\n * @returns Element info for serialization\n */\n mapStylesToElement(styles: string[]): ElementMapping {\n // Check for hyperlink first (takes priority as wrapper element)\n for (const style of styles) {\n if (style.startsWith('hyperlink:')) {\n return {\n element: 'a',\n attrs: { href: style.slice('hyperlink:'.length) },\n };\n }\n }\n\n // Map first recognized style to element\n for (const style of styles) {\n const element = this.styleToElement[style];\n if (element) {\n return {\n element,\n attrs: {},\n };\n }\n }\n\n // Fallback: span with no special attributes\n return { element: 'span', attrs: {} };\n }\n}\n", "/**\n * DOM-based Markup Parser\n *\n * Converts a block element's childNodes into ContentUnit.\n * Uses the browser's DOM rather than regex (unlike edge/PHP which parse raw HTML strings).\n * Mirrors WordPress TS MarkupParser.\n */\n\nimport type { ContentUnit } from '../content/types.js';\nimport { DefaultStyleMapper } from '../content/style-mapper/DefaultStyleMapper.js';\n\nconst styleMapper = new DefaultStyleMapper();\n\n/**\n * Parse a block element into ContentUnit using DOM walking\n */\nexport function parseBlockElement(element: Element): ContentUnit {\n const styles: Record<string, string[]> = {};\n let tagIndex = 0;\n\n function walk(node: Node): string {\n if (node.nodeType === Node.TEXT_NODE) {\n return node.nodeValue ?? '';\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const el = node as Element;\n const tag = el.tagName.toLowerCase();\n\n // Collect attributes\n const attrs: Record<string, string> = {};\n for (let i = 0; i < el.attributes.length; i++) {\n const attr = el.attributes[i];\n attrs[attr.name.toLowerCase()] = attr.value;\n }\n\n const styleList = styleMapper.mapElementToStyles(tag, attrs);\n\n if (styleList.length > 0) {\n // Known styled element \u2014 assign indexed tag\n tagIndex++;\n const idx = tagIndex;\n styles[String(idx)] = styleList;\n\n let inner = '';\n for (let i = 0; i < node.childNodes.length; i++) {\n inner += walk(node.childNodes[i]);\n }\n\n return `<${idx}>${inner}</${idx}>`;\n }\n\n // Unknown element \u2014 strip tag, recurse children\n let result = '';\n for (let i = 0; i < node.childNodes.length; i++) {\n result += walk(node.childNodes[i]);\n }\n return result;\n }\n\n let text = '';\n for (let i = 0; i < element.childNodes.length; i++) {\n text += walk(element.childNodes[i]);\n }\n\n return { text, styles };\n}\n", "/**\n * MD5 Hash Implementation\n * Minimal implementation to match PHP's md5() function\n * Used for generating auto_* keys that match server-side\n */\n\n/* eslint-disable no-bitwise */\n\nfunction safeAdd(x: number, y: number): number {\n const lsw = (x & 0xffff) + (y & 0xffff);\n const msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n return (msw << 16) | (lsw & 0xffff);\n}\n\nfunction bitRotateLeft(num: number, cnt: number): number {\n return (num << cnt) | (num >>> (32 - cnt));\n}\n\nfunction md5cmn(\n q: number,\n a: number,\n b: number,\n x: number,\n s: number,\n t: number\n): number {\n return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);\n}\n\nfunction md5ff(\n a: number,\n b: number,\n c: number,\n d: number,\n x: number,\n s: number,\n t: number\n): number {\n return md5cmn((b & c) | (~b & d), a, b, x, s, t);\n}\n\nfunction md5gg(\n a: number,\n b: number,\n c: number,\n d: number,\n x: number,\n s: number,\n t: number\n): number {\n return md5cmn((b & d) | (c & ~d), a, b, x, s, t);\n}\n\nfunction md5hh(\n a: number,\n b: number,\n c: number,\n d: number,\n x: number,\n s: number,\n t: number\n): number {\n return md5cmn(b ^ c ^ d, a, b, x, s, t);\n}\n\nfunction md5ii(\n a: number,\n b: number,\n c: number,\n d: number,\n x: number,\n s: number,\n t: number\n): number {\n return md5cmn(c ^ (b | ~d), a, b, x, s, t);\n}\n\nfunction binlMD5(x: number[], len: number): number[] {\n x[len >> 5] |= 0x80 << len % 32;\n x[(((len + 64) >>> 9) << 4) + 14] = len;\n\n let a = 1732584193;\n let b = -271733879;\n let c = -1732584194;\n let d = 271733878;\n\n for (let i = 0; i < x.length; i += 16) {\n const olda = a;\n const oldb = b;\n const oldc = c;\n const oldd = d;\n\n a = md5ff(a, b, c, d, x[i], 7, -680876936);\n d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);\n c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);\n b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);\n a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);\n d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);\n c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);\n b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);\n a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);\n d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);\n c = md5ff(c, d, a, b, x[i + 10], 17, -42063);\n b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);\n a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);\n d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);\n c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);\n b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);\n\n a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);\n d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);\n c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);\n b = md5gg(b, c, d, a, x[i], 20, -373897302);\n a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);\n d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);\n c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);\n b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);\n a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);\n d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);\n c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);\n b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);\n a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);\n d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);\n c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);\n b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);\n\n a = md5hh(a, b, c, d, x[i + 5], 4, -378558);\n d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);\n c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);\n b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);\n a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);\n d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);\n c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);\n b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);\n a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);\n d = md5hh(d, a, b, c, x[i + 0], 11, -358537222);\n c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);\n b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);\n a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);\n d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);\n c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);\n b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);\n\n a = md5ii(a, b, c, d, x[i], 6, -198630844);\n d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);\n c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);\n b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);\n a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);\n d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);\n c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);\n b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);\n a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);\n d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);\n c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);\n b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);\n a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);\n d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);\n c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);\n b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);\n\n a = safeAdd(a, olda);\n b = safeAdd(b, oldb);\n c = safeAdd(c, oldc);\n d = safeAdd(d, oldd);\n }\n\n return [a, b, c, d];\n}\n\nfunction binl2hex(binarray: number[]): string {\n const hexTab = '0123456789abcdef';\n let str = '';\n for (let i = 0; i < binarray.length * 4; i++) {\n str +=\n hexTab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xf) +\n hexTab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xf);\n }\n return str;\n}\n\nfunction str2binl(str: string): number[] {\n const bin: number[] = [];\n for (let i = 0; i < str.length * 8; i += 8) {\n bin[i >> 5] |= (str.charCodeAt(i / 8) & 0xff) << i % 32;\n }\n return bin;\n}\n\n/**\n * Generate MD5 hash of a string\n * Matches PHP's md5() function output\n */\nexport function md5(str: string): string {\n return binl2hex(binlMD5(str2binl(str), str.length * 8));\n}\n\n/**\n * Generate auto key matching PHP's TranslationStateManager::generateKey()\n * Format: auto_ + first 12 chars of md5 hash\n */\nexport function generateAutoKey(text: string): string {\n const trimmed = text.trim();\n return 'auto_' + md5(trimmed).substring(0, 12);\n}\n", "/**\n * Key Resolver\n * Resolves a clicked element to its translation key and ContentUnit.\n */\n\nimport type { ContentUnit } from '../../content/types.js';\nimport { parseBlockElement } from '../markup-parser.js';\nimport { generateAutoKey } from '../md5.js';\n\nconst BLOCK_SELECTOR =\n 'p,h1,h2,h3,h4,h5,h6,li,td,th,label,button,figcaption,dt,dd,summary,caption';\n\nexport interface ResolvedKey {\n key: string;\n /** Source ContentUnit (original text with indexed tags) */\n unit: ContentUnit;\n /** Current translation as ContentUnit (if element is already translated) */\n translatedUnit: ContentUnit | null;\n element: Element;\n}\n\n/**\n * Resolve an element to its translation key.\n * Priority: data-lr-block attr \u2192 parseBlockElement \u2192 fallback textContent\n */\nexport function resolveKey(target: Element): ResolvedKey | null {\n // Priority 1: Already translated element with data-lr-block\n const blockEl = target.closest('[data-lr-block]');\n if (blockEl) {\n const key = blockEl.getAttribute('data-lr-block')!;\n const original = blockEl.getAttribute('data-lr-original');\n let unit: ContentUnit;\n let translatedUnit: ContentUnit | null = null;\n\n if (original) {\n // Parse original HTML \u2192 source ContentUnit\n const temp = document.createElement(blockEl.tagName);\n temp.innerHTML = original;\n unit = parseBlockElement(temp);\n // Parse current DOM \u2192 translated ContentUnit\n translatedUnit = parseBlockElement(blockEl);\n } else {\n unit = parseBlockElement(blockEl);\n }\n return { key, unit, translatedUnit, element: blockEl };\n }\n\n // Priority 2: Find nearest block element and parse it\n const nearest = target.closest(BLOCK_SELECTOR);\n if (nearest) {\n const unit = parseBlockElement(nearest);\n const key = generateAutoKey(unit.text);\n return { key, unit, translatedUnit: null, element: nearest };\n }\n\n // Priority 3: Fallback to element text\n const text = target.textContent?.trim();\n if (text && text.length >= 2) {\n const key = generateAutoKey(text);\n const unit: ContentUnit = { text, styles: {} };\n return { key, unit, translatedUnit: null, element: target };\n }\n\n return null;\n}\n", "/**\n * Inspector \u2014 Hover/click handling\n * Shows overlay on hover, resolves key on click, opens sidebar.\n */\n\nimport { resolveKey, ResolvedKey } from './key-resolver.js';\nimport { parseBlockElement } from '../markup-parser.js';\n\nconst SKIP_TAGS = new Set(['SCRIPT', 'STYLE', 'CODE', 'PRE', 'TEXTAREA', 'NOSCRIPT', 'SVG']);\n\nconst BLOCK_SELECTOR =\n 'p,h1,h2,h3,h4,h5,h6,li,td,th,label,button,figcaption,dt,dd,summary,caption';\n\nexport type OnSelectCallback = (resolved: ResolvedKey) => void;\n\nexport class Inspector {\n private overlay: HTMLDivElement;\n private currentTarget: Element | null = null;\n private onSelect: OnSelectCallback;\n private rafId: number | null = null;\n private active = true;\n private rootElement: Element;\n /** When set, clicks resolve keys from this map (snapshot viewer mode)\n * instead of re-computing from the (redacted) DOM text. */\n private snapshotKeyMap: Map<number, string> | null;\n\n constructor(\n shadowRoot: ShadowRoot,\n onSelect: OnSelectCallback,\n rootElement?: Element,\n snapshotKeyMap?: Map<number, string>,\n ) {\n this.onSelect = onSelect;\n // Default scope is the live document body; snapshot viewer passes a\n // sandbox wrapper so blocks outside it are ignored.\n this.rootElement = rootElement || document.body;\n this.snapshotKeyMap = snapshotKeyMap || null;\n\n // Create overlay inside shadow DOM\n this.overlay = document.createElement('div');\n this.overlay.className = 'lr-overlay';\n shadowRoot.appendChild(this.overlay);\n\n // Bind handlers\n this.handleMouseOver = this.handleMouseOver.bind(this);\n this.handleClick = this.handleClick.bind(this);\n this.handleScroll = this.handleScroll.bind(this);\n\n // Listen on document (capture phase to get events before page handlers)\n document.addEventListener('mouseover', this.handleMouseOver, true);\n document.addEventListener('click', this.handleClick, true);\n window.addEventListener('scroll', this.handleScroll, true);\n window.addEventListener('resize', this.handleScroll);\n }\n\n destroy(): void {\n this.active = false;\n document.removeEventListener('mouseover', this.handleMouseOver, true);\n document.removeEventListener('click', this.handleClick, true);\n window.removeEventListener('scroll', this.handleScroll, true);\n window.removeEventListener('resize', this.handleScroll);\n if (this.rafId !== null) cancelAnimationFrame(this.rafId);\n this.overlay.remove();\n }\n\n clearHighlight(): void {\n this.currentTarget = null;\n this.overlay.classList.remove('active');\n }\n\n private handleMouseOver(e: Event): void {\n if (!this.active) return;\n const target = e.target as Element;\n if (!target || !target.closest) return;\n\n // Skip editor UI elements (inside shadow DOM won't trigger this, but be safe)\n if (target.closest('#__lionrapid-editor')) return;\n\n // Skip anything outside the scope root (snapshot viewer mode)\n if (!this.rootElement.contains(target)) return;\n\n // Skip non-translatable elements\n if (this.shouldSkip(target)) {\n this.clearHighlight();\n return;\n }\n\n // Find nearest block element\n const block = target.closest(BLOCK_SELECTOR) || target.closest('[data-lr-block]');\n if (!block) {\n this.clearHighlight();\n return;\n }\n\n if (block === this.currentTarget) return;\n\n this.currentTarget = block;\n this.positionOverlay(block);\n }\n\n private handleClick(e: Event): void {\n if (!this.active) return;\n const target = e.target as Element;\n if (!target || !target.closest) return;\n\n // Skip editor UI\n if (target.closest('#__lionrapid-editor')) return;\n\n // Skip anything outside the scope root (snapshot viewer mode)\n if (!this.rootElement.contains(target)) return;\n\n // Find the block to resolve\n const block = target.closest(BLOCK_SELECTOR) || target.closest('[data-lr-block]');\n if (!block) return;\n\n if (this.shouldSkip(block)) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n // Snapshot viewer mode: look up pre-computed key by data-lr-snap-idx\n // instead of re-running resolveKey on the redacted text.\n if (this.snapshotKeyMap) {\n const idxAttr = block.getAttribute('data-lr-snap-idx');\n if (idxAttr !== null) {\n const idx = parseInt(idxAttr, 10);\n const key = this.snapshotKeyMap.get(idx);\n if (key) {\n const unit = parseBlockElement(block);\n this.onSelect({ key, unit, translatedUnit: null, element: block });\n return;\n }\n }\n // Block has no snap-idx \u2014 not a pre-extracted block, skip\n return;\n }\n\n const resolved = resolveKey(block);\n if (resolved) {\n this.onSelect(resolved);\n }\n }\n\n private handleScroll(): void {\n if (!this.currentTarget) return;\n if (this.rafId !== null) cancelAnimationFrame(this.rafId);\n this.rafId = requestAnimationFrame(() => {\n if (this.currentTarget) {\n this.positionOverlay(this.currentTarget);\n }\n });\n }\n\n private positionOverlay(element: Element): void {\n const rect = element.getBoundingClientRect();\n this.overlay.style.top = `${rect.top}px`;\n this.overlay.style.left = `${rect.left}px`;\n this.overlay.style.width = `${rect.width}px`;\n this.overlay.style.height = `${rect.height}px`;\n this.overlay.classList.add('active');\n }\n\n private shouldSkip(element: Element): boolean {\n // Skip SKIP_TAGS\n let current: Element | null = element;\n while (current) {\n if (SKIP_TAGS.has(current.tagName)) return true;\n if (current.hasAttribute('data-no-translate')) return true;\n if (current.getAttribute('translate') === 'no') return true;\n current = current.parentElement;\n }\n return false;\n }\n}\n", "/**\n * Toolbar \u2014 Draggable FAB that expands to show controls\n * Collapsed: small circle with \"LR\" logo\n * Expanded: horizontal bar with language selector, progress, exit\n */\n\nexport type OnLanguageChange = (locale: string) => void;\nexport type OnExit = () => void;\nexport type OnCaptureSnapshot = () => void;\n\nexport interface ToolbarCaptureOptions {\n /** 'capture' = new snapshot, 'recapture' = overwrite an existing snapshot's version */\n mode?: 'capture' | 'recapture';\n}\n\nexport class Toolbar {\n private el: HTMLDivElement;\n private langBtnEl: HTMLButtonElement;\n private langMenuEl: HTMLDivElement;\n private progressEl: HTMLSpanElement;\n private expanded = false;\n private currentLocale: string;\n private onLanguageChange: OnLanguageChange;\n private onExit: OnExit;\n private onCaptureSnapshot: OnCaptureSnapshot | null;\n\n // Drag state\n private dragging = false;\n private dragOffsetX = 0;\n private dragOffsetY = 0;\n\n constructor(\n shadowRoot: ShadowRoot,\n languages: string[],\n currentLocale: string,\n onLanguageChange: OnLanguageChange,\n onExit: OnExit,\n onCaptureSnapshot: OnCaptureSnapshot | null = null,\n captureOptions: ToolbarCaptureOptions = {},\n ) {\n this.onLanguageChange = onLanguageChange;\n this.onExit = onExit;\n this.onCaptureSnapshot = onCaptureSnapshot;\n this.currentLocale = currentLocale;\n const captureMode = captureOptions.mode ?? 'capture';\n\n this.el = document.createElement('div');\n this.el.className = 'lr-fab';\n\n // FAB button (always visible)\n const fabBtn = document.createElement('button');\n fabBtn.className = 'lr-fab-btn';\n fabBtn.textContent = 'LR';\n fabBtn.addEventListener('click', (e) => {\n // Don't toggle if we just finished dragging\n if (this.dragging) return;\n e.stopPropagation();\n this.toggle();\n });\n this.el.appendChild(fabBtn);\n\n // Expanded panel\n const panel = document.createElement('div');\n panel.className = 'lr-fab-panel';\n\n // Custom language dropdown\n const langWrap = document.createElement('div');\n langWrap.className = 'lr-lang-dropdown';\n\n this.langBtnEl = document.createElement('button');\n this.langBtnEl.className = 'lr-lang-btn';\n this.langBtnEl.textContent = currentLocale.toUpperCase();\n this.langBtnEl.addEventListener('click', (e) => {\n e.stopPropagation();\n this.langMenuEl.classList.toggle('open');\n });\n langWrap.appendChild(this.langBtnEl);\n\n this.langMenuEl = document.createElement('div');\n this.langMenuEl.className = 'lr-lang-menu';\n for (const lang of languages) {\n const item = document.createElement('button');\n item.className = 'lr-lang-item';\n if (lang === currentLocale) item.classList.add('active');\n item.textContent = lang.toUpperCase();\n item.addEventListener('click', (e) => {\n e.stopPropagation();\n this.currentLocale = lang;\n this.langBtnEl.textContent = lang.toUpperCase();\n this.langMenuEl.classList.remove('open');\n // Update active state\n this.langMenuEl.querySelectorAll('.lr-lang-item').forEach((el) => el.classList.remove('active'));\n item.classList.add('active');\n this.onLanguageChange(lang);\n });\n this.langMenuEl.appendChild(item);\n }\n langWrap.appendChild(this.langMenuEl);\n panel.appendChild(langWrap);\n\n // Capture Snapshot button (only in capture mode, not viewer mode).\n // Label/title change when recapture mode is active so the PM knows this\n // click will overwrite an existing snapshot's version instead of making\n // a new one.\n if (this.onCaptureSnapshot) {\n const captureBtn = document.createElement('button');\n captureBtn.className = 'lr-fab-snapshot';\n if (captureMode === 'recapture') {\n captureBtn.textContent = 'Save re-capture';\n captureBtn.title = 'Save this page as a new version of the existing snapshot';\n } else {\n captureBtn.textContent = 'Capture';\n captureBtn.title = 'Capture a redacted snapshot of this page for translators';\n }\n captureBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (this.onCaptureSnapshot) this.onCaptureSnapshot();\n });\n panel.appendChild(captureBtn);\n }\n\n // Progress\n this.progressEl = document.createElement('span');\n this.progressEl.className = 'lr-fab-progress';\n panel.appendChild(this.progressEl);\n\n // Exit button\n const exitBtn = document.createElement('button');\n exitBtn.className = 'lr-fab-exit';\n exitBtn.textContent = 'Exit';\n exitBtn.addEventListener('click', () => this.onExit());\n panel.appendChild(exitBtn);\n\n this.el.appendChild(panel);\n shadowRoot.appendChild(this.el);\n\n // Dragging\n this.handleMouseDown = this.handleMouseDown.bind(this);\n this.handleMouseMove = this.handleMouseMove.bind(this);\n this.handleMouseUp = this.handleMouseUp.bind(this);\n fabBtn.addEventListener('mousedown', this.handleMouseDown);\n }\n\n toggle(): void {\n this.expanded = !this.expanded;\n this.el.classList.toggle('expanded', this.expanded);\n }\n\n updateProgress(translated: number, total: number): void {\n this.progressEl.textContent = `${translated}/${total}`;\n }\n\n getCurrentLocale(): string {\n return this.currentLocale;\n }\n\n destroy(): void {\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n this.el.remove();\n }\n\n private handleMouseDown(e: MouseEvent): void {\n this.dragging = false;\n this.dragOffsetX = e.clientX - this.el.getBoundingClientRect().left;\n this.dragOffsetY = e.clientY - this.el.getBoundingClientRect().top;\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n }\n\n private handleMouseMove(e: MouseEvent): void {\n this.dragging = true;\n const x = Math.max(0, Math.min(e.clientX - this.dragOffsetX, window.innerWidth - this.el.offsetWidth));\n const y = Math.max(0, Math.min(e.clientY - this.dragOffsetY, window.innerHeight - this.el.offsetHeight));\n this.el.style.left = `${x}px`;\n this.el.style.top = `${y}px`;\n this.el.style.right = 'auto';\n this.el.style.bottom = 'auto';\n }\n\n private handleMouseUp(): void {\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n // Reset dragging flag after a tick so the click handler can check it\n if (this.dragging) {\n setTimeout(() => { this.dragging = false; }, 0);\n }\n }\n}\n", "/**\n * HTML serializer for converting ContentUnit to HTML strings\n * @module content/serializer/HTMLSerializer\n */\n\nimport type { ISerializer } from './ISerializer.js';\nimport type { ContentUnit } from '../types.js';\nimport type { IStyleMapper } from '../style-mapper/IStyleMapper.js';\nimport { DefaultStyleMapper } from '../style-mapper/DefaultStyleMapper.js';\n\n/**\n * Configuration options for HTMLSerializer\n */\nexport interface HTMLSerializerOptions {\n /**\n * Custom style mapper for styles \u2192 element conversion\n * Defaults to DefaultStyleMapper\n */\n styleMapper?: IStyleMapper;\n}\n\n/**\n * Serializer that converts ContentUnit format back to HTML strings\n *\n * Transforms indexed tags and style mappings into HTML:\n * - `<1>bold</1>` with styles `{\"1\": [\"bold\"]}` \u2192 `<b>bold</b>`\n * - `<1>link</1>` with styles `{\"1\": [\"hyperlink:/url\"]}` \u2192 `<a href=\"/url\">link</a>`\n *\n * @example\n * ```typescript\n * const serializer = new HTMLSerializer();\n *\n * const html = serializer.serialize({\n * text: 'Read our <1>Terms</1>.',\n * styles: { '1': ['bold'] }\n * });\n * // \u2192 \"Read our <b>Terms</b>.\"\n *\n * const link = serializer.serialize({\n * text: 'Click <1>here</1>.',\n * styles: { '1': ['hyperlink:/url'] }\n * });\n * // \u2192 \"Click <a href=\\\"/url\\\">here</a>.\"\n * ```\n */\nexport class HTMLSerializer implements ISerializer<string> {\n private readonly styleMapper: IStyleMapper;\n\n constructor(options: HTMLSerializerOptions = {}) {\n this.styleMapper = options.styleMapper ?? new DefaultStyleMapper();\n }\n\n /**\n * Serialize ContentUnit to HTML string\n *\n * @param unit - ContentUnit with indexed tags and styles\n * @returns HTML string with semantic elements\n */\n serialize(unit: ContentUnit): string {\n const { text, styles } = unit;\n\n // Pattern to match indexed tags: <1>, </1>, <1/>\n const tagPattern = /<(\\/?)?(\\d+)(\\/)?>/g;\n\n let result = '';\n let lastIndex = 0;\n let match;\n\n while ((match = tagPattern.exec(text)) !== null) {\n // Append text before the tag\n result += text.slice(lastIndex, match.index);\n\n const [fullMatch, closingSlash, indexStr, selfClosingSlash] = match;\n const tagIndex = indexStr;\n const styleList = styles[tagIndex] || [];\n\n if (closingSlash) {\n // Closing tag: </1>\n const mapping = this.styleMapper.mapStylesToElement(styleList);\n result += `</${mapping.element}>`;\n } else if (selfClosingSlash) {\n // Self-closing tag: <1/>\n const mapping = this.styleMapper.mapStylesToElement(styleList);\n const attrs = this.formatAttributes(mapping.attrs);\n result += `<${mapping.element}${attrs} />`;\n } else {\n // Opening tag: <1>\n const mapping = this.styleMapper.mapStylesToElement(styleList);\n const attrs = this.formatAttributes(mapping.attrs);\n result += `<${mapping.element}${attrs}>`;\n }\n\n lastIndex = match.index + fullMatch.length;\n }\n\n // Append remaining text\n result += text.slice(lastIndex);\n\n return result;\n }\n\n /**\n * Format attributes object into HTML attribute string\n */\n private formatAttributes(attrs: Record<string, string>): string {\n const entries = Object.entries(attrs);\n if (entries.length === 0) return '';\n\n return (\n ' ' +\n entries\n .map(([key, value]) => `${key}=\"${this.escapeAttributeValue(value)}\"`)\n .join(' ')\n );\n }\n\n /**\n * Escape special characters in attribute values\n */\n private escapeAttributeValue(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n }\n}\n", "/**\n * Live Preview\n * Optimistically updates DOM elements as the user types translations.\n */\n\nimport type { ContentUnit } from '../../content/types.js';\nimport { HTMLSerializer } from '../../content/serializer/HTMLSerializer.js';\n\nconst htmlSerializer = new HTMLSerializer();\n\n/**\n * Update a single element's content with a new translation.\n * Writes to core cache and updates the DOM without full page retranslate.\n */\nexport function applyLivePreview(\n element: Element,\n text: string,\n styles: Record<string, string[]>,\n key: string,\n locale: string,\n namespace: string,\n): void {\n // Save original HTML before first edit\n if (!element.hasAttribute('data-lr-original')) {\n element.setAttribute('data-lr-original', element.innerHTML);\n }\n\n // Update core cache if available\n const lr = (window as { LionRapid?: { autoTranslator?: { core?: { cache?: { set?: (k: string, v: string, s?: Record<string, string[]>) => void } } } } }).LionRapid;\n const cache = (lr as Record<string, unknown>)?.autoTranslator\n ? getCache()\n : null;\n if (cache) {\n const fullKey = `${locale}:${namespace}:${key}`;\n cache.set(fullKey, text, styles);\n }\n\n // Update DOM\n if (styles && Object.keys(styles).length > 0) {\n const unit: ContentUnit = { text, styles };\n element.innerHTML = htmlSerializer.serialize(unit);\n } else {\n element.textContent = text;\n }\n\n // Mark as translated\n element.setAttribute('data-lr-block', key);\n element.setAttribute('data-lionrapid-client', '1');\n}\n\nfunction getCache(): { set: (key: string, value: string, styles?: Record<string, string[]>) => void } | null {\n try {\n const lr = (window as unknown as { LionRapid?: Record<string, unknown> }).LionRapid;\n if (!lr) return null;\n const at = lr.autoTranslator as Record<string, unknown> | undefined;\n if (!at) return null;\n const core = at.core as Record<string, unknown> | undefined;\n if (!core) return null;\n const cache = core.cache as { set?: (key: string, value: string, styles?: Record<string, string[]>) => void } | undefined;\n if (!cache || typeof cache.set !== 'function') return null;\n return cache as { set: (key: string, value: string, styles?: Record<string, string[]>) => void };\n } catch {\n return null;\n }\n}\n", "/**\n * Exclude Filter\n * Filters out text that should not be translated\n * Mirrors PHP's HtmlTranslator logic\n */\n\nexport interface ExcludePatterns {\n emails: boolean;\n urls: boolean;\n numbers: boolean;\n phones: boolean;\n}\n\nconst DEFAULT_PATTERNS: ExcludePatterns = {\n emails: true,\n urls: true,\n numbers: true,\n phones: true,\n};\n\n// Regex patterns matching PHP's HtmlTranslator\nconst PATTERNS = {\n email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/,\n url: /^(https?:\\/\\/|www\\.)[^\\s]+$/i,\n number: /^[\\d\\s.,+-]+$/,\n phone: /^[+\\d][\\d\\s().-]{6,}$/,\n};\n\nexport class ExcludeFilter {\n private patterns: ExcludePatterns;\n private minTextLength: number;\n\n constructor(patterns: Partial<ExcludePatterns> = {}, minTextLength = 2) {\n this.patterns = { ...DEFAULT_PATTERNS, ...patterns };\n this.minTextLength = minTextLength;\n }\n\n /**\n * Check if text should be excluded from translation\n */\n shouldExclude(text: string): boolean {\n const trimmed = text.trim();\n\n // Too short\n if (trimmed.length < this.minTextLength) {\n return true;\n }\n\n // Check auto-exclude patterns\n if (this.patterns.emails && PATTERNS.email.test(trimmed)) {\n return true;\n }\n\n if (this.patterns.urls && PATTERNS.url.test(trimmed)) {\n return true;\n }\n\n if (this.patterns.numbers && PATTERNS.number.test(trimmed)) {\n return true;\n }\n\n if (this.patterns.phones && PATTERNS.phone.test(trimmed)) {\n return true;\n }\n\n return false;\n }\n}\n", "/**\n * Block Extractor\n * Finds translatable block elements in DOM and parses them into ContentUnit.\n * Mirrors WordPress TS BlockExtractor and edge proxy block-level approach.\n */\n\nimport type { ContentUnit } from '../content/types.js';\nimport { ExcludeFilter, ExcludePatterns } from './exclude-filter.js';\nimport { parseBlockElement } from './markup-parser.js';\nimport { generateAutoKey } from './md5.js';\n\nconst BLOCK_SELECTOR =\n 'p,h1,h2,h3,h4,h5,h6,li,td,th,label,button,figcaption,dt,dd,summary,caption';\n\n// Tags to skip (same as PHP/edge)\nconst SKIP_TAGS = new Set([\n 'SCRIPT',\n 'STYLE',\n 'CODE',\n 'PRE',\n 'TEXTAREA',\n 'NOSCRIPT',\n 'SVG',\n]);\n\n// Attributes that mark elements to skip\nconst SKIP_ATTRIBUTES = [\n 'data-lionrapid-translated', // Server already translated\n 'data-lionrapid-client', // Client already translated\n 'data-no-translate', // Explicitly marked to skip\n];\n\nexport interface ExtractedBlock {\n element: Element;\n unit: ContentUnit;\n key: string;\n}\n\nexport class BlockExtractor {\n private excludeFilter: ExcludeFilter;\n private excludeSelectors: string[];\n\n constructor(\n excludePatterns: Partial<ExcludePatterns> = {},\n excludeSelectors: string[] = [],\n minTextLength = 2\n ) {\n this.excludeFilter = new ExcludeFilter(excludePatterns, minTextLength);\n this.excludeSelectors = excludeSelectors;\n }\n\n /**\n * Extract all translatable block elements from a root.\n * @param includeTranslated - If true, include elements already marked as translated (for editor mode)\n */\n extract(root: Element | Document, includeTranslated = false): ExtractedBlock[] {\n const results: ExtractedBlock[] = [];\n const descendants = root.querySelectorAll(BLOCK_SELECTOR);\n\n // Include the root itself if it matches the block selector\n const elements: Element[] = [];\n if (root instanceof Element && root.matches(BLOCK_SELECTOR)) {\n elements.push(root);\n }\n for (let i = 0; i < descendants.length; i++) {\n elements.push(descendants[i]);\n }\n\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i];\n\n // Skip if inside a SKIP_TAG ancestor\n if (this.isInsideSkipTag(el)) {\n continue;\n }\n\n // Skip if has skip attributes (unless editor mode includes translated)\n if (!includeTranslated && this.hasSkipAttribute(el)) {\n continue;\n }\n\n // Skip if matches exclude selectors\n if (this.matchesExcludeSelector(el)) {\n continue;\n }\n\n // Skip if has translate=\"no\"\n if (el.getAttribute('translate') === 'no') {\n continue;\n }\n\n // Skip nested block elements (let the inner blocks be extracted)\n if (el.querySelector(BLOCK_SELECTOR)) {\n continue;\n }\n\n // For already-translated elements, use original HTML for key + unit\n const lrBlock = el.getAttribute('data-lr-block');\n const lrOriginal = el.getAttribute('data-lr-original');\n\n let unit: ContentUnit;\n if (lrOriginal) {\n // Parse original (source) HTML \u2192 correct ContentUnit for key generation\n const temp = document.createElement(el.tagName);\n temp.innerHTML = lrOriginal;\n unit = parseBlockElement(temp);\n } else {\n unit = parseBlockElement(el);\n }\n\n // Strip indexed tags for exclude filter\n const strippedText = unit.text.replace(/<\\/?[0-9]+\\/?>/g, '');\n\n // Apply exclude filter\n if (this.excludeFilter.shouldExclude(strippedText)) {\n continue;\n }\n\n // Key priority: data-lr-block (translated) \u2192 data-i18n (named) \u2192 auto-generate\n let key: string;\n if (lrBlock) {\n key = lrBlock;\n } else {\n const dataI18n = el.getAttribute('data-i18n');\n if (dataI18n) {\n key = dataI18n.includes(':') ? dataI18n : `common:${dataI18n}`;\n } else {\n key = generateAutoKey(unit.text);\n }\n }\n\n results.push({ element: el, unit, key });\n }\n\n return results;\n }\n\n private isInsideSkipTag(element: Element): boolean {\n let current: Element | null = element.parentElement;\n while (current) {\n if (SKIP_TAGS.has(current.tagName)) {\n return true;\n }\n current = current.parentElement;\n }\n return false;\n }\n\n private hasSkipAttribute(element: Element): boolean {\n let current: Element | null = element;\n while (current) {\n for (const attr of SKIP_ATTRIBUTES) {\n if (current.hasAttribute(attr)) {\n return true;\n }\n }\n current = current.parentElement;\n }\n return false;\n }\n\n private matchesExcludeSelector(element: Element): boolean {\n for (const selector of this.excludeSelectors) {\n try {\n if (element.matches(selector) || element.closest(selector)) {\n return true;\n }\n } catch {\n // Invalid selector, skip\n }\n }\n return false;\n }\n}\n", "/**\n * Sidebar \u2014 Translation editing panel\n * Shows original text, translation textarea, live preview, and page blocks list.\n */\n\nimport type { ContentUnit } from '../../content/types.js';\nimport type { ResolvedKey } from './key-resolver.js';\nimport { HTMLSerializer } from '../../content/serializer/HTMLSerializer.js';\nimport { applyLivePreview } from './live-preview.js';\nimport type { EditorAPI, TargetStatus } from './editor-api.js';\nimport { BlockExtractor } from '../block-extractor.js';\n\nconst htmlSerializer = new HTMLSerializer();\n\nexport class Sidebar {\n private el: HTMLDivElement;\n private bodyEl: HTMLDivElement;\n private statusEl: HTMLDivElement;\n private api: EditorAPI;\n private locale: string;\n private namespace: string;\n private defaultLocale: string;\n private current: ResolvedKey | null = null;\n private blockExtractor: BlockExtractor;\n private onBlockClick: (resolved: ResolvedKey) => void;\n private statusMap: Map<string, TargetStatus | null> = new Map();\n private unsavedKeys: Set<string> = new Set();\n private onProgressUpdate: ((translated: number, total: number) => void) | null = null;\n private lastFetchTime = 0;\n private lastFlushTime = 0;\n\n private userRole: string;\n\n constructor(\n shadowRoot: ShadowRoot,\n api: EditorAPI,\n locale: string,\n namespace: string,\n defaultLocale: string,\n onBlockClick: (resolved: ResolvedKey) => void,\n userRole: string = '',\n ) {\n this.api = api;\n this.locale = locale;\n this.namespace = namespace;\n this.defaultLocale = defaultLocale;\n this.onBlockClick = onBlockClick;\n this.userRole = userRole;\n this.blockExtractor = new BlockExtractor();\n\n this.el = document.createElement('div');\n this.el.className = 'lr-sidebar';\n\n // Resize handle\n const resizeHandle = document.createElement('div');\n resizeHandle.className = 'lr-sidebar-resize';\n this.initResize(resizeHandle);\n this.el.appendChild(resizeHandle);\n\n // Header\n const header = document.createElement('div');\n header.className = 'lr-sidebar-header';\n const title = document.createElement('span');\n title.className = 'lr-sidebar-title';\n title.textContent = 'Edit Translation';\n header.appendChild(title);\n const closeBtn = document.createElement('button');\n closeBtn.className = 'lr-sidebar-close';\n closeBtn.innerHTML = '&times;';\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(closeBtn);\n this.el.appendChild(header);\n\n // Body\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'lr-sidebar-body';\n this.el.appendChild(this.bodyEl);\n\n // Status bar (rendered inline in renderContent, above preview)\n this.statusEl = document.createElement('div');\n this.statusEl.className = 'lr-status';\n\n // Wire up API status\n this.api.setStatusCallback((status, message) => {\n this.statusEl.textContent = message || status;\n this.statusEl.className = `lr-status ${status}`;\n });\n\n // After flush, re-fetch status for saved keys and refresh blocks list\n this.api.setFlushedCallback(async (keys) => {\n this.lastFlushTime = Date.now();\n const freshStatuses = await this.api.fetchStatus(keys, this.locale, this.namespace);\n for (const [key, status] of Object.entries(freshStatuses)) {\n this.statusMap.set(key, status);\n this.unsavedKeys.delete(key);\n }\n this.refreshBlocksList();\n this.emitProgress();\n });\n\n shadowRoot.appendChild(this.el);\n }\n\n open(resolved: ResolvedKey): void {\n this.current = resolved;\n this.el.classList.add('open');\n this.renderContent(resolved);\n }\n\n close(): void {\n this.current = null;\n this.el.classList.remove('open');\n }\n\n isOpen(): boolean {\n return this.el.classList.contains('open');\n }\n\n updateLocale(locale: string): void {\n this.locale = locale;\n // Clear status on locale change \u2014 will be re-fetched\n this.statusMap.clear();\n this.unsavedKeys.clear();\n }\n\n setProgressCallback(cb: (translated: number, total: number) => void): void {\n this.onProgressUpdate = cb;\n }\n\n /**\n * Hydrate the status map with server data for all page blocks.\n * Called once on editor init.\n */\n async hydrateStatus(): Promise<void> {\n const blocks = this.blockExtractor.extract(document.body, true);\n const keys = blocks.map((b) => b.key);\n if (keys.length === 0) return;\n\n const statuses = await this.api.fetchStatus(keys, this.locale, this.namespace);\n for (const [key, status] of Object.entries(statuses)) {\n this.statusMap.set(key, status);\n }\n\n // Apply draft translations to page blocks that the edge proxy didn't render\n // (edge proxy only shows is_ready_for_delivery; editor shows everything)\n for (const block of blocks) {\n const status = this.statusMap.get(block.key);\n if (status && status.text && !status.isReady) {\n applyLivePreview(block.element, status.text, block.unit.styles, block.key, this.locale, this.namespace);\n }\n }\n\n this.emitProgress();\n }\n\n getTranslatedCount(): number {\n let count = 0;\n for (const status of this.statusMap.values()) {\n if (status && status.rowState !== 'empty') count++;\n }\n return count;\n }\n\n getTotalCount(): number {\n return this.blockExtractor.extract(document.body, true).length;\n }\n\n private emitProgress(): void {\n if (this.onProgressUpdate) {\n this.onProgressUpdate(this.getTranslatedCount(), this.getTotalCount());\n }\n }\n\n destroy(): void {\n this.el.remove();\n }\n\n private async renderContent(resolved: ResolvedKey): Promise<void> {\n const { key, unit, element } = resolved;\n this.bodyEl.innerHTML = '';\n\n // Smart fetch: if no flush since last full fetch, only fetch the clicked key.\n // Otherwise re-fetch all blocks to pick up server-side changes from our saves.\n const isStale = this.lastFlushTime > this.lastFetchTime || this.lastFetchTime === 0;\n\n if (isStale) {\n const blocks = this.blockExtractor.extract(document.body, true);\n const allKeys = blocks.map((b) => b.key);\n if (!allKeys.includes(key)) allKeys.push(key);\n const freshStatuses = await this.api.fetchStatus(allKeys, this.locale, this.namespace);\n for (const [k, s] of Object.entries(freshStatuses)) {\n this.statusMap.set(k, s);\n }\n this.lastFetchTime = Date.now();\n } else {\n // Fresh \u2014 only fetch the clicked key\n const freshStatus = await this.api.fetchStatus([key], this.locale, this.namespace);\n if (freshStatus[key] !== undefined) {\n this.statusMap.set(key, freshStatus[key]);\n }\n }\n const status = this.statusMap.get(key) ?? null;\n\n // Key field\n this.addField('Key', () => {\n const keyEl = document.createElement('div');\n keyEl.className = 'lr-field-key';\n keyEl.textContent = key;\n return keyEl;\n });\n\n // Original text\n this.addField('Original', () => {\n const origEl = document.createElement('div');\n origEl.className = 'lr-field-original';\n origEl.innerHTML = this.renderTextWithTags(unit.text);\n return origEl;\n });\n\n const isSourceLocale = this.locale === this.defaultLocale;\n const isLocked = isSourceLocale || status?.isLocked || status?.isReady || false;\n\n // Translation textarea\n const textarea = document.createElement('textarea');\n this.addField('Translation', () => {\n textarea.className = 'lr-textarea';\n // Pre-fill: server status > in-DOM translation > empty\n textarea.value = status?.text || resolved.translatedUnit?.text || '';\n textarea.placeholder = unit.text; // Show source as placeholder\n if (isLocked) {\n textarea.readOnly = true;\n textarea.classList.add('lr-textarea-locked');\n textarea.title = isSourceLocale\n ? 'Source language \u2014 switch to a target language to edit'\n : status?.isReady ? 'Approved for delivery \u2014 read only' : 'Locked \u2014 read only';\n }\n return textarea;\n });\n\n // Status bar (above preview)\n this.bodyEl.appendChild(this.statusEl);\n\n // Preview\n const previewEl = document.createElement('div');\n this.addField('Preview', () => {\n previewEl.className = 'lr-preview';\n if (textarea.value) {\n previewEl.innerHTML = this.renderPreview(textarea.value, unit.styles);\n }\n return previewEl;\n });\n\n // Workflow actions (Phase 3) \u2014 only on target locales (not source).\n // Visibility per role + state is enforced server-side; we hide buttons\n // the server would refuse so users don't see dead ends.\n if (!isSourceLocale) {\n this.renderWorkflowActions(key, status);\n }\n\n // Live preview on input (only if not locked)\n if (!isLocked) {\n textarea.addEventListener('input', () => {\n const text = textarea.value;\n previewEl.innerHTML = this.renderPreview(text, unit.styles);\n if (text) {\n applyLivePreview(element, text, unit.styles, key, this.locale, this.namespace);\n }\n this.unsavedKeys.add(key);\n this.api.queueSave({\n key,\n locale: this.locale,\n namespace: this.namespace,\n text,\n styles: unit.styles,\n });\n });\n }\n\n // Page blocks list\n this.renderBlocksList();\n\n // Focus textarea (only if editable)\n if (!isLocked) {\n setTimeout(() => textarea.focus(), 100);\n }\n }\n\n /**\n * Render Confirm/Reject/Mark-Ready/Unmark-Ready buttons under the preview.\n * Visibility:\n * - Confirm: shown when row is not locked and not already ready\n * - Reject: shown when row is not locked and not already ready (server\n * returns 400 if stage_index is already 0)\n * - Unconfirm: shown when isConfirmed\n * - Mark Ready: PM/admin only, hidden when already ready\n * - Unmark Ready: PM/admin only, only when ready\n * After any successful click we re-fetch status for this key so the UI\n * reflects the new state and the unaffected buttons hide/show themselves.\n */\n private renderWorkflowActions(key: string, status: TargetStatus | null | undefined): void {\n const isPM = this.userRole === 'project_manager' || this.userRole === 'admin';\n const isReady = !!status?.isReady;\n const isLocked = !!status?.isLocked;\n const isConfirmed = !!status?.isConfirmed;\n\n const composite = `${this.locale}:${this.namespace}:${key}`;\n\n const wrap = document.createElement('div');\n wrap.className = 'lr-workflow-actions';\n\n const addBtn = (\n label: string,\n action: 'confirm' | 'unconfirm' | 'reject' | 'mark-ready' | 'unmark-ready',\n variant: 'primary' | 'secondary' | 'danger' = 'secondary',\n ): void => {\n const btn = document.createElement('button');\n btn.className = `lr-wf-btn lr-wf-${variant}`;\n btn.textContent = label;\n btn.addEventListener('click', async () => {\n btn.disabled = true;\n const result = await this.api.transitionTarget(composite, action);\n btn.disabled = false;\n if (result) {\n // Refresh status for this key so the buttons recompute\n await this.refreshStatusForKey(key);\n }\n });\n wrap.appendChild(btn);\n };\n\n // Translator-side actions (subject to can_user_edit_row server-side)\n if (!isLocked && !isReady) {\n addBtn('Confirm', 'confirm', 'primary');\n addBtn('Reject', 'reject', 'danger');\n }\n if (isConfirmed && !isLocked && !isReady) {\n addBtn('Unconfirm', 'unconfirm');\n }\n\n // PM-only actions\n if (isPM) {\n if (!isReady) {\n addBtn('Mark Ready', 'mark-ready', 'primary');\n } else {\n addBtn('Unmark Ready', 'unmark-ready', 'danger');\n }\n }\n\n if (wrap.children.length > 0) {\n this.bodyEl.appendChild(wrap);\n }\n }\n\n /** Re-fetch status for one key and re-render the current view. */\n private async refreshStatusForKey(key: string): Promise<void> {\n const fresh = await this.api.fetchStatus([key], this.locale, this.namespace);\n for (const [k, s] of Object.entries(fresh)) {\n this.statusMap.set(k, s);\n }\n if (this.current) {\n // Re-render the current key to pick up new status\n this.renderContent(this.current);\n }\n this.emitProgress();\n }\n\n private addField(label: string, contentFn: () => HTMLElement): void {\n const field = document.createElement('div');\n field.className = 'lr-field';\n const labelEl = document.createElement('span');\n labelEl.className = 'lr-field-label';\n labelEl.textContent = label;\n field.appendChild(labelEl);\n field.appendChild(contentFn());\n this.bodyEl.appendChild(field);\n }\n\n /**\n * Get CSS class for the status dot based on actual row state.\n */\n private getDotClass(key: string): string {\n if (this.unsavedKeys.has(key)) return 'unsaved';\n const s = this.statusMap.get(key);\n if (!s) return 'missing';\n if (s.isLocked) return 'locked';\n if (s.isReady) return 'ready';\n if (s.isConfirmed) return 'confirmed';\n if (s.rowState === 'edited') return 'edited';\n if (s.rowState === 'machine_translated') return 'mt';\n return 'missing';\n }\n\n private renderTextWithTags(text: string): string {\n // Highlight indexed tags like <1>, </1>\n return text.replace(\n /<(\\/?)?(\\d+)(\\/)?>/g,\n (match) => `<span class=\"lr-field-tag\">${match}</span>`\n );\n }\n\n private renderPreview(text: string, styles: Record<string, string[]>): string {\n if (!text) return '';\n if (Object.keys(styles).length > 0) {\n const unit: ContentUnit = { text, styles };\n return htmlSerializer.serialize(unit);\n }\n return text;\n }\n\n private initResize(handle: HTMLDivElement): void {\n let startX = 0;\n let startWidth = 0;\n\n const onMouseMove = (e: MouseEvent) => {\n const newWidth = startWidth + (startX - e.clientX);\n const clamped = Math.max(280, Math.min(600, newWidth));\n this.el.style.width = `${clamped}px`;\n };\n\n const onMouseUp = () => {\n handle.classList.remove('active');\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n };\n\n handle.addEventListener('mousedown', (e) => {\n e.preventDefault();\n startX = e.clientX;\n startWidth = this.el.offsetWidth;\n handle.classList.add('active');\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n });\n }\n\n private refreshBlocksList(): void {\n const existing = this.bodyEl.querySelector('.lr-blocks-section');\n if (existing) existing.remove();\n this.renderBlocksList();\n }\n\n private renderBlocksList(): void {\n const section = document.createElement('div');\n section.className = 'lr-blocks-section';\n\n const blocks = this.blockExtractor.extract(document.body, true);\n const translatedCount = this.getTranslatedCount();\n\n const title = document.createElement('div');\n title.className = 'lr-blocks-title';\n title.textContent = `Blocks on this page (${translatedCount}/${blocks.length} translated)`;\n section.appendChild(title);\n\n for (const block of blocks) {\n const item = document.createElement('div');\n item.className = 'lr-block-item';\n\n const isActive = this.current && block.element === this.current.element;\n if (isActive) item.classList.add('active');\n\n // Status dot\n const dot = document.createElement('span');\n dot.className = 'lr-status-dot';\n dot.classList.add(this.getDotClass(block.key));\n item.appendChild(dot);\n\n // Source text\n const textWrap = document.createElement('div');\n textWrap.className = 'lr-block-text';\n const displayText = block.unit.text.replace(/<\\/?[0-9]+\\/?>/g, '');\n const sourceSpan = document.createElement('div');\n sourceSpan.className = 'lr-block-source';\n sourceSpan.textContent = displayText.length > 60 ? displayText.slice(0, 60) + '...' : displayText;\n sourceSpan.title = displayText;\n textWrap.appendChild(sourceSpan);\n\n // Translation preview (if exists)\n const blockStatus = this.statusMap.get(block.key);\n if (blockStatus && blockStatus.text) {\n const previewSpan = document.createElement('div');\n previewSpan.className = 'lr-block-preview';\n const previewText = blockStatus.text.replace(/<\\/?[0-9]+\\/?>/g, '');\n previewSpan.textContent = previewText.length > 50 ? previewText.slice(0, 50) + '...' : previewText;\n textWrap.appendChild(previewSpan);\n }\n\n item.appendChild(textWrap);\n\n item.addEventListener('click', () => {\n block.element.scrollIntoView({ behavior: 'smooth', block: 'center' });\n this.onBlockClick({ key: block.key, unit: block.unit, translatedUnit: null, element: block.element });\n });\n\n section.appendChild(item);\n }\n\n this.bodyEl.appendChild(section);\n }\n}\n", "/**\n * Editor API \u2014 Batch save queue + session auth\n * Queues translation edits and flushes them in a single batch API call.\n * Uses editor session JWTs (es_ prefixed) for authentication with auto-renewal.\n */\n\nimport type { CapturedSnapshot, SnapshotTextEntry } from './snapshot-capture.js';\n\nexport interface QueuedTranslation {\n key: string;\n locale: string;\n namespace: string;\n text: string;\n styles: Record<string, string[]>;\n}\n\n// ============================================\n// Snapshot API types\n// ============================================\n\nexport interface SnapshotListItem {\n snapshotUuid: string;\n pageUrl: string;\n title: string;\n capturedBy: string;\n createdAt: string;\n expiresAt: string;\n textEntryCount: number;\n status: string;\n}\n\nexport interface SnapshotDetail {\n snapshotUuid: string;\n pageUrl: string;\n title: string;\n html: string;\n textEntries: SnapshotTextEntry[];\n viewport: { width: number; height: number; devicePixelRatio: number };\n createdAt: string;\n expiresAt: string;\n}\n\nexport interface TargetStatus {\n text: string;\n rowState: string; // \"empty\" | \"machine_translated\" | \"edited\"\n isConfirmed: boolean;\n isReady: boolean; // approved for delivery\n isLocked: boolean; // workflow locked OR delivery locked\n}\n\nexport type StatusCallback = (status: 'unsaved' | 'saving' | 'saved' | 'error', message?: string) => void;\n\nexport class EditorAPI {\n private queue: QueuedTranslation[] = [];\n private apiBase: string;\n private sessionToken: string;\n private projectId: string;\n private flushInterval: ReturnType<typeof setInterval> | null = null;\n private renewalInterval: ReturnType<typeof setInterval> | null = null;\n private onStatus: StatusCallback = () => {};\n private onFlushed: (keys: string[]) => void = () => {};\n private onSessionExpired: (() => void) | null = null;\n\n constructor(apiBase: string, sessionToken: string, projectId: string) {\n this.apiBase = apiBase.replace(/\\/$/, '');\n this.sessionToken = sessionToken;\n this.projectId = projectId;\n }\n\n setStatusCallback(cb: StatusCallback): void {\n this.onStatus = cb;\n }\n\n setFlushedCallback(cb: (keys: string[]) => void): void {\n this.onFlushed = cb;\n }\n\n setSessionExpiredCallback(cb: () => void): void {\n this.onSessionExpired = cb;\n }\n\n /**\n * Start auto-flush (30s interval + visibilitychange) and session renewal (60s check)\n */\n startAutoFlush(): void {\n this.flushInterval = setInterval(() => this.flush(), 30_000);\n document.addEventListener('visibilitychange', this.handleVisibility);\n\n // Check session renewal every 60s\n this.renewalInterval = setInterval(() => this.maybeRenewSession(), 60_000);\n }\n\n /**\n * Stop auto-flush and flush remaining items\n */\n async stopAndFlush(): Promise<void> {\n if (this.flushInterval) {\n clearInterval(this.flushInterval);\n this.flushInterval = null;\n }\n if (this.renewalInterval) {\n clearInterval(this.renewalInterval);\n this.renewalInterval = null;\n }\n document.removeEventListener('visibilitychange', this.handleVisibility);\n await this.flush();\n }\n\n /**\n * Queue a translation for saving\n */\n queueSave(item: QueuedTranslation): void {\n // Replace existing entry for same key+locale\n const idx = this.queue.findIndex(\n (q) => q.key === item.key && q.locale === item.locale && q.namespace === item.namespace\n );\n if (idx >= 0) {\n this.queue[idx] = item;\n } else {\n this.queue.push(item);\n }\n this.onStatus('unsaved', `${this.queue.length} unsaved`);\n\n // Auto-flush if queue is large\n if (this.queue.length > 50) {\n this.flush();\n }\n }\n\n /**\n * Flush all queued translations to the server\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const items = [...this.queue];\n this.onStatus('saving');\n\n try {\n const response = await fetch(\n `${this.apiBase}/api/integrations/targets/batch`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sessionToken}`,\n },\n body: JSON.stringify({\n translations: items.map((t) => ({\n key: `${t.locale}:${t.namespace}:${t.key}`,\n value: { text: t.text, styles: t.styles },\n })),\n }),\n }\n );\n\n if (response.status === 401) {\n this.handleSessionExpired();\n return;\n }\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n // Remove flushed items from queue (new items may have been added during fetch)\n const flushedKeys = items.map((i) => i.key);\n for (const item of items) {\n const idx = this.queue.indexOf(item);\n if (idx >= 0) this.queue.splice(idx, 1);\n }\n\n // Notify sidebar to re-fetch status for flushed keys\n this.onFlushed(flushedKeys);\n\n if (this.queue.length === 0) {\n this.onStatus('saved', 'All changes saved');\n } else {\n this.onStatus('unsaved', `${this.queue.length} unsaved`);\n }\n } catch (err) {\n this.onStatus('error', `Save failed: ${(err as Error).message}`);\n }\n }\n\n private statusAbort: AbortController | null = null;\n\n /**\n * Fetch translation status for a batch of keys (includes unconfirmed rows).\n * Cancels any in-flight status request. Caps at 200 keys per request.\n */\n async fetchStatus(\n keys: string[],\n locale: string,\n namespace: string\n ): Promise<Record<string, TargetStatus | null>> {\n if (keys.length === 0) return {};\n\n // Cancel previous in-flight request\n if (this.statusAbort) this.statusAbort.abort();\n this.statusAbort = new AbortController();\n\n // Cap keys to avoid exceeding URL length limits\n const batch = keys.slice(0, 200);\n\n const params = new URLSearchParams({ locale, namespace, keys: batch.join(',') });\n try {\n const response = await fetch(\n `${this.apiBase}/api/integrations/targets/status?${params}`,\n {\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n signal: this.statusAbort.signal,\n }\n );\n if (response.status === 401) {\n this.handleSessionExpired();\n return {};\n }\n if (!response.ok) return {};\n const data = await response.json();\n return data.translations;\n } catch (err) {\n if ((err as Error).name === 'AbortError') return {};\n return {};\n }\n }\n\n get pendingCount(): number {\n return this.queue.length;\n }\n\n // ============================================\n // Session renewal\n // ============================================\n\n /**\n * Check if session is within 2min of expiry, and renew if so.\n */\n private async maybeRenewSession(): Promise<void> {\n const exp = this.getSessionExp();\n if (!exp) return;\n\n const timeLeft = exp * 1000 - Date.now();\n if (timeLeft > 120_000) return; // More than 2 min left, skip\n\n await this.renewSession();\n }\n\n private async renewSession(): Promise<void> {\n try {\n const response = await fetch(`${this.apiBase}/api/editor/renew`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.sessionToken}`,\n },\n });\n\n if (response.status === 401) {\n this.handleSessionExpired();\n return;\n }\n\n if (!response.ok) return;\n\n const data = await response.json();\n this.sessionToken = data.session_token;\n\n // Update sessionStorage\n try {\n const raw = this.sessionToken.startsWith('es_') ? this.sessionToken.slice(3) : this.sessionToken;\n const parts = raw.split('.');\n if (parts.length === 3) {\n const payload = JSON.parse(atob(parts[1]));\n sessionStorage.setItem('__lr_editor_session', JSON.stringify({\n token: this.sessionToken,\n exp: payload.exp || 0,\n }));\n }\n } catch { /* non-critical */ }\n } catch {\n // Network error \u2014 will retry on next interval\n }\n }\n\n private getSessionExp(): number | null {\n try {\n const raw = this.sessionToken.startsWith('es_') ? this.sessionToken.slice(3) : this.sessionToken;\n const parts = raw.split('.');\n if (parts.length !== 3) return null;\n const payload = JSON.parse(atob(parts[1]));\n return payload.exp || null;\n } catch {\n return null;\n }\n }\n\n private handleSessionExpired(): void {\n this.onStatus('error', 'Session expired. Please reopen the editor from the dashboard.');\n if (this.onSessionExpired) {\n this.onSessionExpired();\n }\n }\n\n private handleVisibility = (): void => {\n if (document.visibilityState === 'hidden') {\n this.flush();\n }\n };\n\n // ============================================\n // Snapshot API\n // ============================================\n\n /**\n * Upload a captured snapshot. Returns the created snapshot's UUID so the\n * caller can build a share URL (`?__lr_snapshot={uuid}`).\n */\n async createSnapshot(\n snapshot: CapturedSnapshot,\n ): Promise<{ snapshotUuid: string } | null> {\n try {\n const response = await fetch(`${this.apiBase}/api/editor/snapshots`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sessionToken}`,\n },\n body: JSON.stringify({\n pageUrl: snapshot.pageUrl,\n title: snapshot.title,\n viewport: snapshot.viewport,\n textEntries: snapshot.textEntries,\n html: snapshot.html,\n }),\n });\n\n if (response.status === 401) {\n this.handleSessionExpired();\n return null;\n }\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n const data = await response.json();\n return { snapshotUuid: data.snapshot_uuid || data.snapshotUuid };\n } catch (err) {\n this.onStatus('error', `Snapshot failed: ${(err as Error).message}`);\n return null;\n }\n }\n\n /**\n * Re-capture an existing snapshot. Server appends a new version and keeps\n * the same `snapshotUuid`. Returns the new version number on success.\n */\n async recaptureSnapshot(\n snapshotUuid: string,\n snapshot: CapturedSnapshot,\n ): Promise<{ snapshotUuid: string; version: number } | null> {\n try {\n const response = await fetch(\n `${this.apiBase}/api/editor/snapshots/${encodeURIComponent(snapshotUuid)}`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sessionToken}`,\n },\n body: JSON.stringify({\n pageUrl: snapshot.pageUrl,\n title: snapshot.title,\n viewport: snapshot.viewport,\n textEntries: snapshot.textEntries,\n html: snapshot.html,\n }),\n },\n );\n\n if (response.status === 401) {\n this.handleSessionExpired();\n return null;\n }\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n const data = await response.json();\n return {\n snapshotUuid: data.snapshot_uuid || data.snapshotUuid,\n version: data.version || 1,\n };\n } catch (err) {\n this.onStatus('error', `Re-capture failed: ${(err as Error).message}`);\n return null;\n }\n }\n\n /**\n * Fetch a single snapshot by UUID. Returns null on auth failure or 404.\n */\n async getSnapshot(snapshotUuid: string): Promise<SnapshotDetail | null> {\n try {\n const response = await fetch(\n `${this.apiBase}/api/editor/snapshots/${encodeURIComponent(snapshotUuid)}`,\n {\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n },\n );\n if (response.status === 401) {\n this.handleSessionExpired();\n return null;\n }\n if (!response.ok) return null;\n return (await response.json()) as SnapshotDetail;\n } catch {\n return null;\n }\n }\n\n /**\n * List all snapshots the current editor session can see.\n */\n async listSnapshots(): Promise<SnapshotListItem[]> {\n try {\n const response = await fetch(`${this.apiBase}/api/editor/snapshots`, {\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n });\n if (response.status === 401) {\n this.handleSessionExpired();\n return [];\n }\n if (!response.ok) return [];\n const data = await response.json();\n return data.snapshots || [];\n } catch {\n return [];\n }\n }\n\n /**\n * Delete (soft) a snapshot by UUID.\n */\n async deleteSnapshot(snapshotUuid: string): Promise<boolean> {\n try {\n const response = await fetch(\n `${this.apiBase}/api/editor/snapshots/${encodeURIComponent(snapshotUuid)}`,\n {\n method: 'DELETE',\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n },\n );\n if (response.status === 401) {\n this.handleSessionExpired();\n return false;\n }\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Workflow transitions (Phase 3). Per-key endpoints on the integrations API\n * that mirror the dashboard's row-level transitions but are addressable by\n * composite editor key (locale:namespace:auto_xxx).\n *\n * Returns the parsed JSON on success, or null on failure (caller usually\n * shows a toast / re-fetches status).\n */\n async transitionTarget(\n composite: string,\n action: 'confirm' | 'unconfirm' | 'reject' | 'mark-ready' | 'unmark-ready',\n ): Promise<Record<string, unknown> | null> {\n try {\n const response = await fetch(\n `${this.apiBase}/api/integrations/targets/${encodeURIComponent(composite)}/${action}`,\n {\n method: 'POST',\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n },\n );\n if (response.status === 401) {\n this.handleSessionExpired();\n return null;\n }\n if (!response.ok) {\n this.onStatus('error', `${action} failed: HTTP ${response.status}`);\n return null;\n }\n return (await response.json()) as Record<string, unknown>;\n } catch (err) {\n this.onStatus('error', `${action} failed: ${(err as Error).message}`);\n return null;\n }\n }\n}\n", "/**\n * PII Redactor \u2014 fine-grained inline replacement of PII patterns in text.\n *\n * Phase 4 of the snapshot feature. Phase 1 redacts whole text nodes only;\n * this module replaces matches *inline*, preserving surrounding prose:\n * \"Contact us at foo@bar.com for help\" \u2192 \"Contact us at [REDACTED] for help\"\n *\n * Two entry points:\n * - `redactString(text)` \u2014 pure string-in/string-out, used in tests and\n * callable independently if a non-DOM caller ever needs it.\n * - `redactTextNodes(root)` \u2014 walks every text node under `root` and\n * replaces PII inline, skipping subtrees marked with `data-no-redact`,\n * and skipping `<code>` / `<pre>` (legitimate examples).\n *\n * Design notes:\n * - Patterns are tuned to avoid common false positives. SSN requires\n * dashes/spaces (so 9-digit order numbers survive); credit cards must\n * pass a Luhn check (so 16-digit tracking IDs survive); IPs reject any\n * octet > 255 (so version strings like 1.2.3.999 survive).\n * - We bias toward under-redaction in ambiguous cases \u2014 better to leak\n * a tracking number than corrupt a customer's real prose.\n */\n\nconst REDACTED = '[REDACTED]';\n\n// ----- Regex catalog ---------------------------------------------------------\n//\n// Every pattern uses the `g` flag so .replace() can hit multiple matches in\n// one string. Anchors (`\\b` or surrounding-char checks) are tuned per pattern.\n\n// Email: standard local@domain.tld, fairly permissive on the local part.\nconst EMAIL_RE =\n /[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}/gi;\n\n// US/intl phone: optional `+1 ` prefix, optional parens around area code,\n// 3-3-4 digit groups separated by space/dash/dot. Requires at least one\n// separator so bare 10-digit numbers don't match (those are usually IDs).\nconst PHONE_RE =\n /(?:\\+\\d{1,3}[\\s.-]?)?(?:\\(\\d{3}\\)|\\d{3})[\\s.-]\\d{3}[\\s.-]\\d{4}/g;\n\n// SSN: XXX-XX-XXXX, dashes or spaces (NOT bare 9 digits \u2014 too many false\n// positives on order numbers, IDs, etc.).\nconst SSN_RE = /\\b\\d{3}[\\s-]\\d{2}[\\s-]\\d{4}\\b/g;\n\n// IPv4: four 1-3 digit octets, dot-separated. We post-filter for \"all\n// octets <= 255\" so version strings like 1.2.3.999 don't match.\nconst IPV4_RE = /\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/g;\n\n// URL: http(s):// or www. then non-whitespace. Greedy through path/query.\nconst URL_RE = /\\b(?:https?:\\/\\/|www\\.)[^\\s<>\"']+/gi;\n\n// Credit card candidate: 13-19 digits in 4-4-4-4 (or contiguous) format,\n// allowing dashes/spaces between groups. Luhn-checked before redacting.\n// Must end on a digit (not a separator) \u2014 prevents greedy matching of\n// trailing whitespace.\nconst CC_CANDIDATE_RE = /\\b\\d(?:[ -]?\\d){12,18}\\b/g;\n\n// ----- Luhn check ------------------------------------------------------------\n\nfunction luhnValid(digits: string): boolean {\n // digits already stripped of separators by caller\n if (digits.length < 13 || digits.length > 19) return false;\n let sum = 0;\n let alt = false;\n for (let i = digits.length - 1; i >= 0; i--) {\n let n = digits.charCodeAt(i) - 48; // '0' = 48\n if (n < 0 || n > 9) return false;\n if (alt) {\n n *= 2;\n if (n > 9) n -= 9;\n }\n sum += n;\n alt = !alt;\n }\n return sum % 10 === 0;\n}\n\n// ----- IPv4 octet bounds check ----------------------------------------------\n\nfunction ipv4Valid(match: string): boolean {\n const parts = match.split('.');\n if (parts.length !== 4) return false;\n for (const p of parts) {\n const n = Number(p);\n if (!Number.isInteger(n) || n < 0 || n > 255) return false;\n }\n return true;\n}\n\n// ----- Public: string redactor ----------------------------------------------\n\n/**\n * Replace every PII match in `text` with `[REDACTED]`. Surrounding prose\n * is preserved.\n *\n * Order matters: URLs first (so `http://...` doesn't get mangled by IPv4\n * matching), then emails, then more specific numeric patterns.\n */\nexport function redactString(text: string): string {\n if (!text) return text;\n let out = text;\n\n out = out.replace(URL_RE, REDACTED);\n out = out.replace(EMAIL_RE, REDACTED);\n out = out.replace(PHONE_RE, REDACTED);\n out = out.replace(SSN_RE, REDACTED);\n out = out.replace(IPV4_RE, (m) => (ipv4Valid(m) ? REDACTED : m));\n out = out.replace(CC_CANDIDATE_RE, (m) => {\n const digits = m.replace(/[\\s-]/g, '');\n return luhnValid(digits) ? REDACTED : m;\n });\n\n return out;\n}\n\n// ----- Public: DOM walker ---------------------------------------------------\n\n/**\n * Tag names whose text we never touch \u2014 code samples, preformatted blocks,\n * and `<style>` content. `<script>` is already removed earlier in the\n * snapshot pipeline, so it's not in this list.\n */\nconst SKIP_TAGS = new Set(['CODE', 'PRE', 'STYLE', 'TEXTAREA']);\n\n/**\n * Walks every text node under `root` and redacts PII inline. Skips:\n * - text nodes inside any ancestor with `[data-no-redact]`\n * - text nodes inside `<code>`, `<pre>`, `<style>`, `<textarea>`\n *\n * Mutates the DOM in place.\n */\nexport function redactTextNodes(root: Element): void {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n // Collect first, mutate after \u2014 walker behaviour with mutation is\n // implementation-defined.\n const toUpdate: { node: Text; value: string }[] = [];\n\n let node = walker.nextNode() as Text | null;\n while (node) {\n if (!isInSkippedSubtree(node)) {\n const original = node.nodeValue || '';\n const replaced = redactString(original);\n if (replaced !== original) {\n toUpdate.push({ node, value: replaced });\n }\n }\n node = walker.nextNode() as Text | null;\n }\n\n for (const { node: textNode, value } of toUpdate) {\n textNode.nodeValue = value;\n }\n}\n\nfunction isInSkippedSubtree(node: Node): boolean {\n let cur: Node | null = node.parentNode;\n while (cur && cur.nodeType === Node.ELEMENT_NODE) {\n const el = cur as Element;\n if (SKIP_TAGS.has(el.tagName)) return true;\n if (el.hasAttribute('data-no-redact')) return true;\n cur = el.parentNode;\n }\n return false;\n}\n", "/**\n * Snapshot Capture \u2014 Serializes the live DOM with PII redaction.\n *\n * Used by the visual editor to let an authenticated admin capture an auth page\n * so a translator (without credentials) can later translate it against a\n * frozen copy. The serialized HTML is uploaded to the server and retrieved in\n * viewer mode (?__lr_snapshot={uuid}) where Inspector + Sidebar boot against\n * the snapshot root instead of document.body.\n *\n * Redaction strategy:\n * - Remove: <script>, <noscript>, <iframe>, <embed>, <object>, editor host\n * - Clear all form <input>, <textarea>, <select> values\n * - Replace [data-pii] / [data-sensitive] text with [REDACTED]\n * - Strip all inline event handlers (onclick, onmouseover, etc.)\n * - Inline PII redaction in text nodes (email / phone / URL / SSN /\n * credit card / IPv4) \u2014 see pii-redactor.ts. `[data-no-redact]`\n * subtrees, `<code>`, and `<pre>` are skipped.\n * - Strip CSRF/CSP meta tags and auth tokens from link/script URLs\n */\n\nimport { BlockExtractor } from '../block-extractor.js';\nimport { redactTextNodes } from './pii-redactor.js';\n\nconst REDACTED = '[REDACTED]';\n\nexport interface SnapshotTextEntry {\n /** auto_xxxxxxxxxxxx \u2014 12-char md5 hash, generated BEFORE redaction so it matches the live page */\n key: string;\n /** The source tag name (P, H1, LI, etc.) \u2014 useful for future analytics */\n tagName: string;\n /** Index of this block among all block elements in the snapshot DOM. Used by\n * the viewer to map a clicked element back to its pre-computed key without\n * re-running BlockExtractor on the redacted text. */\n blockIndex: number;\n}\n\nexport interface SnapshotViewport {\n width: number;\n height: number;\n devicePixelRatio: number;\n}\n\nexport interface CapturedSnapshot {\n html: string;\n textEntries: SnapshotTextEntry[];\n pageUrl: string;\n title: string;\n viewport: SnapshotViewport;\n}\n\n/**\n * Capture the current page as a redacted snapshot.\n *\n * Pure function \u2014 does NOT mutate the live DOM. Clones first, then:\n * 1. Extracts block keys BEFORE redaction (so auto_keys match the live page)\n * 2. Redacts the clone (strips PII, scripts, forms, etc.)\n * 3. Stamps each block element with a data-lr-snap-idx attribute so the\n * viewer can map a click back to the pre-computed key\n * 4. Serializes to HTML\n *\n * The textEntries carry pre-computed keys (no source text) and the HTML is\n * safe to store. The viewer uses textEntries to look up the correct key by\n * index when the translator clicks a block.\n */\nexport function captureSnapshot(): CapturedSnapshot {\n // 1. Clone the entire document element.\n const clone = document.documentElement.cloneNode(true) as HTMLElement;\n\n // 2. Extract blocks BEFORE redaction so keys match the live page.\n // The real text is used for md5 hashing, producing the same auto_keys\n // the edge proxy / auto-init generates on the live page.\n const textEntries = extractTextEntries(clone);\n\n // 3. Stamp each extracted block with a data attribute linking it to its\n // entry index. The viewer uses this to resolve clicks to pre-computed\n // keys without re-running BlockExtractor on the redacted text.\n // (extractTextEntries stores the element reference so we can stamp it)\n\n // 4. Redact the clone. Order: remove dangerous elements first so we don't\n // waste time walking their subtrees.\n removeDangerousElements(clone);\n clearFormValues(clone);\n redactSensitiveElements(clone);\n stripInlineEventHandlers(clone);\n redactTextNodePII(clone);\n stripSensitiveMetaAndHeaders(clone);\n\n // 5. Serialize.\n const html = '<!DOCTYPE html>\\n' + clone.outerHTML;\n\n return {\n html,\n textEntries,\n pageUrl: window.location.href,\n title: document.title,\n viewport: {\n width: window.innerWidth,\n height: window.innerHeight,\n devicePixelRatio: window.devicePixelRatio || 1,\n },\n };\n}\n\n/**\n * Remove elements that should never appear in a snapshot:\n * - <script>, <noscript>: could re-execute or leak source\n * - <iframe>, <embed>, <object>: third-party content, likely auth-bound\n * - #__lionrapid-editor: the editor's own shadow host\n * - <link rel=\"prefetch\"> / <link rel=\"preload\"> that may leak auth URLs\n */\nfunction removeDangerousElements(root: HTMLElement): void {\n const selectors = [\n 'script',\n 'noscript',\n 'iframe',\n 'embed',\n 'object',\n '#__lionrapid-editor',\n 'link[rel=\"prefetch\"]',\n 'link[rel=\"preload\"]',\n 'link[rel=\"modulepreload\"]',\n ];\n for (const selector of selectors) {\n const matches = root.querySelectorAll(selector);\n for (let i = 0; i < matches.length; i++) {\n matches[i].remove();\n }\n }\n}\n\n/**\n * Clear all form field values so no user input leaks.\n * This covers <input> (all types), <textarea>, and <select>.\n */\nfunction clearFormValues(root: HTMLElement): void {\n const inputs = root.querySelectorAll('input, textarea, select');\n for (let i = 0; i < inputs.length; i++) {\n const el = inputs[i] as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n\n // Clear live value\n if ('value' in el) el.value = '';\n\n // Clear the serialized attribute \u2014 cloneNode copies the attribute,\n // not the .value property, so we need to touch both.\n if (el.hasAttribute('value')) el.setAttribute('value', '');\n\n // <textarea> content lives in text children, not an attribute\n if (el.tagName === 'TEXTAREA') el.textContent = '';\n\n // Clear option selection on <select>\n if (el.tagName === 'SELECT') {\n const options = el.querySelectorAll('option');\n for (let j = 0; j < options.length; j++) {\n (options[j] as HTMLOptionElement).selected = false;\n options[j].removeAttribute('selected');\n }\n }\n\n // Remove data-* attributes that often hold state\n const attrs = Array.from(el.attributes);\n for (const attr of attrs) {\n if (attr.name.startsWith('data-value') || attr.name === 'data-initial') {\n el.removeAttribute(attr.name);\n }\n }\n }\n}\n\n/**\n * Replace the text content of elements flagged as sensitive with [REDACTED].\n * Preserves the element itself so layout stays intact.\n */\nfunction redactSensitiveElements(root: HTMLElement): void {\n const sensitive = root.querySelectorAll('[data-pii], [data-sensitive]');\n for (let i = 0; i < sensitive.length; i++) {\n const el = sensitive[i] as HTMLElement;\n el.textContent = REDACTED;\n // Strip all attributes except structural ones so classes/ids still position it.\n const attrs = Array.from(el.attributes);\n for (const attr of attrs) {\n if (attr.name !== 'class' && attr.name !== 'id' && attr.name !== 'style') {\n el.removeAttribute(attr.name);\n }\n }\n }\n}\n\n/**\n * Walk every element and strip any attribute that starts with 'on' (onclick,\n * onmouseover, onload, etc.). These could re-execute in the viewer.\n */\nfunction stripInlineEventHandlers(root: HTMLElement): void {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n let node = walker.nextNode() as HTMLElement | null;\n while (node) {\n const attrs = Array.from(node.attributes);\n for (const attr of attrs) {\n if (attr.name.toLowerCase().startsWith('on')) {\n node.removeAttribute(attr.name);\n }\n }\n node = walker.nextNode() as HTMLElement | null;\n }\n}\n\n/**\n * Walk text nodes and replace PII matches inline. Phase 4: matches are\n * replaced where they appear (\"Contact foo@bar.com today\" \u2192\n * \"Contact [REDACTED] today\") instead of redacting the whole text node.\n * See pii-redactor.ts for pattern details and the data-no-redact escape\n * hatch.\n */\nfunction redactTextNodePII(root: HTMLElement): void {\n redactTextNodes(root);\n}\n\n/**\n * Strip meta tags and link/script URLs that commonly carry auth material.\n */\nfunction stripSensitiveMetaAndHeaders(root: HTMLElement): void {\n // CSRF / CSP nonces\n const sensitiveMetas = root.querySelectorAll(\n 'meta[name=\"csrf-token\"], meta[name=\"csp-nonce\"], meta[name=\"csrf-param\"], meta[http-equiv=\"set-cookie\"]',\n );\n for (let i = 0; i < sensitiveMetas.length; i++) {\n sensitiveMetas[i].remove();\n }\n\n // Strip token-bearing query params from <link> and <a href> URLs\n const TOKEN_PARAMS = ['token', 'auth', 'access_token', 'session', 'sid', 'key', 'api_key', 'apikey'];\n const urlElements = root.querySelectorAll('link[href], a[href], img[src]');\n for (let i = 0; i < urlElements.length; i++) {\n const el = urlElements[i] as HTMLLinkElement | HTMLAnchorElement | HTMLImageElement;\n const attr = el.tagName === 'IMG' ? 'src' : 'href';\n const raw = el.getAttribute(attr);\n if (!raw) continue;\n try {\n const url = new URL(raw, window.location.href);\n let changed = false;\n for (const param of TOKEN_PARAMS) {\n if (url.searchParams.has(param)) {\n url.searchParams.set(param, REDACTED);\n changed = true;\n }\n }\n if (changed) el.setAttribute(attr, url.toString());\n } catch {\n // Not a parseable URL (mailto:, tel:, javascript:, etc.) \u2014 skip\n }\n }\n}\n\n/**\n * Run BlockExtractor on the clone BEFORE redaction to produce text entries\n * with content-hash keys that match the live page. Each extracted block\n * element is stamped with `data-lr-snap-idx` so the viewer can map a click\n * back to the pre-computed key without re-running BlockExtractor on the\n * (now redacted) text.\n *\n * No source text is included in the returned entries \u2014 only the key, tag\n * name, and block index \u2014 so the entries are safe to store even though\n * extraction happened before redaction.\n */\nfunction extractTextEntries(clone: HTMLElement): SnapshotTextEntry[] {\n const extractor = new BlockExtractor(\n { emails: true, urls: true, numbers: true, phones: true },\n [],\n 2,\n );\n const blocks = extractor.extract(clone);\n\n return blocks.map((block, index) => {\n // Stamp the element so the viewer can resolve clicks by data attribute\n block.element.setAttribute('data-lr-snap-idx', String(index));\n\n return {\n key: block.key,\n tagName: block.element.tagName,\n blockIndex: index,\n };\n });\n}\n", "/**\n * Snapshot Viewer \u2014 Renders a saved snapshot in the current page so the\n * Inspector + Sidebar can be pointed at it for translation.\n *\n * When the editor loads with `?__lr_snapshot={uuid}`, the normal page is\n * replaced with the snapshot HTML inside a sandbox wrapper:\n *\n * <div id=\"__lr_snapshot_root\"> \u2190 scoped root passed to Inspector\n * <html>...snapshot...</html>\n * </div>\n *\n * Auto-init retranslation is NOT re-run against the snapshot \u2014 translations\n * saved via the sidebar flow through the normal batch endpoint and will\n * appear on the real auth page on next load.\n */\n\nimport type { EditorAPI } from './editor-api.js';\nimport type { SnapshotTextEntry } from './snapshot-capture.js';\n\nexport interface SnapshotViewerResult {\n /** Scope root to pass to Inspector */\n root: HTMLElement;\n /** Snapshot metadata for display in the toolbar / sidebar */\n pageUrl: string;\n title: string;\n /** Pre-computed key map: blockIndex \u2192 key. The Inspector uses this to resolve\n * clicks without re-running BlockExtractor on the redacted HTML. */\n keyMap: Map<number, string>;\n}\n\n/**\n * Fetch a snapshot from the server and mount it into the current page.\n * Returns the root element Inspector should scope against.\n *\n * On failure (404, network error, deleted snapshot) returns null and displays\n * a user-visible notice via the caller's notice helper.\n */\nexport async function activateSnapshotViewer(\n snapshotUuid: string,\n api: EditorAPI,\n): Promise<SnapshotViewerResult | null> {\n const snapshot = await api.getSnapshot(snapshotUuid);\n if (!snapshot) return null;\n\n // Replace the entire body with a sandbox wrapper holding the snapshot HTML.\n // We keep document.head alone so the editor's Shadow DOM host and existing\n // stylesheets (for rendering) still work.\n //\n // The snapshot HTML is a full document (starts with <!DOCTYPE>), so we\n // parse it with DOMParser and extract the <body> children. The snapshot's\n // <head> <link> and <style> tags are appended to the real head so the\n // snapshot renders with its original styles.\n const parser = new DOMParser();\n const doc = parser.parseFromString(snapshot.html, 'text/html');\n\n // Copy over stylesheets and inline <style> tags from the snapshot head.\n // We prefix them with a data attribute so the cleanup code can remove them\n // if the viewer is ever unmounted (out of scope for Phase 1).\n const snapshotStyles = doc.head.querySelectorAll('link[rel=\"stylesheet\"], style');\n for (let i = 0; i < snapshotStyles.length; i++) {\n const clone = snapshotStyles[i].cloneNode(true) as HTMLElement;\n clone.setAttribute('data-lr-snapshot-style', '');\n document.head.appendChild(clone);\n }\n\n // Copy <title> so the tab title reflects the captured page\n if (snapshot.title) {\n document.title = `[Snapshot] ${snapshot.title}`;\n }\n\n // Clear the current body content (but preserve the editor's shadow host\n // if it's already mounted \u2014 it's attached to #__lionrapid-editor).\n const editorHost = document.getElementById('__lionrapid-editor');\n while (document.body.firstChild) {\n if (document.body.firstChild === editorHost) {\n // Skip past the editor host without removing it\n const next = document.body.firstChild.nextSibling;\n if (!next) break;\n document.body.removeChild(next);\n } else {\n document.body.removeChild(document.body.firstChild);\n }\n }\n\n // Build sandbox wrapper and inject snapshot body\n const root = document.createElement('div');\n root.id = '__lr_snapshot_root';\n root.setAttribute('data-lr-snapshot-uuid', snapshotUuid);\n root.innerHTML = doc.body.innerHTML;\n\n // Insert wrapper before the editor host so the editor stays on top\n if (editorHost && editorHost.parentNode === document.body) {\n document.body.insertBefore(root, editorHost);\n } else {\n document.body.appendChild(root);\n }\n\n // Build key map from textEntries: blockIndex \u2192 auto_key\n const keyMap = new Map<number, string>();\n const entries: SnapshotTextEntry[] = snapshot.textEntries || [];\n for (const entry of entries) {\n keyMap.set(entry.blockIndex, entry.key);\n }\n\n return {\n root,\n pageUrl: snapshot.pageUrl,\n title: snapshot.title,\n keyMap,\n };\n}\n", "/**\n * Visual Translation Editor \u2014 Entry Point\n * Self-executing IIFE bundle loaded by edge proxy or auto-init when ?__lr_editor is detected.\n *\n * Reads script tag attributes, polls for window.LionRapid, creates Shadow DOM,\n * and instantiates Inspector, Sidebar, and Toolbar.\n *\n * Auth flow: grant token \u2192 exchange for scoped session JWT \u2192 use JWT for API calls.\n */\n\nimport { EDITOR_CSS } from './editor-styles.js';\nimport { Inspector } from './inspector.js';\nimport { Toolbar } from './toolbar.js';\nimport { Sidebar } from './sidebar.js';\nimport { EditorAPI } from './editor-api.js';\nimport type { ResolvedKey } from './key-resolver.js';\nimport { captureSnapshot } from './snapshot-capture.js';\nimport { activateSnapshotViewer } from './snapshot-viewer.js';\n\n// ============================================\n// Session helpers\n// ============================================\n\nconst SESSION_KEY = '__lr_editor_session';\n\ninterface StoredSession {\n token: string;\n exp: number;\n}\n\nfunction getStoredSession(): string | null {\n try {\n const raw = sessionStorage.getItem(SESSION_KEY);\n if (!raw) return null;\n const parsed: StoredSession = JSON.parse(raw);\n // Check if expired (with 30s buffer)\n if (parsed.exp * 1000 < Date.now() + 30_000) {\n sessionStorage.removeItem(SESSION_KEY);\n return null;\n }\n return parsed.token;\n } catch {\n return null;\n }\n}\n\nfunction storeSession(token: string): void {\n try {\n // Parse exp from JWT payload (es_<header>.<payload>.<sig>)\n const raw = token.startsWith('es_') ? token.slice(3) : token;\n const parts = raw.split('.');\n if (parts.length !== 3) return;\n const payload = JSON.parse(atob(parts[1]));\n const session: StoredSession = { token, exp: payload.exp || 0 };\n sessionStorage.setItem(SESSION_KEY, JSON.stringify(session));\n } catch {\n // Non-critical \u2014 session just won't persist across navigations\n }\n}\n\nfunction clearSession(): void {\n sessionStorage.removeItem(SESSION_KEY);\n}\n\n/**\n * Decode the role claim from a signed editor session JWT.\n * Used for client-side UI gating (show/hide Capture button etc.) \u2014 the\n * server enforces the same check on every protected endpoint.\n */\nfunction extractSessionRole(token: string): string {\n try {\n const raw = token.startsWith('es_') ? token.slice(3) : token;\n const parts = raw.split('.');\n if (parts.length !== 3) return '';\n const payload = JSON.parse(atob(parts[1]));\n return typeof payload.role === 'string' ? payload.role : '';\n } catch {\n return '';\n }\n}\n\n// ============================================\n// User-visible notice (shown when editor can't activate)\n// ============================================\n\nfunction showEditorNotice(message: string): void {\n const el = document.createElement('div');\n el.setAttribute('data-no-translate', '');\n Object.assign(el.style, {\n position: 'fixed', bottom: '24px', right: '24px', zIndex: '2147483647',\n background: '#1a1a2e', color: '#fff', padding: '16px 20px',\n borderRadius: '8px', fontFamily: 'system-ui, sans-serif', fontSize: '14px',\n maxWidth: '360px', boxShadow: '0 4px 20px rgba(0,0,0,0.3)',\n });\n el.textContent = message;\n const close = document.createElement('button');\n Object.assign(close.style, {\n position: 'absolute', top: '4px', right: '8px',\n background: 'none', border: 'none', color: '#888', cursor: 'pointer', fontSize: '16px',\n });\n close.textContent = '\\u00d7';\n close.addEventListener('click', () => el.remove());\n el.appendChild(close);\n document.body.appendChild(el);\n setTimeout(() => el.remove(), 8000);\n}\n\n// ============================================\n// Init\n// ============================================\n\nfunction initEditor(): void {\n // Support two activation modes:\n // 1. Grant mode \u2014 script tag has data-grant (first-page activation)\n // 2. Session mode \u2014 no grant, but a valid session exists in sessionStorage\n // (subsequent page navigation after grant was consumed)\n //\n // The edge proxy injects the editor script on every page when editor.enabled\n // is true. On pages where there's no active session, the editor silently\n // exits \u2014 no FAB, no network calls.\n const scriptEl =\n (document.querySelector('script[data-grant]') as HTMLScriptElement | null) ||\n (document.querySelector('script[data-lr-editor]') as HTMLScriptElement | null);\n\n if (!scriptEl) {\n // No editor script tag at all \u2014 nothing to do\n return;\n }\n\n const grant = scriptEl.dataset.grant || '';\n const hasValidSession = getStoredSession() !== null;\n\n // Session mode requires an existing stored session; grant mode requires a grant\n if (!grant && !hasValidSession) {\n // No grant and no session \u2014 silently exit (normal visitor, not an editor user)\n return;\n }\n\n const locale = scriptEl.dataset.locale || '';\n const apiBase = scriptEl.dataset.api || 'https://api.lionrapid.com';\n const projectId = scriptEl.dataset.project || '';\n\n // Poll for window.LionRapid (auto-init loads first)\n let attempts = 0;\n const maxAttempts = 100; // 10s at 100ms intervals\n\n const poll = setInterval(() => {\n attempts++;\n const lr = window.LionRapid;\n\n if (lr) {\n clearInterval(poll);\n activate(lr, grant, locale, apiBase, projectId);\n } else if (attempts >= maxAttempts) {\n clearInterval(poll);\n console.warn('[LionRapid Editor] Timed out waiting for window.LionRapid');\n }\n }, 100);\n}\n\nasync function activate(\n lr: NonNullable<typeof window.LionRapid>,\n grant: string,\n locale: string,\n apiBase: string,\n projectId: string,\n): Promise<void> {\n const config = window.__lionrapidConfig;\n const languages = config?.languages || [locale];\n const namespace = config?.namespace || 'default';\n const defaultLocale = config?.defaultLocale || 'en';\n const currentLocale = locale || lr.getCurrentLocale();\n const normalizedApiBase = apiBase.replace(/\\/$/, '');\n\n // --- Session acquisition ---\n let sessionToken = getStoredSession();\n\n if (!sessionToken && grant) {\n // Exchange grant for session JWT\n try {\n const res = await fetch(`${normalizedApiBase}/api/editor/exchange`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ grant, domain: window.location.host }),\n });\n if (!res.ok) {\n console.error('[LionRapid Editor] Grant exchange failed:', res.status);\n showEditorNotice('Editor session expired. Please reopen the editor from the dashboard.');\n return;\n }\n const data = await res.json();\n sessionToken = data.session_token;\n if (sessionToken) {\n storeSession(sessionToken);\n }\n } catch (err) {\n console.error('[LionRapid Editor] Grant exchange error:', err);\n showEditorNotice('Could not connect to LionRapid. Please check your connection and try again.');\n return;\n }\n }\n\n if (!sessionToken) {\n console.error('[LionRapid Editor] No valid session. Please reopen the editor from the dashboard.');\n showEditorNotice('Editor session expired. Please reopen the editor from the dashboard.');\n return;\n }\n\n // Decode the session JWT to extract the user's role. The server signs this\n // token and enforces permissions \u2014 the client-side check here is only to\n // avoid showing actions the server would reject (defense in depth). Never\n // trust client-side role checks for security decisions.\n const role = extractSessionRole(sessionToken);\n const canCaptureSnapshots = role === 'project_manager' || role === 'admin';\n\n // Create Shadow DOM host\n const host = document.createElement('div');\n host.id = '__lionrapid-editor';\n host.setAttribute('data-no-translate', '');\n document.body.appendChild(host);\n const shadow = host.attachShadow({ mode: 'closed' });\n\n // Inject styles\n const styleEl = document.createElement('style');\n styleEl.textContent = EDITOR_CSS;\n shadow.appendChild(styleEl);\n\n // Hide the proxy/auto-init language switcher while editor is active\n const switcherEl = document.querySelector('[data-lionrapid-switcher]') as HTMLElement | null;\n if (switcherEl) switcherEl.style.display = 'none';\n\n // Create API client with session token\n const api = new EditorAPI(normalizedApiBase, sessionToken, projectId);\n api.startAutoFlush();\n\n // --- Snapshot viewer mode ---\n // If the URL has ?__lr_snapshot={uuid}, replace the page with the saved\n // snapshot HTML and scope the Inspector to the sandbox wrapper. Capture\n // button is hidden in viewer mode (a translator shouldn't re-capture).\n //\n // Separately, ?__lr_recapture={uuid} runs on the LIVE page (no viewer)\n // but switches the FAB's Capture button into re-capture mode \u2014 PUT to the\n // existing snapshot uuid instead of POST.\n const currentUrl = new URL(window.location.href);\n const snapshotUuid = currentUrl.searchParams.get('__lr_snapshot');\n const recaptureUuid = currentUrl.searchParams.get('__lr_recapture');\n let inspectorRoot: Element | undefined;\n let snapshotKeyMap: Map<number, string> | undefined;\n if (snapshotUuid) {\n const result = await activateSnapshotViewer(snapshotUuid, api);\n if (!result) {\n showEditorNotice('Snapshot not found or expired. Please check the dashboard.');\n return;\n }\n inspectorRoot = result.root;\n snapshotKeyMap = result.keyMap;\n }\n\n // Create sidebar (needs api + locale)\n const handleBlockSelect = (resolved: ResolvedKey) => {\n sidebar.open(resolved);\n inspector.clearHighlight();\n };\n\n const sidebar = new Sidebar(shadow, api, currentLocale, namespace, defaultLocale, handleBlockSelect, role);\n\n // Create inspector (hover/click \u2192 sidebar)\n const inspector = new Inspector(shadow, handleBlockSelect, inspectorRoot, snapshotKeyMap);\n\n // Create toolbar\n const toolbar = new Toolbar(\n shadow,\n languages,\n currentLocale,\n // Language change\n async (newLocale) => {\n // Edge proxy context: navigate to locale URL instead of client-side translation\n const isEdgeProxy = document.querySelector('script[data-mode=\"dynamic-only\"]') !== null;\n if (isEdgeProxy) {\n const url = new URL(window.location.href);\n // Strip existing locale prefix if present\n const stripped = url.pathname.replace(/^\\/[a-z]{2}(\\/|$)/, '/');\n // Build new URL: /es/path?__lr_editor=grant\n const prefix = newLocale === defaultLocale ? '' : `/${newLocale}`;\n url.pathname = prefix + (stripped === '/' && prefix ? '' : stripped);\n url.searchParams.set('__lr_editor', grant);\n window.location.href = url.toString();\n return;\n }\n sidebar.updateLocale(newLocale);\n sidebar.close();\n inspector.clearHighlight();\n await lr.changeLanguage(newLocale);\n await sidebar.hydrateStatus();\n },\n // Exit\n async () => {\n await api.stopAndFlush();\n inspector.destroy();\n toolbar.destroy();\n sidebar.destroy();\n host.remove();\n clearSession();\n },\n // Capture Snapshot \u2014 only available in live-page mode (not viewer) AND\n // only for PM/admin roles. Translators and proofreaders cannot capture;\n // the server enforces the same check on POST /api/editor/snapshots.\n //\n // If ?__lr_recapture={uuid} is present, the same button re-captures that\n // existing snapshot (PUT) instead of creating a new one (POST).\n snapshotUuid || !canCaptureSnapshots\n ? null\n : async () => {\n try {\n const snapshot = captureSnapshot();\n if (recaptureUuid) {\n const result = await api.recaptureSnapshot(recaptureUuid, snapshot);\n if (result) {\n showEditorNotice(\n `Re-captured as v${result.version} (${snapshot.textEntries.length} blocks). You can close this tab.`,\n );\n } else {\n showEditorNotice('Re-capture failed. Please try again.');\n }\n } else {\n const result = await api.createSnapshot(snapshot);\n if (result) {\n showEditorNotice(\n `Snapshot captured (${snapshot.textEntries.length} blocks). Open it from the Snapshots tab in the dashboard.`,\n );\n } else {\n showEditorNotice('Snapshot upload failed. Please try again.');\n }\n }\n } catch (err) {\n console.error('[LionRapid Editor] Snapshot capture error:', err);\n showEditorNotice('Snapshot capture failed. See console for details.');\n }\n },\n // When in recapture mode, surface it to the toolbar so the button label\n // can change from \"Capture\" to \"Save re-capture\".\n recaptureUuid ? { mode: 'recapture' } : undefined,\n );\n\n // Wire progress counter to sidebar status\n sidebar.setProgressCallback((translated, total) => {\n toolbar.updateProgress(translated, total);\n });\n\n // Hydrate status from server and update progress\n sidebar.hydrateStatus().then(() => {\n toolbar.updateProgress(sidebar.getTranslatedCount(), sidebar.getTotalCount());\n });\n\n // Clean editor params from URL\n const url = new URL(window.location.href);\n let dirty = false;\n if (url.searchParams.has('__lr_editor')) {\n url.searchParams.delete('__lr_editor');\n dirty = true;\n }\n if (url.searchParams.has('__lr_snapshot')) {\n url.searchParams.delete('__lr_snapshot');\n dirty = true;\n }\n if (url.searchParams.has('__lr_recapture')) {\n url.searchParams.delete('__lr_recapture');\n dirty = true;\n }\n if (dirty) {\n history.replaceState(null, '', url.toString());\n }\n}\n\n// Self-execute\ninitEditor();\n"],
5
- "mappings": ";;;;;;;AAKO,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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",
3
+ "sources": ["../../src/browser/editor/editor-styles.ts", "../../src/content/safe-href.ts", "../../src/content/style-mapper/DefaultStyleMapper.ts", "../../src/browser/markup-parser.ts", "../../src/browser/md5.ts", "../../src/browser/editor/key-resolver.ts", "../../src/browser/editor/inspector.ts", "../../src/browser/editor/toolbar.ts", "../../src/content/serializer/HTMLSerializer.ts", "../../src/browser/editor/live-preview.ts", "../../src/browser/exclude-filter.ts", "../../src/browser/block-extractor.ts", "../../src/browser/editor/sidebar.ts", "../../src/browser/editor/editor-api.ts", "../../src/browser/editor/pii-redactor.ts", "../../src/browser/editor/snapshot-capture.ts", "../../src/browser/editor/snapshot-viewer.ts", "../../src/browser/editor/editor-init.ts"],
4
+ "sourcesContent": ["/**\n * Editor CSS Styles\n * All styles are injected into Shadow DOM \u2014 no leakage to host page.\n */\n\nexport const EDITOR_CSS = `\n/* Reset inside shadow DOM */\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #1a1a2e;\n line-height: 1.5;\n box-sizing: border-box;\n}\n\n*, *::before, *::after {\n box-sizing: border-box;\n}\n\n/* \u2500\u2500 FAB (replaces fixed toolbar) \u2500\u2500 */\n.lr-fab {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n gap: 0;\n user-select: none;\n}\n\n.lr-fab-btn {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #2d7f7f;\n color: #fff;\n border: none;\n font-weight: 700;\n font-size: 16px;\n cursor: grab;\n box-shadow: 0 4px 12px rgba(0,0,0,0.25);\n transition: box-shadow 0.15s;\n flex-shrink: 0;\n z-index: 1;\n}\n\n.lr-fab-btn:hover {\n box-shadow: 0 6px 20px rgba(0,0,0,0.3);\n}\n\n.lr-fab-btn:active {\n cursor: grabbing;\n}\n\n.lr-fab-panel {\n display: none;\n align-items: center;\n gap: 8px;\n background: #1a1a2e;\n color: #fff;\n padding: 8px 12px;\n border-radius: 8px;\n margin-right: 8px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.25);\n white-space: nowrap;\n}\n\n.lr-fab.expanded .lr-fab-panel {\n display: flex;\n}\n\n.lr-lang-dropdown {\n position: relative;\n}\n\n.lr-lang-btn {\n background: rgba(255,255,255,0.1);\n color: #fff;\n border: 1px solid rgba(255,255,255,0.2);\n border-radius: 4px;\n padding: 4px 10px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n outline: none;\n}\n\n.lr-lang-btn:hover {\n background: rgba(255,255,255,0.2);\n}\n\n.lr-lang-menu {\n display: none;\n position: absolute;\n bottom: calc(100% + 6px);\n left: 0;\n background: #1a1a2e;\n border: 1px solid rgba(255,255,255,0.15);\n border-radius: 6px;\n padding: 4px;\n min-width: 60px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n}\n\n.lr-lang-menu.open {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.lr-lang-item {\n background: none;\n color: #ccc;\n border: none;\n padding: 6px 10px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n border-radius: 4px;\n text-align: left;\n}\n\n.lr-lang-item:hover {\n background: rgba(255,255,255,0.1);\n color: #fff;\n}\n\n.lr-lang-item.active {\n background: #2d7f7f;\n color: #fff;\n}\n\n.lr-fab-progress {\n font-size: 13px;\n color: rgba(255,255,255,0.7);\n}\n\n.lr-fab-exit {\n background: none;\n border: 1px solid rgba(255,255,255,0.3);\n color: #fff;\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n}\n\n.lr-fab-exit:hover {\n background: rgba(255,255,255,0.1);\n}\n\n.lr-fab-snapshot {\n background: #2d7f7f;\n border: 1px solid #2d7f7f;\n color: #fff;\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 600;\n}\n\n.lr-fab-snapshot:hover {\n background: #3a9999;\n border-color: #3a9999;\n}\n\n.lr-fab-snapshot:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Workflow action buttons (Phase 3) */\n.lr-workflow-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin: 12px 0 4px;\n padding: 8px 0 0;\n border-top: 1px solid #e5e7eb;\n}\n\n.lr-wf-btn {\n font-size: 12px;\n font-weight: 500;\n padding: 5px 10px;\n border-radius: 4px;\n border: 1px solid transparent;\n cursor: pointer;\n transition: background-color 0.1s;\n}\n\n.lr-wf-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.lr-wf-primary {\n background: #2563eb;\n color: white;\n border-color: #2563eb;\n}\n.lr-wf-primary:hover:not(:disabled) {\n background: #1d4ed8;\n}\n\n.lr-wf-secondary {\n background: white;\n color: #374151;\n border-color: #d1d5db;\n}\n.lr-wf-secondary:hover:not(:disabled) {\n background: #f3f4f6;\n}\n\n.lr-wf-danger {\n background: white;\n color: #b91c1c;\n border-color: #fca5a5;\n}\n.lr-wf-danger:hover:not(:disabled) {\n background: #fef2f2;\n}\n\n/* Snapshot viewer sandbox wrapper */\n#__lr_snapshot_root {\n isolation: isolate;\n position: relative;\n width: 100%;\n min-height: 100vh;\n}\n\n/* \u2500\u2500 Overlay \u2500\u2500 */\n.lr-overlay {\n position: fixed;\n pointer-events: none;\n border: 2px solid #2d7f7f;\n border-radius: 3px;\n background: rgba(45, 127, 127, 0.06);\n transition: all 0.1s ease;\n z-index: 2147483646;\n display: none;\n}\n\n.lr-overlay.active {\n display: block;\n}\n\n/* \u2500\u2500 Sidebar \u2500\u2500 */\n.lr-sidebar {\n position: fixed;\n top: 0;\n right: 0;\n width: 360px;\n min-width: 280px;\n max-width: 600px;\n bottom: 0;\n background: #fff;\n border-left: 1px solid #e0e0e0;\n z-index: 2147483647;\n overflow-y: auto;\n transform: translateX(100%);\n transition: transform 0.2s ease;\n}\n\n.lr-sidebar.open {\n transform: translateX(0);\n}\n\n/* Resize handle on left edge */\n.lr-sidebar-resize {\n position: absolute;\n top: 0;\n left: -4px;\n width: 8px;\n bottom: 0;\n cursor: col-resize;\n z-index: 1;\n}\n\n.lr-sidebar-resize:hover,\n.lr-sidebar-resize.active {\n background: rgba(45, 127, 127, 0.3);\n}\n\n.lr-sidebar-header {\n padding: 16px;\n border-bottom: 1px solid #e0e0e0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.lr-sidebar-title {\n font-weight: 600;\n font-size: 15px;\n}\n\n.lr-sidebar-close {\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n color: #666;\n padding: 4px 8px;\n line-height: 1;\n}\n\n.lr-sidebar-close:hover {\n color: #1a1a2e;\n}\n\n.lr-sidebar-body {\n padding: 16px;\n}\n\n.lr-field {\n margin-bottom: 16px;\n}\n\n.lr-field-label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n}\n\n.lr-field-key {\n font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;\n font-size: 12px;\n color: #2d7f7f;\n background: #f0f7f7;\n padding: 4px 8px;\n border-radius: 4px;\n word-break: break-all;\n}\n\n.lr-field-original {\n font-size: 13px;\n color: #333;\n background: #f8f8f8;\n padding: 10px 12px;\n border-radius: 6px;\n border: 1px solid #eee;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.lr-field-tag {\n display: inline;\n background: #d9eded;\n color: #2d7f7f;\n padding: 0 3px;\n border-radius: 2px;\n font-family: monospace;\n font-size: 12px;\n}\n\n.lr-textarea {\n width: 100%;\n min-height: 100px;\n padding: 10px 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-family: inherit;\n font-size: 14px;\n line-height: 1.5;\n resize: vertical;\n outline: none;\n transition: border-color 0.15s;\n}\n\n.lr-textarea:focus {\n border-color: #2d7f7f;\n box-shadow: 0 0 0 3px rgba(45, 127, 127, 0.1);\n}\n\n.lr-preview {\n padding: 10px 12px;\n background: #f8f8f8;\n border: 1px solid #eee;\n border-radius: 6px;\n font-size: 13px;\n min-height: 40px;\n}\n\n.lr-status {\n padding: 10px 16px;\n font-size: 12px;\n color: #666;\n text-align: center;\n border-top: 1px solid #eee;\n background: #fafafa;\n}\n\n.lr-status.saved {\n color: #22c55e;\n}\n\n.lr-status.error {\n color: #ef4444;\n}\n\n.lr-status.unsaved {\n color: #f59e0b;\n}\n\n/* \u2500\u2500 Page blocks list \u2500\u2500 */\n.lr-blocks-section {\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid #eee;\n}\n\n.lr-blocks-title {\n font-size: 12px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n\n.lr-block-item {\n padding: 8px 10px;\n border: 1px solid #eee;\n border-radius: 4px;\n margin-bottom: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n overflow: hidden;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n.lr-block-item:hover {\n background: #f0f7f7;\n border-color: #2d7f7f;\n}\n\n.lr-block-item.active {\n background: #e5f2f2;\n border-color: #2d7f7f;\n}\n\n/* \u2500\u2500 Status dots \u2500\u2500 */\n.lr-status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n margin-top: 5px;\n background: #d1d5db;\n}\n\n.lr-status-dot.missing { background: #d1d5db; }\n.lr-status-dot.mt { background: #60a5fa; }\n.lr-status-dot.edited { background: #f97316; }\n.lr-status-dot.confirmed { background: #22c55e; }\n.lr-status-dot.ready { background: #22c55e; }\n.lr-status-dot.locked { background: #a855f7; }\n.lr-status-dot.unsaved { background: #f59e0b; }\n\n/* \u2500\u2500 Locked textarea \u2500\u2500 */\n.lr-textarea-locked {\n background: #f3f4f6;\n color: #6b7280;\n cursor: not-allowed;\n border-color: #e5e7eb;\n}\n\n/* \u2500\u2500 Block text layout \u2500\u2500 */\n.lr-block-text {\n overflow: hidden;\n min-width: 0;\n}\n\n.lr-block-source {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.lr-block-preview {\n font-size: 11px;\n color: #888;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-top: 2px;\n}\n`;\n", "/**\n * URL scheme allowlist for translation `<a href>` serialization.\n *\n * Mirror of packages/edge/src/content/safe-href.ts and\n * packages/wordpress/src/Runtime/Content/SafeHref.php \u2014 translations come\n * through the editor / batch sync pipeline as `ContentUnit.styles` arrays,\n * and a `hyperlink:<url>` style would be serialized verbatim into\n * `<a href=\"<url>\">`. Without this allowlist, a malicious translation\n * author could embed `javascript:fetch(...)` and execute on every site\n * visitor's browser.\n *\n * Allowed:\n * - http: / https:\n * - mailto: / tel: / sms:\n * - relative paths starting with /, ./, ../, ?, #\n *\n * Rejected (returned as `#` so the link still renders but is inert):\n * - javascript:, vbscript:, data:, file:, blob:, jar:, anything else\n * - protocol-relative `//host` (phishing vector)\n */\n\nconst SAFE_SCHEME = /^[a-z][a-z0-9+.-]*:/i;\nconst ALLOWED_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:', 'sms:']);\n\nexport function safeHref(href: string): string {\n if (!href) return '#';\n const trimmed = href.trim();\n if (!trimmed) return '#';\n\n // Reject protocol-relative //host (phishing vector). Translators can use\n // a fully-qualified https:// URL instead.\n if (trimmed.startsWith('//')) {\n return '#';\n }\n\n if (\n trimmed.startsWith('/') ||\n trimmed.startsWith('?') ||\n trimmed.startsWith('#') ||\n trimmed.startsWith('./') ||\n trimmed.startsWith('../')\n ) {\n return trimmed;\n }\n\n const schemeMatch = SAFE_SCHEME.exec(trimmed);\n if (schemeMatch) {\n const scheme = schemeMatch[0].toLowerCase();\n return ALLOWED_SCHEMES.has(scheme) ? trimmed : '#';\n }\n\n return trimmed;\n}\n", "/**\n * Default style mapper for bidirectional HTML element \u2194 style property mapping\n * @module content/style-mapper/DefaultStyleMapper\n */\n\nimport type { IStyleMapper, ElementMapping } from './IStyleMapper.js';\nimport { safeHref } from '../safe-href.js';\n\n/**\n * Default implementation of style mapping\n *\n * Provides bidirectional conversion between HTML elements and style properties:\n * - mapElementToStyles: `<b>` \u2192 `[\"bold\"]`\n * - mapStylesToElement: `[\"bold\"]` \u2192 `<b>`\n *\n * @example\n * ```typescript\n * const mapper = new DefaultStyleMapper();\n *\n * // Parsing: HTML \u2192 styles\n * mapper.mapElementToStyles('a', { href: '/terms' });\n * // \u2192 [\"hyperlink:/terms\"]\n *\n * // Serializing: styles \u2192 HTML\n * mapper.mapStylesToElement(['bold', 'hyperlink:/terms']);\n * // \u2192 { element: 'a', attrs: { href: '/terms' } }\n * ```\n */\nexport class DefaultStyleMapper implements IStyleMapper {\n /**\n * Element \u2192 Style mapping\n * Maps HTML element names to their style property\n */\n private readonly elementToStyles: Record<string, string> = {\n b: 'bold',\n strong: 'bold',\n i: 'italic',\n em: 'italic',\n u: 'underline',\n s: 'strikethrough',\n del: 'strikethrough',\n strike: 'strikethrough',\n code: 'code',\n mark: 'highlight',\n sub: 'subscript',\n sup: 'superscript',\n };\n\n /**\n * Style \u2192 Element mapping (reverse)\n * Uses simple, familiar elements for developer convenience\n * Also accepts element names directly (strong, em, etc.)\n */\n private readonly styleToElement: Record<string, string> = {\n // Semantic style names \u2192 simple elements\n bold: 'b',\n italic: 'i',\n underline: 'u',\n strikethrough: 's',\n code: 'code',\n highlight: 'mark',\n subscript: 'sub',\n superscript: 'sup',\n // Element names (for servers that store styles as element names)\n strong: 'b',\n b: 'b',\n em: 'i',\n i: 'i',\n u: 'u',\n s: 's',\n del: 's',\n strike: 's',\n mark: 'mark',\n sub: 'sub',\n sup: 'sup',\n };\n\n /**\n * Convert HTML element to style properties\n *\n * @param element - Tag name (e.g., \"b\", \"a\", \"strong\")\n * @param attrs - Element attributes (e.g., { href: \"/url\" })\n * @returns Array of style strings\n */\n mapElementToStyles(element: string, attrs: Record<string, string>): string[] {\n const styles: string[] = [];\n const tag = element.toLowerCase();\n\n // Basic element mapping\n const mappedStyle = this.elementToStyles[tag];\n if (mappedStyle) {\n styles.push(mappedStyle);\n }\n\n // Special: <a href=\"...\"> \u2192 hyperlink:url\n if (tag === 'a' && attrs.href) {\n styles.push(`hyperlink:${attrs.href}`);\n }\n\n return styles;\n }\n\n /**\n * Convert style properties to HTML element\n *\n * Priority order:\n * 1. Hyperlink (becomes wrapper element with href)\n * 2. First recognized style property\n * 3. Fallback to span\n *\n * @param styles - Array of style strings\n * @returns Element info for serialization\n */\n mapStylesToElement(styles: string[]): ElementMapping {\n // Check for hyperlink first (takes priority as wrapper element)\n for (const style of styles) {\n if (style.startsWith('hyperlink:')) {\n // Run href through scheme allowlist \u2014 dangerous schemes\n // (javascript:, data:, vbscript:) collapse to `#` so a malicious\n // translation can't embed code execution into a link.\n return {\n element: 'a',\n attrs: { href: safeHref(style.slice('hyperlink:'.length)) },\n };\n }\n }\n\n // Map first recognized style to element\n for (const style of styles) {\n const element = this.styleToElement[style];\n if (element) {\n return {\n element,\n attrs: {},\n };\n }\n }\n\n // Fallback: span with no special attributes\n return { element: 'span', attrs: {} };\n }\n}\n", "/**\n * DOM-based Markup Parser\n *\n * Converts a block element's childNodes into ContentUnit.\n * Uses the browser's DOM rather than regex (unlike edge/PHP which parse raw HTML strings).\n * Mirrors WordPress TS MarkupParser.\n */\n\nimport type { ContentUnit } from '../content/types.js';\nimport { DefaultStyleMapper } from '../content/style-mapper/DefaultStyleMapper.js';\n\nconst styleMapper = new DefaultStyleMapper();\n\n/**\n * Parse a block element into ContentUnit using DOM walking\n */\nexport function parseBlockElement(element: Element): ContentUnit {\n const styles: Record<string, string[]> = {};\n let tagIndex = 0;\n\n function walk(node: Node): string {\n if (node.nodeType === Node.TEXT_NODE) {\n return node.nodeValue ?? '';\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const el = node as Element;\n const tag = el.tagName.toLowerCase();\n\n // Collect attributes\n const attrs: Record<string, string> = {};\n for (let i = 0; i < el.attributes.length; i++) {\n const attr = el.attributes[i];\n attrs[attr.name.toLowerCase()] = attr.value;\n }\n\n const styleList = styleMapper.mapElementToStyles(tag, attrs);\n\n if (styleList.length > 0) {\n // Known styled element \u2014 assign indexed tag\n tagIndex++;\n const idx = tagIndex;\n styles[String(idx)] = styleList;\n\n let inner = '';\n for (let i = 0; i < node.childNodes.length; i++) {\n inner += walk(node.childNodes[i]);\n }\n\n return `<${idx}>${inner}</${idx}>`;\n }\n\n // Unknown element \u2014 strip tag, recurse children\n let result = '';\n for (let i = 0; i < node.childNodes.length; i++) {\n result += walk(node.childNodes[i]);\n }\n return result;\n }\n\n let text = '';\n for (let i = 0; i < element.childNodes.length; i++) {\n text += walk(element.childNodes[i]);\n }\n\n return { text, styles };\n}\n", "/**\n * MD5 Hash Implementation\n * Minimal implementation to match PHP's md5() function\n * Used for generating auto_* keys that match server-side\n */\n\n/* eslint-disable no-bitwise */\n\nfunction safeAdd(x: number, y: number): number {\n const lsw = (x & 0xffff) + (y & 0xffff);\n const msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n return (msw << 16) | (lsw & 0xffff);\n}\n\nfunction bitRotateLeft(num: number, cnt: number): number {\n return (num << cnt) | (num >>> (32 - cnt));\n}\n\nfunction md5cmn(\n q: number,\n a: number,\n b: number,\n x: number,\n s: number,\n t: number\n): number {\n return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);\n}\n\nfunction md5ff(\n a: number,\n b: number,\n c: number,\n d: number,\n x: number,\n s: number,\n t: number\n): number {\n return md5cmn((b & c) | (~b & d), a, b, x, s, t);\n}\n\nfunction md5gg(\n a: number,\n b: number,\n c: number,\n d: number,\n x: number,\n s: number,\n t: number\n): number {\n return md5cmn((b & d) | (c & ~d), a, b, x, s, t);\n}\n\nfunction md5hh(\n a: number,\n b: number,\n c: number,\n d: number,\n x: number,\n s: number,\n t: number\n): number {\n return md5cmn(b ^ c ^ d, a, b, x, s, t);\n}\n\nfunction md5ii(\n a: number,\n b: number,\n c: number,\n d: number,\n x: number,\n s: number,\n t: number\n): number {\n return md5cmn(c ^ (b | ~d), a, b, x, s, t);\n}\n\nfunction binlMD5(x: number[], len: number): number[] {\n x[len >> 5] |= 0x80 << len % 32;\n x[(((len + 64) >>> 9) << 4) + 14] = len;\n\n let a = 1732584193;\n let b = -271733879;\n let c = -1732584194;\n let d = 271733878;\n\n for (let i = 0; i < x.length; i += 16) {\n const olda = a;\n const oldb = b;\n const oldc = c;\n const oldd = d;\n\n a = md5ff(a, b, c, d, x[i], 7, -680876936);\n d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);\n c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);\n b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);\n a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);\n d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);\n c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);\n b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);\n a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);\n d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);\n c = md5ff(c, d, a, b, x[i + 10], 17, -42063);\n b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);\n a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);\n d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);\n c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);\n b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);\n\n a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);\n d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);\n c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);\n b = md5gg(b, c, d, a, x[i], 20, -373897302);\n a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);\n d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);\n c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);\n b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);\n a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);\n d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);\n c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);\n b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);\n a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);\n d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);\n c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);\n b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);\n\n a = md5hh(a, b, c, d, x[i + 5], 4, -378558);\n d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);\n c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);\n b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);\n a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);\n d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);\n c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);\n b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);\n a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);\n d = md5hh(d, a, b, c, x[i + 0], 11, -358537222);\n c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);\n b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);\n a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);\n d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);\n c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);\n b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);\n\n a = md5ii(a, b, c, d, x[i], 6, -198630844);\n d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);\n c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);\n b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);\n a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);\n d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);\n c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);\n b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);\n a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);\n d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);\n c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);\n b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);\n a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);\n d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);\n c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);\n b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);\n\n a = safeAdd(a, olda);\n b = safeAdd(b, oldb);\n c = safeAdd(c, oldc);\n d = safeAdd(d, oldd);\n }\n\n return [a, b, c, d];\n}\n\nfunction binl2hex(binarray: number[]): string {\n const hexTab = '0123456789abcdef';\n let str = '';\n for (let i = 0; i < binarray.length * 4; i++) {\n str +=\n hexTab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xf) +\n hexTab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xf);\n }\n return str;\n}\n\nfunction str2binl(str: string): number[] {\n const bin: number[] = [];\n for (let i = 0; i < str.length * 8; i += 8) {\n bin[i >> 5] |= (str.charCodeAt(i / 8) & 0xff) << i % 32;\n }\n return bin;\n}\n\n/**\n * Generate MD5 hash of a string\n * Matches PHP's md5() function output\n */\nexport function md5(str: string): string {\n return binl2hex(binlMD5(str2binl(str), str.length * 8));\n}\n\n/**\n * Generate auto key matching PHP's TranslationStateManager::generateKey()\n * Format: auto_ + first 12 chars of md5 hash\n */\nexport function generateAutoKey(text: string): string {\n const trimmed = text.trim();\n return 'auto_' + md5(trimmed).substring(0, 12);\n}\n", "/**\n * Key Resolver\n * Resolves a clicked element to its translation key and ContentUnit.\n */\n\nimport type { ContentUnit } from '../../content/types.js';\nimport { parseBlockElement } from '../markup-parser.js';\nimport { generateAutoKey } from '../md5.js';\n\nconst BLOCK_SELECTOR =\n 'p,h1,h2,h3,h4,h5,h6,li,td,th,label,button,figcaption,dt,dd,summary,caption';\n\nexport interface ResolvedKey {\n key: string;\n /** Source ContentUnit (original text with indexed tags) */\n unit: ContentUnit;\n /** Current translation as ContentUnit (if element is already translated) */\n translatedUnit: ContentUnit | null;\n element: Element;\n}\n\n/**\n * Resolve an element to its translation key.\n * Priority: data-lr-block attr \u2192 parseBlockElement \u2192 fallback textContent\n */\nexport function resolveKey(target: Element): ResolvedKey | null {\n // Priority 1: Already translated element with data-lr-block\n const blockEl = target.closest('[data-lr-block]');\n if (blockEl) {\n const key = blockEl.getAttribute('data-lr-block')!;\n const original = blockEl.getAttribute('data-lr-original');\n let unit: ContentUnit;\n let translatedUnit: ContentUnit | null = null;\n\n if (original) {\n // Parse original HTML \u2192 source ContentUnit\n const temp = document.createElement(blockEl.tagName);\n temp.innerHTML = original;\n unit = parseBlockElement(temp);\n // Parse current DOM \u2192 translated ContentUnit\n translatedUnit = parseBlockElement(blockEl);\n } else {\n unit = parseBlockElement(blockEl);\n }\n return { key, unit, translatedUnit, element: blockEl };\n }\n\n // Priority 2: Find nearest block element and parse it\n const nearest = target.closest(BLOCK_SELECTOR);\n if (nearest) {\n const unit = parseBlockElement(nearest);\n const key = generateAutoKey(unit.text);\n return { key, unit, translatedUnit: null, element: nearest };\n }\n\n // Priority 3: Fallback to element text\n const text = target.textContent?.trim();\n if (text && text.length >= 2) {\n const key = generateAutoKey(text);\n const unit: ContentUnit = { text, styles: {} };\n return { key, unit, translatedUnit: null, element: target };\n }\n\n return null;\n}\n", "/**\n * Inspector \u2014 Hover/click handling\n * Shows overlay on hover, resolves key on click, opens sidebar.\n */\n\nimport { resolveKey, ResolvedKey } from './key-resolver.js';\nimport { parseBlockElement } from '../markup-parser.js';\n\nconst SKIP_TAGS = new Set(['SCRIPT', 'STYLE', 'CODE', 'PRE', 'TEXTAREA', 'NOSCRIPT', 'SVG']);\n\nconst BLOCK_SELECTOR =\n 'p,h1,h2,h3,h4,h5,h6,li,td,th,label,button,figcaption,dt,dd,summary,caption';\n\nexport type OnSelectCallback = (resolved: ResolvedKey) => void;\n\nexport class Inspector {\n private overlay: HTMLDivElement;\n private currentTarget: Element | null = null;\n private onSelect: OnSelectCallback;\n private rafId: number | null = null;\n private active = true;\n private rootElement: Element;\n /** When set, clicks resolve keys from this map (snapshot viewer mode)\n * instead of re-computing from the (redacted) DOM text. */\n private snapshotKeyMap: Map<number, string> | null;\n\n constructor(\n shadowRoot: ShadowRoot,\n onSelect: OnSelectCallback,\n rootElement?: Element,\n snapshotKeyMap?: Map<number, string>,\n ) {\n this.onSelect = onSelect;\n // Default scope is the live document body; snapshot viewer passes a\n // sandbox wrapper so blocks outside it are ignored.\n this.rootElement = rootElement || document.body;\n this.snapshotKeyMap = snapshotKeyMap || null;\n\n // Create overlay inside shadow DOM\n this.overlay = document.createElement('div');\n this.overlay.className = 'lr-overlay';\n shadowRoot.appendChild(this.overlay);\n\n // Bind handlers\n this.handleMouseOver = this.handleMouseOver.bind(this);\n this.handleClick = this.handleClick.bind(this);\n this.handleScroll = this.handleScroll.bind(this);\n\n // Listen on document (capture phase to get events before page handlers)\n document.addEventListener('mouseover', this.handleMouseOver, true);\n document.addEventListener('click', this.handleClick, true);\n window.addEventListener('scroll', this.handleScroll, true);\n window.addEventListener('resize', this.handleScroll);\n }\n\n destroy(): void {\n this.active = false;\n document.removeEventListener('mouseover', this.handleMouseOver, true);\n document.removeEventListener('click', this.handleClick, true);\n window.removeEventListener('scroll', this.handleScroll, true);\n window.removeEventListener('resize', this.handleScroll);\n if (this.rafId !== null) cancelAnimationFrame(this.rafId);\n this.overlay.remove();\n }\n\n clearHighlight(): void {\n this.currentTarget = null;\n this.overlay.classList.remove('active');\n }\n\n private handleMouseOver(e: Event): void {\n if (!this.active) return;\n const target = e.target as Element;\n if (!target || !target.closest) return;\n\n // Skip editor UI elements (inside shadow DOM won't trigger this, but be safe)\n if (target.closest('#__lionrapid-editor')) return;\n\n // Skip anything outside the scope root (snapshot viewer mode)\n if (!this.rootElement.contains(target)) return;\n\n // Skip non-translatable elements\n if (this.shouldSkip(target)) {\n this.clearHighlight();\n return;\n }\n\n // Find nearest block element\n const block = target.closest(BLOCK_SELECTOR) || target.closest('[data-lr-block]');\n if (!block) {\n this.clearHighlight();\n return;\n }\n\n if (block === this.currentTarget) return;\n\n this.currentTarget = block;\n this.positionOverlay(block);\n }\n\n private handleClick(e: Event): void {\n if (!this.active) return;\n const target = e.target as Element;\n if (!target || !target.closest) return;\n\n // Skip editor UI\n if (target.closest('#__lionrapid-editor')) return;\n\n // Skip anything outside the scope root (snapshot viewer mode)\n if (!this.rootElement.contains(target)) return;\n\n // Find the block to resolve\n const block = target.closest(BLOCK_SELECTOR) || target.closest('[data-lr-block]');\n if (!block) return;\n\n if (this.shouldSkip(block)) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n // Snapshot viewer mode: look up pre-computed key by data-lr-snap-idx\n // instead of re-running resolveKey on the redacted text.\n if (this.snapshotKeyMap) {\n const idxAttr = block.getAttribute('data-lr-snap-idx');\n if (idxAttr !== null) {\n const idx = parseInt(idxAttr, 10);\n const key = this.snapshotKeyMap.get(idx);\n if (key) {\n const unit = parseBlockElement(block);\n this.onSelect({ key, unit, translatedUnit: null, element: block });\n return;\n }\n }\n // Block has no snap-idx \u2014 not a pre-extracted block, skip\n return;\n }\n\n const resolved = resolveKey(block);\n if (resolved) {\n this.onSelect(resolved);\n }\n }\n\n private handleScroll(): void {\n if (!this.currentTarget) return;\n if (this.rafId !== null) cancelAnimationFrame(this.rafId);\n this.rafId = requestAnimationFrame(() => {\n if (this.currentTarget) {\n this.positionOverlay(this.currentTarget);\n }\n });\n }\n\n private positionOverlay(element: Element): void {\n const rect = element.getBoundingClientRect();\n this.overlay.style.top = `${rect.top}px`;\n this.overlay.style.left = `${rect.left}px`;\n this.overlay.style.width = `${rect.width}px`;\n this.overlay.style.height = `${rect.height}px`;\n this.overlay.classList.add('active');\n }\n\n private shouldSkip(element: Element): boolean {\n // Skip SKIP_TAGS\n let current: Element | null = element;\n while (current) {\n if (SKIP_TAGS.has(current.tagName)) return true;\n if (current.hasAttribute('data-no-translate')) return true;\n if (current.getAttribute('translate') === 'no') return true;\n current = current.parentElement;\n }\n return false;\n }\n}\n", "/**\n * Toolbar \u2014 Draggable FAB that expands to show controls\n * Collapsed: small circle with \"LR\" logo\n * Expanded: horizontal bar with language selector, progress, exit\n */\n\nexport type OnLanguageChange = (locale: string) => void;\nexport type OnExit = () => void;\nexport type OnCaptureSnapshot = () => void;\n\nexport interface ToolbarCaptureOptions {\n /** 'capture' = new snapshot, 'recapture' = overwrite an existing snapshot's version */\n mode?: 'capture' | 'recapture';\n}\n\nexport class Toolbar {\n private el: HTMLDivElement;\n private langBtnEl: HTMLButtonElement;\n private langMenuEl: HTMLDivElement;\n private progressEl: HTMLSpanElement;\n private expanded = false;\n private currentLocale: string;\n private onLanguageChange: OnLanguageChange;\n private onExit: OnExit;\n private onCaptureSnapshot: OnCaptureSnapshot | null;\n\n // Drag state\n private dragging = false;\n private dragOffsetX = 0;\n private dragOffsetY = 0;\n\n constructor(\n shadowRoot: ShadowRoot,\n languages: string[],\n currentLocale: string,\n onLanguageChange: OnLanguageChange,\n onExit: OnExit,\n onCaptureSnapshot: OnCaptureSnapshot | null = null,\n captureOptions: ToolbarCaptureOptions = {},\n ) {\n this.onLanguageChange = onLanguageChange;\n this.onExit = onExit;\n this.onCaptureSnapshot = onCaptureSnapshot;\n this.currentLocale = currentLocale;\n const captureMode = captureOptions.mode ?? 'capture';\n\n this.el = document.createElement('div');\n this.el.className = 'lr-fab';\n\n // FAB button (always visible)\n const fabBtn = document.createElement('button');\n fabBtn.className = 'lr-fab-btn';\n fabBtn.textContent = 'LR';\n fabBtn.addEventListener('click', (e) => {\n // Don't toggle if we just finished dragging\n if (this.dragging) return;\n e.stopPropagation();\n this.toggle();\n });\n this.el.appendChild(fabBtn);\n\n // Expanded panel\n const panel = document.createElement('div');\n panel.className = 'lr-fab-panel';\n\n // Custom language dropdown\n const langWrap = document.createElement('div');\n langWrap.className = 'lr-lang-dropdown';\n\n this.langBtnEl = document.createElement('button');\n this.langBtnEl.className = 'lr-lang-btn';\n this.langBtnEl.textContent = currentLocale.toUpperCase();\n this.langBtnEl.addEventListener('click', (e) => {\n e.stopPropagation();\n this.langMenuEl.classList.toggle('open');\n });\n langWrap.appendChild(this.langBtnEl);\n\n this.langMenuEl = document.createElement('div');\n this.langMenuEl.className = 'lr-lang-menu';\n for (const lang of languages) {\n const item = document.createElement('button');\n item.className = 'lr-lang-item';\n if (lang === currentLocale) item.classList.add('active');\n item.textContent = lang.toUpperCase();\n item.addEventListener('click', (e) => {\n e.stopPropagation();\n this.currentLocale = lang;\n this.langBtnEl.textContent = lang.toUpperCase();\n this.langMenuEl.classList.remove('open');\n // Update active state\n this.langMenuEl.querySelectorAll('.lr-lang-item').forEach((el) => el.classList.remove('active'));\n item.classList.add('active');\n this.onLanguageChange(lang);\n });\n this.langMenuEl.appendChild(item);\n }\n langWrap.appendChild(this.langMenuEl);\n panel.appendChild(langWrap);\n\n // Capture Snapshot button (only in capture mode, not viewer mode).\n // Label/title change when recapture mode is active so the PM knows this\n // click will overwrite an existing snapshot's version instead of making\n // a new one.\n if (this.onCaptureSnapshot) {\n const captureBtn = document.createElement('button');\n captureBtn.className = 'lr-fab-snapshot';\n if (captureMode === 'recapture') {\n captureBtn.textContent = 'Save re-capture';\n captureBtn.title = 'Save this page as a new version of the existing snapshot';\n } else {\n captureBtn.textContent = 'Capture';\n captureBtn.title = 'Capture a redacted snapshot of this page for translators';\n }\n captureBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (this.onCaptureSnapshot) this.onCaptureSnapshot();\n });\n panel.appendChild(captureBtn);\n }\n\n // Progress\n this.progressEl = document.createElement('span');\n this.progressEl.className = 'lr-fab-progress';\n panel.appendChild(this.progressEl);\n\n // Exit button\n const exitBtn = document.createElement('button');\n exitBtn.className = 'lr-fab-exit';\n exitBtn.textContent = 'Exit';\n exitBtn.addEventListener('click', () => this.onExit());\n panel.appendChild(exitBtn);\n\n this.el.appendChild(panel);\n shadowRoot.appendChild(this.el);\n\n // Dragging\n this.handleMouseDown = this.handleMouseDown.bind(this);\n this.handleMouseMove = this.handleMouseMove.bind(this);\n this.handleMouseUp = this.handleMouseUp.bind(this);\n fabBtn.addEventListener('mousedown', this.handleMouseDown);\n }\n\n toggle(): void {\n this.expanded = !this.expanded;\n this.el.classList.toggle('expanded', this.expanded);\n }\n\n updateProgress(translated: number, total: number): void {\n this.progressEl.textContent = `${translated}/${total}`;\n }\n\n getCurrentLocale(): string {\n return this.currentLocale;\n }\n\n destroy(): void {\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n this.el.remove();\n }\n\n private handleMouseDown(e: MouseEvent): void {\n this.dragging = false;\n this.dragOffsetX = e.clientX - this.el.getBoundingClientRect().left;\n this.dragOffsetY = e.clientY - this.el.getBoundingClientRect().top;\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n }\n\n private handleMouseMove(e: MouseEvent): void {\n this.dragging = true;\n const x = Math.max(0, Math.min(e.clientX - this.dragOffsetX, window.innerWidth - this.el.offsetWidth));\n const y = Math.max(0, Math.min(e.clientY - this.dragOffsetY, window.innerHeight - this.el.offsetHeight));\n this.el.style.left = `${x}px`;\n this.el.style.top = `${y}px`;\n this.el.style.right = 'auto';\n this.el.style.bottom = 'auto';\n }\n\n private handleMouseUp(): void {\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n // Reset dragging flag after a tick so the click handler can check it\n if (this.dragging) {\n setTimeout(() => { this.dragging = false; }, 0);\n }\n }\n}\n", "/**\n * HTML serializer for converting ContentUnit to HTML strings\n * @module content/serializer/HTMLSerializer\n */\n\nimport type { ISerializer } from './ISerializer.js';\nimport type { ContentUnit } from '../types.js';\nimport type { IStyleMapper } from '../style-mapper/IStyleMapper.js';\nimport { DefaultStyleMapper } from '../style-mapper/DefaultStyleMapper.js';\n\n/**\n * Configuration options for HTMLSerializer\n */\nexport interface HTMLSerializerOptions {\n /**\n * Custom style mapper for styles \u2192 element conversion\n * Defaults to DefaultStyleMapper\n */\n styleMapper?: IStyleMapper;\n}\n\n/**\n * Serializer that converts ContentUnit format back to HTML strings\n *\n * Transforms indexed tags and style mappings into HTML:\n * - `<1>bold</1>` with styles `{\"1\": [\"bold\"]}` \u2192 `<b>bold</b>`\n * - `<1>link</1>` with styles `{\"1\": [\"hyperlink:/url\"]}` \u2192 `<a href=\"/url\">link</a>`\n *\n * @example\n * ```typescript\n * const serializer = new HTMLSerializer();\n *\n * const html = serializer.serialize({\n * text: 'Read our <1>Terms</1>.',\n * styles: { '1': ['bold'] }\n * });\n * // \u2192 \"Read our <b>Terms</b>.\"\n *\n * const link = serializer.serialize({\n * text: 'Click <1>here</1>.',\n * styles: { '1': ['hyperlink:/url'] }\n * });\n * // \u2192 \"Click <a href=\\\"/url\\\">here</a>.\"\n * ```\n */\nexport class HTMLSerializer implements ISerializer<string> {\n private readonly styleMapper: IStyleMapper;\n\n constructor(options: HTMLSerializerOptions = {}) {\n this.styleMapper = options.styleMapper ?? new DefaultStyleMapper();\n }\n\n /**\n * Serialize ContentUnit to HTML string\n *\n * @param unit - ContentUnit with indexed tags and styles\n * @returns HTML string with semantic elements\n */\n serialize(unit: ContentUnit): string {\n const { text, styles } = unit;\n\n // Pattern to match indexed tags: <1>, </1>, <1/>\n const tagPattern = /<(\\/?)?(\\d+)(\\/)?>/g;\n\n let result = '';\n let lastIndex = 0;\n let match;\n\n while ((match = tagPattern.exec(text)) !== null) {\n // Append text before the tag\n result += text.slice(lastIndex, match.index);\n\n const [fullMatch, closingSlash, indexStr, selfClosingSlash] = match;\n const tagIndex = indexStr;\n const styleList = styles[tagIndex] || [];\n\n if (closingSlash) {\n // Closing tag: </1>\n const mapping = this.styleMapper.mapStylesToElement(styleList);\n result += `</${mapping.element}>`;\n } else if (selfClosingSlash) {\n // Self-closing tag: <1/>\n const mapping = this.styleMapper.mapStylesToElement(styleList);\n const attrs = this.formatAttributes(mapping.attrs);\n result += `<${mapping.element}${attrs} />`;\n } else {\n // Opening tag: <1>\n const mapping = this.styleMapper.mapStylesToElement(styleList);\n const attrs = this.formatAttributes(mapping.attrs);\n result += `<${mapping.element}${attrs}>`;\n }\n\n lastIndex = match.index + fullMatch.length;\n }\n\n // Append remaining text\n result += text.slice(lastIndex);\n\n return result;\n }\n\n /**\n * Format attributes object into HTML attribute string\n */\n private formatAttributes(attrs: Record<string, string>): string {\n const entries = Object.entries(attrs);\n if (entries.length === 0) return '';\n\n return (\n ' ' +\n entries\n .map(([key, value]) => `${key}=\"${this.escapeAttributeValue(value)}\"`)\n .join(' ')\n );\n }\n\n /**\n * Escape special characters in attribute values\n */\n private escapeAttributeValue(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n }\n}\n", "/**\n * Live Preview\n * Optimistically updates DOM elements as the user types translations.\n */\n\nimport type { ContentUnit } from '../../content/types.js';\nimport { HTMLSerializer } from '../../content/serializer/HTMLSerializer.js';\n\nconst htmlSerializer = new HTMLSerializer();\n\n/**\n * Update a single element's content with a new translation.\n * Writes to core cache and updates the DOM without full page retranslate.\n */\nexport function applyLivePreview(\n element: Element,\n text: string,\n styles: Record<string, string[]>,\n key: string,\n locale: string,\n namespace: string,\n): void {\n // Save original HTML before first edit\n if (!element.hasAttribute('data-lr-original')) {\n element.setAttribute('data-lr-original', element.innerHTML);\n }\n\n // Update core cache if available\n const lr = (window as { LionRapid?: { autoTranslator?: { core?: { cache?: { set?: (k: string, v: string, s?: Record<string, string[]>) => void } } } } }).LionRapid;\n const cache = (lr as Record<string, unknown>)?.autoTranslator\n ? getCache()\n : null;\n if (cache) {\n const fullKey = `${locale}:${namespace}:${key}`;\n cache.set(fullKey, text, styles);\n }\n\n // Update DOM\n if (styles && Object.keys(styles).length > 0) {\n const unit: ContentUnit = { text, styles };\n element.innerHTML = htmlSerializer.serialize(unit);\n } else {\n element.textContent = text;\n }\n\n // Mark as translated\n element.setAttribute('data-lr-block', key);\n element.setAttribute('data-lionrapid-client', '1');\n}\n\nfunction getCache(): { set: (key: string, value: string, styles?: Record<string, string[]>) => void } | null {\n try {\n const lr = (window as unknown as { LionRapid?: Record<string, unknown> }).LionRapid;\n if (!lr) return null;\n const at = lr.autoTranslator as Record<string, unknown> | undefined;\n if (!at) return null;\n const core = at.core as Record<string, unknown> | undefined;\n if (!core) return null;\n const cache = core.cache as { set?: (key: string, value: string, styles?: Record<string, string[]>) => void } | undefined;\n if (!cache || typeof cache.set !== 'function') return null;\n return cache as { set: (key: string, value: string, styles?: Record<string, string[]>) => void };\n } catch {\n return null;\n }\n}\n", "/**\n * Exclude Filter\n * Filters out text that should not be translated\n * Mirrors PHP's HtmlTranslator logic\n */\n\nexport interface ExcludePatterns {\n emails: boolean;\n urls: boolean;\n numbers: boolean;\n phones: boolean;\n}\n\nconst DEFAULT_PATTERNS: ExcludePatterns = {\n emails: true,\n urls: true,\n numbers: true,\n phones: true,\n};\n\n// Regex patterns matching PHP's HtmlTranslator\nconst PATTERNS = {\n email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/,\n url: /^(https?:\\/\\/|www\\.)[^\\s]+$/i,\n number: /^[\\d\\s.,+-]+$/,\n phone: /^[+\\d][\\d\\s().-]{6,}$/,\n};\n\nexport class ExcludeFilter {\n private patterns: ExcludePatterns;\n private minTextLength: number;\n\n constructor(patterns: Partial<ExcludePatterns> = {}, minTextLength = 2) {\n this.patterns = { ...DEFAULT_PATTERNS, ...patterns };\n this.minTextLength = minTextLength;\n }\n\n /**\n * Check if text should be excluded from translation\n */\n shouldExclude(text: string): boolean {\n const trimmed = text.trim();\n\n // Too short\n if (trimmed.length < this.minTextLength) {\n return true;\n }\n\n // Check auto-exclude patterns\n if (this.patterns.emails && PATTERNS.email.test(trimmed)) {\n return true;\n }\n\n if (this.patterns.urls && PATTERNS.url.test(trimmed)) {\n return true;\n }\n\n if (this.patterns.numbers && PATTERNS.number.test(trimmed)) {\n return true;\n }\n\n if (this.patterns.phones && PATTERNS.phone.test(trimmed)) {\n return true;\n }\n\n return false;\n }\n}\n", "/**\n * Block Extractor\n * Finds translatable block elements in DOM and parses them into ContentUnit.\n * Mirrors WordPress TS BlockExtractor and edge proxy block-level approach.\n */\n\nimport type { ContentUnit } from '../content/types.js';\nimport { ExcludeFilter, ExcludePatterns } from './exclude-filter.js';\nimport { parseBlockElement } from './markup-parser.js';\nimport { generateAutoKey } from './md5.js';\n\nconst BLOCK_SELECTOR =\n 'p,h1,h2,h3,h4,h5,h6,li,td,th,label,button,figcaption,dt,dd,summary,caption';\n\n// Tags to skip (same as PHP/edge)\nconst SKIP_TAGS = new Set([\n 'SCRIPT',\n 'STYLE',\n 'CODE',\n 'PRE',\n 'TEXTAREA',\n 'NOSCRIPT',\n 'SVG',\n]);\n\n// Attributes that mark elements to skip\nconst SKIP_ATTRIBUTES = [\n 'data-lionrapid-translated', // Server already translated\n 'data-lionrapid-client', // Client already translated\n 'data-no-translate', // Explicitly marked to skip\n];\n\nexport interface ExtractedBlock {\n element: Element;\n unit: ContentUnit;\n key: string;\n}\n\nexport class BlockExtractor {\n private excludeFilter: ExcludeFilter;\n private excludeSelectors: string[];\n\n constructor(\n excludePatterns: Partial<ExcludePatterns> = {},\n excludeSelectors: string[] = [],\n minTextLength = 2\n ) {\n this.excludeFilter = new ExcludeFilter(excludePatterns, minTextLength);\n this.excludeSelectors = excludeSelectors;\n }\n\n /**\n * Extract all translatable block elements from a root.\n * @param includeTranslated - If true, include elements already marked as translated (for editor mode)\n */\n extract(root: Element | Document, includeTranslated = false): ExtractedBlock[] {\n const results: ExtractedBlock[] = [];\n const descendants = root.querySelectorAll(BLOCK_SELECTOR);\n\n // Include the root itself if it matches the block selector\n const elements: Element[] = [];\n if (root instanceof Element && root.matches(BLOCK_SELECTOR)) {\n elements.push(root);\n }\n for (let i = 0; i < descendants.length; i++) {\n elements.push(descendants[i]);\n }\n\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i];\n\n // Skip if inside a SKIP_TAG ancestor\n if (this.isInsideSkipTag(el)) {\n continue;\n }\n\n // Skip if has skip attributes (unless editor mode includes translated)\n if (!includeTranslated && this.hasSkipAttribute(el)) {\n continue;\n }\n\n // Skip if matches exclude selectors\n if (this.matchesExcludeSelector(el)) {\n continue;\n }\n\n // Skip if has translate=\"no\"\n if (el.getAttribute('translate') === 'no') {\n continue;\n }\n\n // Skip nested block elements (let the inner blocks be extracted)\n if (el.querySelector(BLOCK_SELECTOR)) {\n continue;\n }\n\n // For already-translated elements, use original HTML for key + unit\n const lrBlock = el.getAttribute('data-lr-block');\n const lrOriginal = el.getAttribute('data-lr-original');\n\n let unit: ContentUnit;\n if (lrOriginal) {\n // Parse original (source) HTML \u2192 correct ContentUnit for key generation\n const temp = document.createElement(el.tagName);\n temp.innerHTML = lrOriginal;\n unit = parseBlockElement(temp);\n } else {\n unit = parseBlockElement(el);\n }\n\n // Strip indexed tags for exclude filter\n const strippedText = unit.text.replace(/<\\/?[0-9]+\\/?>/g, '');\n\n // Apply exclude filter\n if (this.excludeFilter.shouldExclude(strippedText)) {\n continue;\n }\n\n // Key priority: data-lr-block (translated) \u2192 data-i18n (named) \u2192 auto-generate\n let key: string;\n if (lrBlock) {\n key = lrBlock;\n } else {\n const dataI18n = el.getAttribute('data-i18n');\n if (dataI18n) {\n key = dataI18n.includes(':') ? dataI18n : `common:${dataI18n}`;\n } else {\n key = generateAutoKey(unit.text);\n }\n }\n\n results.push({ element: el, unit, key });\n }\n\n return results;\n }\n\n private isInsideSkipTag(element: Element): boolean {\n let current: Element | null = element.parentElement;\n while (current) {\n if (SKIP_TAGS.has(current.tagName)) {\n return true;\n }\n current = current.parentElement;\n }\n return false;\n }\n\n private hasSkipAttribute(element: Element): boolean {\n let current: Element | null = element;\n while (current) {\n for (const attr of SKIP_ATTRIBUTES) {\n if (current.hasAttribute(attr)) {\n return true;\n }\n }\n current = current.parentElement;\n }\n return false;\n }\n\n private matchesExcludeSelector(element: Element): boolean {\n for (const selector of this.excludeSelectors) {\n try {\n if (element.matches(selector) || element.closest(selector)) {\n return true;\n }\n } catch {\n // Invalid selector, skip\n }\n }\n return false;\n }\n}\n", "/**\n * Sidebar \u2014 Translation editing panel\n * Shows original text, translation textarea, live preview, and page blocks list.\n */\n\nimport type { ContentUnit } from '../../content/types.js';\nimport type { ResolvedKey } from './key-resolver.js';\nimport { HTMLSerializer } from '../../content/serializer/HTMLSerializer.js';\nimport { applyLivePreview } from './live-preview.js';\nimport type { EditorAPI, TargetStatus } from './editor-api.js';\nimport { BlockExtractor } from '../block-extractor.js';\n\nconst htmlSerializer = new HTMLSerializer();\n\nexport class Sidebar {\n private el: HTMLDivElement;\n private bodyEl: HTMLDivElement;\n private statusEl: HTMLDivElement;\n private api: EditorAPI;\n private locale: string;\n private namespace: string;\n private defaultLocale: string;\n private current: ResolvedKey | null = null;\n private blockExtractor: BlockExtractor;\n private onBlockClick: (resolved: ResolvedKey) => void;\n private statusMap: Map<string, TargetStatus | null> = new Map();\n private unsavedKeys: Set<string> = new Set();\n private onProgressUpdate: ((translated: number, total: number) => void) | null = null;\n private lastFetchTime = 0;\n private lastFlushTime = 0;\n\n private userRole: string;\n\n constructor(\n shadowRoot: ShadowRoot,\n api: EditorAPI,\n locale: string,\n namespace: string,\n defaultLocale: string,\n onBlockClick: (resolved: ResolvedKey) => void,\n userRole: string = '',\n ) {\n this.api = api;\n this.locale = locale;\n this.namespace = namespace;\n this.defaultLocale = defaultLocale;\n this.onBlockClick = onBlockClick;\n this.userRole = userRole;\n this.blockExtractor = new BlockExtractor();\n\n this.el = document.createElement('div');\n this.el.className = 'lr-sidebar';\n\n // Resize handle\n const resizeHandle = document.createElement('div');\n resizeHandle.className = 'lr-sidebar-resize';\n this.initResize(resizeHandle);\n this.el.appendChild(resizeHandle);\n\n // Header\n const header = document.createElement('div');\n header.className = 'lr-sidebar-header';\n const title = document.createElement('span');\n title.className = 'lr-sidebar-title';\n title.textContent = 'Edit Translation';\n header.appendChild(title);\n const closeBtn = document.createElement('button');\n closeBtn.className = 'lr-sidebar-close';\n closeBtn.innerHTML = '&times;';\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(closeBtn);\n this.el.appendChild(header);\n\n // Body\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'lr-sidebar-body';\n this.el.appendChild(this.bodyEl);\n\n // Status bar (rendered inline in renderContent, above preview)\n this.statusEl = document.createElement('div');\n this.statusEl.className = 'lr-status';\n\n // Wire up API status\n this.api.setStatusCallback((status, message) => {\n this.statusEl.textContent = message || status;\n this.statusEl.className = `lr-status ${status}`;\n });\n\n // After flush, re-fetch status for saved keys and refresh blocks list\n this.api.setFlushedCallback(async (keys) => {\n this.lastFlushTime = Date.now();\n const freshStatuses = await this.api.fetchStatus(keys, this.locale, this.namespace);\n for (const [key, status] of Object.entries(freshStatuses)) {\n this.statusMap.set(key, status);\n this.unsavedKeys.delete(key);\n }\n this.refreshBlocksList();\n this.emitProgress();\n });\n\n shadowRoot.appendChild(this.el);\n }\n\n open(resolved: ResolvedKey): void {\n this.current = resolved;\n this.el.classList.add('open');\n this.renderContent(resolved);\n }\n\n close(): void {\n this.current = null;\n this.el.classList.remove('open');\n }\n\n isOpen(): boolean {\n return this.el.classList.contains('open');\n }\n\n updateLocale(locale: string): void {\n this.locale = locale;\n // Clear status on locale change \u2014 will be re-fetched\n this.statusMap.clear();\n this.unsavedKeys.clear();\n }\n\n setProgressCallback(cb: (translated: number, total: number) => void): void {\n this.onProgressUpdate = cb;\n }\n\n /**\n * Hydrate the status map with server data for all page blocks.\n * Called once on editor init.\n */\n async hydrateStatus(): Promise<void> {\n const blocks = this.blockExtractor.extract(document.body, true);\n const keys = blocks.map((b) => b.key);\n if (keys.length === 0) return;\n\n const statuses = await this.api.fetchStatus(keys, this.locale, this.namespace);\n for (const [key, status] of Object.entries(statuses)) {\n this.statusMap.set(key, status);\n }\n\n // Apply draft translations to page blocks that the edge proxy didn't render\n // (edge proxy only shows is_ready_for_delivery; editor shows everything)\n for (const block of blocks) {\n const status = this.statusMap.get(block.key);\n if (status && status.text && !status.isReady) {\n applyLivePreview(block.element, status.text, block.unit.styles, block.key, this.locale, this.namespace);\n }\n }\n\n this.emitProgress();\n }\n\n getTranslatedCount(): number {\n let count = 0;\n for (const status of this.statusMap.values()) {\n if (status && status.rowState !== 'empty') count++;\n }\n return count;\n }\n\n getTotalCount(): number {\n return this.blockExtractor.extract(document.body, true).length;\n }\n\n private emitProgress(): void {\n if (this.onProgressUpdate) {\n this.onProgressUpdate(this.getTranslatedCount(), this.getTotalCount());\n }\n }\n\n destroy(): void {\n this.el.remove();\n }\n\n private async renderContent(resolved: ResolvedKey): Promise<void> {\n const { key, unit, element } = resolved;\n this.bodyEl.innerHTML = '';\n\n // Smart fetch: if no flush since last full fetch, only fetch the clicked key.\n // Otherwise re-fetch all blocks to pick up server-side changes from our saves.\n const isStale = this.lastFlushTime > this.lastFetchTime || this.lastFetchTime === 0;\n\n if (isStale) {\n const blocks = this.blockExtractor.extract(document.body, true);\n const allKeys = blocks.map((b) => b.key);\n if (!allKeys.includes(key)) allKeys.push(key);\n const freshStatuses = await this.api.fetchStatus(allKeys, this.locale, this.namespace);\n for (const [k, s] of Object.entries(freshStatuses)) {\n this.statusMap.set(k, s);\n }\n this.lastFetchTime = Date.now();\n } else {\n // Fresh \u2014 only fetch the clicked key\n const freshStatus = await this.api.fetchStatus([key], this.locale, this.namespace);\n if (freshStatus[key] !== undefined) {\n this.statusMap.set(key, freshStatus[key]);\n }\n }\n const status = this.statusMap.get(key) ?? null;\n\n // Key field\n this.addField('Key', () => {\n const keyEl = document.createElement('div');\n keyEl.className = 'lr-field-key';\n keyEl.textContent = key;\n return keyEl;\n });\n\n // Original text\n this.addField('Original', () => {\n const origEl = document.createElement('div');\n origEl.className = 'lr-field-original';\n origEl.innerHTML = this.renderTextWithTags(unit.text);\n return origEl;\n });\n\n const isSourceLocale = this.locale === this.defaultLocale;\n const isLocked = isSourceLocale || status?.isLocked || status?.isReady || false;\n\n // Translation textarea\n const textarea = document.createElement('textarea');\n this.addField('Translation', () => {\n textarea.className = 'lr-textarea';\n // Pre-fill: server status > in-DOM translation > empty\n textarea.value = status?.text || resolved.translatedUnit?.text || '';\n textarea.placeholder = unit.text; // Show source as placeholder\n if (isLocked) {\n textarea.readOnly = true;\n textarea.classList.add('lr-textarea-locked');\n textarea.title = isSourceLocale\n ? 'Source language \u2014 switch to a target language to edit'\n : status?.isReady ? 'Approved for delivery \u2014 read only' : 'Locked \u2014 read only';\n }\n return textarea;\n });\n\n // Status bar (above preview)\n this.bodyEl.appendChild(this.statusEl);\n\n // Preview\n const previewEl = document.createElement('div');\n this.addField('Preview', () => {\n previewEl.className = 'lr-preview';\n if (textarea.value) {\n previewEl.innerHTML = this.renderPreview(textarea.value, unit.styles);\n }\n return previewEl;\n });\n\n // Workflow actions (Phase 3) \u2014 only on target locales (not source).\n // Visibility per role + state is enforced server-side; we hide buttons\n // the server would refuse so users don't see dead ends.\n if (!isSourceLocale) {\n this.renderWorkflowActions(key, status);\n }\n\n // Live preview on input (only if not locked)\n if (!isLocked) {\n textarea.addEventListener('input', () => {\n const text = textarea.value;\n previewEl.innerHTML = this.renderPreview(text, unit.styles);\n if (text) {\n applyLivePreview(element, text, unit.styles, key, this.locale, this.namespace);\n }\n this.unsavedKeys.add(key);\n this.api.queueSave({\n key,\n locale: this.locale,\n namespace: this.namespace,\n text,\n styles: unit.styles,\n });\n });\n }\n\n // Page blocks list\n this.renderBlocksList();\n\n // Focus textarea (only if editable)\n if (!isLocked) {\n setTimeout(() => textarea.focus(), 100);\n }\n }\n\n /**\n * Render Confirm/Reject/Mark-Ready/Unmark-Ready buttons under the preview.\n * Visibility:\n * - Confirm: shown when row is not locked and not already ready\n * - Reject: shown when row is not locked and not already ready (server\n * returns 400 if stage_index is already 0)\n * - Unconfirm: shown when isConfirmed\n * - Mark Ready: PM/admin only, hidden when already ready\n * - Unmark Ready: PM/admin only, only when ready\n * After any successful click we re-fetch status for this key so the UI\n * reflects the new state and the unaffected buttons hide/show themselves.\n */\n private renderWorkflowActions(key: string, status: TargetStatus | null | undefined): void {\n const isPM = this.userRole === 'project_manager' || this.userRole === 'admin';\n const isReady = !!status?.isReady;\n const isLocked = !!status?.isLocked;\n const isConfirmed = !!status?.isConfirmed;\n\n const composite = `${this.locale}:${this.namespace}:${key}`;\n\n const wrap = document.createElement('div');\n wrap.className = 'lr-workflow-actions';\n\n const addBtn = (\n label: string,\n action: 'confirm' | 'unconfirm' | 'reject' | 'mark-ready' | 'unmark-ready',\n variant: 'primary' | 'secondary' | 'danger' = 'secondary',\n ): void => {\n const btn = document.createElement('button');\n btn.className = `lr-wf-btn lr-wf-${variant}`;\n btn.textContent = label;\n btn.addEventListener('click', async () => {\n btn.disabled = true;\n const result = await this.api.transitionTarget(composite, action);\n btn.disabled = false;\n if (result) {\n // Refresh status for this key so the buttons recompute\n await this.refreshStatusForKey(key);\n }\n });\n wrap.appendChild(btn);\n };\n\n // Translator-side actions (subject to can_user_edit_row server-side)\n if (!isLocked && !isReady) {\n addBtn('Confirm', 'confirm', 'primary');\n addBtn('Reject', 'reject', 'danger');\n }\n if (isConfirmed && !isLocked && !isReady) {\n addBtn('Unconfirm', 'unconfirm');\n }\n\n // PM-only actions\n if (isPM) {\n if (!isReady) {\n addBtn('Mark Ready', 'mark-ready', 'primary');\n } else {\n addBtn('Unmark Ready', 'unmark-ready', 'danger');\n }\n }\n\n if (wrap.children.length > 0) {\n this.bodyEl.appendChild(wrap);\n }\n }\n\n /** Re-fetch status for one key and re-render the current view. */\n private async refreshStatusForKey(key: string): Promise<void> {\n const fresh = await this.api.fetchStatus([key], this.locale, this.namespace);\n for (const [k, s] of Object.entries(fresh)) {\n this.statusMap.set(k, s);\n }\n if (this.current) {\n // Re-render the current key to pick up new status\n this.renderContent(this.current);\n }\n this.emitProgress();\n }\n\n private addField(label: string, contentFn: () => HTMLElement): void {\n const field = document.createElement('div');\n field.className = 'lr-field';\n const labelEl = document.createElement('span');\n labelEl.className = 'lr-field-label';\n labelEl.textContent = label;\n field.appendChild(labelEl);\n field.appendChild(contentFn());\n this.bodyEl.appendChild(field);\n }\n\n /**\n * Get CSS class for the status dot based on actual row state.\n */\n private getDotClass(key: string): string {\n if (this.unsavedKeys.has(key)) return 'unsaved';\n const s = this.statusMap.get(key);\n if (!s) return 'missing';\n if (s.isLocked) return 'locked';\n if (s.isReady) return 'ready';\n if (s.isConfirmed) return 'confirmed';\n if (s.rowState === 'edited') return 'edited';\n if (s.rowState === 'machine_translated') return 'mt';\n return 'missing';\n }\n\n private renderTextWithTags(text: string): string {\n // Highlight indexed tags like <1>, </1>\n return text.replace(\n /<(\\/?)?(\\d+)(\\/)?>/g,\n (match) => `<span class=\"lr-field-tag\">${match}</span>`\n );\n }\n\n private renderPreview(text: string, styles: Record<string, string[]>): string {\n if (!text) return '';\n if (Object.keys(styles).length > 0) {\n const unit: ContentUnit = { text, styles };\n return htmlSerializer.serialize(unit);\n }\n return text;\n }\n\n private initResize(handle: HTMLDivElement): void {\n let startX = 0;\n let startWidth = 0;\n\n const onMouseMove = (e: MouseEvent) => {\n const newWidth = startWidth + (startX - e.clientX);\n const clamped = Math.max(280, Math.min(600, newWidth));\n this.el.style.width = `${clamped}px`;\n };\n\n const onMouseUp = () => {\n handle.classList.remove('active');\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n };\n\n handle.addEventListener('mousedown', (e) => {\n e.preventDefault();\n startX = e.clientX;\n startWidth = this.el.offsetWidth;\n handle.classList.add('active');\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n });\n }\n\n private refreshBlocksList(): void {\n const existing = this.bodyEl.querySelector('.lr-blocks-section');\n if (existing) existing.remove();\n this.renderBlocksList();\n }\n\n private renderBlocksList(): void {\n const section = document.createElement('div');\n section.className = 'lr-blocks-section';\n\n const blocks = this.blockExtractor.extract(document.body, true);\n const translatedCount = this.getTranslatedCount();\n\n const title = document.createElement('div');\n title.className = 'lr-blocks-title';\n title.textContent = `Blocks on this page (${translatedCount}/${blocks.length} translated)`;\n section.appendChild(title);\n\n for (const block of blocks) {\n const item = document.createElement('div');\n item.className = 'lr-block-item';\n\n const isActive = this.current && block.element === this.current.element;\n if (isActive) item.classList.add('active');\n\n // Status dot\n const dot = document.createElement('span');\n dot.className = 'lr-status-dot';\n dot.classList.add(this.getDotClass(block.key));\n item.appendChild(dot);\n\n // Source text\n const textWrap = document.createElement('div');\n textWrap.className = 'lr-block-text';\n const displayText = block.unit.text.replace(/<\\/?[0-9]+\\/?>/g, '');\n const sourceSpan = document.createElement('div');\n sourceSpan.className = 'lr-block-source';\n sourceSpan.textContent = displayText.length > 60 ? displayText.slice(0, 60) + '...' : displayText;\n sourceSpan.title = displayText;\n textWrap.appendChild(sourceSpan);\n\n // Translation preview (if exists)\n const blockStatus = this.statusMap.get(block.key);\n if (blockStatus && blockStatus.text) {\n const previewSpan = document.createElement('div');\n previewSpan.className = 'lr-block-preview';\n const previewText = blockStatus.text.replace(/<\\/?[0-9]+\\/?>/g, '');\n previewSpan.textContent = previewText.length > 50 ? previewText.slice(0, 50) + '...' : previewText;\n textWrap.appendChild(previewSpan);\n }\n\n item.appendChild(textWrap);\n\n item.addEventListener('click', () => {\n block.element.scrollIntoView({ behavior: 'smooth', block: 'center' });\n this.onBlockClick({ key: block.key, unit: block.unit, translatedUnit: null, element: block.element });\n });\n\n section.appendChild(item);\n }\n\n this.bodyEl.appendChild(section);\n }\n}\n", "/**\n * Editor API \u2014 Batch save queue + session auth\n * Queues translation edits and flushes them in a single batch API call.\n * Uses editor session JWTs (es_ prefixed) for authentication with auto-renewal.\n */\n\nimport type { CapturedSnapshot, SnapshotTextEntry } from './snapshot-capture.js';\n\nexport interface QueuedTranslation {\n key: string;\n locale: string;\n namespace: string;\n text: string;\n styles: Record<string, string[]>;\n}\n\n// ============================================\n// Snapshot API types\n// ============================================\n\nexport interface SnapshotListItem {\n snapshotUuid: string;\n pageUrl: string;\n title: string;\n capturedBy: string;\n createdAt: string;\n expiresAt: string;\n textEntryCount: number;\n status: string;\n}\n\nexport interface SnapshotDetail {\n snapshotUuid: string;\n pageUrl: string;\n title: string;\n html: string;\n textEntries: SnapshotTextEntry[];\n viewport: { width: number; height: number; devicePixelRatio: number };\n createdAt: string;\n expiresAt: string;\n}\n\nexport interface TargetStatus {\n text: string;\n rowState: string; // \"empty\" | \"machine_translated\" | \"edited\"\n isConfirmed: boolean;\n isReady: boolean; // approved for delivery\n isLocked: boolean; // workflow locked OR delivery locked\n}\n\nexport type StatusCallback = (status: 'unsaved' | 'saving' | 'saved' | 'error', message?: string) => void;\n\nexport class EditorAPI {\n private queue: QueuedTranslation[] = [];\n private apiBase: string;\n private sessionToken: string;\n private projectId: string;\n private flushInterval: ReturnType<typeof setInterval> | null = null;\n private renewalInterval: ReturnType<typeof setInterval> | null = null;\n private onStatus: StatusCallback = () => {};\n private onFlushed: (keys: string[]) => void = () => {};\n private onSessionExpired: (() => void) | null = null;\n\n constructor(apiBase: string, sessionToken: string, projectId: string) {\n this.apiBase = apiBase.replace(/\\/$/, '');\n this.sessionToken = sessionToken;\n this.projectId = projectId;\n }\n\n setStatusCallback(cb: StatusCallback): void {\n this.onStatus = cb;\n }\n\n setFlushedCallback(cb: (keys: string[]) => void): void {\n this.onFlushed = cb;\n }\n\n setSessionExpiredCallback(cb: () => void): void {\n this.onSessionExpired = cb;\n }\n\n /**\n * Start auto-flush (30s interval + visibilitychange) and session renewal (60s check)\n */\n startAutoFlush(): void {\n this.flushInterval = setInterval(() => this.flush(), 30_000);\n document.addEventListener('visibilitychange', this.handleVisibility);\n\n // Check session renewal every 60s\n this.renewalInterval = setInterval(() => this.maybeRenewSession(), 60_000);\n }\n\n /**\n * Stop auto-flush and flush remaining items\n */\n async stopAndFlush(): Promise<void> {\n if (this.flushInterval) {\n clearInterval(this.flushInterval);\n this.flushInterval = null;\n }\n if (this.renewalInterval) {\n clearInterval(this.renewalInterval);\n this.renewalInterval = null;\n }\n document.removeEventListener('visibilitychange', this.handleVisibility);\n await this.flush();\n }\n\n /**\n * Queue a translation for saving\n */\n queueSave(item: QueuedTranslation): void {\n // Replace existing entry for same key+locale\n const idx = this.queue.findIndex(\n (q) => q.key === item.key && q.locale === item.locale && q.namespace === item.namespace\n );\n if (idx >= 0) {\n this.queue[idx] = item;\n } else {\n this.queue.push(item);\n }\n this.onStatus('unsaved', `${this.queue.length} unsaved`);\n\n // Auto-flush if queue is large\n if (this.queue.length > 50) {\n this.flush();\n }\n }\n\n /**\n * Flush all queued translations to the server\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n\n const items = [...this.queue];\n this.onStatus('saving');\n\n try {\n const response = await fetch(\n `${this.apiBase}/api/integrations/targets/batch`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sessionToken}`,\n },\n body: JSON.stringify({\n translations: items.map((t) => ({\n key: `${t.locale}:${t.namespace}:${t.key}`,\n value: { text: t.text, styles: t.styles },\n })),\n }),\n }\n );\n\n if (response.status === 401) {\n this.handleSessionExpired();\n return;\n }\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n // Remove flushed items from queue (new items may have been added during fetch)\n const flushedKeys = items.map((i) => i.key);\n for (const item of items) {\n const idx = this.queue.indexOf(item);\n if (idx >= 0) this.queue.splice(idx, 1);\n }\n\n // Notify sidebar to re-fetch status for flushed keys\n this.onFlushed(flushedKeys);\n\n if (this.queue.length === 0) {\n this.onStatus('saved', 'All changes saved');\n } else {\n this.onStatus('unsaved', `${this.queue.length} unsaved`);\n }\n } catch (err) {\n this.onStatus('error', `Save failed: ${(err as Error).message}`);\n }\n }\n\n private statusAbort: AbortController | null = null;\n\n /**\n * Fetch translation status for a batch of keys (includes unconfirmed rows).\n * Cancels any in-flight status request. Caps at 200 keys per request.\n */\n async fetchStatus(\n keys: string[],\n locale: string,\n namespace: string\n ): Promise<Record<string, TargetStatus | null>> {\n if (keys.length === 0) return {};\n\n // Cancel previous in-flight request\n if (this.statusAbort) this.statusAbort.abort();\n this.statusAbort = new AbortController();\n\n // Cap keys to avoid exceeding URL length limits\n const batch = keys.slice(0, 200);\n\n const params = new URLSearchParams({ locale, namespace, keys: batch.join(',') });\n try {\n const response = await fetch(\n `${this.apiBase}/api/integrations/targets/status?${params}`,\n {\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n signal: this.statusAbort.signal,\n }\n );\n if (response.status === 401) {\n this.handleSessionExpired();\n return {};\n }\n if (!response.ok) return {};\n const data = await response.json();\n return data.translations;\n } catch (err) {\n if ((err as Error).name === 'AbortError') return {};\n return {};\n }\n }\n\n get pendingCount(): number {\n return this.queue.length;\n }\n\n // ============================================\n // Session renewal\n // ============================================\n\n /**\n * Check if session is within 2min of expiry, and renew if so.\n */\n private async maybeRenewSession(): Promise<void> {\n const exp = this.getSessionExp();\n if (!exp) return;\n\n const timeLeft = exp * 1000 - Date.now();\n if (timeLeft > 120_000) return; // More than 2 min left, skip\n\n await this.renewSession();\n }\n\n private async renewSession(): Promise<void> {\n try {\n const response = await fetch(`${this.apiBase}/api/editor/renew`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.sessionToken}`,\n },\n });\n\n if (response.status === 401) {\n this.handleSessionExpired();\n return;\n }\n\n if (!response.ok) return;\n\n const data = await response.json();\n this.sessionToken = data.session_token;\n\n // Update sessionStorage\n try {\n const raw = this.sessionToken.startsWith('es_') ? this.sessionToken.slice(3) : this.sessionToken;\n const parts = raw.split('.');\n if (parts.length === 3) {\n const payload = JSON.parse(atob(parts[1]));\n sessionStorage.setItem('__lr_editor_session', JSON.stringify({\n token: this.sessionToken,\n exp: payload.exp || 0,\n }));\n }\n } catch { /* non-critical */ }\n } catch {\n // Network error \u2014 will retry on next interval\n }\n }\n\n private getSessionExp(): number | null {\n try {\n const raw = this.sessionToken.startsWith('es_') ? this.sessionToken.slice(3) : this.sessionToken;\n const parts = raw.split('.');\n if (parts.length !== 3) return null;\n const payload = JSON.parse(atob(parts[1]));\n return payload.exp || null;\n } catch {\n return null;\n }\n }\n\n private handleSessionExpired(): void {\n this.onStatus('error', 'Session expired. Please reopen the editor from the dashboard.');\n if (this.onSessionExpired) {\n this.onSessionExpired();\n }\n }\n\n private handleVisibility = (): void => {\n if (document.visibilityState === 'hidden') {\n this.flush();\n }\n };\n\n // ============================================\n // Snapshot API\n // ============================================\n\n /**\n * Upload a captured snapshot. Returns the created snapshot's UUID so the\n * caller can build a share URL (`?__lr_snapshot={uuid}`).\n */\n async createSnapshot(\n snapshot: CapturedSnapshot,\n ): Promise<{ snapshotUuid: string } | null> {\n try {\n const response = await fetch(`${this.apiBase}/api/editor/snapshots`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sessionToken}`,\n },\n body: JSON.stringify({\n pageUrl: snapshot.pageUrl,\n title: snapshot.title,\n viewport: snapshot.viewport,\n textEntries: snapshot.textEntries,\n html: snapshot.html,\n }),\n });\n\n if (response.status === 401) {\n this.handleSessionExpired();\n return null;\n }\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n const data = await response.json();\n return { snapshotUuid: data.snapshot_uuid || data.snapshotUuid };\n } catch (err) {\n this.onStatus('error', `Snapshot failed: ${(err as Error).message}`);\n return null;\n }\n }\n\n /**\n * Re-capture an existing snapshot. Server appends a new version and keeps\n * the same `snapshotUuid`. Returns the new version number on success.\n */\n async recaptureSnapshot(\n snapshotUuid: string,\n snapshot: CapturedSnapshot,\n ): Promise<{ snapshotUuid: string; version: number } | null> {\n try {\n const response = await fetch(\n `${this.apiBase}/api/editor/snapshots/${encodeURIComponent(snapshotUuid)}`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.sessionToken}`,\n },\n body: JSON.stringify({\n pageUrl: snapshot.pageUrl,\n title: snapshot.title,\n viewport: snapshot.viewport,\n textEntries: snapshot.textEntries,\n html: snapshot.html,\n }),\n },\n );\n\n if (response.status === 401) {\n this.handleSessionExpired();\n return null;\n }\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n const data = await response.json();\n return {\n snapshotUuid: data.snapshot_uuid || data.snapshotUuid,\n version: data.version || 1,\n };\n } catch (err) {\n this.onStatus('error', `Re-capture failed: ${(err as Error).message}`);\n return null;\n }\n }\n\n /**\n * Fetch a single snapshot by UUID. Returns null on auth failure or 404.\n */\n async getSnapshot(snapshotUuid: string): Promise<SnapshotDetail | null> {\n try {\n const response = await fetch(\n `${this.apiBase}/api/editor/snapshots/${encodeURIComponent(snapshotUuid)}`,\n {\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n },\n );\n if (response.status === 401) {\n this.handleSessionExpired();\n return null;\n }\n if (!response.ok) return null;\n return (await response.json()) as SnapshotDetail;\n } catch {\n return null;\n }\n }\n\n /**\n * List all snapshots the current editor session can see.\n */\n async listSnapshots(): Promise<SnapshotListItem[]> {\n try {\n const response = await fetch(`${this.apiBase}/api/editor/snapshots`, {\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n });\n if (response.status === 401) {\n this.handleSessionExpired();\n return [];\n }\n if (!response.ok) return [];\n const data = await response.json();\n return data.snapshots || [];\n } catch {\n return [];\n }\n }\n\n /**\n * Delete (soft) a snapshot by UUID.\n */\n async deleteSnapshot(snapshotUuid: string): Promise<boolean> {\n try {\n const response = await fetch(\n `${this.apiBase}/api/editor/snapshots/${encodeURIComponent(snapshotUuid)}`,\n {\n method: 'DELETE',\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n },\n );\n if (response.status === 401) {\n this.handleSessionExpired();\n return false;\n }\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Workflow transitions (Phase 3). Per-key endpoints on the integrations API\n * that mirror the dashboard's row-level transitions but are addressable by\n * composite editor key (locale:namespace:auto_xxx).\n *\n * Returns the parsed JSON on success, or null on failure (caller usually\n * shows a toast / re-fetches status).\n */\n async transitionTarget(\n composite: string,\n action: 'confirm' | 'unconfirm' | 'reject' | 'mark-ready' | 'unmark-ready',\n ): Promise<Record<string, unknown> | null> {\n try {\n const response = await fetch(\n `${this.apiBase}/api/integrations/targets/${encodeURIComponent(composite)}/${action}`,\n {\n method: 'POST',\n headers: { 'Authorization': `Bearer ${this.sessionToken}` },\n },\n );\n if (response.status === 401) {\n this.handleSessionExpired();\n return null;\n }\n if (!response.ok) {\n this.onStatus('error', `${action} failed: HTTP ${response.status}`);\n return null;\n }\n return (await response.json()) as Record<string, unknown>;\n } catch (err) {\n this.onStatus('error', `${action} failed: ${(err as Error).message}`);\n return null;\n }\n }\n}\n", "/**\n * PII Redactor \u2014 fine-grained inline replacement of PII patterns in text.\n *\n * Phase 4 of the snapshot feature. Phase 1 redacts whole text nodes only;\n * this module replaces matches *inline*, preserving surrounding prose:\n * \"Contact us at foo@bar.com for help\" \u2192 \"Contact us at [REDACTED] for help\"\n *\n * Two entry points:\n * - `redactString(text)` \u2014 pure string-in/string-out, used in tests and\n * callable independently if a non-DOM caller ever needs it.\n * - `redactTextNodes(root)` \u2014 walks every text node under `root` and\n * replaces PII inline, skipping subtrees marked with `data-no-redact`,\n * and skipping `<code>` / `<pre>` (legitimate examples).\n *\n * Design notes:\n * - Patterns are tuned to avoid common false positives. SSN requires\n * dashes/spaces (so 9-digit order numbers survive); credit cards must\n * pass a Luhn check (so 16-digit tracking IDs survive); IPs reject any\n * octet > 255 (so version strings like 1.2.3.999 survive).\n * - We bias toward under-redaction in ambiguous cases \u2014 better to leak\n * a tracking number than corrupt a customer's real prose.\n */\n\nconst REDACTED = '[REDACTED]';\n\n// ----- Regex catalog ---------------------------------------------------------\n//\n// Every pattern uses the `g` flag so .replace() can hit multiple matches in\n// one string. Anchors (`\\b` or surrounding-char checks) are tuned per pattern.\n\n// Email: standard local@domain.tld, fairly permissive on the local part.\nconst EMAIL_RE =\n /[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}/gi;\n\n// US/intl phone: optional `+1 ` prefix, optional parens around area code,\n// 3-3-4 digit groups separated by space/dash/dot. Requires at least one\n// separator so bare 10-digit numbers don't match (those are usually IDs).\nconst PHONE_RE =\n /(?:\\+\\d{1,3}[\\s.-]?)?(?:\\(\\d{3}\\)|\\d{3})[\\s.-]\\d{3}[\\s.-]\\d{4}/g;\n\n// SSN: XXX-XX-XXXX, dashes or spaces (NOT bare 9 digits \u2014 too many false\n// positives on order numbers, IDs, etc.).\nconst SSN_RE = /\\b\\d{3}[\\s-]\\d{2}[\\s-]\\d{4}\\b/g;\n\n// IPv4: four 1-3 digit octets, dot-separated. We post-filter for \"all\n// octets <= 255\" so version strings like 1.2.3.999 don't match.\nconst IPV4_RE = /\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/g;\n\n// URL: http(s):// or www. then non-whitespace. Greedy through path/query.\nconst URL_RE = /\\b(?:https?:\\/\\/|www\\.)[^\\s<>\"']+/gi;\n\n// Credit card candidate: 13-19 digits in 4-4-4-4 (or contiguous) format,\n// allowing dashes/spaces between groups. Luhn-checked before redacting.\n// Must end on a digit (not a separator) \u2014 prevents greedy matching of\n// trailing whitespace.\nconst CC_CANDIDATE_RE = /\\b\\d(?:[ -]?\\d){12,18}\\b/g;\n\n// ----- Luhn check ------------------------------------------------------------\n\nfunction luhnValid(digits: string): boolean {\n // digits already stripped of separators by caller\n if (digits.length < 13 || digits.length > 19) return false;\n let sum = 0;\n let alt = false;\n for (let i = digits.length - 1; i >= 0; i--) {\n let n = digits.charCodeAt(i) - 48; // '0' = 48\n if (n < 0 || n > 9) return false;\n if (alt) {\n n *= 2;\n if (n > 9) n -= 9;\n }\n sum += n;\n alt = !alt;\n }\n return sum % 10 === 0;\n}\n\n// ----- IPv4 octet bounds check ----------------------------------------------\n\nfunction ipv4Valid(match: string): boolean {\n const parts = match.split('.');\n if (parts.length !== 4) return false;\n for (const p of parts) {\n const n = Number(p);\n if (!Number.isInteger(n) || n < 0 || n > 255) return false;\n }\n return true;\n}\n\n// ----- Public: string redactor ----------------------------------------------\n\n/**\n * Replace every PII match in `text` with `[REDACTED]`. Surrounding prose\n * is preserved.\n *\n * Order matters: URLs first (so `http://...` doesn't get mangled by IPv4\n * matching), then emails, then more specific numeric patterns.\n */\nexport function redactString(text: string): string {\n if (!text) return text;\n let out = text;\n\n out = out.replace(URL_RE, REDACTED);\n out = out.replace(EMAIL_RE, REDACTED);\n out = out.replace(PHONE_RE, REDACTED);\n out = out.replace(SSN_RE, REDACTED);\n out = out.replace(IPV4_RE, (m) => (ipv4Valid(m) ? REDACTED : m));\n out = out.replace(CC_CANDIDATE_RE, (m) => {\n const digits = m.replace(/[\\s-]/g, '');\n return luhnValid(digits) ? REDACTED : m;\n });\n\n return out;\n}\n\n// ----- Public: DOM walker ---------------------------------------------------\n\n/**\n * Tag names whose text we never touch \u2014 code samples, preformatted blocks,\n * and `<style>` content. `<script>` is already removed earlier in the\n * snapshot pipeline, so it's not in this list.\n */\nconst SKIP_TAGS = new Set(['CODE', 'PRE', 'STYLE', 'TEXTAREA']);\n\n/**\n * Walks every text node under `root` and redacts PII inline. Skips:\n * - text nodes inside any ancestor with `[data-no-redact]`\n * - text nodes inside `<code>`, `<pre>`, `<style>`, `<textarea>`\n *\n * Mutates the DOM in place.\n */\nexport function redactTextNodes(root: Element): void {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n // Collect first, mutate after \u2014 walker behaviour with mutation is\n // implementation-defined.\n const toUpdate: { node: Text; value: string }[] = [];\n\n let node = walker.nextNode() as Text | null;\n while (node) {\n if (!isInSkippedSubtree(node)) {\n const original = node.nodeValue || '';\n const replaced = redactString(original);\n if (replaced !== original) {\n toUpdate.push({ node, value: replaced });\n }\n }\n node = walker.nextNode() as Text | null;\n }\n\n for (const { node: textNode, value } of toUpdate) {\n textNode.nodeValue = value;\n }\n}\n\nfunction isInSkippedSubtree(node: Node): boolean {\n let cur: Node | null = node.parentNode;\n while (cur && cur.nodeType === Node.ELEMENT_NODE) {\n const el = cur as Element;\n if (SKIP_TAGS.has(el.tagName)) return true;\n if (el.hasAttribute('data-no-redact')) return true;\n cur = el.parentNode;\n }\n return false;\n}\n", "/**\n * Snapshot Capture \u2014 Serializes the live DOM with PII redaction.\n *\n * Used by the visual editor to let an authenticated admin capture an auth page\n * so a translator (without credentials) can later translate it against a\n * frozen copy. The serialized HTML is uploaded to the server and retrieved in\n * viewer mode (?__lr_snapshot={uuid}) where Inspector + Sidebar boot against\n * the snapshot root instead of document.body.\n *\n * Redaction strategy:\n * - Remove: <script>, <noscript>, <iframe>, <embed>, <object>, editor host\n * - Clear all form <input>, <textarea>, <select> values\n * - Replace [data-pii] / [data-sensitive] text with [REDACTED]\n * - Strip all inline event handlers (onclick, onmouseover, etc.)\n * - Inline PII redaction in text nodes (email / phone / URL / SSN /\n * credit card / IPv4) \u2014 see pii-redactor.ts. `[data-no-redact]`\n * subtrees, `<code>`, and `<pre>` are skipped.\n * - Strip CSRF/CSP meta tags and auth tokens from link/script URLs\n */\n\nimport { BlockExtractor } from '../block-extractor.js';\nimport { redactTextNodes } from './pii-redactor.js';\n\nconst REDACTED = '[REDACTED]';\n\nexport interface SnapshotTextEntry {\n /** auto_xxxxxxxxxxxx \u2014 12-char md5 hash, generated BEFORE redaction so it matches the live page */\n key: string;\n /** The source tag name (P, H1, LI, etc.) \u2014 useful for future analytics */\n tagName: string;\n /** Index of this block among all block elements in the snapshot DOM. Used by\n * the viewer to map a clicked element back to its pre-computed key without\n * re-running BlockExtractor on the redacted text. */\n blockIndex: number;\n}\n\nexport interface SnapshotViewport {\n width: number;\n height: number;\n devicePixelRatio: number;\n}\n\nexport interface CapturedSnapshot {\n html: string;\n textEntries: SnapshotTextEntry[];\n pageUrl: string;\n title: string;\n viewport: SnapshotViewport;\n}\n\n/**\n * Capture the current page as a redacted snapshot.\n *\n * Pure function \u2014 does NOT mutate the live DOM. Clones first, then:\n * 1. Extracts block keys BEFORE redaction (so auto_keys match the live page)\n * 2. Redacts the clone (strips PII, scripts, forms, etc.)\n * 3. Stamps each block element with a data-lr-snap-idx attribute so the\n * viewer can map a click back to the pre-computed key\n * 4. Serializes to HTML\n *\n * The textEntries carry pre-computed keys (no source text) and the HTML is\n * safe to store. The viewer uses textEntries to look up the correct key by\n * index when the translator clicks a block.\n */\nexport function captureSnapshot(): CapturedSnapshot {\n // 1. Clone the entire document element.\n const clone = document.documentElement.cloneNode(true) as HTMLElement;\n\n // 2. Extract blocks BEFORE redaction so keys match the live page.\n // The real text is used for md5 hashing, producing the same auto_keys\n // the edge proxy / auto-init generates on the live page.\n const textEntries = extractTextEntries(clone);\n\n // 3. Stamp each extracted block with a data attribute linking it to its\n // entry index. The viewer uses this to resolve clicks to pre-computed\n // keys without re-running BlockExtractor on the redacted text.\n // (extractTextEntries stores the element reference so we can stamp it)\n\n // 4. Redact the clone. Order: remove dangerous elements first so we don't\n // waste time walking their subtrees.\n removeDangerousElements(clone);\n clearFormValues(clone);\n redactSensitiveElements(clone);\n stripInlineEventHandlers(clone);\n redactTextNodePII(clone);\n stripSensitiveMetaAndHeaders(clone);\n\n // 5. Serialize.\n const html = '<!DOCTYPE html>\\n' + clone.outerHTML;\n\n return {\n html,\n textEntries,\n pageUrl: window.location.href,\n title: document.title,\n viewport: {\n width: window.innerWidth,\n height: window.innerHeight,\n devicePixelRatio: window.devicePixelRatio || 1,\n },\n };\n}\n\n/**\n * Remove elements that should never appear in a snapshot:\n * - <script>, <noscript>: could re-execute or leak source\n * - <iframe>, <embed>, <object>: third-party content, likely auth-bound\n * - #__lionrapid-editor: the editor's own shadow host\n * - <link rel=\"prefetch\"> / <link rel=\"preload\"> that may leak auth URLs\n */\nfunction removeDangerousElements(root: HTMLElement): void {\n const selectors = [\n 'script',\n 'noscript',\n 'iframe',\n 'embed',\n 'object',\n '#__lionrapid-editor',\n 'link[rel=\"prefetch\"]',\n 'link[rel=\"preload\"]',\n 'link[rel=\"modulepreload\"]',\n ];\n for (const selector of selectors) {\n const matches = root.querySelectorAll(selector);\n for (let i = 0; i < matches.length; i++) {\n matches[i].remove();\n }\n }\n}\n\n/**\n * Clear all form field values so no user input leaks.\n * This covers <input> (all types), <textarea>, and <select>.\n */\nfunction clearFormValues(root: HTMLElement): void {\n const inputs = root.querySelectorAll('input, textarea, select');\n for (let i = 0; i < inputs.length; i++) {\n const el = inputs[i] as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n\n // Clear live value\n if ('value' in el) el.value = '';\n\n // Clear the serialized attribute \u2014 cloneNode copies the attribute,\n // not the .value property, so we need to touch both.\n if (el.hasAttribute('value')) el.setAttribute('value', '');\n\n // <textarea> content lives in text children, not an attribute\n if (el.tagName === 'TEXTAREA') el.textContent = '';\n\n // Clear option selection on <select>\n if (el.tagName === 'SELECT') {\n const options = el.querySelectorAll('option');\n for (let j = 0; j < options.length; j++) {\n (options[j] as HTMLOptionElement).selected = false;\n options[j].removeAttribute('selected');\n }\n }\n\n // Remove data-* attributes that often hold state\n const attrs = Array.from(el.attributes);\n for (const attr of attrs) {\n if (attr.name.startsWith('data-value') || attr.name === 'data-initial') {\n el.removeAttribute(attr.name);\n }\n }\n }\n}\n\n/**\n * Replace the text content of elements flagged as sensitive with [REDACTED].\n * Preserves the element itself so layout stays intact.\n */\nfunction redactSensitiveElements(root: HTMLElement): void {\n const sensitive = root.querySelectorAll('[data-pii], [data-sensitive]');\n for (let i = 0; i < sensitive.length; i++) {\n const el = sensitive[i] as HTMLElement;\n el.textContent = REDACTED;\n // Strip all attributes except structural ones so classes/ids still position it.\n const attrs = Array.from(el.attributes);\n for (const attr of attrs) {\n if (attr.name !== 'class' && attr.name !== 'id' && attr.name !== 'style') {\n el.removeAttribute(attr.name);\n }\n }\n }\n}\n\n/**\n * Walk every element and strip any attribute that starts with 'on' (onclick,\n * onmouseover, onload, etc.). These could re-execute in the viewer.\n */\nfunction stripInlineEventHandlers(root: HTMLElement): void {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n let node = walker.nextNode() as HTMLElement | null;\n while (node) {\n const attrs = Array.from(node.attributes);\n for (const attr of attrs) {\n if (attr.name.toLowerCase().startsWith('on')) {\n node.removeAttribute(attr.name);\n }\n }\n node = walker.nextNode() as HTMLElement | null;\n }\n}\n\n/**\n * Walk text nodes and replace PII matches inline. Phase 4: matches are\n * replaced where they appear (\"Contact foo@bar.com today\" \u2192\n * \"Contact [REDACTED] today\") instead of redacting the whole text node.\n * See pii-redactor.ts for pattern details and the data-no-redact escape\n * hatch.\n */\nfunction redactTextNodePII(root: HTMLElement): void {\n redactTextNodes(root);\n}\n\n/**\n * Strip meta tags and link/script URLs that commonly carry auth material.\n */\nfunction stripSensitiveMetaAndHeaders(root: HTMLElement): void {\n // CSRF / CSP nonces\n const sensitiveMetas = root.querySelectorAll(\n 'meta[name=\"csrf-token\"], meta[name=\"csp-nonce\"], meta[name=\"csrf-param\"], meta[http-equiv=\"set-cookie\"]',\n );\n for (let i = 0; i < sensitiveMetas.length; i++) {\n sensitiveMetas[i].remove();\n }\n\n // Strip token-bearing query params from <link> and <a href> URLs\n const TOKEN_PARAMS = ['token', 'auth', 'access_token', 'session', 'sid', 'key', 'api_key', 'apikey'];\n const urlElements = root.querySelectorAll('link[href], a[href], img[src]');\n for (let i = 0; i < urlElements.length; i++) {\n const el = urlElements[i] as HTMLLinkElement | HTMLAnchorElement | HTMLImageElement;\n const attr = el.tagName === 'IMG' ? 'src' : 'href';\n const raw = el.getAttribute(attr);\n if (!raw) continue;\n try {\n const url = new URL(raw, window.location.href);\n let changed = false;\n for (const param of TOKEN_PARAMS) {\n if (url.searchParams.has(param)) {\n url.searchParams.set(param, REDACTED);\n changed = true;\n }\n }\n if (changed) el.setAttribute(attr, url.toString());\n } catch {\n // Not a parseable URL (mailto:, tel:, javascript:, etc.) \u2014 skip\n }\n }\n}\n\n/**\n * Run BlockExtractor on the clone BEFORE redaction to produce text entries\n * with content-hash keys that match the live page. Each extracted block\n * element is stamped with `data-lr-snap-idx` so the viewer can map a click\n * back to the pre-computed key without re-running BlockExtractor on the\n * (now redacted) text.\n *\n * No source text is included in the returned entries \u2014 only the key, tag\n * name, and block index \u2014 so the entries are safe to store even though\n * extraction happened before redaction.\n */\nfunction extractTextEntries(clone: HTMLElement): SnapshotTextEntry[] {\n const extractor = new BlockExtractor(\n { emails: true, urls: true, numbers: true, phones: true },\n [],\n 2,\n );\n const blocks = extractor.extract(clone);\n\n return blocks.map((block, index) => {\n // Stamp the element so the viewer can resolve clicks by data attribute\n block.element.setAttribute('data-lr-snap-idx', String(index));\n\n return {\n key: block.key,\n tagName: block.element.tagName,\n blockIndex: index,\n };\n });\n}\n", "/**\n * Snapshot Viewer \u2014 Renders a saved snapshot in the current page so the\n * Inspector + Sidebar can be pointed at it for translation.\n *\n * When the editor loads with `?__lr_snapshot={uuid}`, the normal page is\n * replaced with the snapshot HTML inside a sandbox wrapper:\n *\n * <div id=\"__lr_snapshot_root\"> \u2190 scoped root passed to Inspector\n * <html>...snapshot...</html>\n * </div>\n *\n * Auto-init retranslation is NOT re-run against the snapshot \u2014 translations\n * saved via the sidebar flow through the normal batch endpoint and will\n * appear on the real auth page on next load.\n */\n\nimport type { EditorAPI } from './editor-api.js';\nimport type { SnapshotTextEntry } from './snapshot-capture.js';\n\nexport interface SnapshotViewerResult {\n /** Scope root to pass to Inspector */\n root: HTMLElement;\n /** Snapshot metadata for display in the toolbar / sidebar */\n pageUrl: string;\n title: string;\n /** Pre-computed key map: blockIndex \u2192 key. The Inspector uses this to resolve\n * clicks without re-running BlockExtractor on the redacted HTML. */\n keyMap: Map<number, string>;\n}\n\n/**\n * Fetch a snapshot from the server and mount it into the current page.\n * Returns the root element Inspector should scope against.\n *\n * On failure (404, network error, deleted snapshot) returns null and displays\n * a user-visible notice via the caller's notice helper.\n */\nexport async function activateSnapshotViewer(\n snapshotUuid: string,\n api: EditorAPI,\n): Promise<SnapshotViewerResult | null> {\n const snapshot = await api.getSnapshot(snapshotUuid);\n if (!snapshot) return null;\n\n // Replace the entire body with a sandbox wrapper holding the snapshot HTML.\n // We keep document.head alone so the editor's Shadow DOM host and existing\n // stylesheets (for rendering) still work.\n //\n // The snapshot HTML is a full document (starts with <!DOCTYPE>), so we\n // parse it with DOMParser and extract the <body> children. The snapshot's\n // <head> <link> and <style> tags are appended to the real head so the\n // snapshot renders with its original styles.\n const parser = new DOMParser();\n const doc = parser.parseFromString(snapshot.html, 'text/html');\n\n // Copy over stylesheets and inline <style> tags from the snapshot head.\n // We prefix them with a data attribute so the cleanup code can remove them\n // if the viewer is ever unmounted (out of scope for Phase 1).\n const snapshotStyles = doc.head.querySelectorAll('link[rel=\"stylesheet\"], style');\n for (let i = 0; i < snapshotStyles.length; i++) {\n const clone = snapshotStyles[i].cloneNode(true) as HTMLElement;\n clone.setAttribute('data-lr-snapshot-style', '');\n document.head.appendChild(clone);\n }\n\n // Copy <title> so the tab title reflects the captured page\n if (snapshot.title) {\n document.title = `[Snapshot] ${snapshot.title}`;\n }\n\n // Clear the current body content (but preserve the editor's shadow host\n // if it's already mounted \u2014 it's attached to #__lionrapid-editor).\n const editorHost = document.getElementById('__lionrapid-editor');\n while (document.body.firstChild) {\n if (document.body.firstChild === editorHost) {\n // Skip past the editor host without removing it\n const next = document.body.firstChild.nextSibling;\n if (!next) break;\n document.body.removeChild(next);\n } else {\n document.body.removeChild(document.body.firstChild);\n }\n }\n\n // Build sandbox wrapper and inject snapshot body\n const root = document.createElement('div');\n root.id = '__lr_snapshot_root';\n root.setAttribute('data-lr-snapshot-uuid', snapshotUuid);\n root.innerHTML = doc.body.innerHTML;\n\n // Insert wrapper before the editor host so the editor stays on top\n if (editorHost && editorHost.parentNode === document.body) {\n document.body.insertBefore(root, editorHost);\n } else {\n document.body.appendChild(root);\n }\n\n // Build key map from textEntries: blockIndex \u2192 auto_key\n const keyMap = new Map<number, string>();\n const entries: SnapshotTextEntry[] = snapshot.textEntries || [];\n for (const entry of entries) {\n keyMap.set(entry.blockIndex, entry.key);\n }\n\n return {\n root,\n pageUrl: snapshot.pageUrl,\n title: snapshot.title,\n keyMap,\n };\n}\n", "/**\n * Visual Translation Editor \u2014 Entry Point\n * Self-executing IIFE bundle loaded by edge proxy or auto-init when ?__lr_editor is detected.\n *\n * Reads script tag attributes, polls for window.LionRapid, creates Shadow DOM,\n * and instantiates Inspector, Sidebar, and Toolbar.\n *\n * Auth flow: grant token \u2192 exchange for scoped session JWT \u2192 use JWT for API calls.\n */\n\nimport { EDITOR_CSS } from './editor-styles.js';\nimport { Inspector } from './inspector.js';\nimport { Toolbar } from './toolbar.js';\nimport { Sidebar } from './sidebar.js';\nimport { EditorAPI } from './editor-api.js';\nimport type { ResolvedKey } from './key-resolver.js';\nimport { captureSnapshot } from './snapshot-capture.js';\nimport { activateSnapshotViewer } from './snapshot-viewer.js';\n\n// ============================================\n// Session helpers\n// ============================================\n\nconst SESSION_KEY = '__lr_editor_session';\n\ninterface StoredSession {\n token: string;\n exp: number;\n}\n\nfunction getStoredSession(): string | null {\n try {\n const raw = sessionStorage.getItem(SESSION_KEY);\n if (!raw) return null;\n const parsed: StoredSession = JSON.parse(raw);\n // Check if expired (with 30s buffer)\n if (parsed.exp * 1000 < Date.now() + 30_000) {\n sessionStorage.removeItem(SESSION_KEY);\n return null;\n }\n return parsed.token;\n } catch {\n return null;\n }\n}\n\nfunction storeSession(token: string): void {\n try {\n // Parse exp from JWT payload (es_<header>.<payload>.<sig>)\n const raw = token.startsWith('es_') ? token.slice(3) : token;\n const parts = raw.split('.');\n if (parts.length !== 3) return;\n const payload = JSON.parse(atob(parts[1]));\n const session: StoredSession = { token, exp: payload.exp || 0 };\n sessionStorage.setItem(SESSION_KEY, JSON.stringify(session));\n } catch {\n // Non-critical \u2014 session just won't persist across navigations\n }\n}\n\nfunction clearSession(): void {\n sessionStorage.removeItem(SESSION_KEY);\n}\n\n/**\n * Decode the role claim from a signed editor session JWT.\n * Used for client-side UI gating (show/hide Capture button etc.) \u2014 the\n * server enforces the same check on every protected endpoint.\n */\nfunction extractSessionRole(token: string): string {\n try {\n const raw = token.startsWith('es_') ? token.slice(3) : token;\n const parts = raw.split('.');\n if (parts.length !== 3) return '';\n const payload = JSON.parse(atob(parts[1]));\n return typeof payload.role === 'string' ? payload.role : '';\n } catch {\n return '';\n }\n}\n\n// ============================================\n// User-visible notice (shown when editor can't activate)\n// ============================================\n\nfunction showEditorNotice(message: string): void {\n const el = document.createElement('div');\n el.setAttribute('data-no-translate', '');\n Object.assign(el.style, {\n position: 'fixed', bottom: '24px', right: '24px', zIndex: '2147483647',\n background: '#1a1a2e', color: '#fff', padding: '16px 20px',\n borderRadius: '8px', fontFamily: 'system-ui, sans-serif', fontSize: '14px',\n maxWidth: '360px', boxShadow: '0 4px 20px rgba(0,0,0,0.3)',\n });\n el.textContent = message;\n const close = document.createElement('button');\n Object.assign(close.style, {\n position: 'absolute', top: '4px', right: '8px',\n background: 'none', border: 'none', color: '#888', cursor: 'pointer', fontSize: '16px',\n });\n close.textContent = '\\u00d7';\n close.addEventListener('click', () => el.remove());\n el.appendChild(close);\n document.body.appendChild(el);\n setTimeout(() => el.remove(), 8000);\n}\n\n// ============================================\n// Init\n// ============================================\n\nfunction initEditor(): void {\n // Support two activation modes:\n // 1. Grant mode \u2014 script tag has data-grant (first-page activation)\n // 2. Session mode \u2014 no grant, but a valid session exists in sessionStorage\n // (subsequent page navigation after grant was consumed)\n //\n // The edge proxy injects the editor script on every page when editor.enabled\n // is true. On pages where there's no active session, the editor silently\n // exits \u2014 no FAB, no network calls.\n const scriptEl =\n (document.querySelector('script[data-grant]') as HTMLScriptElement | null) ||\n (document.querySelector('script[data-lr-editor]') as HTMLScriptElement | null);\n\n if (!scriptEl) {\n // No editor script tag at all \u2014 nothing to do\n return;\n }\n\n const grant = scriptEl.dataset.grant || '';\n const hasValidSession = getStoredSession() !== null;\n\n // Session mode requires an existing stored session; grant mode requires a grant\n if (!grant && !hasValidSession) {\n // No grant and no session \u2014 silently exit (normal visitor, not an editor user)\n return;\n }\n\n const locale = scriptEl.dataset.locale || '';\n const apiBase = scriptEl.dataset.api || 'https://api.lionrapid.com';\n const projectId = scriptEl.dataset.project || '';\n\n // Poll for window.LionRapid (auto-init loads first)\n let attempts = 0;\n const maxAttempts = 100; // 10s at 100ms intervals\n\n const poll = setInterval(() => {\n attempts++;\n const lr = window.LionRapid;\n\n if (lr) {\n clearInterval(poll);\n activate(lr, grant, locale, apiBase, projectId);\n } else if (attempts >= maxAttempts) {\n clearInterval(poll);\n console.warn('[LionRapid Editor] Timed out waiting for window.LionRapid');\n }\n }, 100);\n}\n\nasync function activate(\n lr: NonNullable<typeof window.LionRapid>,\n grant: string,\n locale: string,\n apiBase: string,\n projectId: string,\n): Promise<void> {\n const config = window.__lionrapidConfig;\n const languages = config?.languages || [locale];\n const namespace = config?.namespace || 'default';\n const defaultLocale = config?.defaultLocale || 'en';\n const currentLocale = locale || lr.getCurrentLocale();\n const normalizedApiBase = apiBase.replace(/\\/$/, '');\n\n // --- Session acquisition ---\n let sessionToken = getStoredSession();\n\n if (!sessionToken && grant) {\n // Exchange grant for session JWT\n try {\n const res = await fetch(`${normalizedApiBase}/api/editor/exchange`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ grant, domain: window.location.host }),\n });\n if (!res.ok) {\n console.error('[LionRapid Editor] Grant exchange failed:', res.status);\n showEditorNotice('Editor session expired. Please reopen the editor from the dashboard.');\n return;\n }\n const data = await res.json();\n sessionToken = data.session_token;\n if (sessionToken) {\n storeSession(sessionToken);\n }\n } catch (err) {\n console.error('[LionRapid Editor] Grant exchange error:', err);\n showEditorNotice('Could not connect to LionRapid. Please check your connection and try again.');\n return;\n }\n }\n\n if (!sessionToken) {\n console.error('[LionRapid Editor] No valid session. Please reopen the editor from the dashboard.');\n showEditorNotice('Editor session expired. Please reopen the editor from the dashboard.');\n return;\n }\n\n // Decode the session JWT to extract the user's role. The server signs this\n // token and enforces permissions \u2014 the client-side check here is only to\n // avoid showing actions the server would reject (defense in depth). Never\n // trust client-side role checks for security decisions.\n const role = extractSessionRole(sessionToken);\n const canCaptureSnapshots = role === 'project_manager' || role === 'admin';\n\n // Create Shadow DOM host\n const host = document.createElement('div');\n host.id = '__lionrapid-editor';\n host.setAttribute('data-no-translate', '');\n document.body.appendChild(host);\n const shadow = host.attachShadow({ mode: 'closed' });\n\n // Inject styles\n const styleEl = document.createElement('style');\n styleEl.textContent = EDITOR_CSS;\n shadow.appendChild(styleEl);\n\n // Hide the proxy/auto-init language switcher while editor is active\n const switcherEl = document.querySelector('[data-lionrapid-switcher]') as HTMLElement | null;\n if (switcherEl) switcherEl.style.display = 'none';\n\n // Create API client with session token\n const api = new EditorAPI(normalizedApiBase, sessionToken, projectId);\n api.startAutoFlush();\n\n // --- Snapshot viewer mode ---\n // If the URL has ?__lr_snapshot={uuid}, replace the page with the saved\n // snapshot HTML and scope the Inspector to the sandbox wrapper. Capture\n // button is hidden in viewer mode (a translator shouldn't re-capture).\n //\n // Separately, ?__lr_recapture={uuid} runs on the LIVE page (no viewer)\n // but switches the FAB's Capture button into re-capture mode \u2014 PUT to the\n // existing snapshot uuid instead of POST.\n const currentUrl = new URL(window.location.href);\n const snapshotUuid = currentUrl.searchParams.get('__lr_snapshot');\n const recaptureUuid = currentUrl.searchParams.get('__lr_recapture');\n let inspectorRoot: Element | undefined;\n let snapshotKeyMap: Map<number, string> | undefined;\n if (snapshotUuid) {\n const result = await activateSnapshotViewer(snapshotUuid, api);\n if (!result) {\n showEditorNotice('Snapshot not found or expired. Please check the dashboard.');\n return;\n }\n inspectorRoot = result.root;\n snapshotKeyMap = result.keyMap;\n }\n\n // Create sidebar (needs api + locale)\n const handleBlockSelect = (resolved: ResolvedKey) => {\n sidebar.open(resolved);\n inspector.clearHighlight();\n };\n\n const sidebar = new Sidebar(shadow, api, currentLocale, namespace, defaultLocale, handleBlockSelect, role);\n\n // Create inspector (hover/click \u2192 sidebar)\n const inspector = new Inspector(shadow, handleBlockSelect, inspectorRoot, snapshotKeyMap);\n\n // Create toolbar\n const toolbar = new Toolbar(\n shadow,\n languages,\n currentLocale,\n // Language change\n async (newLocale) => {\n // Edge proxy context: navigate to locale URL instead of client-side translation\n const isEdgeProxy = document.querySelector('script[data-mode=\"dynamic-only\"]') !== null;\n if (isEdgeProxy) {\n const url = new URL(window.location.href);\n // Strip existing locale prefix if present\n const stripped = url.pathname.replace(/^\\/[a-z]{2}(\\/|$)/, '/');\n // Build new URL: /es/path?__lr_editor=grant\n const prefix = newLocale === defaultLocale ? '' : `/${newLocale}`;\n url.pathname = prefix + (stripped === '/' && prefix ? '' : stripped);\n url.searchParams.set('__lr_editor', grant);\n window.location.href = url.toString();\n return;\n }\n sidebar.updateLocale(newLocale);\n sidebar.close();\n inspector.clearHighlight();\n await lr.changeLanguage(newLocale);\n await sidebar.hydrateStatus();\n },\n // Exit\n async () => {\n await api.stopAndFlush();\n inspector.destroy();\n toolbar.destroy();\n sidebar.destroy();\n host.remove();\n clearSession();\n },\n // Capture Snapshot \u2014 only available in live-page mode (not viewer) AND\n // only for PM/admin roles. Translators and proofreaders cannot capture;\n // the server enforces the same check on POST /api/editor/snapshots.\n //\n // If ?__lr_recapture={uuid} is present, the same button re-captures that\n // existing snapshot (PUT) instead of creating a new one (POST).\n snapshotUuid || !canCaptureSnapshots\n ? null\n : async () => {\n try {\n const snapshot = captureSnapshot();\n if (recaptureUuid) {\n const result = await api.recaptureSnapshot(recaptureUuid, snapshot);\n if (result) {\n showEditorNotice(\n `Re-captured as v${result.version} (${snapshot.textEntries.length} blocks). You can close this tab.`,\n );\n } else {\n showEditorNotice('Re-capture failed. Please try again.');\n }\n } else {\n const result = await api.createSnapshot(snapshot);\n if (result) {\n showEditorNotice(\n `Snapshot captured (${snapshot.textEntries.length} blocks). Open it from the Snapshots tab in the dashboard.`,\n );\n } else {\n showEditorNotice('Snapshot upload failed. Please try again.');\n }\n }\n } catch (err) {\n console.error('[LionRapid Editor] Snapshot capture error:', err);\n showEditorNotice('Snapshot capture failed. See console for details.');\n }\n },\n // When in recapture mode, surface it to the toolbar so the button label\n // can change from \"Capture\" to \"Save re-capture\".\n recaptureUuid ? { mode: 'recapture' } : undefined,\n );\n\n // Wire progress counter to sidebar status\n sidebar.setProgressCallback((translated, total) => {\n toolbar.updateProgress(translated, total);\n });\n\n // Hydrate status from server and update progress\n sidebar.hydrateStatus().then(() => {\n toolbar.updateProgress(sidebar.getTranslatedCount(), sidebar.getTotalCount());\n });\n\n // Clean editor params from URL\n const url = new URL(window.location.href);\n let dirty = false;\n if (url.searchParams.has('__lr_editor')) {\n url.searchParams.delete('__lr_editor');\n dirty = true;\n }\n if (url.searchParams.has('__lr_snapshot')) {\n url.searchParams.delete('__lr_snapshot');\n dirty = true;\n }\n if (url.searchParams.has('__lr_recapture')) {\n url.searchParams.delete('__lr_recapture');\n dirty = true;\n }\n if (dirty) {\n history.replaceState(null, '', url.toString());\n }\n}\n\n// Self-execute\ninitEditor();\n"],
5
+ "mappings": ";;;;;;;AAKO,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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",
6
6
  "names": ["BLOCK_SELECTOR", "BLOCK_SELECTOR", "SKIP_TAGS", "htmlSerializer", "SKIP_TAGS", "REDACTED", "url"]
7
7
  }