@l1yp/file-viewer 0.1.0 → 0.1.2

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 (439) hide show
  1. package/README.md +2 -0
  2. package/dist/FileViewer.js +2 -0
  3. package/dist/FileViewer.js.map +1 -0
  4. package/dist/FileViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  5. package/dist/FileViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  6. package/dist/components/AppxViewer.js +2 -0
  7. package/dist/components/AppxViewer.js.map +1 -0
  8. package/dist/components/AppxViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  9. package/dist/components/AppxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  10. package/dist/components/ArchiveBrowser.js +2 -0
  11. package/dist/components/ArchiveBrowser.js.map +1 -0
  12. package/dist/components/ArchiveBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  13. package/dist/components/ArchiveBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  14. package/dist/components/AudioViewer.js +2 -0
  15. package/dist/components/AudioViewer.js.map +1 -0
  16. package/dist/components/AudioViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  17. package/dist/components/AudioViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  18. package/dist/components/BinObjBrowser.js +2 -0
  19. package/dist/components/BinObjBrowser.js.map +1 -0
  20. package/dist/components/BinObjBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  21. package/dist/components/BinObjBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  22. package/dist/components/CertViewer.js +2 -0
  23. package/dist/components/CertViewer.js.map +1 -0
  24. package/dist/components/CertViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  25. package/dist/components/CertViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  26. package/dist/components/ClassViewer.js +2 -0
  27. package/dist/components/ClassViewer.js.map +1 -0
  28. package/dist/components/ClassViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  29. package/dist/components/ClassViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  30. package/dist/components/CodeBlock.js +2 -0
  31. package/dist/components/CodeBlock.js.map +1 -0
  32. package/dist/components/CodeBlock.vue_vue_type_script_setup_true_lang.js +2 -0
  33. package/dist/components/CodeBlock.vue_vue_type_script_setup_true_lang.js.map +1 -0
  34. package/dist/components/CodeView.js +2 -0
  35. package/dist/components/CodeView.js.map +1 -0
  36. package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js +2 -0
  37. package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js.map +1 -0
  38. package/dist/components/CsvViewer.js +2 -0
  39. package/dist/components/CsvViewer.js.map +1 -0
  40. package/dist/components/CsvViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  41. package/dist/components/CsvViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  42. package/dist/components/DicomViewer.js +2 -0
  43. package/dist/components/DicomViewer.js.map +1 -0
  44. package/dist/components/DicomViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  45. package/dist/components/DicomViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  46. package/dist/components/DocxNavigationPane.js +9 -0
  47. package/dist/components/DocxNavigationPane.js.map +1 -0
  48. package/dist/components/DocxNavigationPane.vue.d.ts +23 -0
  49. package/dist/components/DocxNavigationPane.vue_vue_type_script_setup_true_lang.js +98 -0
  50. package/dist/components/DocxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -0
  51. package/dist/components/DocxViewer.js +3 -1
  52. package/dist/components/DocxViewer.js.map +1 -0
  53. package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js +72 -37
  54. package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  55. package/dist/components/DrawioViewer.js +2 -0
  56. package/dist/components/DrawioViewer.js.map +1 -0
  57. package/dist/components/DrawioViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  58. package/dist/components/DrawioViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  59. package/dist/components/DxfViewer.js +2 -0
  60. package/dist/components/DxfViewer.js.map +1 -0
  61. package/dist/components/DxfViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  62. package/dist/components/DxfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  63. package/dist/components/EbookViewer.js +2 -0
  64. package/dist/components/EbookViewer.js.map +1 -0
  65. package/dist/components/EbookViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  66. package/dist/components/EbookViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  67. package/dist/components/EmlViewer.js +2 -0
  68. package/dist/components/EmlViewer.js.map +1 -0
  69. package/dist/components/EmlViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  70. package/dist/components/EmlViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  71. package/dist/components/EplViewer.js +2 -0
  72. package/dist/components/EplViewer.js.map +1 -0
  73. package/dist/components/EplViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  74. package/dist/components/EplViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  75. package/dist/components/FileViewerBody.js +3 -1
  76. package/dist/components/FileViewerBody.js.map +1 -0
  77. package/dist/components/FileViewerBody.vue.d.ts +5 -0
  78. package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js +250 -247
  79. package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js.map +1 -0
  80. package/dist/components/FileViewerPanel.js +2 -0
  81. package/dist/components/FileViewerPanel.js.map +1 -0
  82. package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js +2 -0
  83. package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  84. package/dist/components/FontViewer.js +2 -0
  85. package/dist/components/FontViewer.js.map +1 -0
  86. package/dist/components/FontViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  87. package/dist/components/FontViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  88. package/dist/components/FrontmatterCard.js +2 -0
  89. package/dist/components/FrontmatterCard.js.map +1 -0
  90. package/dist/components/FrontmatterCard.vue_vue_type_script_setup_true_lang.js +2 -0
  91. package/dist/components/FrontmatterCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  92. package/dist/components/GeoViewer.js +2 -0
  93. package/dist/components/GeoViewer.js.map +1 -0
  94. package/dist/components/GeoViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  95. package/dist/components/GeoViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  96. package/dist/components/HarViewer.js +2 -0
  97. package/dist/components/HarViewer.js.map +1 -0
  98. package/dist/components/HarViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  99. package/dist/components/HarViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  100. package/dist/components/HexViewer.js +2 -0
  101. package/dist/components/HexViewer.js.map +1 -0
  102. package/dist/components/HexViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  103. package/dist/components/HexViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  104. package/dist/components/HprofViewer.js +2 -0
  105. package/dist/components/HprofViewer.js.map +1 -0
  106. package/dist/components/HprofViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  107. package/dist/components/HprofViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  108. package/dist/components/ImageLightbox.js +2 -0
  109. package/dist/components/ImageLightbox.js.map +1 -0
  110. package/dist/components/ImageLightbox.vue_vue_type_script_setup_true_lang.js +2 -0
  111. package/dist/components/ImageLightbox.vue_vue_type_script_setup_true_lang.js.map +1 -0
  112. package/dist/components/InlineText.js +2 -0
  113. package/dist/components/InlineText.js.map +1 -0
  114. package/dist/components/JksViewer.js +2 -0
  115. package/dist/components/JksViewer.js.map +1 -0
  116. package/dist/components/JksViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  117. package/dist/components/JksViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  118. package/dist/components/JsonlViewer.js +2 -0
  119. package/dist/components/JsonlViewer.js.map +1 -0
  120. package/dist/components/JsonlViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  121. package/dist/components/JsonlViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  122. package/dist/components/LogViewer.js +2 -0
  123. package/dist/components/LogViewer.js.map +1 -0
  124. package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  125. package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  126. package/dist/components/LrcViewer.js +2 -0
  127. package/dist/components/LrcViewer.js.map +1 -0
  128. package/dist/components/LrcViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  129. package/dist/components/LrcViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  130. package/dist/components/MarkdownTable.js +2 -0
  131. package/dist/components/MarkdownTable.js.map +1 -0
  132. package/dist/components/MarkdownTable.vue_vue_type_script_setup_true_lang.js +2 -0
  133. package/dist/components/MarkdownTable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  134. package/dist/components/MarkdownText.js +2 -0
  135. package/dist/components/MarkdownText.js.map +1 -0
  136. package/dist/components/MhtViewer.js +2 -0
  137. package/dist/components/MhtViewer.js.map +1 -0
  138. package/dist/components/MhtViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  139. package/dist/components/MhtViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  140. package/dist/components/MindMapView.js +2 -0
  141. package/dist/components/MindMapView.js.map +1 -0
  142. package/dist/components/MindMapView.vue_vue_type_script_setup_true_lang.js +2 -0
  143. package/dist/components/MindMapView.vue_vue_type_script_setup_true_lang.js.map +1 -0
  144. package/dist/components/MissingDependency.js +2 -0
  145. package/dist/components/MissingDependency.js.map +1 -0
  146. package/dist/components/MissingDependency.vue_vue_type_script_setup_true_lang.js +2 -0
  147. package/dist/components/MissingDependency.vue_vue_type_script_setup_true_lang.js.map +1 -0
  148. package/dist/components/ModelViewer.js +2 -0
  149. package/dist/components/ModelViewer.js.map +1 -0
  150. package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  151. package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  152. package/dist/components/MsiViewer.js +2 -0
  153. package/dist/components/MsiViewer.js.map +1 -0
  154. package/dist/components/MsiViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  155. package/dist/components/MsiViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  156. package/dist/components/NotebookViewer.js +2 -0
  157. package/dist/components/NotebookViewer.js.map +1 -0
  158. package/dist/components/NotebookViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  159. package/dist/components/NotebookViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  160. package/dist/components/PdfViewer.js +2 -0
  161. package/dist/components/PdfViewer.js.map +1 -0
  162. package/dist/components/PdfViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  163. package/dist/components/PdfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  164. package/dist/components/PptxNavigationPane.js +9 -0
  165. package/dist/components/PptxNavigationPane.js.map +1 -0
  166. package/dist/components/PptxNavigationPane.vue.d.ts +20 -0
  167. package/dist/components/PptxNavigationPane.vue_vue_type_script_setup_true_lang.js +120 -0
  168. package/dist/components/PptxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -0
  169. package/dist/components/PptxViewer.js +3 -1
  170. package/dist/components/PptxViewer.js.map +1 -0
  171. package/dist/components/PptxViewer.vue_vue_type_script_setup_true_lang.js +71 -39
  172. package/dist/components/PptxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  173. package/dist/components/PsdViewer.js +2 -0
  174. package/dist/components/PsdViewer.js.map +1 -0
  175. package/dist/components/PsdViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  176. package/dist/components/PsdViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  177. package/dist/components/QmcAudioViewer.js +2 -0
  178. package/dist/components/QmcAudioViewer.js.map +1 -0
  179. package/dist/components/QmcAudioViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  180. package/dist/components/QmcAudioViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  181. package/dist/components/RasterViewer.js +2 -0
  182. package/dist/components/RasterViewer.js.map +1 -0
  183. package/dist/components/RasterViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  184. package/dist/components/RasterViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  185. package/dist/components/RtfViewer.js +2 -0
  186. package/dist/components/RtfViewer.js.map +1 -0
  187. package/dist/components/RtfViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  188. package/dist/components/RtfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  189. package/dist/components/SevenZipBrowser.js +2 -0
  190. package/dist/components/SevenZipBrowser.js.map +1 -0
  191. package/dist/components/SevenZipBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  192. package/dist/components/SevenZipBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  193. package/dist/components/SqliteViewer.js +2 -0
  194. package/dist/components/SqliteViewer.js.map +1 -0
  195. package/dist/components/SqliteViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  196. package/dist/components/SqliteViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  197. package/dist/components/SubtitleViewer.js +2 -0
  198. package/dist/components/SubtitleViewer.js.map +1 -0
  199. package/dist/components/SubtitleViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  200. package/dist/components/SubtitleViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  201. package/dist/components/XlsxChart.js +2 -0
  202. package/dist/components/XlsxChart.js.map +1 -0
  203. package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js +2 -0
  204. package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js.map +1 -0
  205. package/dist/components/XlsxViewer.js +3 -1
  206. package/dist/components/XlsxViewer.js.map +1 -0
  207. package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js +301 -304
  208. package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  209. package/dist/components/XmindViewer.js +2 -0
  210. package/dist/components/XmindViewer.js.map +1 -0
  211. package/dist/components/XmindViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  212. package/dist/components/XmindViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  213. package/dist/components/ZipBrowser.js +3 -1
  214. package/dist/components/ZipBrowser.js.map +1 -0
  215. package/dist/components/ZipBrowser.vue.d.ts +3 -1
  216. package/dist/components/ZipBrowser.vue_vue_type_script_setup_true_lang.js +154 -122
  217. package/dist/components/ZipBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  218. package/dist/components/ZoomImage.js +2 -0
  219. package/dist/components/ZoomImage.js.map +1 -0
  220. package/dist/components/ZoomImage.vue_vue_type_script_setup_true_lang.js +2 -0
  221. package/dist/components/ZoomImage.vue_vue_type_script_setup_true_lang.js.map +1 -0
  222. package/dist/components/epl/EplCodeBlock.js +2 -0
  223. package/dist/components/epl/EplCodeBlock.js.map +1 -0
  224. package/dist/components/epl/EplCodeBlock.vue_vue_type_script_setup_true_lang.js +2 -0
  225. package/dist/components/epl/EplCodeBlock.vue_vue_type_script_setup_true_lang.js.map +1 -0
  226. package/dist/components/epl/EplDoc.js +2 -0
  227. package/dist/components/epl/EplDoc.js.map +1 -0
  228. package/dist/components/epl/EplDoc.vue_vue_type_script_setup_true_lang.js +2 -0
  229. package/dist/components/epl/EplDoc.vue_vue_type_script_setup_true_lang.js.map +1 -0
  230. package/dist/components/epl/EplMethod.js +2 -0
  231. package/dist/components/epl/EplMethod.js.map +1 -0
  232. package/dist/components/epl/EplMethod.vue_vue_type_script_setup_true_lang.js +2 -0
  233. package/dist/components/epl/EplMethod.vue_vue_type_script_setup_true_lang.js.map +1 -0
  234. package/dist/components/epl/EplResource.js +2 -0
  235. package/dist/components/epl/EplResource.js.map +1 -0
  236. package/dist/components/epl/EplResource.vue_vue_type_script_setup_true_lang.js +2 -0
  237. package/dist/components/epl/EplResource.vue_vue_type_script_setup_true_lang.js.map +1 -0
  238. package/dist/components/epl/EplTree.js +2 -0
  239. package/dist/components/epl/EplTree.js.map +1 -0
  240. package/dist/components/epl/EplTree.vue_vue_type_script_setup_true_lang.js +2 -0
  241. package/dist/components/epl/EplTree.vue_vue_type_script_setup_true_lang.js.map +1 -0
  242. package/dist/components/epl/EplVarTable.js +2 -0
  243. package/dist/components/epl/EplVarTable.js.map +1 -0
  244. package/dist/components/epl/EplVarTable.vue_vue_type_script_setup_true_lang.js +2 -0
  245. package/dist/components/epl/EplVarTable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  246. package/dist/components/epl/numbering.js +2 -0
  247. package/dist/components/epl/numbering.js.map +1 -0
  248. package/dist/components/icons/Icon.js +2 -0
  249. package/dist/components/icons/Icon.js.map +1 -0
  250. package/dist/components/icons/Icon.vue_vue_type_script_setup_true_lang.js +2 -0
  251. package/dist/components/icons/Icon.vue_vue_type_script_setup_true_lang.js.map +1 -0
  252. package/dist/components/icons/iconPaths.js +2 -0
  253. package/dist/components/icons/iconPaths.js.map +1 -0
  254. package/dist/components/optionalViewer.js +2 -0
  255. package/dist/components/optionalViewer.js.map +1 -0
  256. package/dist/components/ui/ClampBlock.js +2 -0
  257. package/dist/components/ui/ClampBlock.js.map +1 -0
  258. package/dist/composables/useElementNavigation.d.ts +21 -0
  259. package/dist/composables/useElementNavigation.js +63 -0
  260. package/dist/composables/useElementNavigation.js.map +1 -0
  261. package/dist/composables/useFileViewer.js +2 -0
  262. package/dist/composables/useFileViewer.js.map +1 -0
  263. package/dist/composables/useLightbox.js +2 -0
  264. package/dist/composables/useLightbox.js.map +1 -0
  265. package/dist/composables/useLogRules.js +2 -0
  266. package/dist/composables/useLogRules.js.map +1 -0
  267. package/dist/lib/aes.js +2 -0
  268. package/dist/lib/aes.js.map +1 -0
  269. package/dist/lib/appx.js +2 -0
  270. package/dist/lib/appx.js.map +1 -0
  271. package/dist/lib/archiveHtml.d.ts +49 -0
  272. package/dist/lib/archiveHtml.js +377 -0
  273. package/dist/lib/archiveHtml.js.map +1 -0
  274. package/dist/lib/asn1.js +2 -0
  275. package/dist/lib/asn1.js.map +1 -0
  276. package/dist/lib/binobj.js +2 -0
  277. package/dist/lib/binobj.js.map +1 -0
  278. package/dist/lib/brotli.js +2 -0
  279. package/dist/lib/brotli.js.map +1 -0
  280. package/dist/lib/bzip2.js +2 -0
  281. package/dist/lib/bzip2.js.map +1 -0
  282. package/dist/lib/classfile.js +2 -0
  283. package/dist/lib/classfile.js.map +1 -0
  284. package/dist/lib/codePreview.js +2 -0
  285. package/dist/lib/codePreview.js.map +1 -0
  286. package/dist/lib/codefold.js +2 -0
  287. package/dist/lib/codefold.js.map +1 -0
  288. package/dist/lib/codeformat.js +2 -0
  289. package/dist/lib/codeformat.js.map +1 -0
  290. package/dist/lib/csv.js +2 -0
  291. package/dist/lib/csv.js.map +1 -0
  292. package/dist/lib/des.js +2 -0
  293. package/dist/lib/des.js.map +1 -0
  294. package/dist/lib/diagram.js +2 -0
  295. package/dist/lib/diagram.js.map +1 -0
  296. package/dist/lib/dicom.js +2 -0
  297. package/dist/lib/dicom.js.map +1 -0
  298. package/dist/lib/dicomCodecs.js +2 -0
  299. package/dist/lib/dicomCodecs.js.map +1 -0
  300. package/dist/lib/dicomRender.js +2 -0
  301. package/dist/lib/dicomRender.js.map +1 -0
  302. package/dist/lib/docxNavigation.d.ts +31 -0
  303. package/dist/lib/docxNavigation.js +65 -0
  304. package/dist/lib/docxNavigation.js.map +1 -0
  305. package/dist/lib/dxf.js +2 -0
  306. package/dist/lib/dxf.js.map +1 -0
  307. package/dist/lib/eml.js +2 -0
  308. package/dist/lib/eml.js.map +1 -0
  309. package/dist/lib/encoding.js +2 -0
  310. package/dist/lib/encoding.js.map +1 -0
  311. package/dist/lib/epl/code/codeDataParser.js +2 -0
  312. package/dist/lib/epl/code/codeDataParser.js.map +1 -0
  313. package/dist/lib/epl/code/codeLines.js +2 -0
  314. package/dist/lib/epl/code/codeLines.js.map +1 -0
  315. package/dist/lib/epl/code/textCode.js +2 -0
  316. package/dist/lib/epl/code/textCode.js.map +1 -0
  317. package/dist/lib/epl/eplDocument.js +2 -0
  318. package/dist/lib/epl/eplDocument.js.map +1 -0
  319. package/dist/lib/epl/imageList.js +2 -0
  320. package/dist/lib/epl/imageList.js.map +1 -0
  321. package/dist/lib/epl/index.js +2 -0
  322. package/dist/lib/epl/index.js.map +1 -0
  323. package/dist/lib/epl/io/binaryReader.js +2 -0
  324. package/dist/lib/epl/io/binaryReader.js.map +1 -0
  325. package/dist/lib/epl/io/encoding.js +2 -0
  326. package/dist/lib/epl/io/encoding.js.map +1 -0
  327. package/dist/lib/epl/model/eplSystemId.js +2 -0
  328. package/dist/lib/epl/model/eplSystemId.js.map +1 -0
  329. package/dist/lib/epl/names/eplLibData.js +2 -0
  330. package/dist/lib/epl/names/eplLibData.js.map +1 -0
  331. package/dist/lib/epl/names/idToNameMap.js +2 -0
  332. package/dist/lib/epl/names/idToNameMap.js.map +1 -0
  333. package/dist/lib/epl/names/libNameProvider.js +2 -0
  334. package/dist/lib/epl/names/libNameProvider.js.map +1 -0
  335. package/dist/lib/epl/program.js +2 -0
  336. package/dist/lib/epl/program.js.map +1 -0
  337. package/dist/lib/epl/projectFileReader.js +2 -0
  338. package/dist/lib/epl/projectFileReader.js.map +1 -0
  339. package/dist/lib/fb2.js +2 -0
  340. package/dist/lib/fb2.js.map +1 -0
  341. package/dist/lib/fileType.js +2 -0
  342. package/dist/lib/fileType.js.map +1 -0
  343. package/dist/lib/fonts.js +2 -0
  344. package/dist/lib/fonts.js.map +1 -0
  345. package/dist/lib/format.js +2 -0
  346. package/dist/lib/format.js.map +1 -0
  347. package/dist/lib/frontmatter.js +2 -0
  348. package/dist/lib/frontmatter.js.map +1 -0
  349. package/dist/lib/geo.js +2 -0
  350. package/dist/lib/geo.js.map +1 -0
  351. package/dist/lib/har.js +2 -0
  352. package/dist/lib/har.js.map +1 -0
  353. package/dist/lib/highlight.js +2 -0
  354. package/dist/lib/highlight.js.map +1 -0
  355. package/dist/lib/highlightLangs.js +2 -0
  356. package/dist/lib/highlightLangs.js.map +1 -0
  357. package/dist/lib/hprof.js +2 -0
  358. package/dist/lib/hprof.js.map +1 -0
  359. package/dist/lib/ipynb.js +2 -0
  360. package/dist/lib/ipynb.js.map +1 -0
  361. package/dist/lib/jks.js +2 -0
  362. package/dist/lib/jks.js.map +1 -0
  363. package/dist/lib/jsonl.js +2 -0
  364. package/dist/lib/jsonl.js.map +1 -0
  365. package/dist/lib/lrc.js +2 -0
  366. package/dist/lib/lrc.js.map +1 -0
  367. package/dist/lib/lzma.js +2 -0
  368. package/dist/lib/lzma.js.map +1 -0
  369. package/dist/lib/markdown/blocks.js +2 -0
  370. package/dist/lib/markdown/blocks.js.map +1 -0
  371. package/dist/lib/markdown/inline.js +2 -0
  372. package/dist/lib/markdown/inline.js.map +1 -0
  373. package/dist/lib/markdown/math.js +2 -0
  374. package/dist/lib/markdown/math.js.map +1 -0
  375. package/dist/lib/markdown/segmentize.js +2 -0
  376. package/dist/lib/markdown/segmentize.js.map +1 -0
  377. package/dist/lib/markdown/styles.js +2 -0
  378. package/dist/lib/markdown/styles.js.map +1 -0
  379. package/dist/lib/mht.js +2 -0
  380. package/dist/lib/mht.js.map +1 -0
  381. package/dist/lib/midi.js +2 -0
  382. package/dist/lib/midi.js.map +1 -0
  383. package/dist/lib/mime.js +2 -0
  384. package/dist/lib/mime.js.map +1 -0
  385. package/dist/lib/mindmap.js +2 -0
  386. package/dist/lib/mindmap.js.map +1 -0
  387. package/dist/lib/mobi.js +2 -0
  388. package/dist/lib/mobi.js.map +1 -0
  389. package/dist/lib/msi.js +2 -0
  390. package/dist/lib/msi.js.map +1 -0
  391. package/dist/lib/optionalDep.js +2 -0
  392. package/dist/lib/optionalDep.js.map +1 -0
  393. package/dist/lib/pkcs12.js +2 -0
  394. package/dist/lib/pkcs12.js.map +1 -0
  395. package/dist/lib/pptxNavigation.d.ts +7 -0
  396. package/dist/lib/pptxNavigation.js +29 -0
  397. package/dist/lib/pptxNavigation.js.map +1 -0
  398. package/dist/lib/qmc.js +2 -0
  399. package/dist/lib/qmc.js.map +1 -0
  400. package/dist/lib/rar.js +2 -0
  401. package/dist/lib/rar.js.map +1 -0
  402. package/dist/lib/rawPreview.js +2 -0
  403. package/dist/lib/rawPreview.js.map +1 -0
  404. package/dist/lib/rc2.js +2 -0
  405. package/dist/lib/rc2.js.map +1 -0
  406. package/dist/lib/resolveInput.js +2 -0
  407. package/dist/lib/resolveInput.js.map +1 -0
  408. package/dist/lib/rtf.js +2 -0
  409. package/dist/lib/rtf.js.map +1 -0
  410. package/dist/lib/sevenZip.js +2 -0
  411. package/dist/lib/sevenZip.js.map +1 -0
  412. package/dist/lib/sha1.js +2 -0
  413. package/dist/lib/sha1.js.map +1 -0
  414. package/dist/lib/sha256.js +2 -0
  415. package/dist/lib/sha256.js.map +1 -0
  416. package/dist/lib/speechAudio.js +2 -0
  417. package/dist/lib/speechAudio.js.map +1 -0
  418. package/dist/lib/sqlite.js +2 -0
  419. package/dist/lib/sqlite.js.map +1 -0
  420. package/dist/lib/subtitle.js +2 -0
  421. package/dist/lib/subtitle.js.map +1 -0
  422. package/dist/lib/tarball.js +2 -0
  423. package/dist/lib/tarball.js.map +1 -0
  424. package/dist/lib/viewerFormats.js +2 -0
  425. package/dist/lib/viewerFormats.js.map +1 -0
  426. package/dist/lib/viewerKind.js +2 -0
  427. package/dist/lib/viewerKind.js.map +1 -0
  428. package/dist/lib/x509.js +2 -0
  429. package/dist/lib/x509.js.map +1 -0
  430. package/dist/lib/xlsx.js +2 -0
  431. package/dist/lib/xlsx.js.map +1 -0
  432. package/dist/lib/xlsxCharts.js +2 -0
  433. package/dist/lib/xlsxCharts.js.map +1 -0
  434. package/dist/lib/xmind.js +2 -0
  435. package/dist/lib/xmind.js.map +1 -0
  436. package/dist/lib/zip.js +2 -0
  437. package/dist/lib/zip.js.map +1 -0
  438. package/dist/style.css +1 -1
  439. package/package.json +1 -1
@@ -2,8 +2,10 @@ import { fileExt as e, isDicomFile as t, isTextFile as n } from "../lib/fileType
2
2
  import { canToggleView as r, classifyViewerFile as i, mediaMimeForName as ee } from "../lib/viewerKind.js";
3
3
  import { formatBytes as a } from "../lib/format.js";
4
4
  import o from "./icons/Icon.js";
5
- import { ZipEncryptedError as te, ZipPasswordError as s, extractZipEntry as c, readZip as ne, zipSupported as re } from "../lib/zip.js";
6
- import { Fragment as l, computed as u, createBlock as d, createCommentVNode as f, createElementBlock as p, createElementVNode as m, createVNode as h, defineAsyncComponent as g, defineComponent as _, normalizeClass as v, normalizeStyle as ie, onBeforeUnmount as ae, onMounted as oe, openBlock as y, reactive as se, ref as b, renderList as ce, toDisplayString as x, unref as S, vModelText as le, watch as ue, withDirectives as de, withKeys as fe } from "vue";
5
+ import { decodeTextSniff as te } from "../lib/encoding.js";
6
+ import { ZipEncryptedError as s, ZipPasswordError as c, extractZipEntry as l, readZip as u, zipSupported as ne } from "../lib/zip.js";
7
+ import { buildArchiveHtmlPreview as re } from "../lib/archiveHtml.js";
8
+ import { Fragment as d, computed as f, createBlock as p, createCommentVNode as m, createElementBlock as h, createElementVNode as g, createVNode as _, defineAsyncComponent as v, defineComponent as y, normalizeClass as b, normalizeStyle as ie, onBeforeUnmount as ae, onMounted as oe, openBlock as x, reactive as se, ref as S, renderList as ce, toDisplayString as C, unref as w, vModelText as le, watch as ue, withDirectives as de, withKeys as fe } from "vue";
7
9
  //#region src/components/ZipBrowser.vue?vue&type=script&setup=true&lang.ts
8
10
  var pe = { class: "zip" }, me = {
9
11
  key: 0,
@@ -31,20 +33,20 @@ var pe = { class: "zip" }, me = {
31
33
  }, Oe = ["onClick"], ke = { class: "zip__twisty" }, Ae = { class: "zip__rowicon" }, je = { class: "zip__rowname" }, Me = {
32
34
  key: 1,
33
35
  class: "zip__rowsize"
34
- }, C = /*@__PURE__*/ _({
36
+ }, T = /*@__PURE__*/ y({
35
37
  __name: "ZipBrowser",
36
38
  props: {
37
39
  url: {},
38
40
  name: {}
39
41
  },
40
- setup(_) {
41
- let C = g(() => import("./DicomViewer.js")), Ne = g(() => import("./FileViewerBody.js")), w = _, T = b("loading"), E = b(""), D = null, O = b([]), k = b(""), A = b(""), j = b(!1), Pe = u(() => O.value.some((e) => e.encrypted)), M = b({
42
+ setup(y) {
43
+ let T = v(() => import("./DicomViewer.js")), Ne = v(() => import("./FileViewerBody.js")), E = y, D = S("loading"), O = S(""), k = null, A = S([]), j = S(""), M = S(""), N = S(!1), Pe = f(() => A.value.some((e) => e.encrypted)), P = S({
42
44
  name: "",
43
45
  path: "",
44
46
  isDir: !0,
45
47
  size: 0,
46
48
  children: []
47
- }), N = se(/* @__PURE__ */ new Set()), Fe = u(() => O.value.reduce((e, t) => e + +!t.isDir, 0)), Ie = u(() => O.value.reduce((e, t) => e + (t.isDir ? 0 : t.size), 0));
49
+ }), F = se(/* @__PURE__ */ new Set()), Fe = f(() => A.value.reduce((e, t) => e + +!t.isDir, 0)), Ie = f(() => A.value.reduce((e, t) => e + (t.isDir ? 0 : t.size), 0));
48
50
  function Le(e) {
49
51
  let t = {
50
52
  name: "",
@@ -83,244 +85,274 @@ var pe = { class: "zip" }, me = {
83
85
  children: []
84
86
  });
85
87
  }
86
- return P(t), t;
88
+ return I(t), t;
87
89
  }
88
- function P(e) {
90
+ function I(e) {
89
91
  e.children.sort((e, t) => e.isDir === t.isDir ? e.name.localeCompare(t.name) : e.isDir ? -1 : 1);
90
- for (let t of e.children) t.isDir && P(t);
92
+ for (let t of e.children) t.isDir && I(t);
91
93
  }
92
- let F = u(() => {
94
+ let L = f(() => {
93
95
  let e = [], t = (n, r) => {
94
96
  for (let i of n) e.push({
95
97
  node: i,
96
98
  depth: r
97
- }), i.isDir && N.has(i.path) && t(i.children, r + 1);
99
+ }), i.isDir && F.has(i.path) && t(i.children, r + 1);
98
100
  };
99
- return t(M.value.children, 0), e;
101
+ return t(P.value.children, 0), e;
100
102
  });
101
- async function I() {
102
- if (T.value = "loading", E.value = "", L.value = null, k.value = "", A.value = "", j.value = !1, J(), G.value = [], !re()) {
103
- E.value = "当前浏览器不支持在前端解压 ZIP(缺少 DecompressionStream)", T.value = "error";
103
+ async function R() {
104
+ if (J++, D.value = "loading", O.value = "", z.value = null, U.value = null, W.value = "", j.value = "", M.value = "", N.value = !1, X(), Y.value = [], !ne()) {
105
+ O.value = "当前浏览器不支持在前端解压 ZIP(缺少 DecompressionStream)", D.value = "error";
104
106
  return;
105
107
  }
106
108
  try {
107
- let e = await fetch(w.url);
109
+ let e = await fetch(E.url);
108
110
  if (!e.ok) throw Error(`HTTP ${e.status}`);
109
- D = await e.arrayBuffer();
110
- let t = ne(D);
111
- O.value = t, M.value = Le(t), N.clear(), T.value = "ready";
111
+ k = await e.arrayBuffer();
112
+ let t = u(k);
113
+ A.value = t, P.value = Le(t), F.clear(), D.value = "ready";
112
114
  } catch (e) {
113
- E.value = e instanceof Error ? e.message : String(e), T.value = "error";
115
+ O.value = e instanceof Error ? e.message : String(e), D.value = "error";
114
116
  }
115
117
  }
116
- let L = b(null), R = b("ready"), z = b(""), B = b(""), V = b(null), H = b(!1), U = b("render"), W = b(""), G = b([]), K = b(0), q = b(""), Re = u(() => G.value.reduce((e, t) => e + (t.size ?? 0), 0)), ze = u(() => r(V.value, B.value));
117
- function J() {
118
- W.value &&= (URL.revokeObjectURL(W.value), "");
118
+ let z = S(null), B = S("ready"), V = S(""), H = S(""), U = S(null), W = S(""), G = S(!1), K = S("render"), q = S(""), J = 0, Y = S([]), Re = S(0), ze = S(""), Be = f(() => Y.value.reduce((e, t) => e + (t.size ?? 0), 0)), Ve = f(() => r(U.value, H.value));
119
+ function X() {
120
+ q.value &&= (URL.revokeObjectURL(q.value), "");
119
121
  }
120
- function Y(e) {
122
+ function Z(e) {
121
123
  let t = e.lastIndexOf("/");
122
124
  return t < 0 ? "" : e.slice(0, t);
123
125
  }
124
- function Be(e) {
125
- let n = Y(e.path);
126
- return O.value.filter((e) => !e.isDir && t(e.name) && Y(e.path) === n).sort((e, t) => e.path.localeCompare(t.path, void 0, {
126
+ function He(e) {
127
+ let n = Z(e.path);
128
+ return A.value.filter((e) => !e.isDir && t(e.name) && Z(e.path) === n).sort((e, t) => e.path.localeCompare(t.path, void 0, {
127
129
  numeric: !0,
128
130
  sensitivity: "base"
129
131
  }));
130
132
  }
131
- function Ve(t, r) {
133
+ function Ue(t, r) {
132
134
  if (n(r)) return !0;
133
135
  if (e(r)) return !1;
134
136
  let i = Math.min(t.length, 4096);
135
137
  for (let e = 0; e < i; e++) if (t[e] === 0) return !1;
136
138
  return !0;
137
139
  }
138
- async function X(e) {
139
- if (L.value = e, R.value = "loading", z.value = "", B.value = "", V.value = null, H.value = !1, U.value = "render", J(), G.value = [], D) try {
140
+ async function We(e) {
141
+ let n = ++J, r = "";
142
+ if (z.value = e, B.value = "loading", V.value = "", H.value = "", U.value = null, W.value = "", G.value = !1, K.value = "render", X(), Y.value = [], k) try {
140
143
  if (t(e.name)) {
141
- let t = Be(e);
144
+ let t = He(e);
142
145
  if (t.length > 1) {
143
- G.value = t.map((e) => ({
146
+ Y.value = t.map((e) => ({
144
147
  name: e.name,
145
148
  size: e.size,
146
149
  load: async () => {
147
- let t = await c(D, e, k.value), n = new ArrayBuffer(t.byteLength);
150
+ let t = await l(k, e, j.value), n = new ArrayBuffer(t.byteLength);
148
151
  return new Uint8Array(n).set(t), n;
149
152
  }
150
- })), K.value = Math.max(0, t.findIndex((t) => t.path === e.path)), q.value = Y(e.path).split("/").pop() || e.name, H.value = !0, R.value = "ready";
153
+ })), Re.value = Math.max(0, t.findIndex((t) => t.path === e.path)), ze.value = Z(e.path).split("/").pop() || e.name, G.value = !0, B.value = "ready";
151
154
  return;
152
155
  }
153
156
  }
154
- let n = await c(D, e, k.value);
155
- if (L.value !== e) return;
156
- W.value = URL.createObjectURL(new Blob([n], { type: ee(e.name) })), V.value = i({
157
+ let a = k, o = await l(a, e, j.value);
158
+ if (J !== n || z.value !== e) return;
159
+ let s = URL.createObjectURL(new Blob([o], { type: ee(e.name) }));
160
+ r = s;
161
+ let c = i({
157
162
  name: e.name,
158
- url: W.value,
163
+ url: s,
159
164
  size: e.size,
160
- textHint: Ve(n, e.name)
161
- }), R.value = "ready";
165
+ textHint: Ue(o, e.name)
166
+ }), u = "";
167
+ if (c.html) {
168
+ let t = te(o);
169
+ c.content = t;
170
+ let i = await re({
171
+ html: t,
172
+ documentPath: e.path,
173
+ entries: A.value,
174
+ loadEntry: (e) => l(a, e, j.value)
175
+ });
176
+ if (J !== n || z.value !== e) {
177
+ URL.revokeObjectURL(s), r = "";
178
+ return;
179
+ }
180
+ u = i.html;
181
+ }
182
+ if (J !== n || z.value !== e) {
183
+ URL.revokeObjectURL(s), r = "";
184
+ return;
185
+ }
186
+ q.value = s, r = "", W.value = u, U.value = c, B.value = "ready";
162
187
  } catch (e) {
163
- e instanceof te ? z.value = "该文件已加密:请返回列表并在顶部输入密码" : e instanceof s ? (z.value = "密码错误", j.value = !1) : z.value = e instanceof Error ? e.message : String(e), R.value = "error";
188
+ r && URL.revokeObjectURL(r), e instanceof s ? V.value = "该文件已加密:请返回列表并在顶部输入密码" : e instanceof c ? (V.value = "密码错误", N.value = !1) : V.value = e instanceof Error ? e.message : String(e), B.value = "error";
164
189
  }
165
190
  }
166
- async function Z() {
167
- A.value = "";
168
- let e = O.value.find((e) => !e.isDir && e.encrypted && e.size > 0);
169
- if (!e || !D) {
170
- j.value = !0;
191
+ async function Ge() {
192
+ M.value = "";
193
+ let e = A.value.find((e) => !e.isDir && e.encrypted && e.size > 0);
194
+ if (!e || !k) {
195
+ N.value = !0;
171
196
  return;
172
197
  }
173
198
  try {
174
- await c(D, e, k.value), j.value = !0, L.value && X(L.value);
199
+ await l(k, e, j.value), N.value = !0, z.value && We(z.value);
175
200
  } catch (e) {
176
- j.value = !1, A.value = e instanceof s ? "密码错误" : e instanceof Error ? e.message : String(e);
201
+ N.value = !1, M.value = e instanceof c ? "密码错误" : e instanceof Error ? e.message : String(e);
177
202
  }
178
203
  }
179
- function He(e) {
180
- e.isDir ? N.has(e.path) ? N.delete(e.path) : N.add(e.path) : e.entry && X(e.entry);
204
+ function Ke(e) {
205
+ e.isDir ? F.has(e.path) ? F.delete(e.path) : F.add(e.path) : e.entry && We(e.entry);
181
206
  }
182
- function Ue() {
183
- L.value = null, B.value = "", V.value = null, H.value = !1, J(), G.value = [];
207
+ function qe() {
208
+ J++, z.value = null, H.value = "", U.value = null, W.value = "", G.value = !1, X(), Y.value = [];
184
209
  }
185
- async function We(e) {
186
- if (D) try {
187
- let t = URL.createObjectURL(new Blob([await c(D, e, k.value)])), n = document.createElement("a");
210
+ async function Je(e) {
211
+ if (k) try {
212
+ let t = URL.createObjectURL(new Blob([await l(k, e, j.value)])), n = document.createElement("a");
188
213
  n.href = t, n.download = e.name, document.body.appendChild(n), n.click(), n.remove(), setTimeout(() => URL.revokeObjectURL(t), 1e3);
189
214
  } catch {}
190
215
  }
191
- let Q = b(!1), $;
192
- async function Ge() {
216
+ let Q = S(!1), $;
217
+ async function Ye() {
193
218
  try {
194
- await navigator.clipboard?.writeText(B.value);
219
+ await navigator.clipboard?.writeText(H.value);
195
220
  } catch {}
196
221
  Q.value = !0, clearTimeout($), $ = setTimeout(() => Q.value = !1, 1400);
197
222
  }
198
- return oe(I), ue(() => w.url, I), ae(() => {
199
- J(), clearTimeout($);
200
- }), (e, t) => (y(), p("div", pe, [T.value === "loading" ? (y(), p("p", me, "正在解压…")) : T.value === "error" ? (y(), p("div", he, [m("p", null, x(E.value), 1), m("button", {
223
+ return oe(R), ue(() => E.url, R), ae(() => {
224
+ J++, X(), clearTimeout($);
225
+ }), (e, t) => (x(), h("div", pe, [D.value === "loading" ? (x(), h("p", me, "正在解压…")) : D.value === "error" ? (x(), h("div", he, [g("p", null, C(O.value), 1), g("button", {
201
226
  type: "button",
202
227
  class: "zip__retry",
203
- onClick: I
204
- }, "重试")])) : L.value ? (y(), p(l, { key: 2 }, [m("div", ge, [
205
- m("button", {
228
+ onClick: R
229
+ }, "重试")])) : z.value ? (x(), h(d, { key: 2 }, [g("div", ge, [
230
+ g("button", {
206
231
  type: "button",
207
232
  class: "zip__back",
208
233
  title: "返回列表",
209
- onClick: Ue
210
- }, [h(o, {
234
+ onClick: qe
235
+ }, [_(o, {
211
236
  name: "arrowLeft",
212
237
  size: 16
213
238
  })]),
214
- m("span", {
239
+ g("span", {
215
240
  class: "zip__path",
216
- title: L.value.path
217
- }, x(L.value.path), 9, _e),
218
- m("span", ve, x(S(a)(L.value.size)), 1),
219
- ze.value ? (y(), p("div", ye, [m("button", {
241
+ title: z.value.path
242
+ }, C(z.value.path), 9, _e),
243
+ g("span", ve, C(w(a)(z.value.size)), 1),
244
+ Ve.value ? (x(), h("div", ye, [g("button", {
220
245
  type: "button",
221
- class: v(["zip__vbtn", { "zip__vbtn--on": U.value === "render" }]),
246
+ class: b(["zip__vbtn", { "zip__vbtn--on": K.value === "render" }]),
222
247
  title: "渲染",
223
- onClick: t[0] ||= (e) => U.value = "render"
224
- }, [h(o, {
248
+ onClick: t[0] ||= (e) => K.value = "render"
249
+ }, [_(o, {
225
250
  name: "eye",
226
251
  size: 14
227
- })], 2), m("button", {
252
+ })], 2), g("button", {
228
253
  type: "button",
229
- class: v(["zip__vbtn", { "zip__vbtn--on": U.value === "source" }]),
254
+ class: b(["zip__vbtn", { "zip__vbtn--on": K.value === "source" }]),
230
255
  title: "源码",
231
- onClick: t[1] ||= (e) => U.value = "source"
232
- }, [h(o, {
256
+ onClick: t[1] ||= (e) => K.value = "source"
257
+ }, [_(o, {
233
258
  name: "code",
234
259
  size: 14
235
- })], 2)])) : f("", !0),
236
- B.value && R.value === "ready" ? (y(), p("button", {
260
+ })], 2)])) : m("", !0),
261
+ H.value && B.value === "ready" ? (x(), h("button", {
237
262
  key: 1,
238
263
  type: "button",
239
264
  class: "zip__act",
240
265
  title: Q.value ? "已复制" : "复制",
241
- onClick: Ge
242
- }, [h(o, {
266
+ onClick: Ye
267
+ }, [_(o, {
243
268
  name: "copy",
244
269
  size: 14
245
- })], 8, be)) : f("", !0),
246
- m("button", {
270
+ })], 8, be)) : m("", !0),
271
+ g("button", {
247
272
  type: "button",
248
273
  class: "zip__act",
249
274
  title: "下载",
250
- onClick: t[2] ||= (e) => We(L.value)
251
- }, [h(o, {
275
+ onClick: t[2] ||= (e) => Je(z.value)
276
+ }, [_(o, {
252
277
  name: "download",
253
278
  size: 15
254
279
  })])
255
- ]), R.value === "loading" ? (y(), p("p", xe, "读取中…")) : R.value === "error" ? (y(), p("div", Se, [m("p", null, x(z.value), 1)])) : H.value ? (y(), d(S(C), {
280
+ ]), B.value === "loading" ? (x(), h("p", xe, "读取中…")) : B.value === "error" ? (x(), h("div", Se, [g("p", null, C(V.value), 1)])) : G.value ? (x(), p(w(T), {
256
281
  key: 2,
257
- slices: G.value,
258
- start: K.value,
259
- name: q.value,
260
- size: Re.value
282
+ slices: Y.value,
283
+ start: Re.value,
284
+ name: ze.value,
285
+ size: Be.value
261
286
  }, null, 8, [
262
287
  "slices",
263
288
  "start",
264
289
  "name",
265
290
  "size"
266
- ])) : V.value ? (y(), d(S(Ne), {
291
+ ])) : U.value ? (x(), p(w(Ne), {
267
292
  key: 3,
268
- file: V.value,
269
- mode: U.value,
270
- onLoaded: t[3] ||= (e) => B.value = e
271
- }, null, 8, ["file", "mode"])) : f("", !0)], 64)) : (y(), p(l, { key: 3 }, [
272
- m("div", Ce, x(Fe.value) + " 个文件 · " + x(S(a)(Ie.value)), 1),
273
- Pe.value ? (y(), p("div", {
293
+ file: U.value,
294
+ mode: K.value,
295
+ "html-preview": W.value || void 0,
296
+ onLoaded: t[3] ||= (e) => H.value = e
297
+ }, null, 8, [
298
+ "file",
299
+ "mode",
300
+ "html-preview"
301
+ ])) : m("", !0)], 64)) : (x(), h(d, { key: 3 }, [
302
+ g("div", Ce, C(Fe.value) + " 个文件 · " + C(w(a)(Ie.value)), 1),
303
+ Pe.value ? (x(), h("div", {
274
304
  key: 0,
275
- class: v(["zip__pw", { "zip__pw--ok": j.value }])
305
+ class: b(["zip__pw", { "zip__pw--ok": N.value }])
276
306
  }, [
277
- h(o, {
307
+ _(o, {
278
308
  name: "key",
279
309
  size: 14
280
310
  }),
281
- de(m("input", {
282
- "onUpdate:modelValue": t[4] ||= (e) => k.value = e,
311
+ de(g("input", {
312
+ "onUpdate:modelValue": t[4] ||= (e) => j.value = e,
283
313
  type: "password",
284
314
  class: "zip__pwinput",
285
- placeholder: j.value ? "已解锁(如需可重新输入)" : "此压缩包已加密,输入密码解锁",
286
- onKeyup: fe(Z, ["enter"])
287
- }, null, 40, we), [[le, k.value]]),
288
- m("button", {
315
+ placeholder: N.value ? "已解锁(如需可重新输入)" : "此压缩包已加密,输入密码解锁",
316
+ onKeyup: fe(Ge, ["enter"])
317
+ }, null, 40, we), [[le, j.value]]),
318
+ g("button", {
289
319
  type: "button",
290
320
  class: "zip__pwbtn",
291
- onClick: Z
292
- }, x(j.value ? "已解锁" : "解锁"), 1),
293
- A.value ? (y(), p("span", Te, x(A.value), 1)) : f("", !0)
294
- ], 2)) : f("", !0),
295
- m("div", Ee, [F.value.length === 0 ? (y(), p("p", De, "空压缩包")) : f("", !0), (y(!0), p(l, null, ce(F.value, (e) => (y(), p("button", {
321
+ onClick: Ge
322
+ }, C(N.value ? "已解锁" : "解锁"), 1),
323
+ M.value ? (x(), h("span", Te, C(M.value), 1)) : m("", !0)
324
+ ], 2)) : m("", !0),
325
+ g("div", Ee, [L.value.length === 0 ? (x(), h("p", De, "空压缩包")) : m("", !0), (x(!0), h(d, null, ce(L.value, (e) => (x(), h("button", {
296
326
  key: e.node.path,
297
327
  type: "button",
298
- class: v(["zip__row", { "zip__row--dir": e.node.isDir }]),
328
+ class: b(["zip__row", { "zip__row--dir": e.node.isDir }]),
299
329
  style: ie({ paddingLeft: `${12 + e.depth * 14}px` }),
300
- onClick: (t) => He(e.node)
330
+ onClick: (t) => Ke(e.node)
301
331
  }, [
302
- m("span", ke, [e.node.isDir ? (y(), d(o, {
332
+ g("span", ke, [e.node.isDir ? (x(), p(o, {
303
333
  key: 0,
304
334
  name: "chevronRight",
305
335
  size: 13,
306
- class: v({ "zip__twisty--open": N.has(e.node.path) })
307
- }, null, 8, ["class"])) : f("", !0)]),
308
- m("span", Ae, [h(o, {
336
+ class: b({ "zip__twisty--open": F.has(e.node.path) })
337
+ }, null, 8, ["class"])) : m("", !0)]),
338
+ g("span", Ae, [_(o, {
309
339
  name: e.node.isDir ? "folder" : "fileOutline",
310
340
  size: 15
311
341
  }, null, 8, ["name"])]),
312
- m("span", je, x(e.node.name), 1),
313
- e.node.entry?.encrypted ? (y(), d(o, {
342
+ g("span", je, C(e.node.name), 1),
343
+ e.node.entry?.encrypted ? (x(), p(o, {
314
344
  key: 0,
315
345
  name: "key",
316
346
  size: 12,
317
347
  class: "zip__rowlock",
318
348
  title: "已加密"
319
- })) : f("", !0),
320
- e.node.isDir ? f("", !0) : (y(), p("span", Me, x(S(a)(e.node.size)), 1))
349
+ })) : m("", !0),
350
+ e.node.isDir ? m("", !0) : (x(), h("span", Me, C(w(a)(e.node.size)), 1))
321
351
  ], 14, Oe))), 128))])
322
352
  ], 64))]));
323
353
  }
324
354
  });
325
355
  //#endregion
326
- export { C as default };
356
+ export { T as default };
357
+
358
+ //# sourceMappingURL=ZipBrowser.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ZipBrowser.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../src/components/ZipBrowser.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n computed,\n defineAsyncComponent,\n onBeforeUnmount,\n onMounted,\n reactive,\n ref,\n watch,\n} from 'vue'\nimport {\n extractZipEntry,\n readZip,\n zipSupported,\n ZipEncryptedError,\n ZipPasswordError,\n type ZipEntry,\n} from '@/lib/zip'\nimport type { DicomSlice } from '@/lib/dicom'\nimport type { ViewerFile } from '@/composables/useFileViewer'\nimport { fileExt, isDicomFile, isTextFile } from '@/lib/fileType'\nimport { canToggleView, classifyViewerFile, mediaMimeForName } from '@/lib/viewerKind'\nimport { buildArchiveHtmlPreview } from '@/lib/archiveHtml'\nimport { decodeTextSniff } from '@/lib/encoding'\nimport { formatBytes } from '@/lib/format'\nimport Icon from '@/components/icons/Icon.vue'\n\n// A folder of sibling .dcm files browses as one scrollable series — FileViewerBody has no slice model, so the\n// DICOM stack stays a direct hand-off here (a lone .dcm goes through the body like any other entry).\nconst DicomViewer = defineAsyncComponent(() => import('@/components/DicomViewer.vue'))\n\n// The shared side-viewer body renders a selected entry with the SAME viewers as a top-level file. Lazy-imported\n// to break the module cycle (the body lazy-imports this browser back, for nested archives).\nconst FileViewerBody = defineAsyncComponent(() => import('@/components/FileViewerBody.vue'))\n\n/**\n * The side viewer's ZIP mode: fetch an archive's bytes, decompress them entirely in-browser (see lib/zip.ts),\n * and browse the contents. A master→detail within the narrow pane — a collapsible file tree, and selecting an\n * entry extracts just that one, wraps it in a blob URL, and hands it to {@link FileViewerBody} (so a file\n * inside the zip previews with every viewer a top-level file gets — code/image/pdf/cert/audio/nested-zip/…).\n * HTML is the one multi-entry case: its relative JS/CSS/image/font dependencies are resolved from the same ZIP\n * and rewritten before entering the existing sandboxed iframe. Other entry bytes are not retained; selecting\n * decodes on demand, and the download button re-extracts.\n */\nconst props = defineProps<{ url: string; name: string }>()\n\ntype Status = 'loading' | 'ready' | 'error'\nconst status = ref<Status>('loading')\nconst errorMsg = ref('')\nlet buffer: ArrayBuffer | null = null\nconst entries = ref<ZipEntry[]>([])\n\n// Encrypted archives: a password bar appears once any entry is encrypted. The password is held only in memory\n// and passed to each extraction (ZipCrypto / WinZip AES decrypt happens in lib/zip.ts).\nconst password = ref('')\nconst pwError = ref('')\nconst unlocked = ref(false)\nconst anyEncrypted = computed(() => entries.value.some((e) => e.encrypted))\n\ninterface TreeNode {\n name: string\n path: string\n isDir: boolean\n size: number\n entry?: ZipEntry\n children: TreeNode[]\n}\nconst root = ref<TreeNode>({ name: '', path: '', isDir: true, size: 0, children: [] })\nconst expanded = reactive(new Set<string>())\n\nconst fileCount = computed(() => entries.value.reduce((n, e) => n + (e.isDir ? 0 : 1), 0))\nconst totalSize = computed(() => entries.value.reduce((s, e) => s + (e.isDir ? 0 : e.size), 0))\n\n// Build a folder tree from the flat entry paths (directories may be implicit — derive them either way).\nfunction buildTree(list: ZipEntry[]): TreeNode {\n const rootNode: TreeNode = { name: '', path: '', isDir: true, size: 0, children: [] }\n const dirs = new Map<string, TreeNode>([['', rootNode]])\n const ensureDir = (segs: string[]): TreeNode => {\n let cur = rootNode\n let acc = ''\n for (const seg of segs) {\n acc = acc ? `${acc}/${seg}` : seg\n let node = dirs.get(acc)\n if (!node) {\n node = { name: seg, path: acc, isDir: true, size: 0, children: [] }\n dirs.set(acc, node)\n cur.children.push(node)\n }\n cur = node\n }\n return cur\n }\n for (const e of list) {\n const segs = e.path.split('/').filter(Boolean)\n if (e.isDir) {\n ensureDir(segs)\n continue\n }\n const fname = segs.pop()\n if (!fname) continue\n ensureDir(segs).children.push({\n name: fname,\n path: e.path,\n isDir: false,\n size: e.size,\n entry: e,\n children: [],\n })\n }\n sortNode(rootNode)\n return rootNode\n}\n// Folders first, then files, each alphabetical (case-insensitive).\nfunction sortNode(n: TreeNode): void {\n n.children.sort((a, b) => (a.isDir === b.isDir ? a.name.localeCompare(b.name) : a.isDir ? -1 : 1))\n for (const c of n.children) if (c.isDir) sortNode(c)\n}\n\n// Flatten the tree to the rows currently visible (respecting which folders are expanded).\ninterface Row {\n node: TreeNode\n depth: number\n}\nconst rows = computed<Row[]>(() => {\n const out: Row[] = []\n const walk = (nodes: TreeNode[], depth: number): void => {\n for (const n of nodes) {\n out.push({ node: n, depth })\n if (n.isDir && expanded.has(n.path)) walk(n.children, depth + 1)\n }\n }\n walk(root.value.children, 0)\n return out\n})\n\nasync function load(): Promise<void> {\n selectionRun++\n status.value = 'loading'\n errorMsg.value = ''\n selected.value = null\n entryFile.value = null\n entryHtmlPreview.value = ''\n password.value = ''\n pwError.value = ''\n unlocked.value = false\n revokeBlob()\n stackSlices.value = []\n if (!zipSupported()) {\n errorMsg.value = '当前浏览器不支持在前端解压 ZIP(缺少 DecompressionStream)'\n status.value = 'error'\n return\n }\n try {\n const res = await fetch(props.url)\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n buffer = await res.arrayBuffer()\n const list = readZip(buffer)\n entries.value = list\n root.value = buildTree(list)\n expanded.clear()\n status.value = 'ready'\n } catch (e) {\n errorMsg.value = e instanceof Error ? e.message : String(e)\n status.value = 'error'\n }\n}\n\n// ── selected entry (detail view) ──────────────────────────────────────────────────────────────\nconst selected = ref<ZipEntry | null>(null)\nconst entryStatus = ref<Status>('ready') // covers extraction; the body owns loading once entryFile is set\nconst entryErr = ref('')\nconst entryText = ref('') // the body emits loaded text up so the copy button can use it\nconst entryFile = ref<ViewerFile | null>(null)\nconst entryHtmlPreview = ref('') // dependency-rewritten HTML; source/copy still use the original text\nconst entryStack = ref(false) // DICOM series (handled directly, not via the body)\nconst entryMode = ref<'render' | 'source'>('render')\nconst blobUrl = ref('') // entry blob URL fed to the body (revoked on change/unmount)\nlet selectionRun = 0 // stale guard for async HTML dependency extraction (including selecting the same row twice)\n\n// DICOM series stack: when the clicked .dcm has sibling .dcm files in the same folder, they are browsed as\n// one scrollable series. Slices extract lazily; the DICOM viewer caches/prefetches them.\nconst stackSlices = ref<DicomSlice[]>([])\nconst stackStart = ref(0)\nconst stackName = ref('')\nconst stackTotalSize = computed(() => stackSlices.value.reduce((s, sl) => s + (sl.size ?? 0), 0))\n\nconst canToggle = computed(() => canToggleView(entryFile.value, entryText.value))\n\nfunction revokeBlob(): void {\n if (blobUrl.value) {\n URL.revokeObjectURL(blobUrl.value)\n blobUrl.value = ''\n }\n}\n\nfunction dirOf(path: string): string {\n const i = path.lastIndexOf('/')\n return i < 0 ? '' : path.slice(0, i)\n}\n// Sibling .dcm files in the same folder, natural-sorted (numeric-aware) so e.g. img2 precedes img10.\nfunction dicomSiblings(e: ZipEntry): ZipEntry[] {\n const dir = dirOf(e.path)\n return entries.value\n .filter((x) => !x.isDir && isDicomFile(x.name) && dirOf(x.path) === dir)\n .sort((a, b) => a.path.localeCompare(b.path, undefined, { numeric: true, sensitivity: 'base' }))\n}\n\n// Treat as text if the name says so; for extensionless entries, sniff the first bytes for NULs. Feeds the\n// body's source fall-back so an extensionless text file still opens as source instead of a download card.\nfunction looksText(bytes: Uint8Array, name: string): boolean {\n if (isTextFile(name)) return true\n if (fileExt(name)) return false\n const n = Math.min(bytes.length, 4096)\n for (let i = 0; i < n; i++) if (bytes[i] === 0) return false\n return true\n}\n\nasync function selectEntry(e: ZipEntry): Promise<void> {\n const run = ++selectionRun\n let pendingUrl = ''\n selected.value = e\n entryStatus.value = 'loading'\n entryErr.value = ''\n entryText.value = ''\n entryFile.value = null\n entryHtmlPreview.value = ''\n entryStack.value = false\n entryMode.value = 'render'\n revokeBlob()\n stackSlices.value = []\n if (!buffer) return\n try {\n // DICOM series: a folder holding several .dcm → browse them as one scrollable series (slices on demand).\n if (isDicomFile(e.name)) {\n const siblings = dicomSiblings(e)\n if (siblings.length > 1) {\n stackSlices.value = siblings.map((se) => ({\n name: se.name,\n size: se.size,\n load: async () => {\n const u = await extractZipEntry(buffer as ArrayBuffer, se, password.value)\n const out = new ArrayBuffer(u.byteLength)\n new Uint8Array(out).set(u)\n return out\n },\n }))\n stackStart.value = Math.max(\n 0,\n siblings.findIndex((se) => se.path === e.path),\n )\n stackName.value = dirOf(e.path).split('/').pop() || e.name\n entryStack.value = true\n entryStatus.value = 'ready'\n return\n }\n }\n const archiveBuffer = buffer\n const bytes = await extractZipEntry(archiveBuffer, e, password.value)\n if (selectionRun !== run || selected.value !== e) return\n const url = URL.createObjectURL(new Blob([bytes], { type: mediaMimeForName(e.name) }))\n pendingUrl = url\n const file = classifyViewerFile({\n name: e.name,\n url,\n size: e.size,\n textHint: looksText(bytes, e.name),\n })\n let htmlPreview = ''\n if (file.html) {\n const source = decodeTextSniff(bytes)\n file.content = source\n const preview = await buildArchiveHtmlPreview({\n html: source,\n documentPath: e.path,\n entries: entries.value,\n loadEntry: (dependency) => extractZipEntry(archiveBuffer, dependency, password.value),\n })\n if (selectionRun !== run || selected.value !== e) {\n URL.revokeObjectURL(url)\n pendingUrl = ''\n return\n }\n htmlPreview = preview.html\n }\n if (selectionRun !== run || selected.value !== e) {\n URL.revokeObjectURL(url)\n pendingUrl = ''\n return\n }\n blobUrl.value = url\n pendingUrl = ''\n entryHtmlPreview.value = htmlPreview\n entryFile.value = file\n entryStatus.value = 'ready'\n } catch (err) {\n if (pendingUrl) URL.revokeObjectURL(pendingUrl)\n if (err instanceof ZipEncryptedError)\n entryErr.value = '该文件已加密:请返回列表并在顶部输入密码'\n else if (err instanceof ZipPasswordError) {\n entryErr.value = '密码错误'\n unlocked.value = false\n } else entryErr.value = err instanceof Error ? err.message : String(err)\n entryStatus.value = 'error'\n }\n}\n\n// Validate the entered password against the first encrypted entry, then unlock (and re-open any selected file).\nasync function applyPassword(): Promise<void> {\n pwError.value = ''\n const enc = entries.value.find((e) => !e.isDir && e.encrypted && e.size > 0)\n if (!enc || !buffer) {\n unlocked.value = true\n return\n }\n try {\n await extractZipEntry(buffer, enc, password.value)\n unlocked.value = true\n if (selected.value) void selectEntry(selected.value)\n } catch (e) {\n unlocked.value = false\n pwError.value =\n e instanceof ZipPasswordError ? '密码错误' : e instanceof Error ? e.message : String(e)\n }\n}\n\nfunction onRow(node: TreeNode): void {\n if (node.isDir) {\n if (expanded.has(node.path)) expanded.delete(node.path)\n else expanded.add(node.path)\n } else if (node.entry) {\n void selectEntry(node.entry)\n }\n}\n\nfunction back(): void {\n selectionRun++\n selected.value = null\n entryText.value = ''\n entryFile.value = null\n entryHtmlPreview.value = ''\n entryStack.value = false\n revokeBlob()\n stackSlices.value = []\n}\n\n// Re-extract on demand so we don't retain decompressed bytes for the whole session.\nasync function downloadEntry(e: ZipEntry): Promise<void> {\n if (!buffer) return\n try {\n const url = URL.createObjectURL(new Blob([await extractZipEntry(buffer, e, password.value)]))\n const a = document.createElement('a')\n a.href = url\n a.download = e.name\n document.body.appendChild(a)\n a.click()\n a.remove()\n setTimeout(() => URL.revokeObjectURL(url), 1000)\n } catch {\n /* extraction failed — nothing to download */\n }\n}\n\nconst copied = ref(false)\nlet copyTimer: ReturnType<typeof setTimeout> | undefined\nasync function copyEntry(): Promise<void> {\n try {\n await navigator.clipboard?.writeText(entryText.value)\n } catch {\n /* clipboard unavailable — ignore */\n }\n copied.value = true\n clearTimeout(copyTimer)\n copyTimer = setTimeout(() => (copied.value = false), 1400)\n}\n\nonMounted(load)\nwatch(() => props.url, load)\nonBeforeUnmount(() => {\n selectionRun++\n revokeBlob()\n clearTimeout(copyTimer)\n})\n</script>\n\n<template>\n <div class=\"zip\">\n <p v-if=\"status === 'loading'\" class=\"zip__msg\">正在解压…</p>\n\n <div v-else-if=\"status === 'error'\" class=\"zip__msg zip__msg--error\">\n <p>{{ errorMsg }}</p>\n <button type=\"button\" class=\"zip__retry\" @click=\"load\">重试</button>\n </div>\n\n <!-- detail: one selected entry -->\n <template v-else-if=\"selected\">\n <div class=\"zip__bar\">\n <button type=\"button\" class=\"zip__back\" title=\"返回列表\" @click=\"back\">\n <Icon name=\"arrowLeft\" :size=\"16\" />\n </button>\n <span class=\"zip__path\" :title=\"selected.path\">{{ selected.path }}</span>\n <span class=\"zip__bsize\">{{ formatBytes(selected.size) }}</span>\n <div v-if=\"canToggle\" class=\"zip__view\" role=\"group\" aria-label=\"渲染或源码\">\n <button\n type=\"button\"\n class=\"zip__vbtn\"\n :class=\"{ 'zip__vbtn--on': entryMode === 'render' }\"\n title=\"渲染\"\n @click=\"entryMode = 'render'\"\n >\n <Icon name=\"eye\" :size=\"14\" />\n </button>\n <button\n type=\"button\"\n class=\"zip__vbtn\"\n :class=\"{ 'zip__vbtn--on': entryMode === 'source' }\"\n title=\"源码\"\n @click=\"entryMode = 'source'\"\n >\n <Icon name=\"code\" :size=\"14\" />\n </button>\n </div>\n <button\n v-if=\"entryText && entryStatus === 'ready'\"\n type=\"button\"\n class=\"zip__act\"\n :title=\"copied ? '已复制' : '复制'\"\n @click=\"copyEntry\"\n >\n <Icon name=\"copy\" :size=\"14\" />\n </button>\n <button type=\"button\" class=\"zip__act\" title=\"下载\" @click=\"downloadEntry(selected)\">\n <Icon name=\"download\" :size=\"15\" />\n </button>\n </div>\n\n <p v-if=\"entryStatus === 'loading'\" class=\"zip__msg\">读取中…</p>\n <div v-else-if=\"entryStatus === 'error'\" class=\"zip__msg zip__msg--error\">\n <p>{{ entryErr }}</p>\n </div>\n\n <!-- dicom series: a whole folder of .dcm slices browsed as one scrollable series (wheel/cine翻层) -->\n <DicomViewer\n v-else-if=\"entryStack\"\n :slices=\"stackSlices\"\n :start=\"stackStart\"\n :name=\"stackName\"\n :size=\"stackTotalSize\"\n />\n\n <!-- everything else: the shared body picks the right viewer from the extracted blob -->\n <FileViewerBody\n v-else-if=\"entryFile\"\n :file=\"entryFile\"\n :mode=\"entryMode\"\n :html-preview=\"entryHtmlPreview || undefined\"\n @loaded=\"entryText = $event\"\n />\n </template>\n\n <!-- list: the file tree -->\n <template v-else>\n <div class=\"zip__summary\">{{ fileCount }} 个文件 · {{ formatBytes(totalSize) }}</div>\n\n <!-- password bar: shown when the archive has encrypted entries (ZipCrypto / WinZip AES) -->\n <div v-if=\"anyEncrypted\" class=\"zip__pw\" :class=\"{ 'zip__pw--ok': unlocked }\">\n <Icon name=\"key\" :size=\"14\" />\n <input\n v-model=\"password\"\n type=\"password\"\n class=\"zip__pwinput\"\n :placeholder=\"unlocked ? '已解锁(如需可重新输入)' : '此压缩包已加密,输入密码解锁'\"\n @keyup.enter=\"applyPassword\"\n />\n <button type=\"button\" class=\"zip__pwbtn\" @click=\"applyPassword\">\n {{ unlocked ? '已解锁' : '解锁' }}\n </button>\n <span v-if=\"pwError\" class=\"zip__pwerr\">{{ pwError }}</span>\n </div>\n\n <div class=\"zip__scroll zip__tree\">\n <p v-if=\"rows.length === 0\" class=\"zip__msg\">空压缩包</p>\n <button\n v-for=\"row in rows\"\n :key=\"row.node.path\"\n type=\"button\"\n class=\"zip__row\"\n :class=\"{ 'zip__row--dir': row.node.isDir }\"\n :style=\"{ paddingLeft: `${12 + row.depth * 14}px` }\"\n @click=\"onRow(row.node)\"\n >\n <span class=\"zip__twisty\">\n <Icon\n v-if=\"row.node.isDir\"\n name=\"chevronRight\"\n :size=\"13\"\n :class=\"{ 'zip__twisty--open': expanded.has(row.node.path) }\"\n />\n </span>\n <span class=\"zip__rowicon\">\n <Icon :name=\"row.node.isDir ? 'folder' : 'fileOutline'\" :size=\"15\" />\n </span>\n <span class=\"zip__rowname\">{{ row.node.name }}</span>\n <Icon\n v-if=\"row.node.entry?.encrypted\"\n name=\"key\"\n :size=\"12\"\n class=\"zip__rowlock\"\n title=\"已加密\"\n />\n <span v-if=\"!row.node.isDir\" class=\"zip__rowsize\">{{ formatBytes(row.node.size) }}</span>\n </button>\n </div>\n </template>\n </div>\n</template>\n\n<style scoped>\n.zip {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n background: var(--surface);\n}\n\n.zip__msg {\n padding: 20px 16px;\n color: var(--muted);\n font-size: 13px;\n}\n.zip__msg--error {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 10px;\n color: var(--danger);\n}\n.zip__retry {\n font-family: inherit;\n font-size: 12.5px;\n color: var(--text);\n background: var(--surface);\n border: 1px solid var(--border-2);\n border-radius: 8px;\n padding: 5px 12px;\n cursor: pointer;\n}\n.zip__retry:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n\n/* List view ------------------------------------------------------------------------------------ */\n.zip__summary {\n flex-shrink: 0;\n padding: 9px 16px;\n border-bottom: 1px solid var(--border);\n font-size: 11.5px;\n letter-spacing: 0.02em;\n color: var(--faint);\n}\n/* Password bar (encrypted archives). */\n.zip__pw {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n padding: 8px 12px;\n border-bottom: 1px solid var(--border);\n background: var(--surface-2);\n color: var(--muted);\n}\n.zip__pw--ok {\n color: var(--accent);\n}\n.zip__pwinput {\n flex: 1 1 auto;\n min-width: 0;\n height: 28px;\n padding: 0 9px;\n font-family: inherit;\n font-size: 12.5px;\n color: var(--text);\n background: var(--surface);\n border: 1px solid var(--border-2);\n border-radius: 7px;\n}\n.zip__pwinput:focus {\n outline: none;\n border-color: var(--accent);\n}\n.zip__pwbtn {\n flex-shrink: 0;\n height: 28px;\n padding: 0 12px;\n font-family: inherit;\n font-size: 12px;\n color: var(--text);\n background: var(--surface);\n border: 1px solid var(--border-2);\n border-radius: 7px;\n cursor: pointer;\n}\n.zip__pwbtn:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n.zip__pwerr {\n flex-shrink: 0;\n font-size: 11.5px;\n color: var(--danger);\n}\n.zip__rowlock {\n flex-shrink: 0;\n color: var(--faint);\n}\n\n.zip__scroll {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n overscroll-behavior: contain;\n}\n.zip__tree {\n padding: 6px 0;\n}\n.zip__row {\n display: flex;\n align-items: center;\n gap: 7px;\n width: 100%;\n padding: 5px 12px 5px 12px;\n background: transparent;\n border: none;\n font-family: inherit;\n font-size: 12.5px;\n color: var(--text);\n text-align: left;\n cursor: pointer;\n}\n.zip__row:hover {\n background: var(--surface-2);\n}\n.zip__twisty {\n flex-shrink: 0;\n display: inline-flex;\n width: 13px;\n color: var(--faint);\n}\n.zip__twisty--open {\n transform: rotate(90deg);\n transition: transform 0.12s;\n}\n.zip__rowicon {\n flex-shrink: 0;\n display: inline-flex;\n color: var(--faint);\n}\n.zip__row--dir .zip__rowicon {\n color: var(--accent);\n}\n.zip__rowname {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.zip__row--dir .zip__rowname {\n font-weight: 500;\n}\n.zip__rowsize {\n flex-shrink: 0;\n font-size: 11px;\n color: var(--faint);\n font-variant-numeric: tabular-nums;\n}\n\n/* Detail bar ----------------------------------------------------------------------------------- */\n.zip__bar {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n padding: 7px 10px 7px 8px;\n border-bottom: 1px solid var(--border);\n background: var(--surface);\n}\n.zip__back,\n.zip__act {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 30px;\n height: 28px;\n background: transparent;\n border: none;\n border-radius: 7px;\n color: var(--muted);\n cursor: pointer;\n transition:\n background 0.15s,\n color 0.15s;\n}\n.zip__back:hover,\n.zip__act:hover {\n background: var(--surface-2);\n color: var(--accent);\n}\n.zip__path {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n direction: rtl;\n text-align: left;\n font-size: 12.5px;\n font-weight: 500;\n color: var(--text-strong);\n}\n.zip__bsize {\n flex-shrink: 0;\n font-size: 11px;\n color: var(--faint);\n font-variant-numeric: tabular-nums;\n}\n/* Render/source toggle (when the selected entry supports it) — compact segmented control. */\n.zip__view {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n gap: 2px;\n padding: 2px;\n border-radius: 7px;\n background: var(--surface-2);\n}\n.zip__vbtn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 24px;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 5px;\n color: var(--faint);\n cursor: pointer;\n}\n.zip__vbtn--on {\n background: var(--surface);\n color: var(--accent);\n box-shadow: var(--shadow);\n}\n</style>\n"],"mappings":"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"}
@@ -5,3 +5,5 @@ import t from "./ZoomImage.vue_vue_type_script_setup_true_lang.js";
5
5
  var n = /*#__PURE__*/ e(t, [["__scopeId", "data-v-96f5f467"]]);
6
6
  //#endregion
7
7
  export { n as default };
8
+
9
+ //# sourceMappingURL=ZoomImage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ZoomImage.js","names":[],"sources":["../../src/components/ZoomImage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\n/**\n * A pan + zoom image stage, shared by the full-screen {@link ImageLightbox} and the in-archive image preview\n * ({@link ZipBrowser}/{@link SevenZipBrowser}/{@link ArchiveBrowser}). Fills its parent (which must give it a\n * size). Wheel zooms toward the cursor, drag pans, double-click toggles fit↔2×, and a bottom toolbar offers\n * −/百分比/+. Initial fit is \"contain\" for a normal image, or fill-width-top-aligned for a `long` one (a tall\n * screenshot) so it reads top-down and pans vertically. A no-drag click on empty area emits `emptyClick` (the\n * lightbox closes on it; the archive preview ignores it).\n *\n * Exposes `zoomIn`/`zoomOut`/`fit` so a host can wire keyboard shortcuts to them.\n */\nconst props = withDefaults(defineProps<{ src: string; alt?: string; long?: boolean }>(), {\n alt: '',\n long: false,\n})\nconst emit = defineEmits<{ emptyClick: [] }>()\n\nconst stageEl = ref<HTMLElement | null>(null)\nconst imgEl = ref<HTMLImageElement | null>(null)\nconst natW = ref(0)\nconst natH = ref(0)\nconst scale = ref(1) // CSS px per image px (1 = 100%)\nconst tx = ref(0) // translate of the image's top-left within the stage\nconst ty = ref(0)\nconst fitScale = ref(1) // scale that \"contains\" the image in the stage\nconst ready = ref(false) // image measured → show it (avoids a pre-fit flash)\n\nconst percent = ref(100)\nfunction syncPercent(): void {\n percent.value = Math.round(scale.value * 100)\n}\n\nfunction stageSize(): { w: number; h: number } {\n const el = stageEl.value\n if (el && el.clientWidth) return { w: el.clientWidth, h: el.clientHeight }\n return { w: 1024, h: 768 }\n}\nfunction minScale(): number {\n return Math.max(0.05, Math.min(fitScale.value, 1) * 0.5)\n}\nfunction maxScale(): number {\n return Math.max(fitScale.value, 1) * 8\n}\n\n// Keep the image within the stage: center an axis whose content is smaller than the stage, otherwise clamp so\n// its edges can't be dragged inside the viewport. `topAlign` pins a too-tall image to its top (initial long view).\nfunction clampView(topAlign = false): void {\n const { w, h } = stageSize()\n const cw = natW.value * scale.value\n const ch = natH.value * scale.value\n tx.value = cw <= w ? (w - cw) / 2 : Math.min(0, Math.max(w - cw, tx.value))\n if (ch <= h) ty.value = (h - ch) / 2\n else if (topAlign) ty.value = 0\n else ty.value = Math.min(0, Math.max(h - ch, ty.value))\n syncPercent()\n}\n\n// (Re)fit the measured image: contain it, or — for a long image — fill the width and pin to the top.\nfunction fitView(): void {\n if (!natW.value || !natH.value) return\n const { w, h } = stageSize()\n fitScale.value = Math.min(w / natW.value, h / natH.value)\n scale.value = props.long ? (w * 0.98) / natW.value : Math.min(fitScale.value, 1)\n clampView(props.long)\n}\n\nfunction clampScale(s: number): number {\n return Math.min(maxScale(), Math.max(minScale(), s))\n}\n\n// Zoom keeping the image point under (cx, cy) — stage-relative coords — fixed in place.\nfunction zoomAt(cx: number, cy: number, factor: number): void {\n const next = clampScale(scale.value * factor)\n if (next === scale.value) return\n const ix = (cx - tx.value) / scale.value\n const iy = (cy - ty.value) / scale.value\n scale.value = next\n tx.value = cx - ix * next\n ty.value = cy - iy * next\n clampView(false)\n}\nfunction zoomCenter(factor: number): void {\n const { w, h } = stageSize()\n zoomAt(w / 2, h / 2, factor)\n}\n\nfunction onWheel(e: WheelEvent): void {\n const rect = stageEl.value?.getBoundingClientRect()\n const cx = rect ? e.clientX - rect.left : e.clientX\n const cy = rect ? e.clientY - rect.top : e.clientY\n zoomAt(cx, cy, e.deltaY < 0 ? 1.15 : 1 / 1.15)\n}\nfunction onDblClick(e: MouseEvent): void {\n const rect = stageEl.value?.getBoundingClientRect()\n const cx = rect ? e.clientX - rect.left : e.clientX\n const cy = rect ? e.clientY - rect.top : e.clientY\n // Near the fit scale → zoom in toward the cursor; otherwise snap back to fit.\n if (scale.value <= fitScale.value * 1.05)\n zoomAt(cx, cy, Math.max(2, 1 / Math.max(fitScale.value, 0.001)))\n else fitView()\n}\n\n// Pointer drag → pan (covers mouse + touch). A no-move pointerup on empty area emits `emptyClick`.\nlet dragging = false\nlet moved = false\nlet lastX = 0\nlet lastY = 0\nlet downTarget: EventTarget | null = null\n\nfunction onPointerDown(e: PointerEvent): void {\n if (e.button !== 0) return\n dragging = true\n moved = false\n lastX = e.clientX\n lastY = e.clientY\n downTarget = e.target\n stageEl.value?.setPointerCapture(e.pointerId)\n}\nfunction onPointerMove(e: PointerEvent): void {\n if (!dragging) return\n const dx = e.clientX - lastX\n const dy = e.clientY - lastY\n if (!moved && Math.abs(dx) + Math.abs(dy) > 3) moved = true\n lastX = e.clientX\n lastY = e.clientY\n tx.value += dx\n ty.value += dy\n clampView(false)\n}\nfunction onPointerUp(e: PointerEvent): void {\n if (!dragging) return\n dragging = false\n try {\n stageEl.value?.releasePointerCapture(e.pointerId)\n } catch {\n /* capture already released — ignore */\n }\n if (!moved && downTarget !== imgEl.value) emit('emptyClick')\n}\n\nfunction onImgLoad(): void {\n const img = imgEl.value\n if (!img) return\n natW.value = img.naturalWidth || 1\n natH.value = img.naturalHeight || 1\n fitView()\n ready.value = true\n}\n\n// Re-fit when the container is resized (the side panel's drag splitter, or the window).\nlet ro: ResizeObserver | null = null\nfunction onResize(): void {\n if (ready.value) fitView()\n}\n\n// Reset for a new source; the transform is recomputed on the <img>'s load.\nwatch(\n () => props.src,\n () => {\n ready.value = false\n natW.value = 0\n natH.value = 0\n scale.value = 1\n tx.value = 0\n ty.value = 0\n fitScale.value = 1\n syncPercent()\n },\n)\n\nonMounted(() => {\n if (typeof ResizeObserver !== 'undefined' && stageEl.value) {\n ro = new ResizeObserver(onResize)\n ro.observe(stageEl.value)\n }\n})\nonBeforeUnmount(() => ro?.disconnect())\n\ndefineExpose({\n zoomIn: () => zoomCenter(1.2),\n zoomOut: () => zoomCenter(1 / 1.2),\n fit: () => fitView(),\n})\n</script>\n\n<template>\n <div\n ref=\"stageEl\"\n class=\"zi\"\n :class=\"{ 'zi--grab': scale > fitScale }\"\n @wheel.prevent=\"onWheel\"\n @pointerdown=\"onPointerDown\"\n @pointermove=\"onPointerMove\"\n @pointerup=\"onPointerUp\"\n @pointercancel=\"onPointerUp\"\n @dblclick=\"onDblClick\"\n >\n <img\n ref=\"imgEl\"\n class=\"zi__img\"\n :class=\"{ 'zi__img--ready': ready }\"\n :src=\"src\"\n :alt=\"alt\"\n draggable=\"false\"\n :style=\"{ transform: `translate(${tx}px, ${ty}px) scale(${scale})` }\"\n @load=\"onImgLoad\"\n @dragstart.prevent\n />\n <div class=\"zi__toolbar\" @pointerdown.stop @dblclick.stop @wheel.stop>\n <button type=\"button\" class=\"zi__tool\" title=\"缩小 (-)\" @click=\"zoomCenter(1 / 1.2)\">\n −\n </button>\n <button type=\"button\" class=\"zi__pct\" title=\"适应窗口 (0)\" @click=\"fitView()\">\n {{ percent }}%\n </button>\n <button type=\"button\" class=\"zi__tool\" title=\"放大 (+)\" @click=\"zoomCenter(1.2)\">+</button>\n </div>\n </div>\n</template>\n\n<style scoped>\n.zi {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n cursor: zoom-out;\n touch-action: none;\n}\n.zi--grab {\n cursor: grab;\n}\n.zi--grab:active {\n cursor: grabbing;\n}\n.zi__img {\n position: absolute;\n top: 0;\n left: 0;\n transform-origin: 0 0;\n will-change: transform;\n user-select: none;\n -webkit-user-drag: none;\n opacity: 0;\n}\n.zi__img--ready {\n opacity: 1;\n}\n.zi__toolbar {\n position: absolute;\n bottom: 14px;\n left: 50%;\n transform: translateX(-50%);\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 4px;\n border-radius: 12px;\n background: rgba(28, 28, 30, 0.82);\n backdrop-filter: blur(8px);\n box-shadow: 0 8px 28px rgba(0, 0, 0, 0.4);\n}\n.zi__tool {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 32px;\n border: none;\n border-radius: 9px;\n background: transparent;\n color: #fff;\n font-size: 19px;\n line-height: 1;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.zi__tool:hover {\n background: rgba(255, 255, 255, 0.16);\n}\n.zi__pct {\n min-width: 56px;\n height: 32px;\n padding: 0 8px;\n border: none;\n border-radius: 9px;\n background: transparent;\n color: #fff;\n font-family: inherit;\n font-size: 12.5px;\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.zi__pct:hover {\n background: rgba(255, 255, 255, 0.16);\n}\n</style>\n"],"mappings":""}
@@ -145,3 +145,5 @@ var f = ["src", "alt"], p = /*@__PURE__*/ n({
145
145
  });
146
146
  //#endregion
147
147
  export { p as default };
148
+
149
+ //# sourceMappingURL=ZoomImage.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ZoomImage.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../src/components/ZoomImage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\n/**\n * A pan + zoom image stage, shared by the full-screen {@link ImageLightbox} and the in-archive image preview\n * ({@link ZipBrowser}/{@link SevenZipBrowser}/{@link ArchiveBrowser}). Fills its parent (which must give it a\n * size). Wheel zooms toward the cursor, drag pans, double-click toggles fit↔2×, and a bottom toolbar offers\n * −/百分比/+. Initial fit is \"contain\" for a normal image, or fill-width-top-aligned for a `long` one (a tall\n * screenshot) so it reads top-down and pans vertically. A no-drag click on empty area emits `emptyClick` (the\n * lightbox closes on it; the archive preview ignores it).\n *\n * Exposes `zoomIn`/`zoomOut`/`fit` so a host can wire keyboard shortcuts to them.\n */\nconst props = withDefaults(defineProps<{ src: string; alt?: string; long?: boolean }>(), {\n alt: '',\n long: false,\n})\nconst emit = defineEmits<{ emptyClick: [] }>()\n\nconst stageEl = ref<HTMLElement | null>(null)\nconst imgEl = ref<HTMLImageElement | null>(null)\nconst natW = ref(0)\nconst natH = ref(0)\nconst scale = ref(1) // CSS px per image px (1 = 100%)\nconst tx = ref(0) // translate of the image's top-left within the stage\nconst ty = ref(0)\nconst fitScale = ref(1) // scale that \"contains\" the image in the stage\nconst ready = ref(false) // image measured → show it (avoids a pre-fit flash)\n\nconst percent = ref(100)\nfunction syncPercent(): void {\n percent.value = Math.round(scale.value * 100)\n}\n\nfunction stageSize(): { w: number; h: number } {\n const el = stageEl.value\n if (el && el.clientWidth) return { w: el.clientWidth, h: el.clientHeight }\n return { w: 1024, h: 768 }\n}\nfunction minScale(): number {\n return Math.max(0.05, Math.min(fitScale.value, 1) * 0.5)\n}\nfunction maxScale(): number {\n return Math.max(fitScale.value, 1) * 8\n}\n\n// Keep the image within the stage: center an axis whose content is smaller than the stage, otherwise clamp so\n// its edges can't be dragged inside the viewport. `topAlign` pins a too-tall image to its top (initial long view).\nfunction clampView(topAlign = false): void {\n const { w, h } = stageSize()\n const cw = natW.value * scale.value\n const ch = natH.value * scale.value\n tx.value = cw <= w ? (w - cw) / 2 : Math.min(0, Math.max(w - cw, tx.value))\n if (ch <= h) ty.value = (h - ch) / 2\n else if (topAlign) ty.value = 0\n else ty.value = Math.min(0, Math.max(h - ch, ty.value))\n syncPercent()\n}\n\n// (Re)fit the measured image: contain it, or — for a long image — fill the width and pin to the top.\nfunction fitView(): void {\n if (!natW.value || !natH.value) return\n const { w, h } = stageSize()\n fitScale.value = Math.min(w / natW.value, h / natH.value)\n scale.value = props.long ? (w * 0.98) / natW.value : Math.min(fitScale.value, 1)\n clampView(props.long)\n}\n\nfunction clampScale(s: number): number {\n return Math.min(maxScale(), Math.max(minScale(), s))\n}\n\n// Zoom keeping the image point under (cx, cy) — stage-relative coords — fixed in place.\nfunction zoomAt(cx: number, cy: number, factor: number): void {\n const next = clampScale(scale.value * factor)\n if (next === scale.value) return\n const ix = (cx - tx.value) / scale.value\n const iy = (cy - ty.value) / scale.value\n scale.value = next\n tx.value = cx - ix * next\n ty.value = cy - iy * next\n clampView(false)\n}\nfunction zoomCenter(factor: number): void {\n const { w, h } = stageSize()\n zoomAt(w / 2, h / 2, factor)\n}\n\nfunction onWheel(e: WheelEvent): void {\n const rect = stageEl.value?.getBoundingClientRect()\n const cx = rect ? e.clientX - rect.left : e.clientX\n const cy = rect ? e.clientY - rect.top : e.clientY\n zoomAt(cx, cy, e.deltaY < 0 ? 1.15 : 1 / 1.15)\n}\nfunction onDblClick(e: MouseEvent): void {\n const rect = stageEl.value?.getBoundingClientRect()\n const cx = rect ? e.clientX - rect.left : e.clientX\n const cy = rect ? e.clientY - rect.top : e.clientY\n // Near the fit scale → zoom in toward the cursor; otherwise snap back to fit.\n if (scale.value <= fitScale.value * 1.05)\n zoomAt(cx, cy, Math.max(2, 1 / Math.max(fitScale.value, 0.001)))\n else fitView()\n}\n\n// Pointer drag → pan (covers mouse + touch). A no-move pointerup on empty area emits `emptyClick`.\nlet dragging = false\nlet moved = false\nlet lastX = 0\nlet lastY = 0\nlet downTarget: EventTarget | null = null\n\nfunction onPointerDown(e: PointerEvent): void {\n if (e.button !== 0) return\n dragging = true\n moved = false\n lastX = e.clientX\n lastY = e.clientY\n downTarget = e.target\n stageEl.value?.setPointerCapture(e.pointerId)\n}\nfunction onPointerMove(e: PointerEvent): void {\n if (!dragging) return\n const dx = e.clientX - lastX\n const dy = e.clientY - lastY\n if (!moved && Math.abs(dx) + Math.abs(dy) > 3) moved = true\n lastX = e.clientX\n lastY = e.clientY\n tx.value += dx\n ty.value += dy\n clampView(false)\n}\nfunction onPointerUp(e: PointerEvent): void {\n if (!dragging) return\n dragging = false\n try {\n stageEl.value?.releasePointerCapture(e.pointerId)\n } catch {\n /* capture already released — ignore */\n }\n if (!moved && downTarget !== imgEl.value) emit('emptyClick')\n}\n\nfunction onImgLoad(): void {\n const img = imgEl.value\n if (!img) return\n natW.value = img.naturalWidth || 1\n natH.value = img.naturalHeight || 1\n fitView()\n ready.value = true\n}\n\n// Re-fit when the container is resized (the side panel's drag splitter, or the window).\nlet ro: ResizeObserver | null = null\nfunction onResize(): void {\n if (ready.value) fitView()\n}\n\n// Reset for a new source; the transform is recomputed on the <img>'s load.\nwatch(\n () => props.src,\n () => {\n ready.value = false\n natW.value = 0\n natH.value = 0\n scale.value = 1\n tx.value = 0\n ty.value = 0\n fitScale.value = 1\n syncPercent()\n },\n)\n\nonMounted(() => {\n if (typeof ResizeObserver !== 'undefined' && stageEl.value) {\n ro = new ResizeObserver(onResize)\n ro.observe(stageEl.value)\n }\n})\nonBeforeUnmount(() => ro?.disconnect())\n\ndefineExpose({\n zoomIn: () => zoomCenter(1.2),\n zoomOut: () => zoomCenter(1 / 1.2),\n fit: () => fitView(),\n})\n</script>\n\n<template>\n <div\n ref=\"stageEl\"\n class=\"zi\"\n :class=\"{ 'zi--grab': scale > fitScale }\"\n @wheel.prevent=\"onWheel\"\n @pointerdown=\"onPointerDown\"\n @pointermove=\"onPointerMove\"\n @pointerup=\"onPointerUp\"\n @pointercancel=\"onPointerUp\"\n @dblclick=\"onDblClick\"\n >\n <img\n ref=\"imgEl\"\n class=\"zi__img\"\n :class=\"{ 'zi__img--ready': ready }\"\n :src=\"src\"\n :alt=\"alt\"\n draggable=\"false\"\n :style=\"{ transform: `translate(${tx}px, ${ty}px) scale(${scale})` }\"\n @load=\"onImgLoad\"\n @dragstart.prevent\n />\n <div class=\"zi__toolbar\" @pointerdown.stop @dblclick.stop @wheel.stop>\n <button type=\"button\" class=\"zi__tool\" title=\"缩小 (-)\" @click=\"zoomCenter(1 / 1.2)\">\n −\n </button>\n <button type=\"button\" class=\"zi__pct\" title=\"适应窗口 (0)\" @click=\"fitView()\">\n {{ percent }}%\n </button>\n <button type=\"button\" class=\"zi__tool\" title=\"放大 (+)\" @click=\"zoomCenter(1.2)\">+</button>\n </div>\n </div>\n</template>\n\n<style scoped>\n.zi {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n cursor: zoom-out;\n touch-action: none;\n}\n.zi--grab {\n cursor: grab;\n}\n.zi--grab:active {\n cursor: grabbing;\n}\n.zi__img {\n position: absolute;\n top: 0;\n left: 0;\n transform-origin: 0 0;\n will-change: transform;\n user-select: none;\n -webkit-user-drag: none;\n opacity: 0;\n}\n.zi__img--ready {\n opacity: 1;\n}\n.zi__toolbar {\n position: absolute;\n bottom: 14px;\n left: 50%;\n transform: translateX(-50%);\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 4px;\n border-radius: 12px;\n background: rgba(28, 28, 30, 0.82);\n backdrop-filter: blur(8px);\n box-shadow: 0 8px 28px rgba(0, 0, 0, 0.4);\n}\n.zi__tool {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 32px;\n border: none;\n border-radius: 9px;\n background: transparent;\n color: #fff;\n font-size: 19px;\n line-height: 1;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.zi__tool:hover {\n background: rgba(255, 255, 255, 0.16);\n}\n.zi__pct {\n min-width: 56px;\n height: 32px;\n padding: 0 8px;\n border: none;\n border-radius: 9px;\n background: transparent;\n color: #fff;\n font-family: inherit;\n font-size: 12.5px;\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.zi__pct:hover {\n background: rgba(255, 255, 255, 0.16);\n}\n</style>\n"],"mappings":"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"}
@@ -5,3 +5,5 @@ import t from "./EplCodeBlock.vue_vue_type_script_setup_true_lang.js";
5
5
  var n = /*#__PURE__*/ e(t, [["__scopeId", "data-v-4eade126"]]);
6
6
  //#endregion
7
7
  export { n as default };
8
+
9
+ //# sourceMappingURL=EplCodeBlock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EplCodeBlock.js","names":[],"sources":["../../../src/components/epl/EplCodeBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { CodeLine, GuideSeg } from '@/lib/epl'\n\n/**\n * Renders a method body as the 易语言 IDE does: a line-number gutter (numbers come from the document-wide\n * counter via `nos`, so they stay continuous with the definition tables above), dashed block-guide brackets\n * in the indent columns (corner at a block's header/footer, tee to each inner line — precomputed in\n * {@link methodCodeLines}), and lightly syntax-coloured text (comments green, strings red, keyword blue with\n * its leading `.` hidden).\n */\nconst props = defineProps<{ lines: CodeLine[]; nos: (number | null)[] }>()\n\ntype Tok = { t: 'text' | 'string' | 'comment' | 'keyword'; s: string }\n\nfunction tokenize(text: string): Tok[] {\n const out: Tok[] = []\n let i = 0\n let buf = ''\n const flush = (): void => {\n if (buf) {\n out.push({ t: 'text', s: buf })\n buf = ''\n }\n }\n while (i < text.length) {\n const ch = text[i]\n if (ch === '“') {\n flush()\n let j = text.indexOf('”', i + 1)\n if (j === -1) j = text.length - 1\n out.push({ t: 'string', s: text.slice(i, j + 1) })\n i = j + 1\n } else if (ch === \"'\") {\n flush()\n out.push({ t: 'comment', s: text.slice(i) })\n i = text.length\n } else {\n buf += ch\n i++\n }\n }\n flush()\n // A leading dot-keyword (`.如果真` / `.判断循环首` …): colour it blue and DROP the dot (the IDE hides it).\n if (out.length && out[0].t === 'text') {\n const m = /^(\\s*)\\.([^\\s((]+)([\\s\\S]*)$/.exec(out[0].s)\n if (m) {\n const repl: Tok[] = []\n if (m[1]) repl.push({ t: 'text', s: m[1] })\n repl.push({ t: 'keyword', s: m[2] })\n if (m[3]) repl.push({ t: 'text', s: m[3] })\n out.splice(0, 1, ...repl)\n }\n }\n return out\n}\n\nconst rows = computed(() =>\n props.lines.map((ln, i) => ({\n // null → a hidden terminator row: render the guide but leave the number gutter blank.\n no: props.nos[i] ?? null,\n segs: ln.segs as GuideSeg[],\n tokens: tokenize(ln.text),\n })),\n)\n</script>\n\n<template>\n <div class=\"cb\">\n <div v-for=\"(row, i) in rows\" :key=\"i\" class=\"cb__row\">\n <span class=\"cb__no\">{{ row.no ?? '' }}</span>\n <span v-for=\"(seg, k) in row.segs\" :key=\"k\" class=\"cb__g\" :class=\"'cb__g--' + seg\" />\n <code class=\"cb__text\"\n ><span v-for=\"(tk, j) in row.tokens\" :key=\"j\" :class=\"'tk-' + tk.t\">{{ tk.s }}</span\n ><span v-if=\"row.tokens.length === 0\">&nbsp;</span></code\n >\n </div>\n </div>\n</template>\n\n<style scoped>\n.cb {\n font-family: var(--font-mono);\n font-size: 12.5px;\n line-height: 1.55;\n width: max-content;\n min-width: 100%;\n}\n.cb__row {\n display: flex;\n align-items: stretch;\n}\n.cb__row:hover {\n background: var(--epl-row-hover);\n}\n.cb__no {\n flex: 0 0 auto;\n width: 3.4em;\n padding-right: 10px;\n text-align: right;\n color: var(--epl-gutter);\n background: var(--epl-gutter-bg);\n user-select: none;\n position: sticky;\n left: 0;\n z-index: 1;\n}\n.cb__g {\n position: relative;\n flex: 0 0 auto;\n width: 1.45em;\n}\n.cb__g::before {\n /* vertical dashed bracket line (full height by default → 'mid' / 'tee') */\n content: '';\n position: absolute;\n left: 50%;\n top: 0;\n bottom: 0;\n border-left: 1px dashed var(--epl-guide);\n}\n.cb__g--top::before {\n /* header ┌: the vertical drops in at mid-row (lower half), then runs down through the body below */\n top: 50%;\n}\n.cb__g--bottom::before {\n /* end └: the vertical arrives from above and stops at mid-row */\n bottom: 50%;\n}\n.cb__g--blank::before {\n /* commented-out control flow: the column still indents the body, but draws no guide line */\n display: none;\n}\n.cb__g--top::after,\n.cb__g--bottom::after,\n.cb__g--tee::after {\n /* horizontal tick reaching toward the body text (┌ header · ├ branch divider · └ end) */\n content: '';\n position: absolute;\n left: 50%;\n right: 0;\n top: 50%;\n border-top: 1px dashed var(--epl-guide);\n}\n.cb__text {\n flex: 1 1 auto;\n white-space: pre;\n padding-right: 24px;\n color: var(--epl-fg);\n}\n.tk-comment {\n color: var(--epl-comment);\n}\n.tk-string {\n color: var(--epl-string);\n}\n.tk-keyword {\n color: var(--epl-keyword);\n font-weight: 600;\n}\n</style>\n"],"mappings":""}
@@ -70,3 +70,5 @@ var u = { class: "cb" }, d = { class: "cb__no" }, f = { class: "cb__text" }, p =
70
70
  });
71
71
  //#endregion
72
72
  export { m as default };
73
+
74
+ //# sourceMappingURL=EplCodeBlock.vue_vue_type_script_setup_true_lang.js.map