flea-qml 0.0.0-stage → 0.1.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 +478 -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 +402 -0
- package/src/archiveops.js +697 -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 +129 -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/transfer.js +669 -0
- package/src/trash-record.js +41 -0
- package/src/trash.js +210 -0
- package/src/trashbrowse.js +326 -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 +241 -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-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-html-security.mjs +23 -0
- package/test/manual-html-ui.mjs +30 -0
- package/test/manual-syntax-preview.mjs +26 -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 +68 -0
- package/ui/ArchiveCompressDialog.qml +378 -0
- package/ui/ArchivePasswordDialog.qml +257 -0
- package/ui/Backend.qml +771 -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 +523 -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 +115 -0
- package/ui/Pane.qml +1296 -0
- package/ui/PaneMenuActions.qml +527 -0
- package/ui/PanePath.qml +90 -0
- package/ui/PaneRail.qml +239 -0
- package/ui/PaneStates.qml +88 -0
- package/ui/PaneSwap.qml +339 -0
- package/ui/PaneWire.qml +605 -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 +1004 -0
- package/ui/PreviewAnimation.qml +24 -0
- package/ui/PreviewArchive.qml +66 -0
- package/ui/PreviewColumn.qml +551 -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 +38 -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 +732 -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/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 +827 -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 +122 -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 +364 -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 +502 -0
- package/ui/js/FolderSorts.js +108 -0
- package/ui/js/FolderViews.js +44 -0
- package/ui/js/Format.js +305 -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 +736 -0
- package/ui/js/Tags.js +134 -0
- package/ui/js/Taildrop.js +128 -0
- package/ui/js/Tap.js +174 -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 +81 -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 +228 -0
package/ui/js/Places.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Mounts.js" as Mounts
|
|
4
|
+
.import "UserDirs.js" as UserDirs
|
|
5
|
+
|
|
6
|
+
// Sample input: XDG_DOWNLOAD_DIR="$HOME/Downloads"
|
|
7
|
+
function userDirs(body, home) {
|
|
8
|
+
return UserDirs.userDirs(body, home)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Sample input: file:///home/gm/Downloads Downloads
|
|
12
|
+
function bookmarks(body) {
|
|
13
|
+
var out = []
|
|
14
|
+
var lines = String(body || "").split("\n")
|
|
15
|
+
for (var i = 0; i < lines.length; i++) {
|
|
16
|
+
var line = lines[i].trim()
|
|
17
|
+
// corner: a bookmark may be smb:// or sftp://, which is a Location and not a Favorite.
|
|
18
|
+
if (line.indexOf("file://") !== 0)
|
|
19
|
+
continue
|
|
20
|
+
var space = line.indexOf(" ")
|
|
21
|
+
var uri = space < 0 ? line : line.substring(0, space)
|
|
22
|
+
var label = space < 0 ? "" : line.substring(space + 1).trim()
|
|
23
|
+
var path = Mounts.decodePath(uri.substring("file://".length))
|
|
24
|
+
out.push({ path: path, label: label.length > 0 ? label : leaf(path) })
|
|
25
|
+
}
|
|
26
|
+
return out
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// The FAVORITES rail's rows, Home first and always, then XDG dirs and bookmarked places in file
|
|
30
|
+
// order, a path seen twice keeping its first position. glyphFor resolves each row's mark so the
|
|
31
|
+
// rail's Icons import stays the rail's own business; see ui/Sidebar.qml's rebuild.
|
|
32
|
+
function favorites(home, dirsText, marksText, glyphFor) {
|
|
33
|
+
var favs = [{ path: home, label: "Home", group: "favorite", kind: "favorite", glyph: glyphFor("Home") }]
|
|
34
|
+
var seen = {}
|
|
35
|
+
seen[home] = true
|
|
36
|
+
var groups = [userDirs(dirsText, home), bookmarks(marksText)]
|
|
37
|
+
for (var g = 0; g < groups.length; g++) {
|
|
38
|
+
for (var i = 0; i < groups[g].length; i++) {
|
|
39
|
+
if (seen[groups[g][i].path])
|
|
40
|
+
continue
|
|
41
|
+
var e = groups[g][i]
|
|
42
|
+
seen[e.path] = true
|
|
43
|
+
favs.push({ path: e.path, label: e.label, group: "favorite", kind: "favorite", glyph: glyphFor(e.label) })
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return favs
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function leaf(path) {
|
|
50
|
+
var cut = path.lastIndexOf("/")
|
|
51
|
+
return cut < 0 ? path : path.substring(cut + 1)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Sample input: "smb://192.168.1.10/data NAS"; see AGENTS.md "Places.relabel" for the matching, duplicate and control-character rules.
|
|
55
|
+
function relabel(body, path, name) {
|
|
56
|
+
// A trust boundary: an embedded newline could otherwise split one bookmark into two lines.
|
|
57
|
+
var trimmed = String(name || "").replace(/[\r\n]/g, "").trim()
|
|
58
|
+
if (trimmed.length === 0)
|
|
59
|
+
return String(body || "")
|
|
60
|
+
var target = Mounts.normalize(path)
|
|
61
|
+
var lines = String(body || "").split("\n")
|
|
62
|
+
var found = false
|
|
63
|
+
for (var i = 0; i < lines.length; i++) {
|
|
64
|
+
// Read off the trimmed line the way Mounts.removeBookmark reads it, or an indented bookmark
|
|
65
|
+
// is one Remove can drop and this could only ever duplicate.
|
|
66
|
+
var line = lines[i].trim()
|
|
67
|
+
if (line.length === 0)
|
|
68
|
+
continue
|
|
69
|
+
var space = line.indexOf(" ")
|
|
70
|
+
var uri = space < 0 ? line : line.substring(0, space)
|
|
71
|
+
if (Mounts.normalize(uri) === target) {
|
|
72
|
+
lines[i] = uri + " " + trimmed
|
|
73
|
+
found = true
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (found)
|
|
77
|
+
return lines.join("\n")
|
|
78
|
+
var out = String(body || "")
|
|
79
|
+
if (out.length > 0 && out.charAt(out.length - 1) !== "\n")
|
|
80
|
+
out += "\n"
|
|
81
|
+
return out + target + " " + trimmed + "\n"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Sample input: body as relabel's, oldUri the saved line being rewritten, newUri the address the
|
|
85
|
+
// form's Mounts-as line showed. Matched the way relabel matches, so a live mount's trailing slash
|
|
86
|
+
// still finds the saved line, and an empty oldUri matches nothing and appends instead. PR 21.
|
|
87
|
+
function replace(body, oldUri, newUri, label) {
|
|
88
|
+
var next = Mounts.normalize(newUri)
|
|
89
|
+
if (next.length === 0)
|
|
90
|
+
return String(body || "")
|
|
91
|
+
// The same trust boundary relabel names: an embedded newline would split one bookmark into two.
|
|
92
|
+
var name = String(label || "").replace(/[\r\n]/g, "").trim()
|
|
93
|
+
if (name.length === 0)
|
|
94
|
+
name = leaf(next)
|
|
95
|
+
var target = Mounts.normalize(oldUri)
|
|
96
|
+
var lines = String(body || "").split("\n")
|
|
97
|
+
var found = false
|
|
98
|
+
for (var i = 0; i < lines.length; i++) {
|
|
99
|
+
var line = lines[i].trim()
|
|
100
|
+
if (line.length === 0)
|
|
101
|
+
continue
|
|
102
|
+
var space = line.indexOf(" ")
|
|
103
|
+
var uri = space < 0 ? line : line.substring(0, space)
|
|
104
|
+
if (target.length > 0 && Mounts.normalize(uri) === target) {
|
|
105
|
+
lines[i] = next + " " + name
|
|
106
|
+
found = true
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (found)
|
|
110
|
+
return lines.join("\n")
|
|
111
|
+
var out = String(body || "")
|
|
112
|
+
if (out.length > 0 && out.charAt(out.length - 1) !== "\n")
|
|
113
|
+
out += "\n"
|
|
114
|
+
return out + next + " " + name + "\n"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
var WIDTH_STOPS = [160, 192, 224, 256]
|
|
118
|
+
function sidebarWidth(value) {
|
|
119
|
+
if (typeof value !== "number" || !isFinite(value)) return 192
|
|
120
|
+
var nearest = WIDTH_STOPS[0]
|
|
121
|
+
for (var i = 1; i < WIDTH_STOPS.length; i++) {
|
|
122
|
+
if (Math.abs(WIDTH_STOPS[i] - value) < Math.abs(nearest - value)) nearest = WIDTH_STOPS[i]
|
|
123
|
+
}
|
|
124
|
+
return nearest
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function recordError(record) {
|
|
128
|
+
if (!record || typeof record !== "object" || Array.isArray(record)) return "invalid favorite record"
|
|
129
|
+
if (typeof record.label !== "string" || record.label.trim().length === 0) return "label needs visible text"
|
|
130
|
+
if (typeof record.path !== "string" || /[\u0000-\u001f\u007f]/.test(record.path)) return "invalid path"
|
|
131
|
+
if (record.path.charAt(0) === "/" || record.path === "~" || record.path.indexOf("~/") === 0) return ""
|
|
132
|
+
var schemes = ["smb://", "sftp://", "ftp://", "dav://", "davs://", "afp://", "nfs://", "file://"]
|
|
133
|
+
for (var i = 0; i < schemes.length; i++) {
|
|
134
|
+
if (record.path.indexOf(schemes[i]) === 0 && record.path.length > schemes[i].length) return ""
|
|
135
|
+
}
|
|
136
|
+
return "use a full path, a path that starts with ~/, or a network address"
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function storedEntries(records, home) {
|
|
140
|
+
var out = []
|
|
141
|
+
for (var i = 0; Array.isArray(records) && i < records.length; i++) {
|
|
142
|
+
var record = records[i]
|
|
143
|
+
var error = recordError(record)
|
|
144
|
+
var label = record && typeof record.label === "string" ? record.label : JSON.stringify(record)
|
|
145
|
+
var path = record && typeof record.path === "string" ? record.path : ""
|
|
146
|
+
var resolved = path === "~" ? home : path.indexOf("~/") === 0 ? home + path.substring(1) : path
|
|
147
|
+
out.push({ label: label || "Invalid favorite", path: resolved, storedPath: path,
|
|
148
|
+
error: error, original: record, favouriteIndex: i, group: "favourite", kind: "favourite",
|
|
149
|
+
glyph: path.indexOf("://") >= 0 ? "network" : "folder" })
|
|
150
|
+
}
|
|
151
|
+
return out
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// flea-qml: Home, then the folders the backend found by looking (src/places.js), each
|
|
155
|
+
// { path, label, glyph }. Upstream drew the folders user-dirs.dirs names, there or not; here a
|
|
156
|
+
// row is a folder that answered, and until the backend's first line the list is Home alone.
|
|
157
|
+
function homeEntries(home, probed, glyphFor) {
|
|
158
|
+
var entries = [{ label: "Home", path: home, group: "home", kind: "home", glyph: glyphFor("Home") }]
|
|
159
|
+
var rows = Array.isArray(probed) ? probed : []
|
|
160
|
+
for (var i = 0; i < rows.length; i++) {
|
|
161
|
+
var row = rows[i]
|
|
162
|
+
if (!row || typeof row.path !== "string" || row.path.length === 0 || row.path === home)
|
|
163
|
+
continue
|
|
164
|
+
entries.push({ label: String(row.label || row.path), path: row.path, group: "home", kind: "home", glyph: String(row.glyph || "folder") })
|
|
165
|
+
}
|
|
166
|
+
return entries
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// flea-qml: the drives the backend found by looking, drawn under DEVICES as plain folders: a row
|
|
170
|
+
// opens its path and offers a place's menu, and nothing here mounts or ejects. A drive lsblk
|
|
171
|
+
// already lists, by the mount point of one of `listed`'s rows, is that row and not a second one.
|
|
172
|
+
function volumeEntries(volumes, listed) {
|
|
173
|
+
var out = []
|
|
174
|
+
var rows = Array.isArray(volumes) ? volumes : []
|
|
175
|
+
var held = {}
|
|
176
|
+
for (var d = 0; Array.isArray(listed) && d < listed.length; d++) {
|
|
177
|
+
if (listed[d] && typeof listed[d].path === "string" && listed[d].path.length > 0)
|
|
178
|
+
held[listed[d].path] = true
|
|
179
|
+
}
|
|
180
|
+
for (var i = 0; i < rows.length; i++) {
|
|
181
|
+
var row = rows[i]
|
|
182
|
+
if (!row || typeof row.path !== "string" || row.path.length === 0 || held[row.path])
|
|
183
|
+
continue
|
|
184
|
+
out.push({ label: String(row.label || row.path), path: row.path, group: "home", kind: "home", volume: true,
|
|
185
|
+
glyph: String(row.glyph || "drive"), size: typeof row.size === "number" ? row.size : null })
|
|
186
|
+
}
|
|
187
|
+
return out
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// The rail and query use the same validation, URI decoding and mount-first open.
|
|
191
|
+
function openEntry(entry, ports) {
|
|
192
|
+
if (!entry) return
|
|
193
|
+
if (entry.kind === "trash") { ports.trash(); return }
|
|
194
|
+
var error = entry.kind === "favourite" ? recordError(entry.original) : ""
|
|
195
|
+
if (error) { ports.message("Could not open %1 · %2".replace(/%([12])/g, function (m, n) { return n === "1" ? entry.label : error }), true); return }
|
|
196
|
+
if (entry.path.indexOf("://") >= 0 && entry.path.indexOf("file://") !== 0) {
|
|
197
|
+
var host = ports.networkHost()
|
|
198
|
+
if (host) host.openChildShare(entry.path, entry.label, ports.pane)
|
|
199
|
+
} else {
|
|
200
|
+
ports.opened(entry.path.indexOf("file://") === 0 ? Mounts.decodePath(entry.path.substring(7)) : entry.path)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function railIdentity(entry) {
|
|
205
|
+
if (!entry) return ""
|
|
206
|
+
if (entry.kind === "favourite") return JSON.stringify([entry.kind, entry.original])
|
|
207
|
+
return JSON.stringify([entry.group, entry.kind, Mounts.railKey(entry) || entry.device || entry.uri || entry.path])
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Duplicate originals have no stored ID; a changed multiplicity cannot safely identify the selected occurrence.
|
|
211
|
+
function railCursorAfter(before, after, index) {
|
|
212
|
+
if (before.length === 0 && index === 0) return 0
|
|
213
|
+
if (index < 0 || index >= before.length) return -1
|
|
214
|
+
var key = railIdentity(before[index]), oldCount = 0, occurrence = 0, matches = []
|
|
215
|
+
for (var i = 0; i < before.length; i++) {
|
|
216
|
+
if (railIdentity(before[i]) !== key) continue
|
|
217
|
+
oldCount++
|
|
218
|
+
if (i < index) occurrence++
|
|
219
|
+
}
|
|
220
|
+
for (var j = 0; j < after.length; j++) {
|
|
221
|
+
if (railIdentity(after[j]) === key) matches.push(j)
|
|
222
|
+
}
|
|
223
|
+
return matches.length === oldCount ? matches[occurrence] : -1
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Under gvfs only the mounted row opened under view.shareKey lights, never a folder prefix or the disk.
|
|
227
|
+
function heldBy(entries, dir, view) {
|
|
228
|
+
var list = entries || []
|
|
229
|
+
var at = view || ({ kind: "dir" })
|
|
230
|
+
var path = String(dir || "")
|
|
231
|
+
var gvfs = Mounts.underGvfs(path)
|
|
232
|
+
var best = -1, depth = -1
|
|
233
|
+
for (var i = 0; i < list.length; i++) {
|
|
234
|
+
var e = list[i]
|
|
235
|
+
if (at.kind !== "dir") {
|
|
236
|
+
if (e.kind === at.kind && (at.kind !== "tag" || e.tag === at.tag))
|
|
237
|
+
return i
|
|
238
|
+
continue
|
|
239
|
+
}
|
|
240
|
+
if (e.kind === "recent" || e.kind === "trash" || e.kind === "tag" || e.error || e.mounted === false)
|
|
241
|
+
continue
|
|
242
|
+
if (gvfs) {
|
|
243
|
+
var key = String(at.shareKey || "")
|
|
244
|
+
if (key.length > 0 && !e.path && (Mounts.normalize(e.uri) === key || Mounts.normalize(e.mountUri) === key))
|
|
245
|
+
return i
|
|
246
|
+
continue
|
|
247
|
+
}
|
|
248
|
+
if (typeof e.path !== "string" || e.path.length === 0)
|
|
249
|
+
continue
|
|
250
|
+
if ((e.path === "/" ? path.charAt(0) === "/" : Mounts.inside(path, e.path)) && e.path.length > depth) {
|
|
251
|
+
best = i
|
|
252
|
+
depth = e.path.length
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return best
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// pathAlias is the pane's remembered gvfs share (or null); its key is the share's normalized address.
|
|
259
|
+
function litView(trashOpened, recentMode, searchMode, answeredQuery, pathAlias) {
|
|
260
|
+
if (trashOpened || recentMode === "trash") return { kind: "trash" }
|
|
261
|
+
if (String(recentMode || "").length > 0) return { kind: "recent" }
|
|
262
|
+
var query = String(answeredQuery || "")
|
|
263
|
+
if (String(searchMode || "").length > 0 && query.indexOf("tag:") === 0) return { kind: "tag", tag: query.substring(4) }
|
|
264
|
+
return { kind: "dir", shareKey: pathAlias ? String(pathAlias.key || "") : "" }
|
|
265
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "PreviewSettle.js" as PreviewSettle
|
|
4
|
+
.import "ExtThumbs.js" as ExtThumbs
|
|
5
|
+
|
|
6
|
+
// The cursor row's single thumbnail ask, shared by the early ask and load()'s askThumb, so the second sends nothing twice.
|
|
7
|
+
|
|
8
|
+
// Sample input: canRead, storageKnown, one selection, index 3, rowT, unasked, local storage answers {ask: [3], drop: [], cacheOnly: false}.
|
|
9
|
+
function workFor(o) {
|
|
10
|
+
if (!o.canRead || !o.storageKnown || o.selectionCount > 1) return null
|
|
11
|
+
if (o.index < 0 || o.rowT !== true || o.asked === true) return null
|
|
12
|
+
return { ask: [o.index], drop: [], cacheOnly: ExtThumbs.cacheOnly(o.storageClass, o.preview) }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// The idle half of the early ask is the settle's own rule: a walk step trails and asks nothing early.
|
|
16
|
+
function earlyWorkFor(o) {
|
|
17
|
+
if (PreviewSettle.plan(o.now, o.lastMoveAt, o.interval, o.key, o.lastMoveKey, o.armed, o.pending) !== "now")
|
|
18
|
+
return null
|
|
19
|
+
if (ExtThumbs.manualHold(o.storageClass, o.preview)) return null
|
|
20
|
+
return workFor(o)
|
|
21
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Filter.js" as Filter
|
|
4
|
+
.import "Marks.js" as Marks
|
|
5
|
+
.import "Search.js" as Search
|
|
6
|
+
.import "Thumbs.js" as Thumbs
|
|
7
|
+
.import "Scroll.js" as Scroll
|
|
8
|
+
|
|
9
|
+
// What the preview overlay does with a key, split out of Focus.js at its 300-line hard cap the
|
|
10
|
+
// same way ui/js/Trash.js was: Focus.js decides which surface owns a key, and this is the surface.
|
|
11
|
+
|
|
12
|
+
// Left/Right's seek step, Task 22's operator ruling; act is the only reader.
|
|
13
|
+
var SEEK_MS = 5000
|
|
14
|
+
// The zoom ladder Quick Look's PDF strip walks: the bottom rung fits the frame, one step a press, up to four times.
|
|
15
|
+
var PDF_ZOOM_MIN = 1
|
|
16
|
+
var PDF_ZOOM_MAX = 4
|
|
17
|
+
var PDF_ZOOM_STEP = 0.25
|
|
18
|
+
|
|
19
|
+
// A zoom after steps presses (negative steps down), kept on the ladder; the image pane walks the same rungs as the PDF.
|
|
20
|
+
function zoomStep(zoom, steps) {
|
|
21
|
+
return Math.max(PDF_ZOOM_MIN, Math.min(PDF_ZOOM_MAX, zoom + steps * PDF_ZOOM_STEP))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// All advertised page keys share one route in Quick Look and the preview column.
|
|
25
|
+
function pageDirection(action) {
|
|
26
|
+
if (action === "pageDown" || action === "previewPageForward") return 1
|
|
27
|
+
if (action === "pageUp" || action === "previewPageBack") return -1
|
|
28
|
+
return 0
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function pageViewport(view, direction) {
|
|
32
|
+
if (!view || !direction) return
|
|
33
|
+
if (typeof view.cancelFlick === "function") view.cancelFlick()
|
|
34
|
+
Scroll.stopTail(view)
|
|
35
|
+
var bounds = Scroll.limitsY(view)
|
|
36
|
+
view.contentY = Math.max(bounds.min, Math.min(bounds.max, view.contentY + direction * view.height))
|
|
37
|
+
if (typeof view.forceLayout === "function") view.forceLayout()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The column's PDF has no strip: pages scroll, and Space, Return or e opens Quick Look at the page in view.
|
|
41
|
+
function columnPdfAction(action, viewer) {
|
|
42
|
+
if (pageDirection(action)) { viewer.pageBy(pageDirection(action)); return }
|
|
43
|
+
if (action === "open" || action === "preview" || action === "expand") viewer.toggleExpand()
|
|
44
|
+
else if (action === "seekBack" || action === "parent") viewer.turnPage(-1)
|
|
45
|
+
else if (action === "seekForward" || action === "pageForward") viewer.turnPage(1)
|
|
46
|
+
else if (action === "cursorDown" || action === "cursorUp") viewer.scrollPage(action === "cursorDown" ? 1 : -1)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function pdfAction(action, viewer) {
|
|
50
|
+
if (pageDirection(action)) { viewer.pageBy(pageDirection(action)); return }
|
|
51
|
+
var controls = viewer.pdfControls
|
|
52
|
+
if (controls === undefined) return columnPdfAction(action, viewer)
|
|
53
|
+
if (action === "focusNext" || action === "focusPrevious") {
|
|
54
|
+
var step = action === "focusPrevious" ? -1 : 1
|
|
55
|
+
var next = viewer.pdfControlIndex
|
|
56
|
+
if (next < 0) next = step > 0 ? -1 : 0
|
|
57
|
+
for (var i = 0; i < controls.length; i++) {
|
|
58
|
+
next = (next + step + controls.length) % controls.length
|
|
59
|
+
if (controls[next].enabled && controls[next].visible) {
|
|
60
|
+
viewer.pdfControlIndex = next
|
|
61
|
+
break
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} else if (action === "open" || action === "preview") {
|
|
65
|
+
var control = controls[viewer.pdfControlIndex]
|
|
66
|
+
if (control && control.enabled && control.visible) control.activated()
|
|
67
|
+
} else if (action === "seekBack" || action === "parent") viewer.turnPage(-1)
|
|
68
|
+
else if (action === "seekForward" || action === "pageForward") viewer.turnPage(1)
|
|
69
|
+
else if (action === "zoomOut") viewer.zoomBy(-1)
|
|
70
|
+
else if (action === "zoomIn") viewer.zoomBy(1)
|
|
71
|
+
else if (action === "expand") viewer.toggleExpand()
|
|
72
|
+
else if (action === "cursorDown" || action === "cursorUp") viewer.scrollPage(action === "cursorDown" ? 1 : -1)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Space on a folder is a silent no-op; a file carries its cached thumbnail so the overlay shows it at once.
|
|
76
|
+
function open(root) {
|
|
77
|
+
if (!Filter.cursorShown(root)) return
|
|
78
|
+
var row = root.rowFor(root.cursorIndex)
|
|
79
|
+
if (row && !row.d)
|
|
80
|
+
root.quickLook().open(root.join(Search.baseOf(root), row.n), row.i, row.s, root.kindNames[row.k] || "",
|
|
81
|
+
root.thumbState && root.thumbState.file ? Thumbs.fileFor(root.thumbState, root.cursorIndex) : "")
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Preview open: j/k move the cursor and the preview follows; escape always closes, and so does a
|
|
85
|
+
// second space, on every kind including media (decided 2026-09-11: pressing Space a second time
|
|
86
|
+
// closes the preview, the way Finder does). That reverses Task 22, which had space toggle
|
|
87
|
+
// play/pause on a media preview; the strip's own play control still does that with the pointer.
|
|
88
|
+
// Any key reveals the media strip, even one that does nothing else, matching "move the mouse or
|
|
89
|
+
// press anything" from the same ruling.
|
|
90
|
+
function act(action, root) {
|
|
91
|
+
root.preview.revealStrip()
|
|
92
|
+
if (pageDirection(action)) { root.preview.pageBy(pageDirection(action)); return }
|
|
93
|
+
switch (action) {
|
|
94
|
+
// A Compare overlay names two files, so the cursor moving under it opens no other file in its place.
|
|
95
|
+
case "cursorDown":
|
|
96
|
+
case "cursorUp":
|
|
97
|
+
var direction = action === "cursorDown" ? 1 : -1
|
|
98
|
+
if (!root.preview.isCompare) { Filter.moveCursor(root, direction); Marks.follow(root); follow(root) }
|
|
99
|
+
return
|
|
100
|
+
case "preview": root.preview.close(); return
|
|
101
|
+
// Space closes every kind now, so playback has its own key; it self-guards, because p reaches
|
|
102
|
+
// this only in the media context and a still image has nothing to play.
|
|
103
|
+
case "playPause":
|
|
104
|
+
if (root.preview.isMedia) root.preview.togglePlay()
|
|
105
|
+
return
|
|
106
|
+
case "focusPreview":
|
|
107
|
+
case "escape": root.preview.close(); return
|
|
108
|
+
// Compare's y: the whole patch goes to the clipboard; the overlay guards on its own kind.
|
|
109
|
+
case "copyPatch": root.preview.copyPatch(); return
|
|
110
|
+
case "seekBack":
|
|
111
|
+
if (root.preview.isPdf) root.preview.turnPage(-1)
|
|
112
|
+
else root.preview.seek(-SEEK_MS)
|
|
113
|
+
return
|
|
114
|
+
case "seekForward":
|
|
115
|
+
if (root.preview.isPdf) root.preview.turnPage(1)
|
|
116
|
+
else root.preview.seek(SEEK_MS)
|
|
117
|
+
return
|
|
118
|
+
// h keeps its own "parent" name from keys.toml; turnPage self-guards, so a media preview
|
|
119
|
+
// ignores both of these rather than seeking on a key the strip never advertised.
|
|
120
|
+
case "parent": root.preview.turnPage(-1); return
|
|
121
|
+
case "pageForward": root.preview.turnPage(1); return
|
|
122
|
+
case "zoomOut": root.preview.zoomBy(-1); return
|
|
123
|
+
case "zoomIn": root.preview.zoomBy(1); return
|
|
124
|
+
case "zoomFit": root.preview.zoomFit(); return
|
|
125
|
+
case "expand": root.preview.toggleExpand(); return
|
|
126
|
+
// MediaMute rule 5: the flag is the preview's to flip, and it silences without pausing.
|
|
127
|
+
case "mute": root.preview.toggleMute(); return
|
|
128
|
+
// r flips only the open document Quick Look between rendered and source.
|
|
129
|
+
case "markdownView":
|
|
130
|
+
if (root.preview.isDocument) root.preview.toggleMarkdownView()
|
|
131
|
+
return
|
|
132
|
+
// Focus.js lets w through for a code or text Quick Look only; the choice is remembered in ui.json.
|
|
133
|
+
case "toggleWrap": root.preview.toggleWrap(); return
|
|
134
|
+
// The text bar toggles Close; Compare owns its actual Copy and Close focus walk.
|
|
135
|
+
case "focusNext":
|
|
136
|
+
case "focusPrevious":
|
|
137
|
+
if (root.preview.isCompare) {
|
|
138
|
+
var compare = root.preview.surfaceItem()
|
|
139
|
+
if (compare) compare.stepFocus(action === "focusPrevious")
|
|
140
|
+
} else if (root.preview.hasBar) root.preview.toggleMarkdownClose()
|
|
141
|
+
return
|
|
142
|
+
case "open":
|
|
143
|
+
if (root.preview.hasBar && root.preview.markdownCloseFocused) root.preview.close()
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// The row under the moved cursor, handed to Preview.follow so a held key settles before it reloads.
|
|
149
|
+
function follow(root) {
|
|
150
|
+
if (!Filter.cursorShown(root)) return
|
|
151
|
+
var row = root.rowFor(root.cursorIndex)
|
|
152
|
+
if (row && !row.d)
|
|
153
|
+
root.preview.follow(root.join(Search.baseOf(root), row.n), row.i, row.s, root.kindNames[row.k] || "",
|
|
154
|
+
root.thumbState && root.thumbState.file ? Thumbs.fileFor(root.thumbState, root.cursorIndex) : "")
|
|
155
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// Cursor preview loads stamp distinct moves: due(200, 0, 120) and due(100, 200, 120) load now; due(50, 0, 120) trails.
|
|
4
|
+
function due(now, last, interval) {
|
|
5
|
+
var elapsed = now - last
|
|
6
|
+
return elapsed >= interval || elapsed < 0
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// A settle armed for this row before its move reached the clock (ColumnsArea's folder to file step) is left to the clock.
|
|
10
|
+
// plan(50, 0, 120, "b", "b", true) keeps the pending timer; plan(1000, 0, 120, "c", "b", true, false) is "now".
|
|
11
|
+
function plan(now, last, interval, key, lastKey, armedForKey, pending) {
|
|
12
|
+
if (key === lastKey && armedForKey === true)
|
|
13
|
+
return "same"
|
|
14
|
+
if (pending === true)
|
|
15
|
+
return "later"
|
|
16
|
+
return due(now, last, interval) ? "now" : "later"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// A PDF opens at once only when the cursor is idle and no page render is in flight.
|
|
20
|
+
function pdfOpenNow(now, lastRequestAt, intervalMs, renderLoading) {
|
|
21
|
+
return renderLoading !== true && due(now, lastRequestAt, intervalMs)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// A lone selection never keys on the version Marks.follow bumps on every plain move.
|
|
25
|
+
function selectionKey(count, version) {
|
|
26
|
+
if (count <= 1)
|
|
27
|
+
return ""
|
|
28
|
+
return count + ":" + version
|
|
29
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Swap.js" as Swap
|
|
4
|
+
.import "Facts.js" as Facts
|
|
5
|
+
|
|
6
|
+
// The preview swap's decisions, see AGENTS.md "The preview swap"; ui/PreviewSwap.qml holds the picture and the timer.
|
|
7
|
+
|
|
8
|
+
// ui/PreviewPdf.qml opens a document only this long after its path settles (issue 117).
|
|
9
|
+
var DOCUMENT_SETTLE_MS = 120
|
|
10
|
+
|
|
11
|
+
// A capture draws on the next frame; one not drawn in this long means the window is not drawing at all.
|
|
12
|
+
var CAPTURE_MS = 100
|
|
13
|
+
|
|
14
|
+
// How long the new preview may build under the held picture from its own start; a PDF's document settle runs under it.
|
|
15
|
+
function capMs(isPdf) {
|
|
16
|
+
return Swap.CAP_MS
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// When a held preview lets go: -1 while the new one is not whole, else the ms a loading state on screen is still owed.
|
|
20
|
+
function releaseIn(ready, started, shownAt, now) {
|
|
21
|
+
if (ready !== true || started !== true)
|
|
22
|
+
return -1
|
|
23
|
+
return Swap.showLeft(shownAt, now)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Past the cap the loading state stands from shownAt or now; sample input: fallBack(true, 0, 1066) is { shownAt: 1066, left: 100, keeps: true }.
|
|
27
|
+
function fallBack(held, shownAt, now) {
|
|
28
|
+
var at = shownAt > 0 ? shownAt : now
|
|
29
|
+
var left = Swap.showLeft(at, now)
|
|
30
|
+
return { shownAt: at, left: left, keeps: held === true && left > 0 }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// What a move does to a swap: start a hold, join the one already starting for this key, or, when the
|
|
34
|
+
// host lets a burst end it, give up a picture that no longer names anything near the cursor.
|
|
35
|
+
var HOLD = "hold"
|
|
36
|
+
var JOIN = "join"
|
|
37
|
+
var BURST = "burst"
|
|
38
|
+
|
|
39
|
+
function onMove(state, key, burstEnds) {
|
|
40
|
+
if (!state.capturing && !state.holding)
|
|
41
|
+
return HOLD
|
|
42
|
+
if (state.key === key || burstEnds !== true)
|
|
43
|
+
return JOIN
|
|
44
|
+
return BURST
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// A frame drawn with the swap in each state: "held" shows the old picture, "mid" is the defect a hold
|
|
48
|
+
// exists to prevent, "loading" is the fallback's own state and allowed, held in the picture or live.
|
|
49
|
+
function frameKind(held, ready, fellBack, showing) {
|
|
50
|
+
if (showing === true)
|
|
51
|
+
return "loading"
|
|
52
|
+
if (held === true)
|
|
53
|
+
return "held"
|
|
54
|
+
if (ready === true)
|
|
55
|
+
return ""
|
|
56
|
+
return fellBack === true ? "loading" : "mid"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Sample input: { state: "image", thumb: true, frame: 1, noThumbComing: false, pdfDrawn: false,
|
|
60
|
+
// pdfFailed: false, linesLoading: false, meta: true } for the preview column's cursor row, where frame is the
|
|
61
|
+
// thumbnail Image's status (Image.Null 0, Ready 1, Loading 2, Error 3).
|
|
62
|
+
function columnReady(p) {
|
|
63
|
+
switch (p.state) {
|
|
64
|
+
case Facts.LOADING:
|
|
65
|
+
return false
|
|
66
|
+
case Facts.IMAGE:
|
|
67
|
+
// The cache file, or with none coming the original the frame decodes itself, drawn or refused.
|
|
68
|
+
return (p.thumb === true || p.noThumbComing === true) && (p.frame === 1 || p.frame === 3)
|
|
69
|
+
case Facts.VIDEO:
|
|
70
|
+
// The poster drawn or refused, or none coming at all and the kind's mark standing in.
|
|
71
|
+
return p.thumb === true ? p.frame === 1 || p.frame === 3 : p.noThumbComing === true
|
|
72
|
+
case Facts.PDF:
|
|
73
|
+
return p.pdfDrawn === true || p.pdfFailed === true
|
|
74
|
+
case Facts.TEXT:
|
|
75
|
+
case Facts.CODE:
|
|
76
|
+
return p.linesLoading !== true
|
|
77
|
+
case Facts.ARCHIVE:
|
|
78
|
+
return p.meta === true
|
|
79
|
+
}
|
|
80
|
+
return true
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Quick Look is ready when nothing loads, a PDF shows a page or is refused, or the interim or a Markdown head shows whole.
|
|
84
|
+
function lookReady(status, isPdf, pdfShown, pdfFailed, interimShown, headShown) {
|
|
85
|
+
if (interimShown === true || headShown === true)
|
|
86
|
+
return true
|
|
87
|
+
if (status === "loading")
|
|
88
|
+
return false
|
|
89
|
+
return isPdf !== true || pdfShown === true || pdfFailed === true
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Sample input: interimRect(754, 471, 6000, 4000, 1) is 706.5x471 at 24,0; upright aspect-fit, never enlarged, unknown is null.
|
|
93
|
+
function interimRect(surfaceW, surfaceH, imageW, imageH, orient) {
|
|
94
|
+
if (!(imageW > 0) || !(imageH > 0))
|
|
95
|
+
return null
|
|
96
|
+
var ow = orient >= 5 ? imageH : imageW
|
|
97
|
+
var oh = orient >= 5 ? imageW : imageH
|
|
98
|
+
var s = Math.min(1, surfaceW / ow, surfaceH / oh)
|
|
99
|
+
var w = ow * s, h = oh * s
|
|
100
|
+
return { x: Math.round((surfaceW - w) / 2), y: Math.round((surfaceH - h) / 2), w: w, h: h }
|
|
101
|
+
}
|