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/Focus.js
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
.import "Input.js" as Input
|
|
3
|
+
.import "ChromeKeys.js" as ChromeKeys
|
|
4
|
+
.import "Eject.js" as Eject
|
|
5
|
+
.import "Filter.js" as Filter
|
|
6
|
+
.import "Grid.js" as Grid
|
|
7
|
+
.import "Format.js" as Format
|
|
8
|
+
.import "Keymap.js" as Keymap
|
|
9
|
+
.import "KeyName.js" as KeyName
|
|
10
|
+
.import "Marks.js" as Marks
|
|
11
|
+
.import "Mounts.js" as Mounts
|
|
12
|
+
.import "Ops.js" as Ops
|
|
13
|
+
.import "PreviewKeys.js" as PreviewKeys
|
|
14
|
+
.import "RailKeys.js" as RailKeys
|
|
15
|
+
.import "Reload.js" as Reload
|
|
16
|
+
.import "Nav.js" as Nav
|
|
17
|
+
.import "RecentMode.js" as RecentMode
|
|
18
|
+
.import "Status.js" as Status
|
|
19
|
+
.import "Search.js" as Search
|
|
20
|
+
.import "Sort.js" as Sort
|
|
21
|
+
.import "Swap.js" as Swap
|
|
22
|
+
.import "TextSize.js" as TextSize
|
|
23
|
+
.import "Trash.js" as Trash
|
|
24
|
+
.import "Tabs.js" as Tabs
|
|
25
|
+
|
|
26
|
+
// Whole sentences with "%1" for the key the running preset binds, filled by KeyName.hinted.
|
|
27
|
+
var WORDS = {
|
|
28
|
+
filterTip: "Press %1 to filter this folder by name"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
var LIST = "list"
|
|
32
|
+
var RAIL = "rail"
|
|
33
|
+
var CHROME = "chrome"
|
|
34
|
+
var STRIP = "strip"
|
|
35
|
+
// The stops Tab walks, in order; the list is always one and the others only while drawn.
|
|
36
|
+
var RING = [LIST, RAIL, CHROME, STRIP]
|
|
37
|
+
|
|
38
|
+
// Refusal where gio has no Trash, from ui/js/Status.js, which recognises it to drop it when the pane leaves that place; a preset with no key reads bare.
|
|
39
|
+
var NO_TRASH = Status.NO_TRASH
|
|
40
|
+
function noTrashHint() { return Status.trashHint().replace(" · ", "") }
|
|
41
|
+
function noTrashLine() { return Status.noTrashLine() }
|
|
42
|
+
|
|
43
|
+
// Tab is the only thing that moves focus between views, so the rule lives in one function; drawn names the optional stops that are there, as ChromeKeys.drawn says.
|
|
44
|
+
function next(current, drawn, forward) {
|
|
45
|
+
// RailAdditions rule 4: a hidden rail is not a place the keyboard can go, so Tab skips it. Directive 77: one that auto-hide withdrew is, because arriving there is what reveals it.
|
|
46
|
+
var stops = RING.filter(function (view) { return view === LIST || drawn[view] === true })
|
|
47
|
+
var at = stops.indexOf(current)
|
|
48
|
+
return at < 0 ? LIST : stops[(at + (forward ? 1 : stops.length - 1)) % stops.length]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Tab and Shift+Tab. In the dual view the two lists are consecutive stops and the pane switch is the step between them; the rail is the left pane's, so any pane's step onto it hands the keyboard to that one.
|
|
52
|
+
function tabStep(root, sidebar, forward) {
|
|
53
|
+
if (root.dualMode && root.focusView === LIST && forward !== (root.listOnly === true)) { root.switchPane(); return }
|
|
54
|
+
var to = next(root.focusView, ChromeKeys.drawn(root, sidebar || root.sidebar || root.railAvailable), forward)
|
|
55
|
+
if (to === LIST) {
|
|
56
|
+
root.focusView = LIST
|
|
57
|
+
// Forward lands on the left list and backward on the right one, wherever the keyboard stood.
|
|
58
|
+
if (root.dualMode && (root.listOnly === true) === forward) root.switchPane()
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
if (to === RAIL && root.dualMode) {
|
|
62
|
+
root.focusView = LIST
|
|
63
|
+
root.switchToRail()
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
ChromeKeys.enter(root, to, forward)
|
|
67
|
+
root.focusView = to
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Hiding the rail while it holds the keyboard strands focusView, so the listing takes the logical view and the actual focus together.
|
|
71
|
+
function railHidden(root) {
|
|
72
|
+
// Both panes share the hidden state, so only the active one answers it; undefined stays compatible with fixtures that predate the flag.
|
|
73
|
+
if (root.paneFocused === false || root.focusView !== RAIL) return
|
|
74
|
+
root.focusView = LIST
|
|
75
|
+
if (root.listArea) root.listArea.forceActiveFocus()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function shareBrowserHere(root) {
|
|
79
|
+
return !!(root.shareBrowser && root.shareBrowser.active && (!root.shareBrowser.owner || root.shareBrowser.owner === root))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The one gate the z key and the "z undoes" click share: no undo under a listing, rename, overlay or query line.
|
|
83
|
+
function canUndo(pane, sidebar) {
|
|
84
|
+
if (!pane || Swap.swallows(pane.listInFlight, "undo"))
|
|
85
|
+
return false
|
|
86
|
+
if (pane.selectionBand !== null || pane.renameEditor() !== null)
|
|
87
|
+
return false
|
|
88
|
+
if (sidebar && sidebar.renameEditor() !== null)
|
|
89
|
+
return false
|
|
90
|
+
if (pane.searchMode === Search.TYPING || pane.filterTyping)
|
|
91
|
+
return false
|
|
92
|
+
if ((pane.preview && pane.preview.active) || shareBrowserHere(pane))
|
|
93
|
+
return false
|
|
94
|
+
if (pane.menuVisible || (pane.menuActions && pane.menuActions.opened))
|
|
95
|
+
return false
|
|
96
|
+
if ((pane.collide && (pane.collide.opened || pane.collide.pending !== null))
|
|
97
|
+
|| (pane.keymapSheet && pane.keymapSheet.opened)
|
|
98
|
+
|| (pane.settingsPanel && pane.settingsPanel.opened))
|
|
99
|
+
return false
|
|
100
|
+
return true
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Pane.qml's one key lookup: the keys.toml action for the focused context, narrowed below per view and overlay.
|
|
104
|
+
function lookup(event, root) {
|
|
105
|
+
var context = (root.preview && root.preview.active) ? (root.preview.isPdf ? "pdf" : root.preview.isMedia ? "media" : "preview")
|
|
106
|
+
: shareBrowserHere(root) ? "menu" : root.focusView === RAIL ? "rail" : "listing"
|
|
107
|
+
// Grid arrows address visual neighbours even when the preset uses them to open folders in List.
|
|
108
|
+
// Issue 114, muellan: h and l are the arrows spelled as letters, so in the grid they mean what
|
|
109
|
+
// the arrows mean and not the tree's own pair, which is what the eye reads off a row of tiles.
|
|
110
|
+
if (context === "listing" && root.viewMode === "grid" && event.modifiers === Qt.NoModifier) {
|
|
111
|
+
if (Grid.sideways(event) < 0) return "cursorLeft"
|
|
112
|
+
if (Grid.sideways(event) > 0) return "cursorRight"
|
|
113
|
+
}
|
|
114
|
+
var action = Keymap.lookup(event.key, event.text, event.modifiers, context)
|
|
115
|
+
// The share listing borrows the menu context for j/k/enter, but it has no submenu to step into.
|
|
116
|
+
if (action === "menuRight" && shareBrowserHere(root)) return "open"
|
|
117
|
+
// flea-qml: every view filters the held rows it draws, Find's results included; the two are
|
|
118
|
+
// independent, so a standing Find never takes the key away.
|
|
119
|
+
// Left and Right seek inside a media preview and turn the page in a PDF one, which is the only
|
|
120
|
+
// place the map binds either action now that the browsing pair is parent and browse-in; the grid
|
|
121
|
+
// takes the bare arrows above, before the map is consulted.
|
|
122
|
+
if (action === "seekBack" || action === "seekForward")
|
|
123
|
+
return root.preview && root.preview.active && (root.preview.isMedia || root.preview.isPdf) ? action : ""
|
|
124
|
+
// The zoom keys reach a PDF or an image, 0 reaches an image only (keys.toml binds it in that context), and e expands a PDF only. l is h's forward: page, else enter or preview.
|
|
125
|
+
if (action === "zoomOut" || action === "zoomIn" || action === "zoomFit" || action === "expand")
|
|
126
|
+
return (root.preview && root.preview.active && (root.preview.isPdf || ((root.preview.isImage || root.preview.isHtml) && action !== "expand"))) ? action : ""
|
|
127
|
+
// w wraps code, text and Markdown Source; other preview kinds keep no wrap action.
|
|
128
|
+
if (action === "toggleWrap")
|
|
129
|
+
return (root.preview && root.preview.active && (root.preview.isCodeText
|
|
130
|
+
|| (root.preview.isDocument && root.preview.markdownShown
|
|
131
|
+
&& root.preview.markdownShown.shownView === "source"))) ? action : ""
|
|
132
|
+
if (action === "pageForward") {
|
|
133
|
+
if (root.preview && root.preview.active)
|
|
134
|
+
return root.preview.isPdf ? action : ""
|
|
135
|
+
if (shareBrowserHere(root) || root.focusView === RAIL)
|
|
136
|
+
return "open"
|
|
137
|
+
var row = root.rowFor(root.cursorIndex)
|
|
138
|
+
return row && (row.d || (Format.isSymlink(row.p) && row.i === "folder")) ? "open" : (row ? "preview" : "")
|
|
139
|
+
}
|
|
140
|
+
// The key follows the row: where gio has no Trash the refusal names trashRefused, never arming a d that can only fail.
|
|
141
|
+
if ((action === "trashArm" || action === "trash") && root.recentMode !== "trash" && !Mounts.trashable(root.path, !root.backend || root.backend.dirWritable !== false))
|
|
142
|
+
return "trashRefused"
|
|
143
|
+
// reveal only means something on a search result or a recent row, so o is discarded everywhere else.
|
|
144
|
+
if (action === "reveal" && root.searchMode !== Search.RESULTS && root.recentMode.length === 0)
|
|
145
|
+
return ""
|
|
146
|
+
// A sort ends the running walk in the backend and the search strip hides the mark that would
|
|
147
|
+
// show it happening, so both sort keys go quiet for as long as a search owns the header.
|
|
148
|
+
if (action === "sortNext" || action === "sortReverse")
|
|
149
|
+
return root.searchMode.length === 0 ? action : ""
|
|
150
|
+
// A reload re-lists the folder it is on, so it goes quiet where a walk owns the header.
|
|
151
|
+
if (action === "reload" && root.searchMode.length > 0)
|
|
152
|
+
return ""
|
|
153
|
+
return action
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Lifted from Pane.qml's Keys.onPressed: the map holds the keys, this holds the behaviour.
|
|
157
|
+
// Takes the Pane root because every case is a method call or a property read on it.
|
|
158
|
+
function act(action, root, menuId, paths) {
|
|
159
|
+
switch (action) {
|
|
160
|
+
// List steps follow item order; in the grid ui/js/Grid.js takes j/k and the arrows as visual cells.
|
|
161
|
+
case "cursorDown": step(root, 1); Marks.follow(root); return
|
|
162
|
+
case "cursorUp": step(root, -1); Marks.follow(root); return
|
|
163
|
+
case "cursorLeft": step(root, -1); Marks.follow(root); return
|
|
164
|
+
case "cursorRight": step(root, 1); Marks.follow(root); return
|
|
165
|
+
case "cursorFirst": Filter.setCursorView(root, 0); Marks.follow(root); return
|
|
166
|
+
case "cursorLast": Filter.setCursorView(root, root.shownTotal - 1); Marks.follow(root); return
|
|
167
|
+
case "pageDown": step(root, Math.max(1, Math.floor(root.visibleRows / 2))); Marks.follow(root); return
|
|
168
|
+
case "pageUp": step(root, -Math.max(1, Math.floor(root.visibleRows / 2))); Marks.follow(root); return
|
|
169
|
+
case "open": root.openCursor(); return
|
|
170
|
+
case "openTab": Tabs.openCursorTab(root); return
|
|
171
|
+
case "parent": root.openParent(); return
|
|
172
|
+
case "historyBack": root.goBack(); return
|
|
173
|
+
case "historyForward": root.goForward(); return
|
|
174
|
+
case "togglePreview": root.togglePreviewColumn(); return
|
|
175
|
+
case "previewPageForward":
|
|
176
|
+
case "previewPageBack": if (root.previewColumnItem) root.previewColumnItem.pageBy(action === "previewPageForward" ? 1 : -1); return
|
|
177
|
+
case "factsToggle": if (root.previewColumnItem && root.previewColumnItem.visible) root.previewColumnItem.toggleFacts(); return
|
|
178
|
+
case "loadPreview": root.loadSelectionPreview(); return
|
|
179
|
+
case "focusPreview": root.focusPreviewColumn(); return
|
|
180
|
+
case "windowNew": root.newWindow(); return
|
|
181
|
+
case "toggleHidden": root.toggleHidden(); return
|
|
182
|
+
// ExtThumbs: the background menu's class row and any future chord land here.
|
|
183
|
+
case "extThumbs": root.toggleExtThumbs(); return
|
|
184
|
+
case "sidebar": root.toggleRail(); return
|
|
185
|
+
// Popups handle Escape first; the focused listing then unwinds filter, search, status and marks.
|
|
186
|
+
case "escape":
|
|
187
|
+
if (root.filterTyping || root.filterQuery.length > 0) Filter.close(root)
|
|
188
|
+
else if (root.searchMode.length > 0 && root.focusView === LIST) Search.abort(root)
|
|
189
|
+
else if (root.recentMode.length > 0 && root.focusView === LIST) RecentMode.close(root)
|
|
190
|
+
else if (root.statusBar && root.statusBar.escapePressed()) return
|
|
191
|
+
else if (escapeUp(root)) root.openParent()
|
|
192
|
+
else root.escapePressed()
|
|
193
|
+
return
|
|
194
|
+
case "reload": Reload.begin(root, root.wire); return
|
|
195
|
+
case "preview": PreviewKeys.open(root); return
|
|
196
|
+
case "toggleSelect": root.toggleSelect(); return
|
|
197
|
+
case "extendDown": root.extendSelection(1); return
|
|
198
|
+
case "extendUp": root.extendSelection(-1); return
|
|
199
|
+
case "selectAll": root.selectAll(); return
|
|
200
|
+
// flea-qml: Find and Filter are independent; a filter left up narrows the results by name too.
|
|
201
|
+
case "search": Search.start(root); return
|
|
202
|
+
case "searchContents": Search.contents(root); return
|
|
203
|
+
// flea-qml: = measures the selected folders, or the cursor's; Alt+= every folder (src/dirsize.js).
|
|
204
|
+
case "measureDirs": root.measureDirs(root.selectionCount() > 0 ? root.selectedIndices() : [root.cursorIndex]); return
|
|
205
|
+
case "measureAllDirs": root.measureAllDirs(); return
|
|
206
|
+
case "filter": Filter.start(root); return
|
|
207
|
+
case "reveal": if (root.recentMode.length > 0) { if (root.listInFlight) root.message("A directory is already loading.", false); else RecentMode.reveal(root) } else Search.reveal(root); return
|
|
208
|
+
// The write operations; every one of them is reversible with undo, so none of them confirms.
|
|
209
|
+
case "duplicate": Ops.duplicate(root, menuId); return
|
|
210
|
+
case "trash": Ops.trash(root, menuId); return
|
|
211
|
+
case "trashArm": Trash.arm(root); return
|
|
212
|
+
// A trash key where there is no Trash refuses in the error role, hinting the key that still works.
|
|
213
|
+
case "trashRefused": root.message(noTrashLine(), true); return
|
|
214
|
+
case "copy": Ops.clip(root, false, paths); return
|
|
215
|
+
case "copydirpath": root.copyDirPath(); return
|
|
216
|
+
// MenuAdditions040: c copies as, P pastes as, V flips the selection.
|
|
217
|
+
case "copyAs": root.openCopyAs(); return
|
|
218
|
+
case "pasteAs":
|
|
219
|
+
if (root.recentMode.length > 0) { root.message((root.recentMode === "trash" ? "Trash" : "Recent") + " is a collection. Open a folder before pasting", false); return }
|
|
220
|
+
root.openPasteAs(); return
|
|
221
|
+
case "invertSelection": root.invertSelection(); return
|
|
222
|
+
case "showOriginal": root.showOriginal(); return
|
|
223
|
+
case "makeExecutable": root.makeExecutable(paths); return
|
|
224
|
+
case "compare": Ops.open(root, paths); return
|
|
225
|
+
case "copyPath": Ops.copyAs(root, "path", paths); return
|
|
226
|
+
case "copyName": Ops.copyAs(root, "name", paths); return
|
|
227
|
+
case "copyStem": Ops.copyAs(root, "stem", paths); return
|
|
228
|
+
case "copyUri": Ops.copyAs(root, "uri", paths); return
|
|
229
|
+
case "copyQuoted": Ops.copyAs(root, "quoted", paths); return
|
|
230
|
+
case "pasteLink":
|
|
231
|
+
case "pasteAbsoluteLink":
|
|
232
|
+
case "pasteHardLink":
|
|
233
|
+
if (RecentMode.refusePaste(root)) return
|
|
234
|
+
root.pasteLink(action === "pasteAbsoluteLink" ? "absolute" : action === "pasteHardLink" ? "hard" : "relative"); return
|
|
235
|
+
case "cut": Ops.clip(root, true, paths); return
|
|
236
|
+
// Recent is a history, not a directory: pasting or creating there would land in the root it stands on.
|
|
237
|
+
case "paste": if (root.recentMode.length > 0) { root.message((root.recentMode === "trash" ? "Trash" : "Recent") + " is a collection. Open a folder before pasting", false); return } Ops.paste(root); return
|
|
238
|
+
case "movePaste":
|
|
239
|
+
if (root.recentMode.length > 0) { root.message((root.recentMode === "trash" ? "Trash" : "Recent") + " is a collection. Open a folder before pasting", false); return }
|
|
240
|
+
Ops.paste(root, true)
|
|
241
|
+
return
|
|
242
|
+
case "undo": Ops.undo(root); return
|
|
243
|
+
case "redo": root.backend.send({c: "redo"}); return
|
|
244
|
+
// m opens the row menu, or says why no row was under the cursor.
|
|
245
|
+
case "menu":
|
|
246
|
+
if (!root.openCursorMenu())
|
|
247
|
+
root.message("No item under the cursor to open a menu on", false)
|
|
248
|
+
return
|
|
249
|
+
// The run card's own entrances; see ui/js/Nav.js runCursor.
|
|
250
|
+
case "run": Nav.runCursor(root, root.opener, "open"); return
|
|
251
|
+
case "openAsText": Nav.runCursor(root, root.opener, "openText"); return
|
|
252
|
+
case "tags": root.tags().openMenu(); return
|
|
253
|
+
case "extract": Ops.extract(root, menuId); return
|
|
254
|
+
case "dropbox": root.moveToDropbox(menuId); return
|
|
255
|
+
case "sharelink": root.copyShareLink(); return
|
|
256
|
+
// Convert opens the one popup this whole design has; every other operation answers without one.
|
|
257
|
+
case "convert": root.openConvert(menuId); return
|
|
258
|
+
// The header answers the same two through ui/Pane.qml, so the key and the click share one route.
|
|
259
|
+
case "sortNext": Sort.next(root); return
|
|
260
|
+
case "sortReverse": Sort.reverse(root); return
|
|
261
|
+
// F4 fits every drawn list column; anywhere but the list view it says where that lives.
|
|
262
|
+
case "autofitColumns":
|
|
263
|
+
if (root.viewMode === "list") root.header.autofitAll()
|
|
264
|
+
else root.message("Autofit needs the list view.", false)
|
|
265
|
+
return
|
|
266
|
+
case "addNetwork": if (root.sidebar) root.sidebar.addRequested(); return
|
|
267
|
+
case "eject": Eject.release(root, root.sidebar, false); return
|
|
268
|
+
// Finder's Cmd+1/2/3/4; the chrome's four buttons write the same property, so they follow.
|
|
269
|
+
case "viewList": root.chooseView("list"); return
|
|
270
|
+
case "viewColumns": root.chooseView("columns"); return
|
|
271
|
+
case "viewGrid": root.chooseView("grid"); return
|
|
272
|
+
case "viewDual": root.chooseView("dual"); return
|
|
273
|
+
case "newFolder": if (root.recentMode.length > 0) { root.message((root.recentMode === "trash" ? "Trash" : "Recent") + " is a collection. Open a folder first", false); return } Ops.newFolder(root); return
|
|
274
|
+
// The directory being shown, not the row: the menu row and the chord both land here.
|
|
275
|
+
case "openTerminal": root.openTerminal(); return
|
|
276
|
+
// The background menu's Update Flea row, drawn only while an update is known, opens Omarchy's updater through the pane's opener.
|
|
277
|
+
case "updateFlea": root.opener.updateFlea(root); return
|
|
278
|
+
}
|
|
279
|
+
// A submenu row fires "<action>:<id>", which is how one signal covers Taildrop and Compress both.
|
|
280
|
+
if (action.indexOf("tags:") === 0) { root.tags().choose(action.substring(5)); return }
|
|
281
|
+
if (action.indexOf("compress:") === 0) {
|
|
282
|
+
var picked = action.substring("compress:".length)
|
|
283
|
+
// The submenu's last row opens the password dialog, routed by the pane: this file takes no new first-frame import.
|
|
284
|
+
if (picked === "compressPassword") { root.compressPasswordRequested(paths || null, menuId || 0); return }
|
|
285
|
+
if (paths) Ops.compressResolved(root, paths, picked, menuId)
|
|
286
|
+
else Ops.compress(root, picked)
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
// The background menu's Sort by flyout, routed to the header click's own function so an aimed
|
|
290
|
+
// click and an aimed menu row cannot come to mean different things.
|
|
291
|
+
if (action.indexOf("sort:") === 0) {
|
|
292
|
+
Sort.column(root, action.substring("sort:".length))
|
|
293
|
+
return
|
|
294
|
+
}
|
|
295
|
+
// Tabs run here and handleKey opens the path bar, so neither answers unbuilt any more.
|
|
296
|
+
if (action.indexOf("tab") === 0) { Tabs.act(action, root); return }
|
|
297
|
+
root.message("That action is not available yet", false)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Issue 29: Escape climbs only when nothing else owns it, so each unwound state keeps the key.
|
|
301
|
+
function escapeUp(root) {
|
|
302
|
+
return root.escapeUp === true && root.searchMode.length === 0
|
|
303
|
+
&& root.filterQuery.length === 0 && !root.filterTyping && !root.menuVisible
|
|
304
|
+
&& !(root.collide && root.collide.opened) && !hasDeliberateMarks(root) && !root.listInFlight
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Only the row a navigation landed on never counts as a selection, so Escape keeps climbing.
|
|
308
|
+
function hasDeliberateMarks(root) {
|
|
309
|
+
if (root.selectionCount() === 0)
|
|
310
|
+
return false
|
|
311
|
+
if (root.selection && root.selection.isLanded && root.selection.isLanded())
|
|
312
|
+
return false
|
|
313
|
+
return true
|
|
314
|
+
}
|
|
315
|
+
// Only a step from an end wraps; page overshoots and selection extensions retain their clamps.
|
|
316
|
+
function step(root, delta) {
|
|
317
|
+
var last = root.shownTotal - 1
|
|
318
|
+
if (root.wrapAtEnds !== true || last < 0) {
|
|
319
|
+
Filter.moveCursor(root, delta)
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
var from = Filter.viewOf(root.shown, root.cursorIndex)
|
|
323
|
+
var to = from + delta
|
|
324
|
+
if (to < 0)
|
|
325
|
+
to = from === 0 ? last : 0
|
|
326
|
+
if (to > last)
|
|
327
|
+
to = from === last ? 0 : last
|
|
328
|
+
Filter.setCursorView(root, to)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ui/ShareBrowser.qml's own overlay, the same j/k/open/escape shape PreviewKeys.act uses.
|
|
332
|
+
function shareBrowserAct(action, root) {
|
|
333
|
+
switch (action) {
|
|
334
|
+
case "cursorDown": root.shareBrowser.moveCursor(1); return
|
|
335
|
+
case "cursorUp": root.shareBrowser.moveCursor(-1); return
|
|
336
|
+
case "open": root.shareBrowser.activateCursor(); return
|
|
337
|
+
case "escape": root.shareBrowser.close(); return
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// The cursor keys and only those, resolved through the generated table rather than through a second
|
|
342
|
+
// list of key codes, which is how issue 28's Home, End and page keys came with issue 12 for free. A
|
|
343
|
+
// printable character is excluded before the lookup, or j and k would leave the line instead of
|
|
344
|
+
// being typed into it.
|
|
345
|
+
var LEAVES_LINE = ["cursorDown", "cursorUp", "cursorFirst", "cursorLast", "pageDown", "pageUp"]
|
|
346
|
+
|
|
347
|
+
function leavesLine(event) {
|
|
348
|
+
if (Input.isPrintable(event.text))
|
|
349
|
+
return false
|
|
350
|
+
return LEAVES_LINE.indexOf(Keymap.lookup(event.key, event.text, event.modifiers)) >= 0
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// One stamp for a vim pair's seat, so Escape and the pair read the same identity.
|
|
354
|
+
function stampOf(root) {
|
|
355
|
+
return JSON.stringify([root.path, root.cursorIndex, root.selectionVersion, root.viewMode])
|
|
356
|
+
}
|
|
357
|
+
// Only the second press of the same pair on the same selection fires.
|
|
358
|
+
var ARMED_PAIRS = { copyArm: true, cutArm: true, pasteArm: true, cursorFirstArm: true }
|
|
359
|
+
// Vim pairs are consecutive inputs on the same selection; pointer or navigation changes disarm them.
|
|
360
|
+
function sequenceAction(action, root) {
|
|
361
|
+
var pairs = { copyArm: "copy", cutArm: "cut", pasteArm: "paste", cursorFirstArm: "cursorFirst" }
|
|
362
|
+
var stamp = stampOf(root)
|
|
363
|
+
var paired = pairs[action] && root.keySequence === action && root.keySequenceIdentity === stamp
|
|
364
|
+
root.keySequence = paired || !pairs[action] ? "" : action
|
|
365
|
+
root.keySequenceIdentity = paired || !pairs[action] ? "" : stamp
|
|
366
|
+
return paired ? pairs[action] : pairs[action] ? "" : action
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Lifted whole from Pane.qml's Keys.onPressed, which had grown past its file's 400-line cap; returns whether the key was consumed.
|
|
370
|
+
function handleKey(event, root, sidebar, field) {
|
|
371
|
+
// Embedded terminals own ordinary keys; never turn shell typing into file operations.
|
|
372
|
+
if (root.terminalId && !field && !(sidebar && sidebar.activeFocus)) return false
|
|
373
|
+
if (root.selectionBand) {
|
|
374
|
+
if (event.key === Qt.Key_Escape)
|
|
375
|
+
root.selectionBand.cancel()
|
|
376
|
+
return true
|
|
377
|
+
}
|
|
378
|
+
// A live rename editor owns keys; an index left behind by a hidden or recycled editor does not.
|
|
379
|
+
if ((sidebar && sidebar.renameEditor() !== null) || root.renameEditor() !== null) {
|
|
380
|
+
return true
|
|
381
|
+
}
|
|
382
|
+
// A focused query owns Escape. Outside the inputs, unwind Filter first.
|
|
383
|
+
if (event.key === Qt.Key_Escape) {
|
|
384
|
+
if (field === "find") { Search.abort(root); return true }
|
|
385
|
+
if (field === "filter" || root.filterTyping || root.filterQuery.length > 0) {
|
|
386
|
+
Filter.close(root)
|
|
387
|
+
return true
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
root.inputAt = Date.now()
|
|
391
|
+
root.rowsAt = 0
|
|
392
|
+
// The query line owns every key unless Quick Look or the share listing is over it; cursor motions act on the results through the one route.
|
|
393
|
+
if (field !== "filter" && root.searchMode === Search.TYPING && !(root.preview && root.preview.active) && !shareBrowserHere(root)) {
|
|
394
|
+
if (leavesLine(event)) {
|
|
395
|
+
var action = Keymap.lookup(event.key, event.text, event.modifiers)
|
|
396
|
+
// No key off the line moves rows a listing or the search's exit is about to replace, as below and in Search.typeKey.
|
|
397
|
+
if (root.searchLeaving === true) return true
|
|
398
|
+
if (Swap.swallows(root.listInFlight, action)) { root.message(Swap.LOADING, false); return true }
|
|
399
|
+
if (Grid.arrow(event, action, root)) {
|
|
400
|
+
return true
|
|
401
|
+
}
|
|
402
|
+
act(action, root)
|
|
403
|
+
return true
|
|
404
|
+
}
|
|
405
|
+
return Search.typeKey(event, root)
|
|
406
|
+
}
|
|
407
|
+
if (root.filterTyping && leavesLine(event)) {
|
|
408
|
+
Filter.commit(root)
|
|
409
|
+
}
|
|
410
|
+
// The filter's query line owns every key while it has the caret, the same as the search's above.
|
|
411
|
+
if (root.filterTyping) {
|
|
412
|
+
return Filter.typeKey(event, root)
|
|
413
|
+
}
|
|
414
|
+
var action = lookup(event, root)
|
|
415
|
+
// A key that means an action ends a pending slow click, so its rename never lands after that key's result; a bare modifier means none.
|
|
416
|
+
if (action.length > 0 && root.cancelSlowClick) root.cancelSlowClick()
|
|
417
|
+
// With escape-up on Escape cancels an armed trash or a live vim pair and stops, with it off Escape disarms through the sequence and runs its own action.
|
|
418
|
+
var escapeCancelsArm = action === "escape" && root.escapeUp === true
|
|
419
|
+
&& (root.trashArmedAt > 0 || (ARMED_PAIRS[root.keySequence] === true && root.keySequenceIdentity === stampOf(root)))
|
|
420
|
+
action = sequenceAction(action, root)
|
|
421
|
+
// Anything that is not the second d of the pair disarms it, so an arm never outlives the key
|
|
422
|
+
// after it; ui/js/Trash.js re-stamps on its own, which is why it reads the stamp before writing.
|
|
423
|
+
if (action !== "trashArm") {
|
|
424
|
+
root.trashArmedAt = 0
|
|
425
|
+
}
|
|
426
|
+
if (root.preview && root.preview.active) {
|
|
427
|
+
PreviewKeys.act(action, root)
|
|
428
|
+
return true
|
|
429
|
+
}
|
|
430
|
+
if (shareBrowserHere(root)) {
|
|
431
|
+
shareBrowserAct(action, root)
|
|
432
|
+
return true
|
|
433
|
+
}
|
|
434
|
+
if (windowAction(action, root, sidebar)) return true
|
|
435
|
+
if ((root.focusView === CHROME || root.focusView === STRIP) && ChromeKeys.act(event, root)) return true
|
|
436
|
+
if (root.focusView === RAIL && sidebar) {
|
|
437
|
+
RailKeys.act(action, root, sidebar, event)
|
|
438
|
+
return true
|
|
439
|
+
}
|
|
440
|
+
// An armed pair keeps Escape to cancel the arm instead of climbing.
|
|
441
|
+
if (action === "escape" && escapeCancelsArm) {
|
|
442
|
+
root.trashArmedAt = 0
|
|
443
|
+
root.keySequence = ""
|
|
444
|
+
root.keySequenceIdentity = ""
|
|
445
|
+
root.message("", false)
|
|
446
|
+
return true
|
|
447
|
+
}
|
|
448
|
+
// No row action runs against a listing still in flight.
|
|
449
|
+
if (Swap.swallows(root.listInFlight, action)) { root.message(Swap.LOADING, false); return true }
|
|
450
|
+
if (action === "undo" && !canUndo(root, sidebar)) return true
|
|
451
|
+
if (Grid.arrow(event, action, root)) return true
|
|
452
|
+
if (action.length > 0 || Keymap.lookup(event.key, event.text, event.modifiers).length > 0) {
|
|
453
|
+
if (action.length > 0) dispatchAction(action, root)
|
|
454
|
+
return true
|
|
455
|
+
}
|
|
456
|
+
// Unbound printable keys name the filter instead of jumping into destructive bindings.
|
|
457
|
+
if (root.shown === null && Input.isPrintable(event.text)) {
|
|
458
|
+
var tip = KeyName.hinted(WORDS.filterTip, "filter")
|
|
459
|
+
if (tip.length > 0) root.message(tip, false)
|
|
460
|
+
return true
|
|
461
|
+
}
|
|
462
|
+
return false
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Keys and query actions share the window's dispatcher before reaching pane actions.
|
|
466
|
+
function dispatchAction(action, root) {
|
|
467
|
+
if (!windowAction(action, root)) root.act(action)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function windowAction(action, root, sidebar) {
|
|
471
|
+
if (action === "focusNext" || action === "focusPrevious") {
|
|
472
|
+
tabStep(root, sidebar, action === "focusNext")
|
|
473
|
+
return true
|
|
474
|
+
}
|
|
475
|
+
if (action === "focusPreview") {
|
|
476
|
+
if (!root.dualMode) root.focusPreviewColumn()
|
|
477
|
+
return true
|
|
478
|
+
}
|
|
479
|
+
if (action === "keymapSheet") {
|
|
480
|
+
root.keymapSheet.open(root)
|
|
481
|
+
return true
|
|
482
|
+
}
|
|
483
|
+
// Tabs answer from either view.
|
|
484
|
+
if (action.indexOf("tab") === 0) {
|
|
485
|
+
root.act(action)
|
|
486
|
+
return true
|
|
487
|
+
}
|
|
488
|
+
// Issue 9: the text size belongs to the window, so it answers from either view.
|
|
489
|
+
if (action.indexOf("textSize") === 0) {
|
|
490
|
+
root.textSizeRequested(TextSize.direction(action))
|
|
491
|
+
return true
|
|
492
|
+
}
|
|
493
|
+
// The chrome owns the path field.
|
|
494
|
+
if (action === "pathBar") {
|
|
495
|
+
root.pathBarRequested()
|
|
496
|
+
return true
|
|
497
|
+
}
|
|
498
|
+
// These answer from the rail as well as the list, so they are taken before the rail's own keys.
|
|
499
|
+
if (action === "windowNew" || action === "reload" || action === "sidebar" || action === "openTerminal" || action === "settings" || action === "copydirpath") {
|
|
500
|
+
root.act(action)
|
|
501
|
+
return true
|
|
502
|
+
}
|
|
503
|
+
return false
|
|
504
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
.import "UserDirs.js" as UserDirs
|
|
3
|
+
|
|
4
|
+
// Owned here so Backend.qml loads no sort closure at startup.
|
|
5
|
+
var ORDERS = ["name", "size", "mtime", "kind"]
|
|
6
|
+
|
|
7
|
+
// Written only on a user sort in that folder, read once per listing, oldest first.
|
|
8
|
+
|
|
9
|
+
// The cap ui.json holds, oldest first; setting past it drops the folders sorted longest ago.
|
|
10
|
+
var MAX = 500
|
|
11
|
+
|
|
12
|
+
// Sample input: XDG_DOWNLOAD_DIR="$HOME/Inbox"; absent PICTURES and VIDEOS use their conventional names.
|
|
13
|
+
function newestPaths(body, home) {
|
|
14
|
+
var roles = ["DOWNLOAD", "PICTURES", "VIDEOS"]
|
|
15
|
+
var names = ["Downloads", "Pictures", "Videos"]
|
|
16
|
+
var paths = []
|
|
17
|
+
if (!home) return paths
|
|
18
|
+
var configured = {}
|
|
19
|
+
var entries = UserDirs.readRoles(body, home)
|
|
20
|
+
for (var e = 0; e < entries.length; e++)
|
|
21
|
+
configured[entries[e].role] = entries[e].path
|
|
22
|
+
for (var i = 0; i < roles.length; i++) {
|
|
23
|
+
var path = configured[roles[i]] === undefined ? home + "/" + names[i] : configured[roles[i]]
|
|
24
|
+
if (path && path !== home && paths.indexOf(path) < 0)
|
|
25
|
+
paths.push(path)
|
|
26
|
+
}
|
|
27
|
+
return paths
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function defaultOrder(path, newest) {
|
|
31
|
+
var folder = String(path || "").replace(/\/+$/, "")
|
|
32
|
+
return newest && newest.indexOf(folder) >= 0 ? { key: "mtime", reverse: true } : null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Settings stores Modified as "date" while ORDERS and the backend spell it "mtime".
|
|
36
|
+
function liveKey(key) {
|
|
37
|
+
return key === "date" ? "mtime" : key
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Sample input: {"/home/gm/Work": {"key": "size", "reverse": true}}.
|
|
41
|
+
function get(sorts, path) {
|
|
42
|
+
var entry = sorts ? sorts[path] : null
|
|
43
|
+
if (!entry || ORDERS.indexOf(liveKey(entry.key)) < 0)
|
|
44
|
+
return null
|
|
45
|
+
return { key: liveKey(entry.key), reverse: entry.reverse === true }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function has(sorts, path) {
|
|
49
|
+
return get(sorts, path) !== null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function count(sorts) {
|
|
53
|
+
return sorts ? Object.keys(sorts).length : 0
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// A re-sort moves its folder to the most recent end; past the cap the oldest entries go.
|
|
57
|
+
function set(sorts, path, key, reverse) {
|
|
58
|
+
var next = {}
|
|
59
|
+
if (sorts) {
|
|
60
|
+
for (var k in sorts) {
|
|
61
|
+
if (k !== path)
|
|
62
|
+
next[k] = sorts[k]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
next[path] = { key: key, reverse: reverse === true }
|
|
66
|
+
var keys = Object.keys(next)
|
|
67
|
+
while (keys.length > MAX)
|
|
68
|
+
delete next[keys.shift()]
|
|
69
|
+
return next
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function forget(sorts, path) {
|
|
73
|
+
var next = {}
|
|
74
|
+
if (sorts) {
|
|
75
|
+
for (var k in sorts) {
|
|
76
|
+
if (k !== path)
|
|
77
|
+
next[k] = sorts[k]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return next
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// A user sort writes its folder only while remembering is on.
|
|
84
|
+
function shouldRemember(remember, path) {
|
|
85
|
+
return remember !== false && !!path
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Columns pass keep: a saved order wins over XDG defaults; remembering off uses the global order, except kind, unsupported by peeks.
|
|
89
|
+
function peekOrder(sorts, path, remember, keep, newest, fallback) {
|
|
90
|
+
if (!Array.isArray(keep)) return {}
|
|
91
|
+
var own = remember !== false ? get(sorts, path) || defaultOrder(path, newest)
|
|
92
|
+
: fallback ? orderFor(null, path, fallback, false) : null
|
|
93
|
+
if (remember === false && own && own.key === "name" && !own.reverse) return {}
|
|
94
|
+
return own && own.key !== "kind" ? { by: own.key, desc: own.reverse } : {}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// An unknown stored key reads as the default, so a newer Flea never wedges this one.
|
|
98
|
+
function orderFor(sorts, path, fallback, remember, newest) {
|
|
99
|
+
if (remember !== false) {
|
|
100
|
+
var own = get(sorts, path) || defaultOrder(path, newest)
|
|
101
|
+
if (own)
|
|
102
|
+
return own
|
|
103
|
+
}
|
|
104
|
+
fallback = fallback || {}
|
|
105
|
+
var key = liveKey(fallback.key)
|
|
106
|
+
return { key: ORDERS.indexOf(key) >= 0 ? key : "name",
|
|
107
|
+
reverse: fallback.reverse === true }
|
|
108
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// The three layouts a directory can own. Dual pane is a window shape, not a folder view.
|
|
4
|
+
var MODES = ["list", "columns", "grid"]
|
|
5
|
+
var MAX = 500
|
|
6
|
+
|
|
7
|
+
function get(views, path) {
|
|
8
|
+
var mode = views ? views[path] : ""
|
|
9
|
+
return MODES.indexOf(mode) >= 0 ? mode : ""
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function has(views, path) {
|
|
13
|
+
return get(views, path).length > 0
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// A re-selection moves its folder to the most recent end; past the cap the oldest goes.
|
|
17
|
+
function set(views, path, mode) {
|
|
18
|
+
var next = {}
|
|
19
|
+
if (views) {
|
|
20
|
+
for (var key in views) {
|
|
21
|
+
if (key !== path)
|
|
22
|
+
next[key] = views[key]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
next[path] = mode
|
|
26
|
+
var keys = Object.keys(next)
|
|
27
|
+
while (keys.length > MAX)
|
|
28
|
+
delete next[keys.shift()]
|
|
29
|
+
return next
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// A stored folder preference is opt-in. With it off, the existing global view remains the fallback.
|
|
33
|
+
function viewFor(views, path, fallback, remember) {
|
|
34
|
+
if (remember === true) {
|
|
35
|
+
var own = get(views, path)
|
|
36
|
+
if (own)
|
|
37
|
+
return own
|
|
38
|
+
}
|
|
39
|
+
return MODES.indexOf(fallback) >= 0 ? fallback : "list"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function shouldRemember(remember, path) {
|
|
43
|
+
return remember === true && !!path
|
|
44
|
+
}
|