flea-qml 0.0.0-stage → 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 (637) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +511 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +407 -0
  51. package/src/archiveops.js +728 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +135 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/terminal-server.js +95 -0
  82. package/src/terminal-shell.js +26 -0
  83. package/src/transfer.js +669 -0
  84. package/src/trash-record.js +41 -0
  85. package/src/trash.js +210 -0
  86. package/src/trashbrowse.js +327 -0
  87. package/src/uistate.js +393 -0
  88. package/src/uistore.js +168 -0
  89. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  90. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  91. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  92. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  93. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  94. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  95. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  96. package/src/vendor/pele.js +145 -0
  97. package/src/vendor/temml.mjs +14708 -0
  98. package/src/watch.js +98 -0
  99. package/src/wayland/client.js +109 -0
  100. package/src/wayland/protocol.js +55 -0
  101. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  102. package/src/wayland/protocols/wayland.xml +3248 -0
  103. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  104. package/src/wayland/resource-io.js +6 -0
  105. package/src/wayland/socket-discovery.js +26 -0
  106. package/src/wayland/transport-posix.js +120 -0
  107. package/src/wayland/transport-win32.js +11 -0
  108. package/src/wayland/transport.js +3 -0
  109. package/src/wayland/win32-resources.js +80 -0
  110. package/src/wayland/win32-wire.js +62 -0
  111. package/test/archive.test.js +80 -0
  112. package/test/bench-markdown-scroll.mjs +190 -0
  113. package/test/clip-host.test.js +113 -0
  114. package/test/code-preview.test.js +35 -0
  115. package/test/compare-ui-paths.test.js +24 -0
  116. package/test/compare.test.js +54 -0
  117. package/test/delete-trash.test.js +67 -0
  118. package/test/dirsize.test.js +138 -0
  119. package/test/file-ops.test.js +307 -0
  120. package/test/file-url.test.js +24 -0
  121. package/test/find-contents.test.js +161 -0
  122. package/test/find-input.test.js +66 -0
  123. package/test/fixtures/pele-parity.json +1006 -0
  124. package/test/highlight-launcher.test.js +35 -0
  125. package/test/html-preview.test.js +22 -0
  126. package/test/input.test.js +15 -0
  127. package/test/keymap.test.js +26 -0
  128. package/test/language-icons.test.js +36 -0
  129. package/test/launcher.test.js +51 -0
  130. package/test/manual-archive-here-ui.mjs +47 -0
  131. package/test/manual-code-scroll.mjs +28 -0
  132. package/test/manual-column-scroll.mjs +24 -0
  133. package/test/manual-compare-ui.mjs +20 -0
  134. package/test/manual-find-status.mjs +37 -0
  135. package/test/manual-folder-focus.mjs +63 -0
  136. package/test/manual-html-security.mjs +23 -0
  137. package/test/manual-html-ui.mjs +30 -0
  138. package/test/manual-syntax-preview.mjs +26 -0
  139. package/test/manual-terminal-lifecycle.mjs +42 -0
  140. package/test/manual-terminal-navigation.mjs +48 -0
  141. package/test/manual-terminal-ui.mjs +47 -0
  142. package/test/manual-trash-ui.mjs +86 -0
  143. package/test/markdown-diagrams.test.js +93 -0
  144. package/test/markdown-html.test.js +105 -0
  145. package/test/mathml.test.js +92 -0
  146. package/test/menu-transfer.test.js +57 -0
  147. package/test/office-preview.test.js +154 -0
  148. package/test/pele-parity.test.js +28 -0
  149. package/test/places.test.js +134 -0
  150. package/test/preview-keys.test.js +60 -0
  151. package/test/preview-language.test.js +22 -0
  152. package/test/status-filename.test.js +20 -0
  153. package/test/transfer-replace-merge.test.js +187 -0
  154. package/test/trash-address.test.js +23 -0
  155. package/test/trash-view.test.js +37 -0
  156. package/test/trashbrowse.test.js +135 -0
  157. package/ui/AboutFacts.qml +78 -0
  158. package/ui/ArchiveCards.qml +95 -0
  159. package/ui/ArchiveCompressDialog.qml +378 -0
  160. package/ui/ArchiveHereConfirm.qml +127 -0
  161. package/ui/ArchivePasswordDialog.qml +257 -0
  162. package/ui/Backend.qml +775 -0
  163. package/ui/BulkOldNames.qml +47 -0
  164. package/ui/BulkRenameDialog.qml +380 -0
  165. package/ui/CardFrame.qml +67 -0
  166. package/ui/CardScroll.qml +79 -0
  167. package/ui/CheckBox.qml +73 -0
  168. package/ui/ChromeBar.qml +360 -0
  169. package/ui/ChromeButton.qml +131 -0
  170. package/ui/ChromeModes.qml +43 -0
  171. package/ui/CodeLines.qml +256 -0
  172. package/ui/CodeRefusal.qml +52 -0
  173. package/ui/CollideConfirm.qml +147 -0
  174. package/ui/CollideHost.qml +167 -0
  175. package/ui/ColumnPane.qml +525 -0
  176. package/ui/ColumnRow.qml +380 -0
  177. package/ui/ColumnsArea.qml +594 -0
  178. package/ui/ColumnsLanding.qml +147 -0
  179. package/ui/CompareView.qml +321 -0
  180. package/ui/ContextMenu.qml +743 -0
  181. package/ui/ConvertDialog.qml +456 -0
  182. package/ui/CountedWorker.qml +7 -0
  183. package/ui/Crumb.qml +64 -0
  184. package/ui/CrumbDrop.qml +25 -0
  185. package/ui/CsvTable.qml +394 -0
  186. package/ui/CursorMark.qml +41 -0
  187. package/ui/DefaultClaim.qml +130 -0
  188. package/ui/DeviceLock.qml +47 -0
  189. package/ui/DeviceMounts.qml +540 -0
  190. package/ui/DialogButton.qml +150 -0
  191. package/ui/DialogField.qml +147 -0
  192. package/ui/DialogHeader.qml +31 -0
  193. package/ui/DialogScrim.qml +20 -0
  194. package/ui/DialogTitle.qml +37 -0
  195. package/ui/Divider.qml +9 -0
  196. package/ui/DropInto.qml +126 -0
  197. package/ui/DropTarget.qml +35 -0
  198. package/ui/DropboxMark.qml +60 -0
  199. package/ui/EmptyState.qml +150 -0
  200. package/ui/EscapeHint.qml +11 -0
  201. package/ui/FactsTable.qml +54 -0
  202. package/ui/FastScrollHandler.qml +476 -0
  203. package/ui/FatNamesConfirm.qml +157 -0
  204. package/ui/Favourites.qml +143 -0
  205. package/ui/FigureService.qml +120 -0
  206. package/ui/FileDrag.qml +267 -0
  207. package/ui/FilterStrip.qml +133 -0
  208. package/ui/FitMetrics.qml +22 -0
  209. package/ui/FlashDriveRows.qml +137 -0
  210. package/ui/FlashHost.qml +72 -0
  211. package/ui/FlashImageRow.qml +104 -0
  212. package/ui/FlashRunner.qml +119 -0
  213. package/ui/FlashStepRow.qml +172 -0
  214. package/ui/FlashStrip.qml +38 -0
  215. package/ui/FlashView.qml +397 -0
  216. package/ui/FleaMark.qml +88 -0
  217. package/ui/FlyoutFade.qml +23 -0
  218. package/ui/FontPane.qml +170 -0
  219. package/ui/Glass.qml +114 -0
  220. package/ui/GlassTagger.qml +59 -0
  221. package/ui/Glyph.qml +64 -0
  222. package/ui/GlyphSolid.qml +22 -0
  223. package/ui/GridArea.qml +664 -0
  224. package/ui/GridTile.qml +325 -0
  225. package/ui/GvfsBridge.qml +164 -0
  226. package/ui/Header.qml +433 -0
  227. package/ui/HoverTimers.qml +39 -0
  228. package/ui/HtmlClip.qml +30 -0
  229. package/ui/HtmlPane.qml +63 -0
  230. package/ui/HyprlandMark.qml +45 -0
  231. package/ui/Ipc.qml +1005 -0
  232. package/ui/IpcControls.qml +7 -0
  233. package/ui/IpcMenuState.qml +48 -0
  234. package/ui/IpcPreviewState.qml +185 -0
  235. package/ui/JumpPath.qml +51 -0
  236. package/ui/KeymapSheet.qml +561 -0
  237. package/ui/KeymapSheetResult.qml +89 -0
  238. package/ui/KindStack.qml +40 -0
  239. package/ui/LangMark.qml +51 -0
  240. package/ui/LangMarkLoader.qml +26 -0
  241. package/ui/List.qml +480 -0
  242. package/ui/LoadingState.qml +54 -0
  243. package/ui/LocalSend.qml +56 -0
  244. package/ui/LocalSendMark.qml +73 -0
  245. package/ui/MarkdownBlockView.qml +311 -0
  246. package/ui/MarkdownBlocks.qml +35 -0
  247. package/ui/MarkdownFigure.qml +254 -0
  248. package/ui/MarkdownImages.qml +72 -0
  249. package/ui/MarkdownList.qml +81 -0
  250. package/ui/MarkdownMathsText.qml +97 -0
  251. package/ui/MarkdownPane.qml +83 -0
  252. package/ui/MarkdownPictures.qml +41 -0
  253. package/ui/MarkdownQuote.qml +52 -0
  254. package/ui/MarkdownRemote.qml +82 -0
  255. package/ui/MarkdownSource.qml +155 -0
  256. package/ui/MarkdownTable.qml +222 -0
  257. package/ui/MarkdownTableScroll.qml +64 -0
  258. package/ui/MarkdownTableWheel.qml +126 -0
  259. package/ui/MarkdownText.qml +87 -0
  260. package/ui/MarkdownWorker.js +132 -0
  261. package/ui/MatchText.qml +99 -0
  262. package/ui/MediaSession.qml +38 -0
  263. package/ui/MediaSound.qml +26 -0
  264. package/ui/MediaStrip.qml +191 -0
  265. package/ui/MediaTrack.qml +36 -0
  266. package/ui/MediaVolume.qml +54 -0
  267. package/ui/MenuActionDialog.qml +396 -0
  268. package/ui/MenuEdgeFade.qml +24 -0
  269. package/ui/MenuHost.qml +227 -0
  270. package/ui/MenuRow.qml +351 -0
  271. package/ui/MountListing.qml +100 -0
  272. package/ui/NetworkDialog.qml +435 -0
  273. package/ui/NetworkForm.qml +426 -0
  274. package/ui/NetworkMounts.qml +913 -0
  275. package/ui/NetworkPlaces.qml +127 -0
  276. package/ui/OpenWithDialog.qml +613 -0
  277. package/ui/Opener.qml +95 -0
  278. package/ui/Pane.qml +1320 -0
  279. package/ui/PaneMenuActions.qml +527 -0
  280. package/ui/PanePath.qml +90 -0
  281. package/ui/PaneRail.qml +268 -0
  282. package/ui/PaneStates.qml +88 -0
  283. package/ui/PaneSwap.qml +339 -0
  284. package/ui/PaneWire.qml +601 -0
  285. package/ui/ParkedWait.qml +9 -0
  286. package/ui/PathEntry.qml +186 -0
  287. package/ui/PathJump.qml +400 -0
  288. package/ui/PdfViewer.qml +297 -0
  289. package/ui/PermissionsDialog.qml +658 -0
  290. package/ui/PermissionsHeadings.qml +31 -0
  291. package/ui/PhoneMounts.qml +67 -0
  292. package/ui/PickerAnswers.qml +75 -0
  293. package/ui/PickerBox.qml +26 -0
  294. package/ui/PickerChrome.qml +295 -0
  295. package/ui/PickerFilter.qml +97 -0
  296. package/ui/PickerGrid.qml +308 -0
  297. package/ui/PickerHeader.qml +28 -0
  298. package/ui/PickerLifecycle.qml +27 -0
  299. package/ui/PickerList.qml +218 -0
  300. package/ui/PickerListing.qml +149 -0
  301. package/ui/PickerPathBar.qml +127 -0
  302. package/ui/PickerPlaces.qml +189 -0
  303. package/ui/PickerRecent.qml +92 -0
  304. package/ui/PickerSave.qml +101 -0
  305. package/ui/PickerSelection.qml +155 -0
  306. package/ui/PickerWindow.qml +846 -0
  307. package/ui/PowerSectorsReader.qml +10 -0
  308. package/ui/PrebuildDriver.qml +146 -0
  309. package/ui/Preview.qml +1005 -0
  310. package/ui/PreviewAnimation.qml +24 -0
  311. package/ui/PreviewArchive.qml +91 -0
  312. package/ui/PreviewColumn.qml +553 -0
  313. package/ui/PreviewEdge.qml +63 -0
  314. package/ui/PreviewFacts.qml +30 -0
  315. package/ui/PreviewFactsLine.qml +34 -0
  316. package/ui/PreviewHtml.qml +233 -0
  317. package/ui/PreviewImage.qml +253 -0
  318. package/ui/PreviewImagePan.qml +13 -0
  319. package/ui/PreviewImageSharp.qml +32 -0
  320. package/ui/PreviewLines.qml +106 -0
  321. package/ui/PreviewMarkdown.qml +706 -0
  322. package/ui/PreviewMedia.qml +250 -0
  323. package/ui/PreviewPdf.qml +482 -0
  324. package/ui/PreviewScroll.qml +201 -0
  325. package/ui/PreviewSwap.qml +335 -0
  326. package/ui/PreviewText.qml +149 -0
  327. package/ui/ProtocolChip.qml +18 -0
  328. package/ui/QuickLookArchive.qml +41 -0
  329. package/ui/QuickLookBar.qml +103 -0
  330. package/ui/QuickLookPrepare.qml +355 -0
  331. package/ui/QuickLookSwap.qml +10 -0
  332. package/ui/QuickLookWarm.qml +65 -0
  333. package/ui/RailDrop.qml +155 -0
  334. package/ui/RailHeading.qml +19 -0
  335. package/ui/RailPlaces.qml +38 -0
  336. package/ui/RailTrashRow.qml +67 -0
  337. package/ui/RenameField.qml +353 -0
  338. package/ui/RendererRetry.qml +11 -0
  339. package/ui/ResizeHandle.qml +52 -0
  340. package/ui/Reveal.qml +54 -0
  341. package/ui/Row.qml +476 -0
  342. package/ui/RowDrag.qml +213 -0
  343. package/ui/RowDropTarget.qml +27 -0
  344. package/ui/RunCard.qml +286 -0
  345. package/ui/Scripts.qml +65 -0
  346. package/ui/SearchStrip.qml +232 -0
  347. package/ui/SelectionBand.qml +140 -0
  348. package/ui/SelectionPreview.qml +370 -0
  349. package/ui/SettingsFavourite.qml +122 -0
  350. package/ui/SettingsGroup.qml +96 -0
  351. package/ui/SettingsHint.qml +12 -0
  352. package/ui/SettingsMetrics.qml +29 -0
  353. package/ui/SettingsPane.qml +178 -0
  354. package/ui/SettingsPanel.qml +547 -0
  355. package/ui/SettingsRail.qml +128 -0
  356. package/ui/SettingsRow.qml +409 -0
  357. package/ui/SettingsRuler.qml +85 -0
  358. package/ui/SettingsSegment.qml +85 -0
  359. package/ui/ShareBrowser.qml +113 -0
  360. package/ui/ShareLink.qml +67 -0
  361. package/ui/ShelfPins.qml +101 -0
  362. package/ui/Sidebar.qml +728 -0
  363. package/ui/SidebarRow.qml +358 -0
  364. package/ui/Spinner.qml +60 -0
  365. package/ui/StableModel.qml +89 -0
  366. package/ui/StateMessage.qml +84 -0
  367. package/ui/StatusBar.qml +512 -0
  368. package/ui/StatusFileName.qml +27 -0
  369. package/ui/TabBar.qml +673 -0
  370. package/ui/TabDragGeometry.qml +60 -0
  371. package/ui/TagMenuMark.qml +52 -0
  372. package/ui/TagRailSection.qml +53 -0
  373. package/ui/TagSlot.qml +40 -0
  374. package/ui/TagState.qml +150 -0
  375. package/ui/TagSwatch.qml +28 -0
  376. package/ui/Taildrop.qml +86 -0
  377. package/ui/TailscaleMark.qml +50 -0
  378. package/ui/TerminalService.qml +69 -0
  379. package/ui/TerminalTab.qml +48 -0
  380. package/ui/TerminalTabs.qml +27 -0
  381. package/ui/Theme.qml +460 -0
  382. package/ui/ThemeColors.qml +43 -0
  383. package/ui/TransferCard.qml +239 -0
  384. package/ui/TrashConfirm.qml +129 -0
  385. package/ui/TrashDropHandler.qml +11 -0
  386. package/ui/TrashHost.qml +202 -0
  387. package/ui/TrashMonitor.qml +30 -0
  388. package/ui/TrashToolbar.qml +19 -0
  389. package/ui/TrashView.qml +492 -0
  390. package/ui/UnlockDialog.qml +450 -0
  391. package/ui/UnlockHost.qml +206 -0
  392. package/ui/UpdateCheck.qml +97 -0
  393. package/ui/UserDirs.qml +25 -0
  394. package/ui/ViewState.qml +565 -0
  395. package/ui/ViewportScrollBar.qml +195 -0
  396. package/ui/ViewportScrollBars.qml +25 -0
  397. package/ui/WebPreview.qml +33 -0
  398. package/ui/WebPreviewView.qml +26 -0
  399. package/ui/WindowBody.qml +829 -0
  400. package/ui/WindowDrag.qml +35 -0
  401. package/ui/boot/Commons/AudioNodes.qml +50 -0
  402. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  403. package/ui/boot/Commons/Border.qml +243 -0
  404. package/ui/boot/Commons/BorderGeometry.js +373 -0
  405. package/ui/boot/Commons/Color.qml +258 -0
  406. package/ui/boot/Commons/I18n.qml +118 -0
  407. package/ui/boot/Commons/InputDevices.qml +112 -0
  408. package/ui/boot/Commons/InputMethodState.qml +38 -0
  409. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  410. package/ui/boot/Commons/Numbers.js +19 -0
  411. package/ui/boot/Commons/Plural.js +91 -0
  412. package/ui/boot/Commons/ShellIpc.qml +12 -0
  413. package/ui/boot/Commons/Style.qml +561 -0
  414. package/ui/boot/Commons/Translations.qml +100 -0
  415. package/ui/boot/Commons/UntypedInput.qml +152 -0
  416. package/ui/boot/Commons/Util.qml +188 -0
  417. package/ui/boot/Commons/qmldir +13 -0
  418. package/ui/boot/LICENSE-omarchy +20 -0
  419. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  420. package/ui/boot/Ui/BarIconButton.qml +106 -0
  421. package/ui/boot/Ui/BarIconContent.qml +38 -0
  422. package/ui/boot/Ui/BarIndicator.qml +53 -0
  423. package/ui/boot/Ui/BarWidget.qml +50 -0
  424. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  425. package/ui/boot/Ui/BorderSurface.qml +40 -0
  426. package/ui/boot/Ui/Button.qml +224 -0
  427. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  428. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  429. package/ui/boot/Ui/CursorSurface.qml +42 -0
  430. package/ui/boot/Ui/Dropdown.qml +245 -0
  431. package/ui/boot/Ui/FilterInput.qml +26 -0
  432. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  433. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  434. package/ui/boot/Ui/MultiSelect.qml +624 -0
  435. package/ui/boot/Ui/NumberField.qml +86 -0
  436. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  437. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  438. package/ui/boot/Ui/Panel.qml +60 -0
  439. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  440. package/ui/boot/Ui/PanelController.qml +16 -0
  441. package/ui/boot/Ui/PanelHero.qml +112 -0
  442. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  443. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  444. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  445. package/ui/boot/Ui/PanelSlider.qml +156 -0
  446. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  447. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  448. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  449. package/ui/boot/Ui/PopupCard.qml +181 -0
  450. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  451. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  452. package/ui/boot/Ui/SizedImage.qml +125 -0
  453. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  454. package/ui/boot/Ui/TextField.qml +58 -0
  455. package/ui/boot/Ui/Toggle.qml +118 -0
  456. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  457. package/ui/boot/Ui/WidgetButton.qml +172 -0
  458. package/ui/boot/Ui/qmldir +41 -0
  459. package/ui/boot/fleatab.qml +50 -0
  460. package/ui/boot/picker.qml +39 -0
  461. package/ui/boot/shell.qml +131 -0
  462. package/ui/boot/tabtearoff.qml +51 -0
  463. package/ui/js/Anchor.js +379 -0
  464. package/ui/js/AnchorHold.js +162 -0
  465. package/ui/js/Archive.js +157 -0
  466. package/ui/js/ArchiveCard.js +44 -0
  467. package/ui/js/ArchiveOps.js +44 -0
  468. package/ui/js/BackReturn.js +118 -0
  469. package/ui/js/BulkRename.js +100 -0
  470. package/ui/js/Buttons.js +54 -0
  471. package/ui/js/ChromeKeys.js +116 -0
  472. package/ui/js/ClipMarks.js +73 -0
  473. package/ui/js/ClipSelection.js +67 -0
  474. package/ui/js/Clipboard.js +179 -0
  475. package/ui/js/Cloud.js +97 -0
  476. package/ui/js/CodeRuns.js +72 -0
  477. package/ui/js/Collide.js +212 -0
  478. package/ui/js/ColumnFit.js +28 -0
  479. package/ui/js/ColumnMenu.js +111 -0
  480. package/ui/js/Columns.js +298 -0
  481. package/ui/js/ColumnsCarry.js +103 -0
  482. package/ui/js/Compare.js +74 -0
  483. package/ui/js/Contrast.js +157 -0
  484. package/ui/js/ControlReader.js +42 -0
  485. package/ui/js/Convert.js +52 -0
  486. package/ui/js/CopyAs.js +52 -0
  487. package/ui/js/Crumbs.js +178 -0
  488. package/ui/js/Csv.js +231 -0
  489. package/ui/js/Density.js +44 -0
  490. package/ui/js/Devices.js +440 -0
  491. package/ui/js/DirSizes.js +180 -0
  492. package/ui/js/Drag.js +360 -0
  493. package/ui/js/DragOut.js +166 -0
  494. package/ui/js/DropDev.js +52 -0
  495. package/ui/js/Dropbox.js +41 -0
  496. package/ui/js/Eject.js +217 -0
  497. package/ui/js/Errors.js +188 -0
  498. package/ui/js/ExtThumbs.js +115 -0
  499. package/ui/js/Facts.js +402 -0
  500. package/ui/js/FigureDate.js +14 -0
  501. package/ui/js/Filter.js +285 -0
  502. package/ui/js/Find.js +46 -0
  503. package/ui/js/Flash.js +184 -0
  504. package/ui/js/FlashCard.js +79 -0
  505. package/ui/js/FlashEndings.js +125 -0
  506. package/ui/js/FlashPane.js +116 -0
  507. package/ui/js/FleaBin.js +12 -0
  508. package/ui/js/Focus.js +504 -0
  509. package/ui/js/FolderSorts.js +108 -0
  510. package/ui/js/FolderViews.js +44 -0
  511. package/ui/js/Format.js +314 -0
  512. package/ui/js/Fuzzy.js +141 -0
  513. package/ui/js/GlassTag.js +72 -0
  514. package/ui/js/Grid.js +33 -0
  515. package/ui/js/GridGeometry.js +90 -0
  516. package/ui/js/GridNames.js +153 -0
  517. package/ui/js/GvfsBridge.js +200 -0
  518. package/ui/js/HostClipboard.js +29 -0
  519. package/ui/js/Icons.js +218 -0
  520. package/ui/js/Input.js +50 -0
  521. package/ui/js/Jump.js +200 -0
  522. package/ui/js/KeyName.js +64 -0
  523. package/ui/js/Keymap.js +401 -0
  524. package/ui/js/Kinds.js +164 -0
  525. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  526. package/ui/js/LangMarkPaths.js +47 -0
  527. package/ui/js/LangMarks.js +120 -0
  528. package/ui/js/Lists.js +11 -0
  529. package/ui/js/LocalSend.js +39 -0
  530. package/ui/js/LockedMenu.js +63 -0
  531. package/ui/js/MakeDefault.js +186 -0
  532. package/ui/js/MarkBox.js +7 -0
  533. package/ui/js/Markdown.js +119 -0
  534. package/ui/js/MarkdownLists.js +86 -0
  535. package/ui/js/MarkdownMaths.js +58 -0
  536. package/ui/js/MarkdownPictures.js +32 -0
  537. package/ui/js/MarkdownPrepared.js +139 -0
  538. package/ui/js/MarkdownTableFit.js +34 -0
  539. package/ui/js/Marks.js +148 -0
  540. package/ui/js/Marquee.js +96 -0
  541. package/ui/js/Match.js +93 -0
  542. package/ui/js/Material.js +109 -0
  543. package/ui/js/MdBlocks.js +437 -0
  544. package/ui/js/MdBreak.js +71 -0
  545. package/ui/js/MdChunks.js +70 -0
  546. package/ui/js/MdContainer.js +137 -0
  547. package/ui/js/MdDocument.js +337 -0
  548. package/ui/js/MdEmph.js +97 -0
  549. package/ui/js/MdEntity.js +108 -0
  550. package/ui/js/MdEntityTable.js +223 -0
  551. package/ui/js/MdEscape.js +59 -0
  552. package/ui/js/MdFront.js +37 -0
  553. package/ui/js/MdHold.js +32 -0
  554. package/ui/js/MdHtml.js +307 -0
  555. package/ui/js/MdHtmlBlock.js +290 -0
  556. package/ui/js/MdHtmlHeading.js +53 -0
  557. package/ui/js/MdHtmlImage.js +179 -0
  558. package/ui/js/MdInline.js +154 -0
  559. package/ui/js/MdItems.js +212 -0
  560. package/ui/js/MdLeaf.js +309 -0
  561. package/ui/js/MdLink.js +196 -0
  562. package/ui/js/MdMath.js +67 -0
  563. package/ui/js/MdParagraphs.js +138 -0
  564. package/ui/js/MdRefs.js +232 -0
  565. package/ui/js/MdResolve.js +226 -0
  566. package/ui/js/MdRun.js +300 -0
  567. package/ui/js/MdUrl.js +226 -0
  568. package/ui/js/Menu.js +514 -0
  569. package/ui/js/MenuContext.js +85 -0
  570. package/ui/js/MenuFit.js +13 -0
  571. package/ui/js/MenuRefresh.js +74 -0
  572. package/ui/js/MenuWheel.js +35 -0
  573. package/ui/js/Messages.js +186 -0
  574. package/ui/js/Motion.js +16 -0
  575. package/ui/js/Mounts.js +320 -0
  576. package/ui/js/MouseNav.js +13 -0
  577. package/ui/js/Nav.js +329 -0
  578. package/ui/js/NetFs.js +26 -0
  579. package/ui/js/OpenWith.js +83 -0
  580. package/ui/js/Ops.js +585 -0
  581. package/ui/js/Palette.js +33 -0
  582. package/ui/js/PathBar.js +260 -0
  583. package/ui/js/Permissions.js +179 -0
  584. package/ui/js/Phones.js +112 -0
  585. package/ui/js/Picker.js +353 -0
  586. package/ui/js/PlaceMenu.js +96 -0
  587. package/ui/js/Places.js +265 -0
  588. package/ui/js/PreviewAsk.js +21 -0
  589. package/ui/js/PreviewKeys.js +155 -0
  590. package/ui/js/PreviewSettle.js +29 -0
  591. package/ui/js/PreviewSwap.js +101 -0
  592. package/ui/js/PropertyFacts.js +144 -0
  593. package/ui/js/Protocols.js +296 -0
  594. package/ui/js/QuickLookKinds.js +27 -0
  595. package/ui/js/QuickLookRect.js +24 -0
  596. package/ui/js/RailDrop.js +51 -0
  597. package/ui/js/RailKeys.js +87 -0
  598. package/ui/js/RailMenu.js +133 -0
  599. package/ui/js/Recent.js +135 -0
  600. package/ui/js/RecentMode.js +156 -0
  601. package/ui/js/Reload.js +60 -0
  602. package/ui/js/Renderer.js +9 -0
  603. package/ui/js/RunFile.js +143 -0
  604. package/ui/js/Scripts.js +28 -0
  605. package/ui/js/Scroll.js +304 -0
  606. package/ui/js/ScrollOff.js +69 -0
  607. package/ui/js/Search.js +478 -0
  608. package/ui/js/Selection.js +97 -0
  609. package/ui/js/Settings.js +476 -0
  610. package/ui/js/SettingsAbout.js +97 -0
  611. package/ui/js/SettingsShelf.js +52 -0
  612. package/ui/js/SheetKeys.js +42 -0
  613. package/ui/js/SheetQuery.js +281 -0
  614. package/ui/js/ShelfPile.js +27 -0
  615. package/ui/js/SlowClick.js +53 -0
  616. package/ui/js/SlowOp.js +6 -0
  617. package/ui/js/Sort.js +134 -0
  618. package/ui/js/Startup.js +63 -0
  619. package/ui/js/StateWords.js +17 -0
  620. package/ui/js/Status.js +238 -0
  621. package/ui/js/Swap.js +166 -0
  622. package/ui/js/TabMove.js +39 -0
  623. package/ui/js/Tabs.js +751 -0
  624. package/ui/js/Tags.js +134 -0
  625. package/ui/js/Taildrop.js +128 -0
  626. package/ui/js/Tap.js +180 -0
  627. package/ui/js/TextSize.js +107 -0
  628. package/ui/js/Thumbs.js +158 -0
  629. package/ui/js/Transfer.js +172 -0
  630. package/ui/js/Trash.js +84 -0
  631. package/ui/js/TrashDates.js +47 -0
  632. package/ui/js/TrashDrop.js +64 -0
  633. package/ui/js/UiState.js +438 -0
  634. package/ui/js/Unlock.js +152 -0
  635. package/ui/js/Update.js +130 -0
  636. package/ui/js/UserDirs.js +56 -0
  637. package/ui/qmldir +230 -0
@@ -0,0 +1,74 @@
1
+ .pragma library
2
+ .import "MenuContext.js" as MenuContext
3
+
4
+ // What a provider refresh does to an open menu: the answers it draws, whether a rebuild changes anything, where the cursor lands.
5
+
6
+ // The provider inputs off ui/ContextMenu.qml's own properties; the peers are the service's, not gated by the row.
7
+ function live(menu) {
8
+ return MenuContext.live(menu)
9
+ }
10
+
11
+ // A finished refresh's answer, which the menu keeps drawing while the next refresh runs behind it.
12
+ function settle(answer) {
13
+ return MenuContext.settle(answer)
14
+ }
15
+
16
+ // A kept answer for the same install state stands in while a refresh runs, e.g. now { refreshing: true, taildropPeers: [], dropboxPath: "", ... }.
17
+ function providerView(known, now) {
18
+ return MenuContext.providerView(known, now)
19
+ }
20
+
21
+ // Whether a rebuilt inventory is exactly what is drawn, so an answer that changed nothing resets no row.
22
+ function unchanged(previous, next) {
23
+ return JSON.stringify(previous) === JSON.stringify(next)
24
+ }
25
+
26
+ // Release or flyout close schedules the rebuild after tapped dispatch, so the original handler can finish choosing.
27
+ function pressChanged(menu, pressed) {
28
+ if (!pressed && menu.refreshOwed)
29
+ Qt.callLater(function() { if (menu.refreshOwed) menu.refreshProviderRows() })
30
+ }
31
+
32
+ // Only live delegates can hold a refresh; a destroyed pressed row leaves no state behind. A null flyout is a closed one, whose held rows only fade.
33
+ function anyPressed(main, flyout) {
34
+ var repeaters = flyout === null ? [main] : [main, flyout]
35
+ for (var group = 0; group < repeaters.length; group++) {
36
+ var rows = repeaters[group]
37
+ for (var i = 0; i < rows.count; i++) {
38
+ var row = rows.itemAt(i)
39
+ if (row && row.pressed) return true
40
+ }
41
+ }
42
+ return false
43
+ }
44
+
45
+ // Preserve action and peer identity when refreshed capabilities change the inventory beneath the keyboard cursor.
46
+ function refreshedCursor(previous, next, cursor, submenuRow, submenuCursor) {
47
+ var action = previous[cursor] ? previous[cursor].action : ""
48
+ var selected = action ? next.findIndex(function(entry) { return entry.action === action }) : -1
49
+ if (selected < 0) {
50
+ selected = Math.min(Math.max(0, cursor), next.length - 1)
51
+ while (selected < next.length && selected >= 0 && (next[selected].separator || next[selected].disabled)) selected++
52
+ if (selected === next.length) {
53
+ selected--
54
+ while (selected >= 0 && (next[selected].separator || next[selected].disabled)) selected--
55
+ }
56
+ }
57
+ var oldSubmenu = previous[submenuRow]
58
+ var subRow = oldSubmenu ? next.findIndex(function(entry) { return entry.action === oldSubmenu.action }) : -1
59
+ var sub = subRow >= 0 ? next[subRow] : null
60
+ var oldTarget = oldSubmenu && oldSubmenu.submenu ? oldSubmenu.submenu[submenuCursor] : null
61
+ var target = sub && !sub.disabled && oldTarget ? (sub.submenu || []).findIndex(function(entry) { return entry.id === oldTarget.id && !entry.disabled }) : -1
62
+ return { cursor: selected, submenuRow: target >= 0 ? subRow : -1, submenuCursor: Math.max(0, target) }
63
+ }
64
+
65
+ // A changed answer replaces an open menu's rows; cursor and flyout follow their actions, the flyout inside the build hold so it reads its rows once.
66
+ function apply(menu, next) {
67
+ var selection = refreshedCursor(menu.entries, next, menu.cursor, menu.openSubmenuRow, menu.submenuCursor)
68
+ // A lone flyout's leaves come from Menu.flyoutEntries, which no provider answer changes, so it keeps its row and highlight.
69
+ var lone = menu.loneFlyoutAction.length > 0
70
+ menu.setEntries(next, lone ? undefined : selection.submenuRow)
71
+ menu.cursor = selection.cursor
72
+ if (!lone)
73
+ menu.submenuCursor = selection.submenuCursor
74
+ }
@@ -0,0 +1,35 @@
1
+ .pragma library
2
+
3
+ // A menu's wheel answer in raw angleDelta units: highlight steps, content follows through reveal().
4
+
5
+ // One discrete notch in raw angleDelta units, Qt's own convention for a wheel click.
6
+ var NOTCH_UNITS = 120
7
+
8
+ // Folds raw angleDelta into whole notches (remainder kept, dropped on flip, reset on open).
9
+ function notchSteps(accum, angleDelta) {
10
+ var a = Number(accum) || 0
11
+ var d = Number(angleDelta) || 0
12
+ if (d === 0)
13
+ return { steps: 0, rest: a }
14
+ if (a !== 0 && ((a < 0) !== (d < 0)))
15
+ a = 0
16
+ var total = a + d
17
+ var notches = total > 0 ? Math.floor(total / NOTCH_UNITS) : Math.ceil(total / NOTCH_UNITS)
18
+ return { steps: -notches, rest: total - notches * NOTCH_UNITS }
19
+ }
20
+
21
+ // Folds gained travel into whole rows at rowHeight px (leftover kept, reset on ScrollBegin, no tail).
22
+ function touchSteps(accum, gained, rowHeight) {
23
+ var row = Math.max(1, Number(rowHeight) || 0)
24
+ var total = (Number(accum) || 0) + (Number(gained) || 0)
25
+ var steps = 0
26
+ while (total <= -row) {
27
+ steps += 1
28
+ total += row
29
+ }
30
+ while (total >= row) {
31
+ steps -= 1
32
+ total -= row
33
+ }
34
+ return { steps: steps, rest: total }
35
+ }
@@ -0,0 +1,186 @@
1
+ .pragma library
2
+
3
+ .import "DropDev.js" as DropDev
4
+ .import "Menu.js" as Menu
5
+
6
+ // Every line the backend sends, turned into the signal the front end listens for. Split out of
7
+ // ui/Backend.qml, which owns the socket, the requests and the signals themselves: the routing is a
8
+ // long table and a table is not a socket's business. The sample lines live with the signals there.
9
+ function route(root, message) {
10
+ if (message.t === "listed") {
11
+ root.dirDev = message.v || 0
12
+ root.dirWritable = message.w !== false
13
+ root.listed(message.n, message.read, message.sort, message.path || "", message.changed, message.gen || 0)
14
+ } else if (message.t === "rows") {
15
+ var landed = sized(message)
16
+ root.rows(message.start, landed, message.ms, message.kinds || [], message.listing || 0, message.gen || 0)
17
+ } else if (message.t === "error") {
18
+ // The backend names an empty clipboard by code, so the one sentence lives in Menu.EMPTY_CLIPBOARD.
19
+ root.failed(message.where, message.path, message.code === "emptyclipboard" ? Menu.EMPTY_CLIPBOARD : message.msg, message.mode || 0)
20
+ } else if (message.t === "localsendpeers") {
21
+ root.localSendPeers(message.peers || [], message.reason || "")
22
+ } else if (message.t === "localsendsent") {
23
+ root.localSendSent(message.ok === true, message.reason || "")
24
+ } else if (message.t === "thumbed") {
25
+ root.thumbed(message.row, message.file)
26
+ } else if (message.t === "dirsized") {
27
+ root.dirSized(message.row, message.bytes, message.partial)
28
+ } else if (message.t === "dirsizedone") {
29
+ root.dirSizeDone(message.cancelled === true)
30
+ } else if (message.t === "settagged") {
31
+ root.settagged(message)
32
+ } else if (message.t === "tagstates") {
33
+ root.tagStatesResult(message)
34
+ } else if (message.t === "searching") {
35
+ root.searching(message.n, message.scanned, message.ms)
36
+ } else if (message.t === "searched") {
37
+ root.searched(message.n, message.scanned, message.ms, message.cancelled, message.gen || 0, message.walking === true)
38
+ } else if (message.t === "transferstarted") {
39
+ root.transferStarted(message.id, message.n, message.moving, false)
40
+ } else if (message.t === "extractstarted") {
41
+ root.transferStarted(message.id, 1, false, true)
42
+ } else if (message.t === "transferprogress") {
43
+ root.transferProgress(message.id, message.index, message.name, message.bytes, message.total, message.scanned || 0,
44
+ message.phase || "", message.drive || "")
45
+ } else if (message.t === "transferitem") {
46
+ // err rides only on a failure, so an ok item has no field to read here.
47
+ root.transferItem(message.id, message.index, message.name, message.ok, message.err || "")
48
+ } else if (message.t === "transferdone") {
49
+ // durable stays unread until a "written to the drive" sentence exists; note already
50
+ // has one, the verdict's own, which ui/js/Ops.js draws ahead of the undo hint.
51
+ root.transferDone(message.id, message.ok, message.failed, message.skipped, message.cancelled, message.retryPaths || [],
52
+ message.durable === true, message.note || "", message.merged || 0, message.keptBoth || 0, message.into || "")
53
+ } else if (message.t === "collisions") {
54
+ root.collisions(message.id, message.total, message.names || [], message.mergeable === true)
55
+ } else if (message.t === "mergecollisions") {
56
+ root.mergeCollisions(message.id, message.total, message.names || [])
57
+ } else if (message.t === "fatnames") {
58
+ root.fatnames(message.id || 0, message.renames || [], message.fstype || "", message.volume || "")
59
+ // MenuAdditions040: Paste as links answers one line per request, and one
60
+ // journal entry, so one undo removes every link it created.
61
+ } else if (message.t === "linked") {
62
+ root.linked(message.ok || 0, message.failed || 0, message.skipped || 0, message.note || "")
63
+ // MenuAdditions040: Show original reveals the link's target in its own folder.
64
+ } else if (message.t === "linktarget") {
65
+ root.linkTarget(message.path || "", message.directory || "", message.name || "", message.id || 0)
66
+ } else if (message.t === "trashed") {
67
+ root.trashed(message.ok, message.failed, message.err || "")
68
+ } else if (message.t === "renamed") {
69
+ root.renamed(message.ok, message.path)
70
+ } else if (message.t === "slow") {
71
+ // A remote write past its deadline: information first, the reply itself later.
72
+ root.slowOp(message.op || "", message.path || "", message.msg || "")
73
+ } else if (message.t === "bulkrenamed") {
74
+ root.bulkRenamed(message.ok || 0, message.unchanged || 0)
75
+ } else if (message.t === "made") {
76
+ root.made(message.ok, message.path)
77
+ } else if (message.t === "duplicated") {
78
+ root.duplicated(message.ok, message.path)
79
+ } else if (message.t === "undone") {
80
+ root.undone(message.op, message.ok)
81
+ } else if (message.t === "redone") {
82
+ root.redone(message.op, message.ok)
83
+ } else if (message.t === "redostarted") {
84
+ root.redoStarted(message.id, message.n, message.op)
85
+ } else if (message.t === "paths") {
86
+ root.paths(message.paths || [])
87
+ } else if (message.t === "located") {
88
+ root.located(message)
89
+ // flea-qml: the command Find spawns, named once at start; null when nothing can run it.
90
+ } else if (message.t === "findcommand") {
91
+ root.findArgv = Array.isArray(message.argv) && message.argv.length > 0 ? message.argv : null
92
+ root.grepArgv = Array.isArray(message.grep) && message.grep.length > 0 ? message.grep : null
93
+ // flea-qml: the backend's Trash count, sent at start and whenever it changes.
94
+ } else if (message.t === "trashcount") {
95
+ root.trashCount = message.count
96
+ root.trashRevision = message.revision || 0
97
+ // flea-qml: the folders and drives the backend found by looking, sent at start, when a rail
98
+ // asks and whenever they change.
99
+ } else if (message.t === "places") {
100
+ root.placesFound(Array.isArray(message.places) ? message.places : [], Array.isArray(message.volumes) ? message.volumes : [])
101
+ } else if (message.t === "trashbrowse") {
102
+ root.trashResult(message)
103
+ } else if (message.t === "permissions") {
104
+ root.permissionsResult(message)
105
+ } else if (message.t === "picker") {
106
+ root.pickerResult(message)
107
+ } else if (message.t === "menuaction") {
108
+ root.menuResult(message)
109
+ } else if (message.t === "pdfcopied") {
110
+ root.pdfCopied(message.id || 0, message.path || "", message.err || "", message.stalled === true)
111
+ } else if (message.t === "fontlooked") {
112
+ root.fontLooked(message)
113
+ } else if (message.t === "meta") {
114
+ root.metaResult(message)
115
+ root.meta(message.row, message.w, message.h, message.orient || 1, message.ms, message.rate, message.entries, message.unpacked, message.afailed, message.names, message.lines, message.partial, message.lfailed === true, message.target, message.targetdir, message.owner || "", typeof message.topEntries === "number" ? message.topEntries : -1)
116
+ } else if (message.t === "code") {
117
+ root.codeResult(message)
118
+ } else if (message.t === "html") {
119
+ root.htmlResult(message)
120
+ } else if (message.t === "markdownhtml") {
121
+ root.markdownHtmlResult(message)
122
+ } else if (message.t === "figure") {
123
+ root.figureResult(message)
124
+ } else if (message.t === "compare") {
125
+ root.compareResult(message)
126
+ } else if (message.t === "shebang") {
127
+ root.shebang(message.path || "", message.hasShebang === true, message.id || 0)
128
+ } else if (message.t === "clip") {
129
+ root.clipResult(message)
130
+ } else if (message.t === "fsinfo") {
131
+ root.fsInfo(message.fs, message.free, message.path || "", message.class || "", message.tagable === true, message.system === true)
132
+ } else if (message.t === "changed") {
133
+ root.changed(message.path || "")
134
+ } else if (message.t === "unmounted") {
135
+ root.unmounted(message.path || "", message.parent || "")
136
+ } else if (message.t === "jumped") {
137
+ root.jumped(message.id || 0, message.favourites || [], message.zoxide || [], message.recent || [], message.frecency || {})
138
+ } else if (message.t === "devs") {
139
+ if (message.id > 0) root.metaResult(message)
140
+ else root.pathDevs = DropDev.merged(root.pathDevs, message.devs)
141
+ } else if (message.t === "peeked") {
142
+ root.peeked(message.path, message.hidden === true, message.n, message.rows || [], message.failed === true, message.mode || 0, message.hiddenLast === true, message.first || 0, message.v || 0, message.w !== false, message.by || "", message.desc === true)
143
+ } else if (message.t === "formats") {
144
+ root.archiveFormats = message.archive || []
145
+ root.canConvert = message.convert === true
146
+ root.extraction = message.extract || ({archive: false, sevenZip: false})
147
+ root.providers = message.providers || ({})
148
+ root.formatsResult(message)
149
+ } else if (message.t === "archivestarted") {
150
+ root.archiveStarted(message.id)
151
+ } else if (message.t === "archivedone") {
152
+ root.archiveDone(message.id, message.ok, message.verified !== false, message.err || "", message.path || "", message.dest || "")
153
+ } else if (message.t === "convertchecked") {
154
+ root.convertChecked(message)
155
+ } else if (message.t === "convertstarted") {
156
+ root.convertStarted(message.id, message.requestId || 0, message.source || "")
157
+ } else if (message.t === "convertdone") {
158
+ root.convertDone(message.id, message.ok, message.path || "", message.err || "", message.requestId || 0,
159
+ message.source || "", message.collision === true)
160
+ } else if (message.t === "flashimage") {
161
+ root.flashImageResult(message)
162
+ } else if (message.t === "flashtargets") {
163
+ root.flashTargetsResult(message)
164
+ } else if (message.t === "flashstarted") {
165
+ root.flashStartedLine(message.id, message.total || 0, message.known === true)
166
+ } else if (message.t === "flashprogress") {
167
+ root.flashProgressLine(message.id, message.phase || "", message.bytes || 0,
168
+ message.total || 0, message.permille || 0)
169
+ } else if (message.t === "flashdone") {
170
+ root.flashDoneLine(message)
171
+ } else if (message.t === "flasheject") {
172
+ root.flashEjectLine(message)
173
+ }
174
+ }
175
+
176
+ // A live answer's rows line names the folder sizes the backend already knows; each one rides on its own row.
177
+ // Sample input: {"t":"rows","start":20,"rows":[{"n":"c","d":true,"s":4096,"m":1787790423,"p":16877,"i":"folder","t":false,"k":0,"v":2049}],"kinds":["Folder"],"ms":0.410,"listing":5,"gen":3,"z":[[20,96]]} gives row "c" z 96.
178
+ function sized(message) {
179
+ var z = message.z || []
180
+ for (var i = 0; i < z.length; i++) {
181
+ var row = message.rows[z[i][0] - message.start]
182
+ if (row)
183
+ row.z = z[i][1]
184
+ }
185
+ return message.rows
186
+ }
@@ -0,0 +1,16 @@
1
+ .pragma library
2
+
3
+ // The structural transitions use OutCubic, 180 ms to reveal and 140 ms to hide.
4
+
5
+ var durMs = {
6
+ // A reveal reads slower than a hide.
7
+ open: 180,
8
+ close: 140
9
+ }
10
+
11
+ // Open rises into place from this far below its resting position; close does not translate,
12
+ // opacity only (see the Preview/ShareBrowser/NetworkDialog verticalCenterOffset/y bindings).
13
+ var translateUpPx = 10
14
+
15
+ // How long the pointer rests at the left edge before the auto-hidden rail opens; the OEM bar holds its centre peek 120 ms (Bar.qml:834).
16
+ var dwellMs = 120
@@ -0,0 +1,320 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+ .import "Protocols.js" as Protocols
5
+ .import "Menu.js" as Menu
6
+
7
+ // Whole sentences with "%1" for a value, filled by fill so each translates as one; replace would read "$$" in a label as a pattern.
8
+ var WORDS = {
9
+ nothingToRelease: "%1 has nothing to eject or unmount",
10
+ stillEjecting: "Still ejecting %1; wait for its result",
11
+ stillUnmounting: "Still unmounting %1; wait for its result",
12
+ anotherMounting: "Another drive is still mounting. Try again when it finishes",
13
+ stillUnmountingTryAgain: "%1 is still unmounting. Try again when it finishes",
14
+ ejecting: "Ejecting %1. Do not unplug it yet.",
15
+ noFolder: "%1 was mounted, but Flea could not find its folder.",
16
+ ejectUnfinished: "%1 did not finish ejecting and is still mounted.",
17
+ mountFailed: "%1 could not be mounted.",
18
+ damaged: "%1 could not be mounted: its file system is damaged or not supported.",
19
+ unmountFailed: "%1 could not be unmounted.",
20
+ ejectFailed: "%1 could not be ejected.",
21
+ busy: "%1 is busy; close what is using it and try again.",
22
+ mountRefused: "%1 was not mounted: you do not have permission.",
23
+ unmountRefused: "%1 was not unmounted: you do not have permission.",
24
+ ejectRefused: "%1 was not ejected: you do not have permission.",
25
+ noDisc: "%1 has no disc or card in it.",
26
+ notMountable: "%1 cannot be mounted on this computer.",
27
+ anotherOpening: "Another network location is still opening. Try again when it opens",
28
+ notSaved: "%1 is not saved, and stays in the sidebar until it is unmounted",
29
+ forgottenStays: "%1 is forgotten, and stays in the sidebar until it is unmounted",
30
+ forgotten: "%1 is forgotten",
31
+ unmountedLine: "Unmounted %1",
32
+ bridgeMissing: "Could not open %1 because part of Flea did not load. Reinstall Flea.",
33
+ transferUsing: "%1 could not be unmounted. A transfer may still be using it."
34
+ }
35
+
36
+ // Sample input, captured live on the box with one network share mounted (2026-08-31):
37
+ // Drive(0): KBG40ZNS256G NVMe KIOXIA 256GB
38
+ // Type: GProxyDrive (GProxyVolumeMonitorUDisks2)
39
+ // Mount(0): isos on 192.168.1.10 -> smb://192.168.1.10/isos/
40
+ // Type: GDaemonMount
41
+ // Only Mount() lines matter here; Drive() and every indented "Type:" line are noise for the rail.
42
+ function parseMounts(output) {
43
+ var out = []
44
+ var mounts = mountLines(output)
45
+ for (var i = 0; i < mounts.length; i++) {
46
+ var uri = mounts[i].uri
47
+ // corner: a local device mount (file://) is Favorites territory, not Network; Places.js skips the inverse.
48
+ if (uri.indexOf("file://") === 0)
49
+ continue
50
+ // A phone is DEVICES territory the same way: its row is ui/js/Phones.js's, built from the
51
+ // volume block, and this line is gio's shadow GDaemonMount printed beside it. afc is the
52
+ // iPhone's own, whose root mount prints here rather than inside its volume block.
53
+ if (/^(mtp|gphoto2|afc):\/\//i.test(uri))
54
+ continue
55
+ out.push({ label: Protocols.shareName(mounts[i].name, uri), uri: uri })
56
+ }
57
+ return out
58
+ }
59
+
60
+ // Sample input: "Mount(2): isos on 192.168.1.10 -> smb://192.168.1.10/isos/" answers { name: "isos on 192.168.1.10", uri: "smb://192.168.1.10/isos/" }.
61
+ // Every top-level "Mount(N): name -> uri" line of gio mount -l; the one owner of that line's grammar.
62
+ function mountLines(output) {
63
+ var out = []
64
+ var lines = String(output || "").split("\n")
65
+ for (var i = 0; i < lines.length; i++) {
66
+ var m = lines[i].match(/^Mount\(\d+\):\s*(.+?)\s*->\s*(\S+)\s*$/)
67
+ if (m)
68
+ out.push({ name: m[1], uri: m[2] })
69
+ }
70
+ return out
71
+ }
72
+
73
+ // Sample input: "Mount(0): photos -> file:///mnt/kmount-photos" answers { path: "/mnt/kmount-photos", label: "photos", uri: "file:///mnt/kmount-photos" }.
74
+ // Issue #257: what gio adds to a kernel row, matched by path; a non-file line adds nothing, an unlisted mount keeps its leaf label.
75
+ function gioKernelMounts(gioText) {
76
+ var out = []
77
+ var mounts = mountLines(gioText)
78
+ for (var i = 0; i < mounts.length; i++) {
79
+ var m = mounts[i]
80
+ if (m.uri.indexOf("file://") !== 0)
81
+ continue
82
+ var path = decodePath(m.uri.substring("file://".length)).replace(/\/+$/, "")
83
+ out.push({ path: path.length > 0 ? path : "/", label: Protocols.shareName(m.name, m.uri), uri: m.uri })
84
+ }
85
+ return out
86
+ }
87
+
88
+ // Sample input, "gio info" under the C locale ui/NetworkMounts.qml pins on every gio call:
89
+ // uri: smb://192.168.1.10/isos/
90
+ // local path: /run/user/1000/gvfs/smb-share:server=192.168.1.10,share=isos
91
+ // Only a location GVFS exposes through its FUSE mount prints that line, so "" means there is no
92
+ // browsable folder. One resolver, so the product and tests/js/network.js read the same wording.
93
+ function localPath(body) {
94
+ var lines = String(body || "").split("\n")
95
+ for (var i = 0; i < lines.length; i++) {
96
+ if (lines[i].indexOf("local path: ") === 0)
97
+ return lines[i].substring("local path: ".length).trim()
98
+ }
99
+ return ""
100
+ }
101
+
102
+ // Issue 133 (mfilm77): no GVFS backend implements trash, so gio trash refuses every path under its FUSE folder.
103
+ // Sample input: /run/user/1000/gvfs/smb-share:server=192.168.21.25,share=data/photos, where "smb-share:" names the mount.
104
+ // A read-only folder has no trash either: the listed line's own writability rides along, so iso9660
105
+ // and a root-owned stick root offer Delete permanently instead of a Trash row that only fails.
106
+ function trashable(path, writable) {
107
+ if (writable === false)
108
+ return false
109
+ return !underGvfs(path)
110
+ }
111
+
112
+ // A path inside the GVFS FUSE root /run/user/<uid>/gvfs, where the "scheme:" segment names the mount; a folder named gvfs elsewhere is plain.
113
+ function underGvfs(path) {
114
+ return /^\/run\/user\/[^/]+\/gvfs\/[A-Za-z0-9-]+:/.test(String(path || ""))
115
+ }
116
+
117
+ // Sample input: the operator's real bookmarks file, ui/js/Places.js "bookmarks" reads the same lines.
118
+ // file:///home/gm/Downloads Downloads
119
+ // smb://192.168.1.10/ NAS
120
+ // Places.bookmarks() keeps the file:// line and drops the smb:// one; this is the exact mirror.
121
+ function nonFileBookmarks(body) {
122
+ var out = []
123
+ var lines = String(body || "").split("\n")
124
+ for (var i = 0; i < lines.length; i++) {
125
+ var line = lines[i].trim()
126
+ if (line.length === 0 || line.indexOf("file://") === 0)
127
+ continue
128
+ var space = line.indexOf(" ")
129
+ var uri = space < 0 ? line : line.substring(0, space)
130
+ // corner: a line with no scheme at all is not a bookmark, not just not a file:// one.
131
+ if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(uri))
132
+ continue
133
+ var label = space < 0 ? "" : line.substring(space + 1).trim()
134
+ out.push({ uri: uri, label: label.length > 0 ? label : leaf(uri) })
135
+ }
136
+ return out
137
+ }
138
+
139
+ // The bare-root form (smb://host/) has no path leaf, so this falls back to the host itself.
140
+ function leaf(uri) {
141
+ var stripped = String(uri).replace(/^[a-z][a-z0-9+.-]*:\/\//i, "").replace(/\/+$/, "")
142
+ var slash = stripped.lastIndexOf("/")
143
+ var tail = slash < 0 ? stripped : stripped.substring(slash + 1)
144
+ return tail.length > 0 ? tail : stripped
145
+ }
146
+
147
+ // decodeURIComponent throws on a malformed escape, and a bookmarks line is arbitrary text, so a
148
+ // failure answers the raw path rather than taking the whole rail rebuild with it.
149
+ function decodePath(raw) {
150
+ try {
151
+ return decodeURIComponent(String(raw))
152
+ } catch (e) {
153
+ return String(raw)
154
+ }
155
+ }
156
+
157
+ // One canonical form: every trailing slash stripped except a bare host root, which keeps one, and
158
+ // a port the scheme would have used anyway dropped, because gio's own listing never reports one.
159
+ function normalize(uri) {
160
+ var stripped = Protocols.stripDefaultPort(String(uri || "").replace(/\/+$/, ""))
161
+ var bareRoot = /^[a-z][a-z0-9+.-]*:\/\/[^\/]+$/i.test(stripped)
162
+ return bareRoot ? stripped + "/" : stripped
163
+ }
164
+
165
+ // NETWORK shows on its discoveries, DEVICES on those plus its own; the deadline shows whatever each has.
166
+ function railGroupsReady(networkDone, devicesDone, elapsedMs, deadlineMs) {
167
+ if (elapsedMs >= deadlineMs)
168
+ return { showNetwork: true, showDevices: true }
169
+ var showNetwork = networkDone === true
170
+ return { showNetwork: showNetwork, showDevices: showNetwork && devicesDone === true }
171
+ }
172
+
173
+ // A password may be given to any scheme here whose authority names a user.
174
+ function credentialed(uri) {
175
+ return /^(smb|sftp|ftp|ftps|dav|davs):\/\/[^\/]*@/i.test(String(uri || ""))
176
+ }
177
+
178
+ // Try sftp keys before asking for a password.
179
+ function keyless(uri) {
180
+ return /^sftp:\/\//i.test(String(uri || ""))
181
+ }
182
+
183
+ // PR #21: a live mount wins the rail row, and the operator's own bookmark label wins its name, or a
184
+ // rename typed on a mounted share is written to the file and never drawn. Matched the way rebuild dedups.
185
+ function railLabel(mount, marks) {
186
+ for (var i = 0; i < marks.length; i++) {
187
+ if (normalize(marks[i].uri) === normalize(mount.uri)) return marks[i].label
188
+ }
189
+ return mount.label
190
+ }
191
+
192
+ // Sample input: two arrays of rail entries as ui/NetworkMounts.qml and ui/DeviceMounts.qml build
193
+ // them, [{path:"", label:"NAS", group:"network", kind:"share", uri:"smb://example.com/data",
194
+ // mounted:false, glyph:"server"}]. A poll that found no change must not assign a fresh array: the
195
+ // Repeater rebinds every rail row on the assignment, and a rebound row is a row whose editor lost
196
+ // what was typed into it. Both builders are covered, so every field either one writes is compared.
197
+ function sameEntries(a, b) {
198
+ if (!a || !b || a.length !== b.length)
199
+ return false
200
+ for (var i = 0; i < a.length; i++) {
201
+ if (!sameEntry(a[i], b[i]))
202
+ return false
203
+ }
204
+ return true
205
+ }
206
+
207
+ // The two shapes differ only in uri against device, and an absent field is undefined on both sides.
208
+ function sameEntry(x, y) {
209
+ return x.path === y.path && x.label === y.label && x.group === y.group && x.kind === y.kind
210
+ && x.uri === y.uri && x.device === y.device && x.mounted === y.mounted && x.glyph === y.glyph
211
+ && x.size === y.size && x.editable === y.editable && x.removable === y.removable
212
+ && x.fstype === y.fstype && x.fsver === y.fsver && x.mediaRemovable === y.mediaRemovable && x.readOnly === y.readOnly
213
+ && (x.locked || false) === (y.locked || false) && x.loop === y.loop
214
+ }
215
+
216
+ // Sample input: one rail entry as ui/DeviceMounts.qml and ui/NetworkMounts.qml build them,
217
+ // {label:"128GB", group:"device", kind:"volume", device:"/dev/sda1", mounted:true, removable:true}.
218
+ // Rows come from ui/js/Menu.js kind R; gio's -f is offered nowhere, since forcing an unmount over an open write loses data.
219
+ function railMenu(entry) {
220
+ if (!entry)
221
+ return []
222
+ return Menu.railEntries(entry)
223
+ }
224
+
225
+ // A root-only remote mount covers its saved addressable paths; SMB shares remain path-specific.
226
+ function addressMountCovers(liveUri, savedUri) {
227
+ var live = normalize(liveUri)
228
+ var saved = normalize(savedUri)
229
+ return /^(sftp|ftp|ftps|dav|davs):\/\/[^\/]+\/$/i.test(live)
230
+ && saved.length > live.length && saved.indexOf(live) === 0
231
+ }
232
+
233
+ // The rail's right click opens railMenu's rows; ui/js/Eject.js reads railMenu too, so Ctrl+E refuses an unmounted row.
234
+ function rowMenu(entry) {
235
+ return railMenu(entry)
236
+ }
237
+
238
+ // The handle a chosen menu row carries back: a volume's device node, a share's uri, "" for a row
239
+ // with no release. The rail rebuilds on a five second poll, so an index taken when the menu opened
240
+ // can name a different row by the time a row inside it is chosen; a key cannot.
241
+ function railKey(entry) {
242
+ if (!entry)
243
+ return ""
244
+ if (entry.group === "device" && entry.kind === "volume")
245
+ return String(entry.device || "")
246
+ if (entry.group === "device" && entry.kind === "phone")
247
+ return String(entry.uri || "")
248
+ if (entry.group === "network" && entry.kind === "share")
249
+ return String(entry.uri || "")
250
+ return ""
251
+ }
252
+
253
+ // Where that key resolves back to a position in the group's own list, or -1 when the row is gone.
254
+ // An empty key matches nothing: a row that carries no key must never resolve to whatever is at 0.
255
+ function rowByKey(entries, key) {
256
+ if (String(key || "").length === 0)
257
+ return -1
258
+ var list = entries || []
259
+ for (var i = 0; i < list.length; i++) {
260
+ if (railKey(list[i]) === key)
261
+ return i
262
+ }
263
+ return -1
264
+ }
265
+
266
+ // The device or network row with a release whose path holds the directory, or null; a favourite never names a volume.
267
+ function holding(entries, dir) {
268
+ var list = entries || []
269
+ var path = String(dir || "")
270
+ for (var i = 0; i < list.length; i++) {
271
+ var e = list[i]
272
+ if (!e.path || (e.group !== "device" && e.group !== "network") || railMenu(e).length === 0)
273
+ continue
274
+ if (inside(path, e.path))
275
+ return e
276
+ }
277
+ return null
278
+ }
279
+
280
+ // Whether dir is root itself or lies under it; ui/js/Places.js heldBy asks the rail the same question.
281
+ function inside(dir, root) {
282
+ return dir === root || dir.indexOf(root + "/") === 0
283
+ }
284
+
285
+ // The keyboard's route into the rail menu, and where a rail row without one is answered: the sheet
286
+ // advertises m, so a key that silently did nothing on a favourite would read as a broken one.
287
+ function raiseMenu(pane, sidebar) {
288
+ var entry = sidebar.entries[sidebar.cursorIndex]
289
+ if (!entry)
290
+ return
291
+ if (rowMenu(entry).length > 0)
292
+ sidebar.openCursorMenu()
293
+ else
294
+ pane.message(Format.fill(WORDS.nothingToRelease, entry.label), false)
295
+ }
296
+
297
+ // Sample input: (true, "a", "a", "b", "b") answers "skip", while (true, "a", "x", "b", "b") answers "rebuild".
298
+ function pollDecision(listedOnce, polledListing, lastListing, mountinfoText, lastMountinfo) {
299
+ if (!listedOnce) return "none"
300
+ if (polledListing === lastListing && mountinfoText === lastMountinfo) return "skip"
301
+ return "rebuild"
302
+ }
303
+
304
+ // Sample input: the operator's own bookmarks file, favourites and network places in one list.
305
+ // smb://192.168.1.10/isos NAS isos
306
+ // Read off the trimmed line the way nonFileBookmarks reads it, or an indented line is a rail row
307
+ // nothing removes, and normalized the way Places.relabel matches; a kept line is pushed back raw.
308
+ function removeBookmark(body, uri) {
309
+ var target = normalize(uri)
310
+ var lines = String(body || "").split("\n")
311
+ var out = []
312
+ for (var i = 0; i < lines.length; i++) {
313
+ var trimmed = lines[i].trim(), space = trimmed.indexOf(" ")
314
+ var one = space < 0 ? trimmed : trimmed.substring(0, space)
315
+ if (target.length > 0 && one.length > 0 && normalize(one) === target)
316
+ continue
317
+ out.push(lines[i])
318
+ }
319
+ return out.join("\n")
320
+ }
@@ -0,0 +1,13 @@
1
+ .pragma library
2
+
3
+ // The mouse's side buttons: Nav.js mouseBack takes refused, WindowBody.qml takes both after refusing its own overlays.
4
+
5
+ // No navigation closes the pane's context menu or the collision card, so a press behind one would act on another directory's rows.
6
+ function refused(pane) {
7
+ return pane.menuVisible || !!(pane.collide && pane.collide.opened)
8
+ }
9
+
10
+ // Forward takes pane.goForward, the key's own entry, so Trash and Recent refuse it as they refuse the key.
11
+ function forward(pane) {
12
+ if (!refused(pane)) pane.goForward()
13
+ }