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/Archive.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Format.js" as Format
|
|
4
|
+
|
|
5
|
+
// Which rows get an Extract, and what a new archive is called; the backend sends no is-archive flag, so this is the mechanism.
|
|
6
|
+
|
|
7
|
+
// The widened tail of EXTENSIONS, which 7z reads; tar and the zip class keep their own rules.
|
|
8
|
+
var SEVEN_TAILS = [".appimage", ".cpio", ".cab", ".jar", ".apk", ".rpm", ".deb", ".iso"]
|
|
9
|
+
|
|
10
|
+
// Longest form first, so ".tar.gz" matches before ".gz"; .rar is read here and never offered to write (src/backend/archive.rs).
|
|
11
|
+
var EXTENSIONS = [".tar.zst", ".tar.bz2", ".tar.gz", ".tar.xz", ".tgz", ".tzst", ".tar", ".zip", ".7z", ".rar"].concat(SEVEN_TAILS)
|
|
12
|
+
|
|
13
|
+
// A disk image lists in the archive preview and is never extracted.
|
|
14
|
+
var LIST_ONLY = [".iso"]
|
|
15
|
+
|
|
16
|
+
function isArchive(name) {
|
|
17
|
+
var lower = String(name).toLowerCase()
|
|
18
|
+
for (var i = 0; i < EXTENSIONS.length; i++) {
|
|
19
|
+
if (lower.length > EXTENSIONS[i].length && lower.indexOf(EXTENSIONS[i], lower.length - EXTENSIONS[i].length) !== -1) {
|
|
20
|
+
return true
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// The name an extract unpacks into: the archive's own, with every archive extension taken off.
|
|
27
|
+
function extractDir(name) {
|
|
28
|
+
var text = String(name)
|
|
29
|
+
var lower = text.toLowerCase()
|
|
30
|
+
for (var i = 0; i < EXTENSIONS.length; i++) {
|
|
31
|
+
if (lower.length > EXTENSIONS[i].length && lower.indexOf(EXTENSIONS[i], lower.length - EXTENSIONS[i].length) !== -1) {
|
|
32
|
+
return text.substring(0, text.length - EXTENSIONS[i].length)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return text
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// One row compresses under its own name; several compress under the directory holding them.
|
|
39
|
+
function archiveStem(names, parentLeaf) {
|
|
40
|
+
if (names.length === 1) {
|
|
41
|
+
return stripExtension(names[0])
|
|
42
|
+
}
|
|
43
|
+
return parentLeaf.length > 0 ? parentLeaf : "archive"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function stripExtension(name) {
|
|
47
|
+
var text = String(name)
|
|
48
|
+
var cut = text.lastIndexOf(".")
|
|
49
|
+
return cut > 0 ? text.substring(0, cut) : text
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var SHEET_COMPRESS = "Compress to .%1"
|
|
53
|
+
|
|
54
|
+
// The compress submenu is the probed table, so no 7zip means no .7z; the sheet reads each leaf "Compress to .zip" beside the board's file mark.
|
|
55
|
+
function formatEntries(formats) {
|
|
56
|
+
var out = []
|
|
57
|
+
for (var i = 0; i < formats.length; i++) {
|
|
58
|
+
out.push({ id: formats[i], label: "." + formats[i], sheetLabel: SHEET_COMPRESS.replace("%1", formats[i]), glyph: "file" })
|
|
59
|
+
}
|
|
60
|
+
return out
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// A disk image by name, longest form first so ".img.xz" wins over ".img"; a zip needs one such member.
|
|
64
|
+
function imageKind(name) {
|
|
65
|
+
var lower = String(name || "").toLowerCase()
|
|
66
|
+
var table = [[".img.xz", "xz"], [".img.gz", "gz"], [".img.zst", "zst"], [".img.bz2", "bz2"],
|
|
67
|
+
[".iso", "iso"], [".img", "img"], [".raw", "raw"], [".zip", "zip"]]
|
|
68
|
+
for (var i = 0; i < table.length; i++) {
|
|
69
|
+
var suffix = table[i][0]
|
|
70
|
+
if (lower.length > suffix.length && lower.lastIndexOf(suffix) === lower.length - suffix.length)
|
|
71
|
+
return table[i][1]
|
|
72
|
+
}
|
|
73
|
+
return ""
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isDiskImage(name, zipMember) {
|
|
77
|
+
var kind = imageKind(name)
|
|
78
|
+
if (kind === "" || kind === "zip")
|
|
79
|
+
return kind === "zip" && imageKind(zipMember) !== "" && imageKind(zipMember) !== "zip"
|
|
80
|
+
return true
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Whether an installed tool reads this archive: .7z needs 7z, .zip and .rar either tool, tar bsdtar, a disk image none.
|
|
84
|
+
function canExtract(name, extraction) {
|
|
85
|
+
var lower = String(name).toLowerCase()
|
|
86
|
+
var caps = extraction || ({})
|
|
87
|
+
if (isListOnly(name)) return false
|
|
88
|
+
if (hasSuffix(lower, ".7z")) return caps.sevenZip === true
|
|
89
|
+
if (hasSuffix(lower, ".zip") || hasSuffix(lower, ".rar")) return caps.zip === true
|
|
90
|
+
if (isSevenSuffix(lower)) return caps.sevenZip === true
|
|
91
|
+
return caps.archive === true
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// A disk image lists in the archive preview and is never extracted.
|
|
95
|
+
function isListOnly(name) {
|
|
96
|
+
var lower = String(name).toLowerCase()
|
|
97
|
+
for (var i = 0; i < LIST_ONLY.length; i++) {
|
|
98
|
+
if (hasSuffix(lower, LIST_ONLY[i])) return true
|
|
99
|
+
}
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// The seven-tail membership, read off the one table above.
|
|
104
|
+
function isSevenSuffix(lower) {
|
|
105
|
+
for (var i = 0; i < SEVEN_TAILS.length; i++) {
|
|
106
|
+
if (hasSuffix(lower, SEVEN_TAILS[i])) return true
|
|
107
|
+
}
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// The missing program for a disabled Extract: only bsdtar offers "tar" and only 7z offers "7z".
|
|
112
|
+
function extractHint(formats) {
|
|
113
|
+
var table = formats || []
|
|
114
|
+
if (table.indexOf("7z") >= 0) return "bsdtar is not installed"
|
|
115
|
+
if (table.indexOf("tar") >= 0) return "7-Zip is not installed"
|
|
116
|
+
return "No archive tool is installed"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Menu.js's Extract row: absent for none and for a disk image, disabled with its reason for no reader.
|
|
120
|
+
function extractEntry(entry, p, count) {
|
|
121
|
+
if (!p.rowIsArchive || count !== 1) return false
|
|
122
|
+
if (isListOnly(p.archiveName || "")) return false
|
|
123
|
+
if (p.canExtract !== true) {
|
|
124
|
+
entry.disabled = true
|
|
125
|
+
entry.hint = extractHint(p.archiveFormats)
|
|
126
|
+
entry.hintWrap = true
|
|
127
|
+
}
|
|
128
|
+
return true
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function hasSuffix(lower, suffix) {
|
|
132
|
+
return lower.length >= suffix.length && lower.indexOf(suffix, lower.length - suffix.length) !== -1
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// The compress submenu's last row, which opens the password dialog; hidden where 7z is missing, since bsdtar writes no encryption.
|
|
136
|
+
function passwordEntry(formats) {
|
|
137
|
+
var table = formats || []
|
|
138
|
+
if (table.indexOf("7z") < 0) return []
|
|
139
|
+
return [{ separator: true },
|
|
140
|
+
{ id: "compressPassword", label: "With password…", glyph: "key" }]
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// The backend's two password codes, matched exactly the way "cancelled" routes, never as sentences.
|
|
144
|
+
function needsPassword(err) {
|
|
145
|
+
return String(err) === "encrypted"
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function wrongPassword(err) {
|
|
149
|
+
return String(err) === "wrong-password"
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// What an extract's terminal line does: "password" opens the card, "wrong" reopens it with its sentence, "" messages.
|
|
153
|
+
function doneAction(ok, err) {
|
|
154
|
+
if (!ok && needsPassword(err)) return "password"
|
|
155
|
+
if (!ok && wrongPassword(err)) return "wrong"
|
|
156
|
+
return ""
|
|
157
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Format.js" as Format
|
|
4
|
+
|
|
5
|
+
// The archive cards' own sentences and leaves, built with the first compress or password card so a launch compiles none of it.
|
|
6
|
+
|
|
7
|
+
// One whole sentence per count for the compress card's title, so no caller joins a fragment.
|
|
8
|
+
function compressTitle(count) {
|
|
9
|
+
if (count === 1) return "Compress 1 item"
|
|
10
|
+
return "Compress %1 items".replace("%1", Format.count(count))
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// The extract card's title, from the same template rule.
|
|
14
|
+
function encryptedTitle(leaf) {
|
|
15
|
+
return "%1 is encrypted".replace("%1", leaf)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// The card's sentence for a wrong answer, one template filled once.
|
|
19
|
+
function wrongPasswordSentence(leaf) {
|
|
20
|
+
return "That password did not open %1.".replace("%1", leaf)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// The leaf of one path, the one cut every leaf reader shares.
|
|
24
|
+
function leafOf(path) {
|
|
25
|
+
var text = String(path)
|
|
26
|
+
var cut = text.lastIndexOf("/")
|
|
27
|
+
return cut >= 0 ? text.substring(cut + 1) : text
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// The leaf of the archive a card was opened over.
|
|
31
|
+
function sourceLeaf(source) {
|
|
32
|
+
return leafOf(source && source.path ? source.path : "")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// The leaf of each resolved path, for a card opened over more than one file.
|
|
36
|
+
function pathLeaves(paths) {
|
|
37
|
+
var out = []
|
|
38
|
+
var list = paths || []
|
|
39
|
+
for (var i = 0; i < list.length; i++) out.push(leafOf(list[i]))
|
|
40
|
+
return out
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// What a second password request is told while a card is open, one sentence for compress and extract alike.
|
|
44
|
+
var CARD_BUSY = "Another archive is waiting for its password. Enter it, then try again."
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Format.js" as Format
|
|
4
|
+
.import "Ops.js" as Ops
|
|
5
|
+
.import "Search.js" as Search
|
|
6
|
+
|
|
7
|
+
// The With-password compress and the encrypted extract's retry, over resolved paths: a row index names another file once the listing moves.
|
|
8
|
+
function openCompressPassword(pane, menuId, cards) {
|
|
9
|
+
var idx = Ops.targetIndices(pane)
|
|
10
|
+
if (idx.length === 0) return Ops.sayNoTarget(pane)
|
|
11
|
+
pane.pathsPending = { kind: "compressPassword",
|
|
12
|
+
deliver: function (list) { compressPasswordResolved(cards, pane, list, menuId) } }
|
|
13
|
+
pane.backend.askPaths(idx)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// The answer to askPaths: the paths and menu id the cards host opens over.
|
|
17
|
+
function compressPasswordResolved(cards, pane, paths, menuId) {
|
|
18
|
+
if (paths.length === 0) return Ops.sayNoTarget(pane)
|
|
19
|
+
cards.openCompressDialog({ paths: paths, menuId: menuId || 0 }, Ops.leaf(pane.path), pane)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// The dialog's Compress: the name is free, and the backend refuses a destination that appeared meanwhile.
|
|
23
|
+
function submitCompressPassword(pane, source, format, name, password, encryptNames) {
|
|
24
|
+
if (!source || !source.paths || source.paths.length === 0) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
var dest = pane.join(Search.baseOf(pane), name)
|
|
28
|
+
pane.backend.compressPassword(source.paths, dest, format, password, encryptNames, source.menuId)
|
|
29
|
+
// A refused send parks nothing, so only a sent compress shows its running line.
|
|
30
|
+
if (!pane.backend.queueing) pane.sticky(compressSticky(source.paths.length, format))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// The sticky line as one whole sentence per count, filled once, never joined from fragments.
|
|
34
|
+
function compressSticky(count, format) {
|
|
35
|
+
return Format.fill(Ops.WORDS.compressing, Ops.items(count), format)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// The extract card's Extract: the archive and destination the card was opened over, retried with a password.
|
|
39
|
+
function submitExtractPassword(pane, source, password) {
|
|
40
|
+
if (!source || !source.path) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
pane.backend.extractPassword(source.path, source.dest, password, 0)
|
|
44
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// Back and Forward entries and the landing ui/PaneSwap.qml runs in the rows' turn.
|
|
4
|
+
|
|
5
|
+
// A stack entry names the directory and the row its cursor stood on; bare paths read as empty rows.
|
|
6
|
+
function makeEntry(path, name, index) {
|
|
7
|
+
return { path: String(path), name: String(name || ""), index: Math.max(0, Math.floor(Number(index) || 0)) }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function pathOf(entry) {
|
|
11
|
+
return typeof entry === "string" ? entry : String(entry.path || "")
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function asEntry(target) {
|
|
15
|
+
return typeof target === "string" ? makeEntry(target, "", 0) : target
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// The place a listing still out asked for, with the cursor its Back or Forward owes it; null when none is out or it re-reads the drawn folder.
|
|
19
|
+
function pending(pane) {
|
|
20
|
+
if (!pane.listInFlight || !pane.listingPath || pane.listingPath === pane.path)
|
|
21
|
+
return null
|
|
22
|
+
var owed = pane.swap ? pane.swap.restore : null
|
|
23
|
+
if (owed && owed.path === pane.listingPath)
|
|
24
|
+
return makeEntry(owed.path, owed.name, owed.index)
|
|
25
|
+
return makeEntry(pane.listingPath, "", 0)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// A tab switch left its cursor, order and located row to its landing; the listing let go never lands, so a later one must not take them.
|
|
29
|
+
function dropOwed(pane) {
|
|
30
|
+
if (pane.tabs)
|
|
31
|
+
Object.assign(pane.tabs, { pendingCursor: -1, pendingCursorName: null, pendingLocatePath: "", pendingSortBy: "", pendingSortDesc: false })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// The stack a Back or Forward still out pushed the drawn place onto, or "" when the listing out is any other.
|
|
35
|
+
function pushedOnto(pane) {
|
|
36
|
+
var owed = pending(pane) && pane.swap ? pane.swap.restore : null
|
|
37
|
+
return owed && owed.pushedOnto ? owed.pushedOnto : ""
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The drawn folder with the cursor row it stands on; leaving a walk names no row, so the landing stays at the top.
|
|
41
|
+
function drawn(pane) {
|
|
42
|
+
var walk = pane.searchMode === "results" || (pane.searchFrom || "").length > 0
|
|
43
|
+
var row = !walk && pane.rowFor ? pane.rowFor(pane.cursorIndex) : null
|
|
44
|
+
var entry = makeEntry(pane.path, row ? row.n : "", walk ? 0 : pane.cursorIndex)
|
|
45
|
+
if (pane.recentMode === "trash") { entry.collection = "trash"; entry.collectionFrom = pane.recentFrom }
|
|
46
|
+
return entry
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// The departing cursor, or the pending place while a listing is out.
|
|
50
|
+
function capture(pane) {
|
|
51
|
+
return pending(pane) || drawn(pane)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// One step through the stacks after Nav's guard, popping before the open pushes back.
|
|
55
|
+
function travel(pane, from, to) {
|
|
56
|
+
var stack = pane[from]
|
|
57
|
+
var target = asEntry(stack[stack.length - 1])
|
|
58
|
+
pane[to] = (pane[to] || []).concat([capture(pane)])
|
|
59
|
+
pane[from] = stack.slice(0, -1)
|
|
60
|
+
if (target.collection === "trash") {
|
|
61
|
+
pane.trash.open()
|
|
62
|
+
if (target.collectionFrom) pane.recentFrom = target.collectionFrom
|
|
63
|
+
pane.pendingSelect = target.name ? pane.join(target.path, target.name) : ""
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
pane.openWithoutHistory(pathOf(target), { restore: Object.assign({}, target, { pushedOnto: to }), supersede: true })
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// The landing in the rows reply's turn: name, then clamped index, then the top.
|
|
70
|
+
function landRestore(pane, entry) {
|
|
71
|
+
if (!entry)
|
|
72
|
+
return
|
|
73
|
+
if (pane.path !== entry.path || (pane.searchMode || "").length > 0 || pane.total === 0)
|
|
74
|
+
return
|
|
75
|
+
var name = String(entry.name || "")
|
|
76
|
+
if (name.length > 0) {
|
|
77
|
+
for (var i = 0; i < pane.rows.length; i++) {
|
|
78
|
+
if (String(pane.rows[i].n) === name) {
|
|
79
|
+
pane.setCursor(pane.held + i)
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
pane.setCursor(Math.min(entry.index, pane.total - 1))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// True when a Back listing's first window lacks the owed name: the existing locate is sent and the rows wait for its window.
|
|
88
|
+
function deferForLocate(pane, entry, items, listed) {
|
|
89
|
+
if (!entry || entry.pendingPath || !listed || listed.path !== entry.path)
|
|
90
|
+
return false
|
|
91
|
+
var name = String(entry.name || "")
|
|
92
|
+
if (name.length === 0 || !(listed.total > items.length) || (pane.searchMode || "").length > 0)
|
|
93
|
+
return false
|
|
94
|
+
for (var i = 0; i < items.length; i++) {
|
|
95
|
+
if (String(items[i].n) === name)
|
|
96
|
+
return false
|
|
97
|
+
}
|
|
98
|
+
if (!(pane.windowSize > 0) || typeof pane.backend.window !== "function")
|
|
99
|
+
return false
|
|
100
|
+
entry.pendingPath = pane.join(entry.path, name)
|
|
101
|
+
entry.total = listed.total
|
|
102
|
+
pane.backend.send({ c: "locate", path: entry.pendingPath })
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// The locate reply for a waiting landing fetches the window holding the row, or the clamped index on a miss.
|
|
107
|
+
function takeLocated(pane, message) {
|
|
108
|
+
var entry = pane.swap ? pane.swap.restore : null
|
|
109
|
+
if (!entry || !entry.pendingPath || entry.fetched || !message
|
|
110
|
+
|| message.path !== entry.pendingPath || message.directory !== entry.path)
|
|
111
|
+
return false
|
|
112
|
+
var index = Number(message.index)
|
|
113
|
+
if (!(index >= 0) || index >= entry.total)
|
|
114
|
+
index = Math.min(entry.index, entry.total - 1)
|
|
115
|
+
entry.fetched = true
|
|
116
|
+
pane.backend.window(index, pane.windowSize)
|
|
117
|
+
return true
|
|
118
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Format.js" as Format
|
|
4
|
+
|
|
5
|
+
// Every user-facing string is one whole template with %1 slots, filled in one place, with no qsTr.
|
|
6
|
+
var WORDS = {
|
|
7
|
+
footerPair: "%1 renamed · %2 unchanged",
|
|
8
|
+
footerInvalid: "%1 renamed · %2 unchanged · %3 invalid",
|
|
9
|
+
renameButton: "Rename %1",
|
|
10
|
+
cardTitle: "Rename %1 items",
|
|
11
|
+
sameLine: "same as line %1"
|
|
12
|
+
}
|
|
13
|
+
function applyFindReplace(oldNames, find, replace) {
|
|
14
|
+
var out = []
|
|
15
|
+
for (var i = 0; i < oldNames.length; i++) {
|
|
16
|
+
if (!find) out.push(oldNames[i])
|
|
17
|
+
else out.push(String(oldNames[i]).split(find).join(replace))
|
|
18
|
+
}
|
|
19
|
+
return out
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Linux filename components hold at most 255 bytes of UTF-8, the bound the backend refuses past.
|
|
23
|
+
var NAME_BYTES = 255
|
|
24
|
+
|
|
25
|
+
// Sample input: "\u00e9" counts 2, and a surrogate pair counts 4, as UTF-8 does.
|
|
26
|
+
function utf8Bytes(text) {
|
|
27
|
+
var bytes = 0
|
|
28
|
+
for (var i = 0; i < text.length; i++) {
|
|
29
|
+
var code = text.charCodeAt(i)
|
|
30
|
+
if (code < 0x80) bytes += 1
|
|
31
|
+
else if (code < 0x800) bytes += 2
|
|
32
|
+
else if (code >= 0xd800 && code <= 0xdbff && (text.charCodeAt(i + 1) & 0xfc00) === 0xdc00) { bytes += 4; i += 1 }
|
|
33
|
+
else bytes += 3
|
|
34
|
+
}
|
|
35
|
+
return bytes
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Sample input: "trip/4123.HEIC" at line 4 names "contains /".
|
|
39
|
+
function reasons(newNames) {
|
|
40
|
+
var out = new Array(newNames.length)
|
|
41
|
+
var seen = new Map()
|
|
42
|
+
for (var i = newNames.length - 1; i >= 0; i--) {
|
|
43
|
+
var text = String(newNames[i])
|
|
44
|
+
var r = ""
|
|
45
|
+
if (text.length === 0) r = "empty"
|
|
46
|
+
else if (text.indexOf("/") >= 0) r = "contains /"
|
|
47
|
+
else if (text === "." || text === ".." || text.indexOf("\u0000") >= 0 || text.indexOf("\r") >= 0 || text.indexOf("\n") >= 0) r = "invalid"
|
|
48
|
+
else if (utf8Bytes(text) > NAME_BYTES) r = "too long"
|
|
49
|
+
else if (seen.has(text)) r = WORDS.sameLine.replace("%1", seen.get(text) + 1)
|
|
50
|
+
out[i] = r
|
|
51
|
+
seen.set(text, i)
|
|
52
|
+
}
|
|
53
|
+
return out
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Counts split renamed, unchanged and invalid over the live rules alone; the backend refuses a name taken outside the batch.
|
|
57
|
+
function counts(oldNames, newNames, reasons) {
|
|
58
|
+
var renamed = 0, unchanged = 0, invalid = 0
|
|
59
|
+
for (var i = 0; i < newNames.length; i++) {
|
|
60
|
+
if (reasons[i] !== "") invalid += 1
|
|
61
|
+
else if (String(newNames[i]) === String(oldNames[i])) unchanged += 1
|
|
62
|
+
else renamed += 1
|
|
63
|
+
}
|
|
64
|
+
return { renamed: renamed, unchanged: unchanged, invalid: invalid }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Sample input: 5, 1, 0 names "5 renamed \u00b7 1 unchanged".
|
|
68
|
+
function footer(renamed, unchanged, invalid) {
|
|
69
|
+
if (invalid > 0)
|
|
70
|
+
return WORDS.footerInvalid.replace("%1", Format.count(renamed)).replace("%2", Format.count(unchanged)).replace("%3", Format.count(invalid))
|
|
71
|
+
return WORDS.footerPair.replace("%1", Format.count(renamed)).replace("%2", Format.count(unchanged))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// The Rename button label carries the live renamed count.
|
|
75
|
+
function renameLabel(renamed) {
|
|
76
|
+
return WORDS.renameButton.replace("%1", Format.count(renamed))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// The card names its count once; it only opens over several rows, so one plural form holds.
|
|
80
|
+
function title(count) {
|
|
81
|
+
return WORDS.cardTitle.replace("%1", Format.count(count))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// A short newNames reads "" past its end; open()'s two assignments cross for one synchronous turn only, so no frame ever paints it.
|
|
85
|
+
function nameAt(newNames, index) {
|
|
86
|
+
return index < newNames.length ? String(newNames[index]) : ""
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// The card's Tab order, pure so tests/js pins the walk both ways.
|
|
90
|
+
function focusStops(lines) {
|
|
91
|
+
var stops = ["find", "replace"]
|
|
92
|
+
for (var i = 0; i < lines; i++) stops.push("line " + (i + 1))
|
|
93
|
+
return stops.concat(["edit", "cancel", "rename"])
|
|
94
|
+
}
|
|
95
|
+
function nextStop(current, back, lines) {
|
|
96
|
+
var stops = focusStops(lines)
|
|
97
|
+
var at = stops.indexOf(current)
|
|
98
|
+
if (at < 0) return back ? stops[stops.length - 1] : stops[0]
|
|
99
|
+
return stops[(at + (back ? -1 : 1) + stops.length) % stops.length]
|
|
100
|
+
}
|
package/ui/js/Buttons.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// Sample input: primaryFor("collide") === "keep", isDestructive("trash", "delete") === true.
|
|
4
|
+
// Variant A: one control for every dialog button, sized by Theme, primary is the safe Enter action.
|
|
5
|
+
|
|
6
|
+
// The members of a set (the protocols) sit this many hairlines apart, 4 px at base size 14.
|
|
7
|
+
var SET_GAP = 4
|
|
8
|
+
// The segments of a settings chooser sit this many hairlines apart, 2 px at base size 14.
|
|
9
|
+
var SEGMENT_GAP = 2
|
|
10
|
+
// A focused control whose foreground hairline would match its rest draws its own frame this wide, inward.
|
|
11
|
+
var RING = 2
|
|
12
|
+
var DISABLED_OPACITY = 0.55
|
|
13
|
+
// The pointer's wash and the press wash, laid in the control's own ink.
|
|
14
|
+
var WASH_HOVER = 0.08
|
|
15
|
+
var WASH_PRESS = 0.14
|
|
16
|
+
// A primary's resting accent wash, at the press wash's weight.
|
|
17
|
+
var WASH_PRIMARY = WASH_PRESS
|
|
18
|
+
// Chrome marks scale by this factor; dialog buttons inset only their frame and wash by whole pixels.
|
|
19
|
+
var PRESS_SCALE = 0.96
|
|
20
|
+
var PRESS_MS = 150
|
|
21
|
+
|
|
22
|
+
// One primary per dialog, fixed: it never moves with focus.
|
|
23
|
+
var PRIMARY = {
|
|
24
|
+
trash: "cancel",
|
|
25
|
+
collide: "keep",
|
|
26
|
+
openWith: "open",
|
|
27
|
+
convert: "convert",
|
|
28
|
+
newFile: "create",
|
|
29
|
+
moveTo: "move",
|
|
30
|
+
copyTo: "copy",
|
|
31
|
+
network: "action",
|
|
32
|
+
permissions: "apply",
|
|
33
|
+
picker: "accept"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A destructive action rests as the error label in a muted frame, never primary.
|
|
37
|
+
var DESTRUCTIVE = {
|
|
38
|
+
trash: { "delete": true },
|
|
39
|
+
collide: { "replace": true },
|
|
40
|
+
picker: { "replace": true }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Sample input: focusFrame(true, false, false) === "foreground", focusFrame(true, false, true) === "thick", focusFrame(false, false, true) === "thick", focusFrame(true, true, true) === "accent", focusFrame(false, true, false) === "thick".
|
|
44
|
+
// What a focused control's own frame draws: one foreground hairline, one accent hairline for a set member where the accent has hue, or "thick", RING wide in the foreground, where a hairline would match the rest.
|
|
45
|
+
function focusFrame(accentHasHue, setMember, restIsForeground) { return setMember !== true ? (restIsForeground === true ? "thick" : "foreground") : accentHasHue === true ? "accent" : "thick" }
|
|
46
|
+
|
|
47
|
+
function primaryFor(dialog) {
|
|
48
|
+
return PRIMARY[dialog] || ""
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isDestructive(dialog, name) {
|
|
52
|
+
var set = DESTRUCTIVE[dialog] || {}
|
|
53
|
+
return set[name] === true
|
|
54
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Tabs.js" as Tabs
|
|
4
|
+
|
|
5
|
+
// The chrome bar's and tab strip's keys while Tab holds the keyboard there, read raw so no preset shadows them (as ui/js/RailKeys.js).
|
|
6
|
+
|
|
7
|
+
// The chrome's controls in the order Tab and the arrows walk them, named by glyph as ui/ChromeBar.qml names them.
|
|
8
|
+
// flea-qml: the funnel stands left of the magnifier, so it is reached first.
|
|
9
|
+
var ORDER = ["arrow-left", "arrow-up", "filter", "search", "sort", "list", "columns", "grid", "dual", "sliders"]
|
|
10
|
+
// A press on these hands the keyboard to the surface it opens, as the pointer's press does; the rest keep it on the mark.
|
|
11
|
+
var HANDS_OFF = ["search", "filter", "sliders"]
|
|
12
|
+
var BLOCKING = Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier
|
|
13
|
+
|
|
14
|
+
// The controls that are drawn and live, in order; a hidden or disabled one is never a stop.
|
|
15
|
+
function controls(bar) {
|
|
16
|
+
if (!bar || !bar.visible || bar.inputLive === false) return []
|
|
17
|
+
return ORDER.filter(function (glyph) {
|
|
18
|
+
var mark = bar.buttonFor(glyph)
|
|
19
|
+
return mark !== null && mark.visible && mark.enabled
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// How many stops the strip holds: each tab, then New tab; none while one tab leaves the strip closed.
|
|
24
|
+
function tabStops(strip) {
|
|
25
|
+
return strip && strip.open ? strip.tabCount + 1 : 0
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Which of the ring's stops are drawn, keyed by the view name Focus.js gives each.
|
|
29
|
+
function drawn(root, railAvailable) {
|
|
30
|
+
return {
|
|
31
|
+
rail: !!railAvailable,
|
|
32
|
+
chrome: controls(root.chromeBar).length > 0,
|
|
33
|
+
strip: tabStops(root.tabStrip) > 0
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Entering a stop forward lands on its first control (the strip: the current tab), backward on its last.
|
|
38
|
+
function enter(root, view, forward) {
|
|
39
|
+
if (view === "chrome") {
|
|
40
|
+
var glyphs = controls(root.chromeBar)
|
|
41
|
+
root.chromeBar.focusedGlyph = glyphs[forward ? 0 : glyphs.length - 1]
|
|
42
|
+
} else if (view === "strip") {
|
|
43
|
+
root.tabStrip.focusedIndex = forward ? root.tabStrip.currentIndex : root.tabStrip.tabCount
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function press(event) {
|
|
48
|
+
return event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_Space
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Where an arrow, Home or End lands among count stops from at, without wrapping; -1 when the key is none of those.
|
|
52
|
+
function target(event, at, count) {
|
|
53
|
+
if (event.key === Qt.Key_Home) return 0
|
|
54
|
+
if (event.key === Qt.Key_End) return count - 1
|
|
55
|
+
if (event.key === Qt.Key_Left) return Math.max(0, at - 1)
|
|
56
|
+
if (event.key === Qt.Key_Right) return Math.min(count - 1, at + 1)
|
|
57
|
+
return -1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// The live control nearest in ORDER to a glyph that went disabled or hidden; unknown names land on the first stop.
|
|
61
|
+
function nearestLive(glyph, glyphs) {
|
|
62
|
+
var home = glyphs[0]
|
|
63
|
+
var want = ORDER.indexOf(glyph)
|
|
64
|
+
if (want < 0) return home
|
|
65
|
+
var best = Infinity
|
|
66
|
+
for (var i = 0; i < glyphs.length; i++) {
|
|
67
|
+
var dist = Math.abs(ORDER.indexOf(glyphs[i]) - want)
|
|
68
|
+
if (dist < best) { best = dist; home = glyphs[i] }
|
|
69
|
+
}
|
|
70
|
+
return home
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function chromeKey(event, root) {
|
|
74
|
+
var bar = root.chromeBar
|
|
75
|
+
var glyphs = controls(bar)
|
|
76
|
+
var at = glyphs.indexOf(bar.focusedGlyph)
|
|
77
|
+
if (press(event)) {
|
|
78
|
+
// A stop that went disabled or hidden re-homes to the nearest live control and presses nothing, so Enter never acts on a control the user did not see focused.
|
|
79
|
+
if (at < 0) {
|
|
80
|
+
if (glyphs.length > 0) bar.focusedGlyph = nearestLive(bar.focusedGlyph, glyphs)
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
bar.buttonFor(glyphs[at]).activated()
|
|
84
|
+
if (HANDS_OFF.indexOf(glyphs[at]) >= 0) root.focusView = "list"
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
var to = target(event, at, glyphs.length)
|
|
88
|
+
if (to >= 0) bar.focusedGlyph = glyphs[to]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function stripKey(event, root) {
|
|
92
|
+
var strip = root.tabStrip
|
|
93
|
+
var at = Math.min(strip.focusedIndex, strip.tabCount)
|
|
94
|
+
if (press(event)) {
|
|
95
|
+
root.focusView = "list"
|
|
96
|
+
if (at < strip.tabCount) Tabs.selectAt(root, at)
|
|
97
|
+
else Tabs.openNew(root)
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
var to = target(event, at, strip.tabCount + 1)
|
|
101
|
+
if (to >= 0) strip.focusedIndex = to
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Every key a stop holds is answered here and the rest do nothing; a stop that is no longer drawn gives the key back to the list.
|
|
105
|
+
function act(event, root) {
|
|
106
|
+
var chrome = root.focusView === "chrome"
|
|
107
|
+
if (chrome ? controls(root.chromeBar).length === 0 : tabStops(root.tabStrip) === 0) {
|
|
108
|
+
root.focusView = "list"
|
|
109
|
+
return false
|
|
110
|
+
}
|
|
111
|
+
if ((event.modifiers & BLOCKING) !== 0) return true
|
|
112
|
+
if (event.key === Qt.Key_Escape) root.focusView = "list"
|
|
113
|
+
else if (chrome) chromeKey(event, root)
|
|
114
|
+
else stripKey(event, root)
|
|
115
|
+
return true
|
|
116
|
+
}
|