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.
- package/LICENSE +22 -0
- package/README.md +511 -2
- package/THIRD-PARTY-NOTICES.md +29 -0
- package/demos/App.java +5 -0
- package/demos/Dockerfile +4 -0
- package/demos/Main.kt +3 -0
- package/demos/Program.cs +1 -0
- package/demos/README.md +12 -0
- package/demos/app.dart +3 -0
- package/demos/app.deb +0 -0
- package/demos/app.js +1 -0
- package/demos/backup.tar +0 -0
- package/demos/budget.xlsx +0 -0
- package/demos/build.sh +2 -0
- package/demos/bundle.zip +0 -0
- package/demos/clip.mp4 +0 -0
- package/demos/data.sqlite +0 -0
- package/demos/disk.iso +0 -0
- package/demos/engine.cpp +5 -0
- package/demos/firmware.bin +0 -0
- package/demos/flake.nix +4 -0
- package/demos/folder/inside.txt +1 -0
- package/demos/font.ttf +0 -0
- package/demos/index.html +5 -0
- package/demos/index.php +2 -0
- package/demos/init.lua +1 -0
- package/demos/letter.docx +0 -0
- package/demos/lib.rs +3 -0
- package/demos/main.c +6 -0
- package/demos/main.h +3 -0
- package/demos/math-and-diagrams.md +200 -0
- package/demos/notes.tar.gz +0 -0
- package/demos/notes.txt +3 -0
- package/demos/photo.png +0 -0
- package/demos/program +2 -0
- package/demos/report.pdf +32 -0
- package/demos/script.py +1 -0
- package/demos/server.go +7 -0
- package/demos/settings.json +4 -0
- package/demos/slides.pptx +0 -0
- package/demos/song.mp3 +0 -0
- package/demos/style.css +4 -0
- package/demos/tool.rb +1 -0
- package/demos/types.ts +2 -0
- package/docs/pele.md +23 -0
- package/docs/protocol.md +3420 -0
- package/docs/temml.md +63 -0
- package/index.js +107 -0
- package/package.json +34 -4
- package/src/archive.js +407 -0
- package/src/archiveops.js +728 -0
- package/src/backend.js +369 -0
- package/src/bulkrename.js +95 -0
- package/src/clip-host.js +76 -0
- package/src/clip.js +462 -0
- package/src/code.js +168 -0
- package/src/compare.js +74 -0
- package/src/create.js +128 -0
- package/src/dirsize.js +147 -0
- package/src/figure-svg.js +530 -0
- package/src/figure-thread.js +23 -0
- package/src/figure.js +132 -0
- package/src/find.js +55 -0
- package/src/flea.js +39 -0
- package/src/fsinfo.js +39 -0
- package/src/highlight.js +141 -0
- package/src/html.js +52 -0
- package/src/kinds.js +89 -0
- package/src/listing.js +130 -0
- package/src/markdown-html.js +317 -0
- package/src/mathml.js +186 -0
- package/src/menu.js +180 -0
- package/src/meta.js +135 -0
- package/src/office.js +810 -0
- package/src/order.js +100 -0
- package/src/peek.js +49 -0
- package/src/pele-wrapper.js +695 -0
- package/src/permissions.js +180 -0
- package/src/places.js +313 -0
- package/src/preview-language.js +10 -0
- package/src/terminal-server.js +95 -0
- package/src/terminal-shell.js +26 -0
- package/src/transfer.js +669 -0
- package/src/trash-record.js +41 -0
- package/src/trash.js +210 -0
- package/src/trashbrowse.js +327 -0
- package/src/uistate.js +393 -0
- package/src/uistore.js +168 -0
- package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
- package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
- package/src/vendor/LICENSES/MIT-katex.txt +21 -0
- package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
- package/src/vendor/LICENSES/MIT-pele.txt +40 -0
- package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
- package/src/vendor/LICENSES/MIT-temml.txt +21 -0
- package/src/vendor/pele.js +145 -0
- package/src/vendor/temml.mjs +14708 -0
- package/src/watch.js +98 -0
- package/src/wayland/client.js +109 -0
- package/src/wayland/protocol.js +55 -0
- package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
- package/src/wayland/protocols/wayland.xml +3248 -0
- package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
- package/src/wayland/resource-io.js +6 -0
- package/src/wayland/socket-discovery.js +26 -0
- package/src/wayland/transport-posix.js +120 -0
- package/src/wayland/transport-win32.js +11 -0
- package/src/wayland/transport.js +3 -0
- package/src/wayland/win32-resources.js +80 -0
- package/src/wayland/win32-wire.js +62 -0
- package/test/archive.test.js +80 -0
- package/test/bench-markdown-scroll.mjs +190 -0
- package/test/clip-host.test.js +113 -0
- package/test/code-preview.test.js +35 -0
- package/test/compare-ui-paths.test.js +24 -0
- package/test/compare.test.js +54 -0
- package/test/delete-trash.test.js +67 -0
- package/test/dirsize.test.js +138 -0
- package/test/file-ops.test.js +307 -0
- package/test/file-url.test.js +24 -0
- package/test/find-contents.test.js +161 -0
- package/test/find-input.test.js +66 -0
- package/test/fixtures/pele-parity.json +1006 -0
- package/test/highlight-launcher.test.js +35 -0
- package/test/html-preview.test.js +22 -0
- package/test/input.test.js +15 -0
- package/test/keymap.test.js +26 -0
- package/test/language-icons.test.js +36 -0
- package/test/launcher.test.js +51 -0
- package/test/manual-archive-here-ui.mjs +47 -0
- package/test/manual-code-scroll.mjs +28 -0
- package/test/manual-column-scroll.mjs +24 -0
- package/test/manual-compare-ui.mjs +20 -0
- package/test/manual-find-status.mjs +37 -0
- package/test/manual-folder-focus.mjs +63 -0
- package/test/manual-html-security.mjs +23 -0
- package/test/manual-html-ui.mjs +30 -0
- package/test/manual-syntax-preview.mjs +26 -0
- package/test/manual-terminal-lifecycle.mjs +42 -0
- package/test/manual-terminal-navigation.mjs +48 -0
- package/test/manual-terminal-ui.mjs +47 -0
- package/test/manual-trash-ui.mjs +86 -0
- package/test/markdown-diagrams.test.js +93 -0
- package/test/markdown-html.test.js +105 -0
- package/test/mathml.test.js +92 -0
- package/test/menu-transfer.test.js +57 -0
- package/test/office-preview.test.js +154 -0
- package/test/pele-parity.test.js +28 -0
- package/test/places.test.js +134 -0
- package/test/preview-keys.test.js +60 -0
- package/test/preview-language.test.js +22 -0
- package/test/status-filename.test.js +20 -0
- package/test/transfer-replace-merge.test.js +187 -0
- package/test/trash-address.test.js +23 -0
- package/test/trash-view.test.js +37 -0
- package/test/trashbrowse.test.js +135 -0
- package/ui/AboutFacts.qml +78 -0
- package/ui/ArchiveCards.qml +95 -0
- package/ui/ArchiveCompressDialog.qml +378 -0
- package/ui/ArchiveHereConfirm.qml +127 -0
- package/ui/ArchivePasswordDialog.qml +257 -0
- package/ui/Backend.qml +775 -0
- package/ui/BulkOldNames.qml +47 -0
- package/ui/BulkRenameDialog.qml +380 -0
- package/ui/CardFrame.qml +67 -0
- package/ui/CardScroll.qml +79 -0
- package/ui/CheckBox.qml +73 -0
- package/ui/ChromeBar.qml +360 -0
- package/ui/ChromeButton.qml +131 -0
- package/ui/ChromeModes.qml +43 -0
- package/ui/CodeLines.qml +256 -0
- package/ui/CodeRefusal.qml +52 -0
- package/ui/CollideConfirm.qml +147 -0
- package/ui/CollideHost.qml +167 -0
- package/ui/ColumnPane.qml +525 -0
- package/ui/ColumnRow.qml +380 -0
- package/ui/ColumnsArea.qml +594 -0
- package/ui/ColumnsLanding.qml +147 -0
- package/ui/CompareView.qml +321 -0
- package/ui/ContextMenu.qml +743 -0
- package/ui/ConvertDialog.qml +456 -0
- package/ui/CountedWorker.qml +7 -0
- package/ui/Crumb.qml +64 -0
- package/ui/CrumbDrop.qml +25 -0
- package/ui/CsvTable.qml +394 -0
- package/ui/CursorMark.qml +41 -0
- package/ui/DefaultClaim.qml +130 -0
- package/ui/DeviceLock.qml +47 -0
- package/ui/DeviceMounts.qml +540 -0
- package/ui/DialogButton.qml +150 -0
- package/ui/DialogField.qml +147 -0
- package/ui/DialogHeader.qml +31 -0
- package/ui/DialogScrim.qml +20 -0
- package/ui/DialogTitle.qml +37 -0
- package/ui/Divider.qml +9 -0
- package/ui/DropInto.qml +126 -0
- package/ui/DropTarget.qml +35 -0
- package/ui/DropboxMark.qml +60 -0
- package/ui/EmptyState.qml +150 -0
- package/ui/EscapeHint.qml +11 -0
- package/ui/FactsTable.qml +54 -0
- package/ui/FastScrollHandler.qml +476 -0
- package/ui/FatNamesConfirm.qml +157 -0
- package/ui/Favourites.qml +143 -0
- package/ui/FigureService.qml +120 -0
- package/ui/FileDrag.qml +267 -0
- package/ui/FilterStrip.qml +133 -0
- package/ui/FitMetrics.qml +22 -0
- package/ui/FlashDriveRows.qml +137 -0
- package/ui/FlashHost.qml +72 -0
- package/ui/FlashImageRow.qml +104 -0
- package/ui/FlashRunner.qml +119 -0
- package/ui/FlashStepRow.qml +172 -0
- package/ui/FlashStrip.qml +38 -0
- package/ui/FlashView.qml +397 -0
- package/ui/FleaMark.qml +88 -0
- package/ui/FlyoutFade.qml +23 -0
- package/ui/FontPane.qml +170 -0
- package/ui/Glass.qml +114 -0
- package/ui/GlassTagger.qml +59 -0
- package/ui/Glyph.qml +64 -0
- package/ui/GlyphSolid.qml +22 -0
- package/ui/GridArea.qml +664 -0
- package/ui/GridTile.qml +325 -0
- package/ui/GvfsBridge.qml +164 -0
- package/ui/Header.qml +433 -0
- package/ui/HoverTimers.qml +39 -0
- package/ui/HtmlClip.qml +30 -0
- package/ui/HtmlPane.qml +63 -0
- package/ui/HyprlandMark.qml +45 -0
- package/ui/Ipc.qml +1005 -0
- package/ui/IpcControls.qml +7 -0
- package/ui/IpcMenuState.qml +48 -0
- package/ui/IpcPreviewState.qml +185 -0
- package/ui/JumpPath.qml +51 -0
- package/ui/KeymapSheet.qml +561 -0
- package/ui/KeymapSheetResult.qml +89 -0
- package/ui/KindStack.qml +40 -0
- package/ui/LangMark.qml +51 -0
- package/ui/LangMarkLoader.qml +26 -0
- package/ui/List.qml +480 -0
- package/ui/LoadingState.qml +54 -0
- package/ui/LocalSend.qml +56 -0
- package/ui/LocalSendMark.qml +73 -0
- package/ui/MarkdownBlockView.qml +311 -0
- package/ui/MarkdownBlocks.qml +35 -0
- package/ui/MarkdownFigure.qml +254 -0
- package/ui/MarkdownImages.qml +72 -0
- package/ui/MarkdownList.qml +81 -0
- package/ui/MarkdownMathsText.qml +97 -0
- package/ui/MarkdownPane.qml +83 -0
- package/ui/MarkdownPictures.qml +41 -0
- package/ui/MarkdownQuote.qml +52 -0
- package/ui/MarkdownRemote.qml +82 -0
- package/ui/MarkdownSource.qml +155 -0
- package/ui/MarkdownTable.qml +222 -0
- package/ui/MarkdownTableScroll.qml +64 -0
- package/ui/MarkdownTableWheel.qml +126 -0
- package/ui/MarkdownText.qml +87 -0
- package/ui/MarkdownWorker.js +132 -0
- package/ui/MatchText.qml +99 -0
- package/ui/MediaSession.qml +38 -0
- package/ui/MediaSound.qml +26 -0
- package/ui/MediaStrip.qml +191 -0
- package/ui/MediaTrack.qml +36 -0
- package/ui/MediaVolume.qml +54 -0
- package/ui/MenuActionDialog.qml +396 -0
- package/ui/MenuEdgeFade.qml +24 -0
- package/ui/MenuHost.qml +227 -0
- package/ui/MenuRow.qml +351 -0
- package/ui/MountListing.qml +100 -0
- package/ui/NetworkDialog.qml +435 -0
- package/ui/NetworkForm.qml +426 -0
- package/ui/NetworkMounts.qml +913 -0
- package/ui/NetworkPlaces.qml +127 -0
- package/ui/OpenWithDialog.qml +613 -0
- package/ui/Opener.qml +95 -0
- package/ui/Pane.qml +1320 -0
- package/ui/PaneMenuActions.qml +527 -0
- package/ui/PanePath.qml +90 -0
- package/ui/PaneRail.qml +268 -0
- package/ui/PaneStates.qml +88 -0
- package/ui/PaneSwap.qml +339 -0
- package/ui/PaneWire.qml +601 -0
- package/ui/ParkedWait.qml +9 -0
- package/ui/PathEntry.qml +186 -0
- package/ui/PathJump.qml +400 -0
- package/ui/PdfViewer.qml +297 -0
- package/ui/PermissionsDialog.qml +658 -0
- package/ui/PermissionsHeadings.qml +31 -0
- package/ui/PhoneMounts.qml +67 -0
- package/ui/PickerAnswers.qml +75 -0
- package/ui/PickerBox.qml +26 -0
- package/ui/PickerChrome.qml +295 -0
- package/ui/PickerFilter.qml +97 -0
- package/ui/PickerGrid.qml +308 -0
- package/ui/PickerHeader.qml +28 -0
- package/ui/PickerLifecycle.qml +27 -0
- package/ui/PickerList.qml +218 -0
- package/ui/PickerListing.qml +149 -0
- package/ui/PickerPathBar.qml +127 -0
- package/ui/PickerPlaces.qml +189 -0
- package/ui/PickerRecent.qml +92 -0
- package/ui/PickerSave.qml +101 -0
- package/ui/PickerSelection.qml +155 -0
- package/ui/PickerWindow.qml +846 -0
- package/ui/PowerSectorsReader.qml +10 -0
- package/ui/PrebuildDriver.qml +146 -0
- package/ui/Preview.qml +1005 -0
- package/ui/PreviewAnimation.qml +24 -0
- package/ui/PreviewArchive.qml +91 -0
- package/ui/PreviewColumn.qml +553 -0
- package/ui/PreviewEdge.qml +63 -0
- package/ui/PreviewFacts.qml +30 -0
- package/ui/PreviewFactsLine.qml +34 -0
- package/ui/PreviewHtml.qml +233 -0
- package/ui/PreviewImage.qml +253 -0
- package/ui/PreviewImagePan.qml +13 -0
- package/ui/PreviewImageSharp.qml +32 -0
- package/ui/PreviewLines.qml +106 -0
- package/ui/PreviewMarkdown.qml +706 -0
- package/ui/PreviewMedia.qml +250 -0
- package/ui/PreviewPdf.qml +482 -0
- package/ui/PreviewScroll.qml +201 -0
- package/ui/PreviewSwap.qml +335 -0
- package/ui/PreviewText.qml +149 -0
- package/ui/ProtocolChip.qml +18 -0
- package/ui/QuickLookArchive.qml +41 -0
- package/ui/QuickLookBar.qml +103 -0
- package/ui/QuickLookPrepare.qml +355 -0
- package/ui/QuickLookSwap.qml +10 -0
- package/ui/QuickLookWarm.qml +65 -0
- package/ui/RailDrop.qml +155 -0
- package/ui/RailHeading.qml +19 -0
- package/ui/RailPlaces.qml +38 -0
- package/ui/RailTrashRow.qml +67 -0
- package/ui/RenameField.qml +353 -0
- package/ui/RendererRetry.qml +11 -0
- package/ui/ResizeHandle.qml +52 -0
- package/ui/Reveal.qml +54 -0
- package/ui/Row.qml +476 -0
- package/ui/RowDrag.qml +213 -0
- package/ui/RowDropTarget.qml +27 -0
- package/ui/RunCard.qml +286 -0
- package/ui/Scripts.qml +65 -0
- package/ui/SearchStrip.qml +232 -0
- package/ui/SelectionBand.qml +140 -0
- package/ui/SelectionPreview.qml +370 -0
- package/ui/SettingsFavourite.qml +122 -0
- package/ui/SettingsGroup.qml +96 -0
- package/ui/SettingsHint.qml +12 -0
- package/ui/SettingsMetrics.qml +29 -0
- package/ui/SettingsPane.qml +178 -0
- package/ui/SettingsPanel.qml +547 -0
- package/ui/SettingsRail.qml +128 -0
- package/ui/SettingsRow.qml +409 -0
- package/ui/SettingsRuler.qml +85 -0
- package/ui/SettingsSegment.qml +85 -0
- package/ui/ShareBrowser.qml +113 -0
- package/ui/ShareLink.qml +67 -0
- package/ui/ShelfPins.qml +101 -0
- package/ui/Sidebar.qml +728 -0
- package/ui/SidebarRow.qml +358 -0
- package/ui/Spinner.qml +60 -0
- package/ui/StableModel.qml +89 -0
- package/ui/StateMessage.qml +84 -0
- package/ui/StatusBar.qml +512 -0
- package/ui/StatusFileName.qml +27 -0
- package/ui/TabBar.qml +673 -0
- package/ui/TabDragGeometry.qml +60 -0
- package/ui/TagMenuMark.qml +52 -0
- package/ui/TagRailSection.qml +53 -0
- package/ui/TagSlot.qml +40 -0
- package/ui/TagState.qml +150 -0
- package/ui/TagSwatch.qml +28 -0
- package/ui/Taildrop.qml +86 -0
- package/ui/TailscaleMark.qml +50 -0
- package/ui/TerminalService.qml +69 -0
- package/ui/TerminalTab.qml +48 -0
- package/ui/TerminalTabs.qml +27 -0
- package/ui/Theme.qml +460 -0
- package/ui/ThemeColors.qml +43 -0
- package/ui/TransferCard.qml +239 -0
- package/ui/TrashConfirm.qml +129 -0
- package/ui/TrashDropHandler.qml +11 -0
- package/ui/TrashHost.qml +202 -0
- package/ui/TrashMonitor.qml +30 -0
- package/ui/TrashToolbar.qml +19 -0
- package/ui/TrashView.qml +492 -0
- package/ui/UnlockDialog.qml +450 -0
- package/ui/UnlockHost.qml +206 -0
- package/ui/UpdateCheck.qml +97 -0
- package/ui/UserDirs.qml +25 -0
- package/ui/ViewState.qml +565 -0
- package/ui/ViewportScrollBar.qml +195 -0
- package/ui/ViewportScrollBars.qml +25 -0
- package/ui/WebPreview.qml +33 -0
- package/ui/WebPreviewView.qml +26 -0
- package/ui/WindowBody.qml +829 -0
- package/ui/WindowDrag.qml +35 -0
- package/ui/boot/Commons/AudioNodes.qml +50 -0
- package/ui/boot/Commons/AudioNodesModel.js +96 -0
- package/ui/boot/Commons/Border.qml +243 -0
- package/ui/boot/Commons/BorderGeometry.js +373 -0
- package/ui/boot/Commons/Color.qml +258 -0
- package/ui/boot/Commons/I18n.qml +118 -0
- package/ui/boot/Commons/InputDevices.qml +112 -0
- package/ui/boot/Commons/InputMethodState.qml +38 -0
- package/ui/boot/Commons/IpcRegistry.qml +77 -0
- package/ui/boot/Commons/Numbers.js +19 -0
- package/ui/boot/Commons/Plural.js +91 -0
- package/ui/boot/Commons/ShellIpc.qml +12 -0
- package/ui/boot/Commons/Style.qml +561 -0
- package/ui/boot/Commons/Translations.qml +100 -0
- package/ui/boot/Commons/UntypedInput.qml +152 -0
- package/ui/boot/Commons/Util.qml +188 -0
- package/ui/boot/Commons/qmldir +13 -0
- package/ui/boot/LICENSE-omarchy +20 -0
- package/ui/boot/Ui/BackgroundMedia.qml +49 -0
- package/ui/boot/Ui/BarIconButton.qml +106 -0
- package/ui/boot/Ui/BarIconContent.qml +38 -0
- package/ui/boot/Ui/BarIndicator.qml +53 -0
- package/ui/boot/Ui/BarWidget.qml +50 -0
- package/ui/boot/Ui/BorderOverlay.qml +54 -0
- package/ui/boot/Ui/BorderSurface.qml +40 -0
- package/ui/boot/Ui/Button.qml +224 -0
- package/ui/boot/Ui/ButtonGroup.qml +131 -0
- package/ui/boot/Ui/ConfirmDialog.qml +134 -0
- package/ui/boot/Ui/CursorSurface.qml +42 -0
- package/ui/boot/Ui/Dropdown.qml +245 -0
- package/ui/boot/Ui/FilterInput.qml +26 -0
- package/ui/boot/Ui/IconContentBounds.qml +141 -0
- package/ui/boot/Ui/KeyboardPanel.qml +453 -0
- package/ui/boot/Ui/MultiSelect.qml +624 -0
- package/ui/boot/Ui/NumberField.qml +86 -0
- package/ui/boot/Ui/OpticalGlyph.qml +68 -0
- package/ui/boot/Ui/OverlayWindow.qml +102 -0
- package/ui/boot/Ui/Panel.qml +60 -0
- package/ui/boot/Ui/PanelActionButton.qml +105 -0
- package/ui/boot/Ui/PanelController.qml +16 -0
- package/ui/boot/Ui/PanelHero.qml +112 -0
- package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
- package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
- package/ui/boot/Ui/PanelSeparator.qml +19 -0
- package/ui/boot/Ui/PanelSlider.qml +156 -0
- package/ui/boot/Ui/PanelToolTip.qml +50 -0
- package/ui/boot/Ui/PluginBarApi.qml +89 -0
- package/ui/boot/Ui/PointerMoveGate.qml +54 -0
- package/ui/boot/Ui/PopupCard.qml +181 -0
- package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
- package/ui/boot/Ui/SearchableDropdown.qml +354 -0
- package/ui/boot/Ui/SizedImage.qml +125 -0
- package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
- package/ui/boot/Ui/TextField.qml +58 -0
- package/ui/boot/Ui/Toggle.qml +118 -0
- package/ui/boot/Ui/ToggleSwitch.qml +115 -0
- package/ui/boot/Ui/WidgetButton.qml +172 -0
- package/ui/boot/Ui/qmldir +41 -0
- package/ui/boot/fleatab.qml +50 -0
- package/ui/boot/picker.qml +39 -0
- package/ui/boot/shell.qml +131 -0
- package/ui/boot/tabtearoff.qml +51 -0
- package/ui/js/Anchor.js +379 -0
- package/ui/js/AnchorHold.js +162 -0
- package/ui/js/Archive.js +157 -0
- package/ui/js/ArchiveCard.js +44 -0
- package/ui/js/ArchiveOps.js +44 -0
- package/ui/js/BackReturn.js +118 -0
- package/ui/js/BulkRename.js +100 -0
- package/ui/js/Buttons.js +54 -0
- package/ui/js/ChromeKeys.js +116 -0
- package/ui/js/ClipMarks.js +73 -0
- package/ui/js/ClipSelection.js +67 -0
- package/ui/js/Clipboard.js +179 -0
- package/ui/js/Cloud.js +97 -0
- package/ui/js/CodeRuns.js +72 -0
- package/ui/js/Collide.js +212 -0
- package/ui/js/ColumnFit.js +28 -0
- package/ui/js/ColumnMenu.js +111 -0
- package/ui/js/Columns.js +298 -0
- package/ui/js/ColumnsCarry.js +103 -0
- package/ui/js/Compare.js +74 -0
- package/ui/js/Contrast.js +157 -0
- package/ui/js/ControlReader.js +42 -0
- package/ui/js/Convert.js +52 -0
- package/ui/js/CopyAs.js +52 -0
- package/ui/js/Crumbs.js +178 -0
- package/ui/js/Csv.js +231 -0
- package/ui/js/Density.js +44 -0
- package/ui/js/Devices.js +440 -0
- package/ui/js/DirSizes.js +180 -0
- package/ui/js/Drag.js +360 -0
- package/ui/js/DragOut.js +166 -0
- package/ui/js/DropDev.js +52 -0
- package/ui/js/Dropbox.js +41 -0
- package/ui/js/Eject.js +217 -0
- package/ui/js/Errors.js +188 -0
- package/ui/js/ExtThumbs.js +115 -0
- package/ui/js/Facts.js +402 -0
- package/ui/js/FigureDate.js +14 -0
- package/ui/js/Filter.js +285 -0
- package/ui/js/Find.js +46 -0
- package/ui/js/Flash.js +184 -0
- package/ui/js/FlashCard.js +79 -0
- package/ui/js/FlashEndings.js +125 -0
- package/ui/js/FlashPane.js +116 -0
- package/ui/js/FleaBin.js +12 -0
- package/ui/js/Focus.js +504 -0
- package/ui/js/FolderSorts.js +108 -0
- package/ui/js/FolderViews.js +44 -0
- package/ui/js/Format.js +314 -0
- package/ui/js/Fuzzy.js +141 -0
- package/ui/js/GlassTag.js +72 -0
- package/ui/js/Grid.js +33 -0
- package/ui/js/GridGeometry.js +90 -0
- package/ui/js/GridNames.js +153 -0
- package/ui/js/GvfsBridge.js +200 -0
- package/ui/js/HostClipboard.js +29 -0
- package/ui/js/Icons.js +218 -0
- package/ui/js/Input.js +50 -0
- package/ui/js/Jump.js +200 -0
- package/ui/js/KeyName.js +64 -0
- package/ui/js/Keymap.js +401 -0
- package/ui/js/Kinds.js +164 -0
- package/ui/js/LICENSES/ISC-lucide.txt +43 -0
- package/ui/js/LangMarkPaths.js +47 -0
- package/ui/js/LangMarks.js +120 -0
- package/ui/js/Lists.js +11 -0
- package/ui/js/LocalSend.js +39 -0
- package/ui/js/LockedMenu.js +63 -0
- package/ui/js/MakeDefault.js +186 -0
- package/ui/js/MarkBox.js +7 -0
- package/ui/js/Markdown.js +119 -0
- package/ui/js/MarkdownLists.js +86 -0
- package/ui/js/MarkdownMaths.js +58 -0
- package/ui/js/MarkdownPictures.js +32 -0
- package/ui/js/MarkdownPrepared.js +139 -0
- package/ui/js/MarkdownTableFit.js +34 -0
- package/ui/js/Marks.js +148 -0
- package/ui/js/Marquee.js +96 -0
- package/ui/js/Match.js +93 -0
- package/ui/js/Material.js +109 -0
- package/ui/js/MdBlocks.js +437 -0
- package/ui/js/MdBreak.js +71 -0
- package/ui/js/MdChunks.js +70 -0
- package/ui/js/MdContainer.js +137 -0
- package/ui/js/MdDocument.js +337 -0
- package/ui/js/MdEmph.js +97 -0
- package/ui/js/MdEntity.js +108 -0
- package/ui/js/MdEntityTable.js +223 -0
- package/ui/js/MdEscape.js +59 -0
- package/ui/js/MdFront.js +37 -0
- package/ui/js/MdHold.js +32 -0
- package/ui/js/MdHtml.js +307 -0
- package/ui/js/MdHtmlBlock.js +290 -0
- package/ui/js/MdHtmlHeading.js +53 -0
- package/ui/js/MdHtmlImage.js +179 -0
- package/ui/js/MdInline.js +154 -0
- package/ui/js/MdItems.js +212 -0
- package/ui/js/MdLeaf.js +309 -0
- package/ui/js/MdLink.js +196 -0
- package/ui/js/MdMath.js +67 -0
- package/ui/js/MdParagraphs.js +138 -0
- package/ui/js/MdRefs.js +232 -0
- package/ui/js/MdResolve.js +226 -0
- package/ui/js/MdRun.js +300 -0
- package/ui/js/MdUrl.js +226 -0
- package/ui/js/Menu.js +514 -0
- package/ui/js/MenuContext.js +85 -0
- package/ui/js/MenuFit.js +13 -0
- package/ui/js/MenuRefresh.js +74 -0
- package/ui/js/MenuWheel.js +35 -0
- package/ui/js/Messages.js +186 -0
- package/ui/js/Motion.js +16 -0
- package/ui/js/Mounts.js +320 -0
- package/ui/js/MouseNav.js +13 -0
- package/ui/js/Nav.js +329 -0
- package/ui/js/NetFs.js +26 -0
- package/ui/js/OpenWith.js +83 -0
- package/ui/js/Ops.js +585 -0
- package/ui/js/Palette.js +33 -0
- package/ui/js/PathBar.js +260 -0
- package/ui/js/Permissions.js +179 -0
- package/ui/js/Phones.js +112 -0
- package/ui/js/Picker.js +353 -0
- package/ui/js/PlaceMenu.js +96 -0
- package/ui/js/Places.js +265 -0
- package/ui/js/PreviewAsk.js +21 -0
- package/ui/js/PreviewKeys.js +155 -0
- package/ui/js/PreviewSettle.js +29 -0
- package/ui/js/PreviewSwap.js +101 -0
- package/ui/js/PropertyFacts.js +144 -0
- package/ui/js/Protocols.js +296 -0
- package/ui/js/QuickLookKinds.js +27 -0
- package/ui/js/QuickLookRect.js +24 -0
- package/ui/js/RailDrop.js +51 -0
- package/ui/js/RailKeys.js +87 -0
- package/ui/js/RailMenu.js +133 -0
- package/ui/js/Recent.js +135 -0
- package/ui/js/RecentMode.js +156 -0
- package/ui/js/Reload.js +60 -0
- package/ui/js/Renderer.js +9 -0
- package/ui/js/RunFile.js +143 -0
- package/ui/js/Scripts.js +28 -0
- package/ui/js/Scroll.js +304 -0
- package/ui/js/ScrollOff.js +69 -0
- package/ui/js/Search.js +478 -0
- package/ui/js/Selection.js +97 -0
- package/ui/js/Settings.js +476 -0
- package/ui/js/SettingsAbout.js +97 -0
- package/ui/js/SettingsShelf.js +52 -0
- package/ui/js/SheetKeys.js +42 -0
- package/ui/js/SheetQuery.js +281 -0
- package/ui/js/ShelfPile.js +27 -0
- package/ui/js/SlowClick.js +53 -0
- package/ui/js/SlowOp.js +6 -0
- package/ui/js/Sort.js +134 -0
- package/ui/js/Startup.js +63 -0
- package/ui/js/StateWords.js +17 -0
- package/ui/js/Status.js +238 -0
- package/ui/js/Swap.js +166 -0
- package/ui/js/TabMove.js +39 -0
- package/ui/js/Tabs.js +751 -0
- package/ui/js/Tags.js +134 -0
- package/ui/js/Taildrop.js +128 -0
- package/ui/js/Tap.js +180 -0
- package/ui/js/TextSize.js +107 -0
- package/ui/js/Thumbs.js +158 -0
- package/ui/js/Transfer.js +172 -0
- package/ui/js/Trash.js +84 -0
- package/ui/js/TrashDates.js +47 -0
- package/ui/js/TrashDrop.js +64 -0
- package/ui/js/UiState.js +438 -0
- package/ui/js/Unlock.js +152 -0
- package/ui/js/Update.js +130 -0
- package/ui/js/UserDirs.js +56 -0
- package/ui/qmldir +230 -0
package/ui/js/Eject.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Mounts.js" as Mounts
|
|
4
|
+
.import "Format.js" as Format
|
|
5
|
+
.import "Protocols.js" as Protocols
|
|
6
|
+
.import "NetFs.js" as NetFs
|
|
7
|
+
|
|
8
|
+
// Whole sentences with "%1" for the drive and "%2" for the drives still mounted under it, filled by Format.fill; the first three are what Ctrl+E answers with when it releases nothing.
|
|
9
|
+
var WORDS = {
|
|
10
|
+
systemDrive: "%1 is the system drive, which Flea never unmounts",
|
|
11
|
+
systemVolume: "This folder is on a system volume, which Flea never unmounts",
|
|
12
|
+
noVolume: "This folder is not on a volume Flea can unmount",
|
|
13
|
+
safe: "Ejected %1. It is safe to unplug.",
|
|
14
|
+
safeImage: "Ejected %1.",
|
|
15
|
+
stillMounted: "%1 is still mounted; close what is using it.",
|
|
16
|
+
blockedOne: "%1 could not be ejected because %2 on the same drive is still mounted. Eject that instead.",
|
|
17
|
+
blockedMany: "%1 could not be ejected because %2 on the same drive are still mounted. Eject those instead.",
|
|
18
|
+
unconfirmed: "Could not confirm %1 was ejected; do not unplug it yet."
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Sample input: the lsblk --json body ui/js/Mounts.js "parseDevices" reads, taken again after
|
|
22
|
+
// gio mount -e returned for /dev/sda1:
|
|
23
|
+
// {"blockdevices":[
|
|
24
|
+
// {"name":"sda","path":"/dev/sda","label":null,"mountpoints":[null],"rm":true,"size":"116.1G","type":"disk","model":"USB Flash Disk",
|
|
25
|
+
// "children":[{"name":"sda1","path":"/dev/sda1","label":"128GB","mountpoints":[null],"rm":true,"size":"116.1G","type":"part","model":null}]}]}
|
|
26
|
+
// The sda entry is then either gone, or still listed with every mountpoint under it null.
|
|
27
|
+
// gio's exit code is never the witness: it has been 0 over a volume that stayed mounted.
|
|
28
|
+
// "safe" when nothing under the disk that carries the device is mounted, "mounted" when anything
|
|
29
|
+
// under it still is, "unknown" when the body is not a listing this can judge.
|
|
30
|
+
function verdict(body, device) {
|
|
31
|
+
var disk = diskOf(body, device)
|
|
32
|
+
if (disk === undefined)
|
|
33
|
+
return "unknown"
|
|
34
|
+
if (disk === null)
|
|
35
|
+
return "safe"
|
|
36
|
+
return anyMounted(disk) ? "mounted" : "safe"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// The top-level lsblk node that holds the device: undefined when the body is not a listing, null
|
|
40
|
+
// when no node holds it, which is the powered-off shape. The whole disk is what gets judged: gvfs
|
|
41
|
+
// ejects the drive, so a sibling partition or a crypt child still mounted means still in use.
|
|
42
|
+
function diskOf(body, device) {
|
|
43
|
+
var tree
|
|
44
|
+
try {
|
|
45
|
+
tree = JSON.parse(String(body || ""))
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return undefined
|
|
48
|
+
}
|
|
49
|
+
var nodes = tree && tree.blockdevices
|
|
50
|
+
// A box with no block devices at all is not running, so an empty listing is a broken one.
|
|
51
|
+
if (!Array.isArray(nodes) || nodes.length === 0)
|
|
52
|
+
return undefined
|
|
53
|
+
var name = kernelName(device)
|
|
54
|
+
if (name.length === 0)
|
|
55
|
+
return undefined
|
|
56
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
57
|
+
if (holds(nodes[i], name))
|
|
58
|
+
return nodes[i]
|
|
59
|
+
}
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Both sides of every comparison here come from lsblk's own NAME column. volumeRow carries lsblk's
|
|
64
|
+
// PATH now, and a device-mapper volume's path is /dev/mapper/<name>, so the leaf is what is read.
|
|
65
|
+
function kernelName(device) {
|
|
66
|
+
var text = String(device || "")
|
|
67
|
+
var cut = text.lastIndexOf("/")
|
|
68
|
+
return cut < 0 ? text : text.substring(cut + 1)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function holds(node, name) {
|
|
72
|
+
if (String(node.name) === name)
|
|
73
|
+
return true
|
|
74
|
+
var kids = node.children || []
|
|
75
|
+
for (var i = 0; i < kids.length; i++) {
|
|
76
|
+
if (holds(kids[i], name))
|
|
77
|
+
return true
|
|
78
|
+
}
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// lsblk writes "[SWAP]" as a mountpoint of active swap, which is in use like any other mount. This
|
|
83
|
+
// asks whether anything holds the volume at all, which is not Mounts.js mountOf's question: that one
|
|
84
|
+
// answers where to browse, and swap is nowhere.
|
|
85
|
+
function inUse(node) {
|
|
86
|
+
var points = node.mountpoints || []
|
|
87
|
+
for (var i = 0; i < points.length; i++) {
|
|
88
|
+
if (points[i] !== null && String(points[i]).length > 0)
|
|
89
|
+
return true
|
|
90
|
+
}
|
|
91
|
+
return false
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function anyMounted(node) {
|
|
95
|
+
if (inUse(node))
|
|
96
|
+
return true
|
|
97
|
+
var kids = node.children || []
|
|
98
|
+
for (var i = 0; i < kids.length; i++) {
|
|
99
|
+
if (anyMounted(kids[i]))
|
|
100
|
+
return true
|
|
101
|
+
}
|
|
102
|
+
return false
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// What the refusal has to name. Empty when the row itself is still mounted, because a re-press on
|
|
106
|
+
// it is then the right next step; otherwise the labels of what is still mounted under the same disk,
|
|
107
|
+
// because a re-press on a row lsblk now shows unmounted would silently do nothing.
|
|
108
|
+
function blockers(body, device) {
|
|
109
|
+
var disk = diskOf(body, device)
|
|
110
|
+
if (!disk)
|
|
111
|
+
return []
|
|
112
|
+
var mounted = []
|
|
113
|
+
collectMounted(disk, mounted)
|
|
114
|
+
var name = kernelName(device)
|
|
115
|
+
for (var i = 0; i < mounted.length; i++) {
|
|
116
|
+
if (mounted[i].name === name)
|
|
117
|
+
return []
|
|
118
|
+
}
|
|
119
|
+
return mounted.map(function (m) { return m.label })
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function collectMounted(node, out) {
|
|
123
|
+
if (inUse(node))
|
|
124
|
+
out.push({ name: String(node.name), label: node.label ? String(node.label) : String(node.name) })
|
|
125
|
+
var kids = node.children || []
|
|
126
|
+
for (var i = 0; i < kids.length; i++)
|
|
127
|
+
collectMounted(kids[i], out)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Only a real drive's safe verdict may claim it is safe to unplug; an image has nothing to unplug.
|
|
131
|
+
// Other verdicts keep their warnings and name a next step only when pressing it does something.
|
|
132
|
+
function sentence(v, label, others, loop) {
|
|
133
|
+
if (v === "safe")
|
|
134
|
+
return { text: Format.fill(loop === true ? WORDS.safeImage : WORDS.safe, label), isError: false }
|
|
135
|
+
if (v === "attached") // A loop row unmounted, but its loop device could not be detached.
|
|
136
|
+
return { text: "Unmounted " + label + ", but its loop device is still attached.", isError: true }
|
|
137
|
+
if (v === "mounted") {
|
|
138
|
+
var rest = others || []
|
|
139
|
+
if (rest.length === 0)
|
|
140
|
+
return { text: Format.fill(WORDS.stillMounted, label), isError: true }
|
|
141
|
+
return { text: Format.fill(rest.length > 1 ? WORDS.blockedMany : WORDS.blockedOne, label, rest.join(", ")), isError: true }
|
|
142
|
+
}
|
|
143
|
+
return { text: Format.fill(WORDS.unconfirmed, label), isError: true }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Only a releasable mounted row draws the mark in place of the square.
|
|
147
|
+
// Sample input: {label:"NAS", group:"network", kind:"share", uri:"smb://h/data/", mounted:true}.
|
|
148
|
+
function releasable(entry) {
|
|
149
|
+
if (!entry || entry.mounted !== true)
|
|
150
|
+
return false
|
|
151
|
+
if (entry.group === "device" && entry.kind === "volume")
|
|
152
|
+
return entry.removable === true || entry.loop === true
|
|
153
|
+
if (entry.group === "device" && entry.kind === "phone")
|
|
154
|
+
return true
|
|
155
|
+
if (entry.group === "network" && entry.kind === "share") {
|
|
156
|
+
// A kernel row names its fstype for the mark split; a gvfs share's scheme decides it.
|
|
157
|
+
if (entry.fstype)
|
|
158
|
+
return NetFs.isCifsFstype(entry.fstype)
|
|
159
|
+
return Protocols.schemeOf(entry.uri) !== "nfs"
|
|
160
|
+
}
|
|
161
|
+
return false
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// The one-click release mirrors the rows Mounts.railMenu offers.
|
|
165
|
+
function releaseAction(entry) {
|
|
166
|
+
if (!releasable(entry))
|
|
167
|
+
return ""
|
|
168
|
+
if (entry.group === "device" && entry.kind === "phone")
|
|
169
|
+
return "unmountPhone"
|
|
170
|
+
return entry.group === "device" ? "eject" : "unmount"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Picked by name, never position (a volume or phone row leads with Open): Eject, else the row's unmount, else "".
|
|
174
|
+
function releaseFromRows(rows) {
|
|
175
|
+
var list = rows || []
|
|
176
|
+
for (var i = 0; i < list.length; i++) {
|
|
177
|
+
if (list[i].action === "eject")
|
|
178
|
+
return "eject"
|
|
179
|
+
}
|
|
180
|
+
for (var j = 0; j < list.length; j++) {
|
|
181
|
+
if (list[j].action === "unmount" || list[j].action === "unmountVolume" || list[j].action === "unmountPhone")
|
|
182
|
+
return list[j].action
|
|
183
|
+
}
|
|
184
|
+
return ""
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Finder's Cmd+E with Cmd read as Ctrl: from the rail it releases the cursor row, from a listing the
|
|
188
|
+
// mounted volume the directory is inside, so the key can never release a volume the operator is
|
|
189
|
+
// not looking at. The verdict is Mounts.railMenu's either way, off the lsblk poll, and the release
|
|
190
|
+
// goes through the same releaseChosen a chosen menu row takes, carrying the row's key. A hidden rail
|
|
191
|
+
// unloads the Sidebar with its poll, verdict state and releaseChosen, so there is nothing to read
|
|
192
|
+
// and nothing to release through: the pane spins a transient DeviceMounts for one one-shot listing
|
|
193
|
+
// (ui/PaneRail.qml), which completes through this same function with its own entries and
|
|
194
|
+
// releaseChosen. A null rail therefore never answers from silence; it hands the key to that flow.
|
|
195
|
+
function release(root, rail, fromRail) {
|
|
196
|
+
if (!rail) {
|
|
197
|
+
root.ejectHidden()
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
var entry = fromRail ? rail.entries[rail.cursorIndex] : Mounts.holding(rail.entries, root.path)
|
|
201
|
+
if (fromRail && entry && entry.group === "device" && entry.kind === "disk") {
|
|
202
|
+
root.message(Format.fill(WORDS.systemDrive, entry.label), false)
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
if (!entry) {
|
|
206
|
+
// The backend alone names a system volume, off the listing's own device; a Recent history spans mounts, so it names none.
|
|
207
|
+
root.message(root.systemVolume === true && root.recentMode === "" ? WORDS.systemVolume : WORDS.noVolume, false)
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
var rows = Mounts.railMenu(entry)
|
|
211
|
+
var pick = releaseFromRows(rows)
|
|
212
|
+
if (pick === "") {
|
|
213
|
+
root.message(Format.fill(Mounts.WORDS.nothingToRelease, entry.label), false)
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
rail.releaseChosen(pick, Mounts.railKey(entry))
|
|
217
|
+
}
|
package/ui/js/Errors.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Format.js" as Format
|
|
4
|
+
|
|
5
|
+
// Whole sentences, filled by Format.fill where a name goes in; the item is a file or a folder.
|
|
6
|
+
var WORDS = {
|
|
7
|
+
deniedNamed: "%1 cannot be opened: you do not have permission.",
|
|
8
|
+
denied: "This folder cannot be opened: you do not have permission.",
|
|
9
|
+
unreadNamed: "%1 could not be read.",
|
|
10
|
+
unread: "That folder could not be read.",
|
|
11
|
+
taken: "An item with that name is already here.",
|
|
12
|
+
// Whole connection failures, each with its one cause; the mount service says it is a connection failure by flag, never by these words.
|
|
13
|
+
connectRefused: "Could not connect: the server refused the connection.",
|
|
14
|
+
connectNoFolder: "Could not connect: that location has no folder to show.",
|
|
15
|
+
connectMountedAs: "Could not connect: that share is already mounted as %1.",
|
|
16
|
+
connectNoAnswer: "Could not connect: the server did not respond.",
|
|
17
|
+
connectNoPassword: "Could not connect: the server did not accept the password.",
|
|
18
|
+
connectNoPrompt: "Could not connect: Flea could not ask for the password.",
|
|
19
|
+
connectUnopened: "Could not connect: the network location could not be opened."
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Errors reach the user as one sentence, never a raw path or errno. StatusBar board rule 4: the
|
|
23
|
+
// sentence names the input and drops advice nobody can act on. named is the failing directory's own
|
|
24
|
+
// leaf, empty when the breadcrumb is already standing on it and there is nothing to add.
|
|
25
|
+
function sentence(where, message, named) {
|
|
26
|
+
if (where === "scan") {
|
|
27
|
+
if (denied(where, message)) {
|
|
28
|
+
return named ? Format.fill(WORDS.deniedNamed, named) : WORDS.denied
|
|
29
|
+
}
|
|
30
|
+
// A dead share names itself: stale, disconnected and silent each read differently.
|
|
31
|
+
if (shareStale(message)) return "That share changed, so this folder is no longer available."
|
|
32
|
+
if (shareGone(message)) return "That share is disconnected; remount it."
|
|
33
|
+
if (shareSilent(message)) return "That share is not responding."
|
|
34
|
+
return named ? Format.fill(WORDS.unreadNamed, named) : WORDS.unread
|
|
35
|
+
}
|
|
36
|
+
if (where === "sort") {
|
|
37
|
+
// Size and mtime are real orders, so the one refusal left is a key the wire never defined.
|
|
38
|
+
return "Sorting by that column is not available."
|
|
39
|
+
}
|
|
40
|
+
if (where === "read") {
|
|
41
|
+
return "Flea stopped responding. Reopen Flea and try again."
|
|
42
|
+
}
|
|
43
|
+
// The write operations say what they were doing, because the operator is about to try it again.
|
|
44
|
+
if (where === "undo" || where === "redo") {
|
|
45
|
+
// The empty journal is the common case and the backend's own sentence is already the right one.
|
|
46
|
+
return capitalised(message)
|
|
47
|
+
}
|
|
48
|
+
if (where === "rename") {
|
|
49
|
+
if (nameRefusal(message)) return capitalised(message)
|
|
50
|
+
if (readOnly(message)) return capitalised(message)
|
|
51
|
+
return exists(message) ? WORDS.taken : "That file could not be renamed."
|
|
52
|
+
}
|
|
53
|
+
// Bulk rename validates the whole batch first, so its sentence is the backend's own.
|
|
54
|
+
if (where === "bulkrename") {
|
|
55
|
+
return capitalised(message)
|
|
56
|
+
}
|
|
57
|
+
// undo reverses a rename through the same call, so this sentence names no direction.
|
|
58
|
+
if (where === "rename-kept") {
|
|
59
|
+
return "Copied to the new name, but the original was only partly removed. Check the original."
|
|
60
|
+
}
|
|
61
|
+
// Deliberately not the capitalised branch: every other mkdir refusal reaches the UI through
|
|
62
|
+
// src/error.rs from_io, which passes std::io::Error::to_string straight through, errno and all.
|
|
63
|
+
if (where === "mkdir") {
|
|
64
|
+
if (nameRefusal(message)) return capitalised(message)
|
|
65
|
+
if (readOnly(message)) return capitalised(message)
|
|
66
|
+
return exists(message) ? WORDS.taken
|
|
67
|
+
: "That folder could not be created."
|
|
68
|
+
}
|
|
69
|
+
// The state file: what was asked for is still on screen, so the sentence says what did not last.
|
|
70
|
+
if (where === "state") {
|
|
71
|
+
return "That setting could not be saved."
|
|
72
|
+
}
|
|
73
|
+
// And the other way round: main() left a ui.json it could not read alone, so none of it is used.
|
|
74
|
+
if (where === "statefile") {
|
|
75
|
+
return "Your saved settings could not be read, so these are the defaults."
|
|
76
|
+
}
|
|
77
|
+
if (where === "duplicate") {
|
|
78
|
+
if (readOnly(message)) return capitalised(message)
|
|
79
|
+
return "That file could not be duplicated."
|
|
80
|
+
}
|
|
81
|
+
if (where === "trash") {
|
|
82
|
+
if (readOnly(message)) return capitalised(message)
|
|
83
|
+
return "That item could not be moved to Trash."
|
|
84
|
+
}
|
|
85
|
+
// The backend refused rows read from a listing it had already replaced, so nothing ran at all.
|
|
86
|
+
if (where === "stale") {
|
|
87
|
+
return "The listing changed before that arrived, so nothing was done."
|
|
88
|
+
}
|
|
89
|
+
// A window past its deadline names its mount, so the backend's own sentence is the one to show.
|
|
90
|
+
if (where === "window") {
|
|
91
|
+
return capitalised(message)
|
|
92
|
+
}
|
|
93
|
+
// A password request refused before the child started names its archive, like the read sentence names Flea.
|
|
94
|
+
if (where === "archive" && String(message) === "the backend is not running") {
|
|
95
|
+
return named ? Format.fill("%1 could not be opened because the Flea backend stopped; reopen Flea and try again.", named)
|
|
96
|
+
: "This archive could not be opened because the Flea backend stopped; reopen Flea and try again."
|
|
97
|
+
}
|
|
98
|
+
if (where === "transfer" || where === "archive" || where === "convert"
|
|
99
|
+
|| where === "link" || where === "linktarget" || where === "rename-stranded" || where === "pasteimage") {
|
|
100
|
+
return capitalised(message)
|
|
101
|
+
}
|
|
102
|
+
return "That action could not be completed; try again."
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// One condition, two spellings: rename gets the errno's "File exists", while src/backend/ops.rs
|
|
106
|
+
// words mkdir's own collision "a folder or file with that name already exists".
|
|
107
|
+
function exists(message) {
|
|
108
|
+
var text = String(message).toLowerCase()
|
|
109
|
+
return text.indexOf("file exists") >= 0 || text.indexOf("already exists") >= 0
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// A read-only refusal carries its own sentence from src/error.rs, so the write branches keep it.
|
|
113
|
+
function readOnly(message) {
|
|
114
|
+
return String(message).toLowerCase().indexOf("read-only") >= 0
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// A per-filesystem name refusal carries its own sentence from src/backend/fsname.rs, so rename and mkdir keep it.
|
|
118
|
+
function nameRefusal(message) {
|
|
119
|
+
var text = String(message)
|
|
120
|
+
return text.indexOf("is not allowed in a name") >= 0 || text.indexOf("is reserved on this") >= 0
|
|
121
|
+
|| text.indexOf("cannot end in a dot") >= 0 || text.indexOf("cannot end in a space") >= 0
|
|
122
|
+
|| text.indexOf("cannot hold control character") >= 0
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// The backend already writes these as sentences; this only makes one read like one in the bar.
|
|
126
|
+
function capitalised(message) {
|
|
127
|
+
var text = String(message)
|
|
128
|
+
if (text.length === 0) {
|
|
129
|
+
return "That action could not be completed; try again."
|
|
130
|
+
}
|
|
131
|
+
var out = text.charAt(0).toUpperCase() + text.substring(1)
|
|
132
|
+
return out.charAt(out.length - 1) === "." ? out : out + "."
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// The one place the backend's errno wording is read, so the sentence and the pane state can never
|
|
136
|
+
// disagree about which failure this is.
|
|
137
|
+
function denied(where, message) {
|
|
138
|
+
return where === "scan" && String(message).toLowerCase().indexOf("permission denied") >= 0
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ESTALE, ENOTCONN and ETIMEDOUT each read differently; the backend's words are src/error.rs.
|
|
142
|
+
function shareStale(message) {
|
|
143
|
+
var text = String(message).toLowerCase()
|
|
144
|
+
return text.indexOf("stale") >= 0 || text.indexOf("no longer available") >= 0
|
|
145
|
+
}
|
|
146
|
+
function shareGone(message) {
|
|
147
|
+
var text = String(message).toLowerCase()
|
|
148
|
+
return text.indexOf("not connected") >= 0
|
|
149
|
+
}
|
|
150
|
+
function shareSilent(message) {
|
|
151
|
+
var text = String(message).toLowerCase()
|
|
152
|
+
return text.indexOf("timed out") >= 0 || text.indexOf("timeout") >= 0
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Which state the listing area reaches when a listing fails. A denial is the canvas's Locked tile on
|
|
156
|
+
// States.dc.html, which draws the lock mark over the directory's own mode string; the rest are Error.
|
|
157
|
+
function listingState(where, message) {
|
|
158
|
+
return denied(where, message) ? "locked" : "error"
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// That tile's one line, drawn verbatim as "rwx------ · not yours". src/backend/meta.rs answers mode 0
|
|
162
|
+
// when the stat itself failed, and a real st_mode always carries its file-type bits, so a zero here
|
|
163
|
+
// means "I could not look" and earns no line rather than a false "---------".
|
|
164
|
+
function lockedLine(mode) {
|
|
165
|
+
if (!(mode > 0)) {
|
|
166
|
+
return ""
|
|
167
|
+
}
|
|
168
|
+
return Format.permissions(mode) + notYours(mode)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Entering a directory needs its execute bit and listing it needs its read bit, so an owner holding
|
|
172
|
+
// both would not have been denied: a denial on such a directory proves the operator is not the
|
|
173
|
+
// owner. Below that the owner is locked out too, and the line claims nothing it cannot know.
|
|
174
|
+
var OWNER_CAN_LIST = 0o500
|
|
175
|
+
|
|
176
|
+
// A readable, searchable owner mode proves an observed listing denial belongs to another user.
|
|
177
|
+
function notYours(mode) {
|
|
178
|
+
return (mode & OWNER_CAN_LIST) === OWNER_CAN_LIST ? " · not yours" : ""
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 124 and 126/127 name a cause and 77 is tools/flea-gio-auth's proof of a refusal; gio's text is suppressed, so no other status names one.
|
|
182
|
+
function connectFailure(exitCode) {
|
|
183
|
+
if (exitCode === 124) return WORDS.connectNoAnswer
|
|
184
|
+
if (exitCode === 126 || exitCode === 127)
|
|
185
|
+
return WORDS.connectNoPrompt
|
|
186
|
+
if (exitCode === 77) return WORDS.connectNoPassword
|
|
187
|
+
return WORDS.connectUnopened
|
|
188
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Thumbs.js" as Thumbs
|
|
4
|
+
.import "Format.js" as Format
|
|
5
|
+
|
|
6
|
+
// The ExtThumbs board's storage-class gate: network shares and phones are off, USB
|
|
7
|
+
// drives are on, and anything else is local and always gets thumbnails. A class is
|
|
8
|
+
// src/backend/extclass.rs's own word, carried beside the fsinfo line once per
|
|
9
|
+
// directory change, so nothing here classifies and there is no second classifier.
|
|
10
|
+
|
|
11
|
+
// Whole sentences with "%1" for a value, filled by fill so each translates as one; one per state.
|
|
12
|
+
var WORDS = {
|
|
13
|
+
hide: "Hide %1 thumbnails",
|
|
14
|
+
show: "Show %1 thumbnails",
|
|
15
|
+
isOn: "%1 thumbnails are on",
|
|
16
|
+
isOff: "%1 thumbnails are off"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Sample input: "network" answers "thumbNetwork", "" answers "".
|
|
20
|
+
function keyForClass(storageClass) {
|
|
21
|
+
if (storageClass === "network") return "thumbNetwork"
|
|
22
|
+
if (storageClass === "phone") return "thumbPhone"
|
|
23
|
+
if (storageClass === "usb") return "thumbUsb"
|
|
24
|
+
return ""
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// The menu row is present only on network, phone or USB storage, never locally.
|
|
28
|
+
function present(storageClass) {
|
|
29
|
+
return keyForClass(storageClass) !== ""
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Sample input: ("usb", {}) answers true, ("network", {}) answers false.
|
|
33
|
+
function classOn(storageClass, preview) {
|
|
34
|
+
var key = keyForClass(storageClass)
|
|
35
|
+
if (key === "") return true
|
|
36
|
+
if (key === "thumbUsb") return !preview || preview.thumbUsb !== false
|
|
37
|
+
return !!preview && preview[key] === true
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function classOff(storageClass, preview) {
|
|
41
|
+
return present(storageClass) && !classOn(storageClass, preview)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Off is cache-only, not blank: a visible row still asks, and the backend answers from
|
|
45
|
+
// the shared cache with one stat and never starts a decoder. Thumbnails already made
|
|
46
|
+
// still show, because the cache answers them. Sample input: ("network", {}) answers true.
|
|
47
|
+
function cacheOnly(storageClass, preview) {
|
|
48
|
+
if (!classOff(storageClass, preview)) return false
|
|
49
|
+
return !preview || preview.thumbnails !== "off"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// The thumbed line's record: a cache-only miss on a generating class returns to unasked, any other reply is remembered.
|
|
53
|
+
function thumbReply(state, row, file, cap, known, storageClass, preview) {
|
|
54
|
+
if (file === "" && state.file[row] === Thumbs.CACHE_ASKED && (!known || !cacheOnly(storageClass, preview)))
|
|
55
|
+
return { state: Thumbs.miss(state, row, true, cap), missed: true }
|
|
56
|
+
return { state: Thumbs.remember(state, row, file, cap), missed: false }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// In Columns the preview is manual on a class that is off: one condition, two surfaces.
|
|
60
|
+
function manualHold(storageClass, preview) {
|
|
61
|
+
return cacheOnly(storageClass, preview)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// The menu row's own entrance: absent off the three classes, otherwise labelled for
|
|
65
|
+
// the class and its state. Sample input: ({storageClass: "usb"}) answers "Hide USB thumbnails".
|
|
66
|
+
function entry(e, p) {
|
|
67
|
+
if (!present(p.storageClass)) return false
|
|
68
|
+
e.label = label(p.storageClass, classOn(p.storageClass, p.thumbPreview))
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Sample input: ("network", false) answers "Show network thumbnails".
|
|
73
|
+
function label(storageClass, on) {
|
|
74
|
+
var noun = storageClass === "usb" ? "USB" : storageClass
|
|
75
|
+
return Format.fill(on ? WORDS.hide : WORDS.show, noun)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// The status bar's own verdict for the toggle, in the board's words.
|
|
79
|
+
// Sample input: ("network", true) answers "Network thumbnails are on".
|
|
80
|
+
function statusLine(storageClass, on) {
|
|
81
|
+
var noun = storageClass === "usb" ? "USB"
|
|
82
|
+
: storageClass.charAt(0).toUpperCase() + storageClass.slice(1)
|
|
83
|
+
return Format.fill(on ? WORDS.isOn : WORDS.isOff, noun)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// A class switched on decodes again: only its cache-only marks leave the map, so a
|
|
87
|
+
// real refusal stays answered and is never decoded twice. Sample input:
|
|
88
|
+
// {file: {3: "", 4: "/c/x.png", 5: "cache-missed"}, order: [3, 4, 5]} forgets 5 alone.
|
|
89
|
+
function forgetMisses(state) {
|
|
90
|
+
var kept = []
|
|
91
|
+
for (var i = 0; i < state.order.length; i++) {
|
|
92
|
+
var at = state.order[i]
|
|
93
|
+
if (state.file[at] === Thumbs.CACHE_MISS || state.file[at] === Thumbs.CACHE_ASKED) delete state.file[at]
|
|
94
|
+
else kept.push(at)
|
|
95
|
+
}
|
|
96
|
+
state.order = kept
|
|
97
|
+
return { file: state.file, order: state.order }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Sample input: ("network", {}) answers "only|media"; a zoom step or another class keeps it, so refreshes nothing.
|
|
101
|
+
function verdict(storageClass, preview) {
|
|
102
|
+
var mode = preview && preview.thumbnails ? preview.thumbnails : "media"
|
|
103
|
+
return (cacheOnly(storageClass, preview) ? "only" : "full") + "|" + mode
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// FileView reads the whole file, so a row over the gate is refused, not truncated, the
|
|
107
|
+
// same rule ui/PreviewText.qml already keeps. Text previews on network and phone storage
|
|
108
|
+
// read at most the first 256 KiB. Sample input: ("phone") answers 262144.
|
|
109
|
+
var TEXT_PREVIEW_MAX = 1048576
|
|
110
|
+
var REMOTE_TEXT_PREVIEW_MAX = 262144
|
|
111
|
+
|
|
112
|
+
function textLimit(storageClass) {
|
|
113
|
+
if (storageClass === "network" || storageClass === "phone") return REMOTE_TEXT_PREVIEW_MAX
|
|
114
|
+
return TEXT_PREVIEW_MAX
|
|
115
|
+
}
|