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
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import Quickshell.Io
|
|
3
|
+
import "." as Flea
|
|
4
|
+
import "js/CodeRuns.js" as CodeRuns
|
|
5
|
+
import "js/Markdown.js" as Markdown
|
|
6
|
+
import "js/MarkdownPrepared.js" as Prepared
|
|
7
|
+
|
|
8
|
+
// Rendered and Source previews share document insets, and only images beside the document can load.
|
|
9
|
+
Item {
|
|
10
|
+
id: root
|
|
11
|
+
|
|
12
|
+
property bool active: false
|
|
13
|
+
property string path: ""
|
|
14
|
+
property real size: 0
|
|
15
|
+
readonly property alias viewport: body
|
|
16
|
+
property bool externalScrollBars: false
|
|
17
|
+
// "rendered" or "source"; anything else reads as rendered. Only the Quick Look's r asks for source.
|
|
18
|
+
property string view: Markdown.RENDERED
|
|
19
|
+
|
|
20
|
+
// FileView reads whole files, so refuse above maxBytes, with remote storage keeping its smaller 256 KiB gate.
|
|
21
|
+
property int maxBytes: 1048576
|
|
22
|
+
// Retained for its callers; over-limit rows are refused, never truncated, so it reads nothing.
|
|
23
|
+
property bool truncate: false
|
|
24
|
+
readonly property bool tooLarge: root.size > root.maxBytes
|
|
25
|
+
property bool readFailed: false
|
|
26
|
+
// Quick Look only: the one file whose first read may block the key (a page-cache read beats a lost frame), named by the open.
|
|
27
|
+
property string blockPath: ""
|
|
28
|
+
// Reads that blocked the key for the file blockPath named, so a suite tells them from an async read.
|
|
29
|
+
property int blockedReads: 0
|
|
30
|
+
// Quick Look only: a small document's blocks are taken from, and kept in, the one parsed entry a resting cursor prepares.
|
|
31
|
+
property bool shareParse: false
|
|
32
|
+
// Parses a request took from the shared entry instead of running, so a suite can tell a reuse from a parse.
|
|
33
|
+
property int reusedParses: 0
|
|
34
|
+
|
|
35
|
+
// Set by each load, never a binding on file.text(): the blocking first read loaded inside such a binding and re-entered it.
|
|
36
|
+
property string loadedText: ""
|
|
37
|
+
readonly property string rawText: root.loadedText
|
|
38
|
+
function hexOf(c) {
|
|
39
|
+
return Prepared.hexOf(c)
|
|
40
|
+
}
|
|
41
|
+
// The host supplies the code surface colour for its page.
|
|
42
|
+
property color codeSurface: Theme.color.surface
|
|
43
|
+
readonly property string borderHex: hexOf(Theme.color.mutedFrame)
|
|
44
|
+
readonly property string chromeHex: hexOf(root.codeSurface)
|
|
45
|
+
// The render suite reads the ink it asserts beside the border, same assembly, no coercion.
|
|
46
|
+
readonly property string inkHex: hexOf(Theme.color.foreground)
|
|
47
|
+
readonly property string accentHex: hexOf(Theme.color.accent)
|
|
48
|
+
readonly property string mutedHex: hexOf(Theme.color.muted)
|
|
49
|
+
readonly property string surfaceHex: hexOf(Theme.color.surface)
|
|
50
|
+
readonly property int insetX: Theme.spacing.rowPaddingX + Theme.spacing.rowPaddingY - Theme.spacing.hairline
|
|
51
|
+
readonly property int insetY: Theme.spacing.gap + Theme.spacing.rowPaddingY
|
|
52
|
+
// RenderedPreviews resolves its pixels at body 14, and each one follows the body from there: no spacing token equals them at any size.
|
|
53
|
+
readonly property int boardBody: 14
|
|
54
|
+
readonly property int boardBlockGap: 6
|
|
55
|
+
readonly property int boardFencePadX: 12
|
|
56
|
+
readonly property int boardFencePadY: 8
|
|
57
|
+
// Headings are 20 and 15 px at body 14 in both surfaces, over the body the surface sets; deeper levels are body bold.
|
|
58
|
+
readonly property var boardHeadings: [20, 15]
|
|
59
|
+
function boardPx(px) {
|
|
60
|
+
return Math.round(px * Theme.font.body / root.boardBody)
|
|
61
|
+
}
|
|
62
|
+
readonly property int blockGap: root.boardPx(root.boardBlockGap)
|
|
63
|
+
readonly property int fencePadX: root.boardPx(root.boardFencePadX)
|
|
64
|
+
readonly property int fencePadY: root.boardPx(root.boardFencePadY)
|
|
65
|
+
// The preview column sets the document one token under Quick Look's body (RenderedPreviews 13 against 14).
|
|
66
|
+
property bool compact: false
|
|
67
|
+
readonly property int bodyPx: root.compact ? Theme.font.bodySmall : Theme.font.body
|
|
68
|
+
// Code colours use this backend; Quick Look and the column name their requests separately.
|
|
69
|
+
property var backend: null
|
|
70
|
+
// The backend ask slot of this pane: the column is compact, and Quick Look keeps its own.
|
|
71
|
+
property string slot: root.compact ? "column" : "look"
|
|
72
|
+
// w wraps Source lines the way the code view wraps them.
|
|
73
|
+
property bool wrap: false
|
|
74
|
+
readonly property var inks: CodeRuns.inks(Theme.palette, Theme.fallbackColor, String(Theme.color.foreground))
|
|
75
|
+
// Pending fence replies and a sequence for unique slots within this pane.
|
|
76
|
+
property int fenceWaits: 0
|
|
77
|
+
property int fenceSeq: 0
|
|
78
|
+
property var fenceReplies: ({})
|
|
79
|
+
function fenceSlot(fence) {
|
|
80
|
+
root.fenceSeq += 1
|
|
81
|
+
var slot = root.slot + ":fence:" + root.fenceSeq
|
|
82
|
+
root.fenceReplies[slot] = fence
|
|
83
|
+
return slot
|
|
84
|
+
}
|
|
85
|
+
function fenceWaiting(delta) {
|
|
86
|
+
root.fenceWaits = Math.max(0, root.fenceWaits + delta)
|
|
87
|
+
}
|
|
88
|
+
Connections {
|
|
89
|
+
target: root.backend
|
|
90
|
+
function onCodeResult(message) {
|
|
91
|
+
for (var slot in root.fenceReplies) root.fenceReplies[slot].answered(message)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// The faint rule wash the Quick Look bar's bottom hairline draws, shared by the table's header and row rules.
|
|
95
|
+
readonly property real ruleOpacity: 0.12
|
|
96
|
+
function headingPx(level) {
|
|
97
|
+
return level >= 1 && level <= root.boardHeadings.length ? root.boardPx(root.boardHeadings[level - 1]) : root.bodyPx
|
|
98
|
+
}
|
|
99
|
+
// A document past the nesting limit parses to one sentinel block, and the pane then shows its source behind a notice.
|
|
100
|
+
readonly property bool tooDeep: root.blockList.length === 1 && root.blockList[0].type === "deep"
|
|
101
|
+
readonly property string shownView: root.tooDeep ? Markdown.SOURCE : root.view
|
|
102
|
+
readonly property Item noticeItem: sourceList.noticeItem
|
|
103
|
+
readonly property Item sourceItem: sourceList.list
|
|
104
|
+
// Only the active file in Rendered view may request figures.
|
|
105
|
+
readonly property bool figuresArmed: root.active && root.shownView !== Markdown.SOURCE
|
|
106
|
+
// The theme the web page's diagrams are drawn under (src/figure.js): an unplaced figure reads the
|
|
107
|
+
// body font's advance tables, so each label is sized from the font that draws it.
|
|
108
|
+
Loader {
|
|
109
|
+
id: themeProbe
|
|
110
|
+
active: root.useWeb
|
|
111
|
+
sourceComponent: Flea.MarkdownFigure {
|
|
112
|
+
visible: false
|
|
113
|
+
askArmed: false
|
|
114
|
+
kind: "mermaid"
|
|
115
|
+
display: true
|
|
116
|
+
bgHex: root.hexOf(Theme.color.background)
|
|
117
|
+
fgHex: root.inkHex
|
|
118
|
+
accentHex: root.accentHex
|
|
119
|
+
mutedHex: root.mutedHex
|
|
120
|
+
surfaceHex: root.surfaceHex
|
|
121
|
+
fontFamily: Theme.font.family
|
|
122
|
+
bodyPx: root.bodyPx
|
|
123
|
+
}
|
|
124
|
+
// A page asked before the probe existed carried no advance tables; it is asked again with them.
|
|
125
|
+
onLoaded: root.askWeb()
|
|
126
|
+
}
|
|
127
|
+
// Parse sequence numbers reject replies for an older file.
|
|
128
|
+
property var blockList: []
|
|
129
|
+
property int parseSeq: 0
|
|
130
|
+
property int appliedSeq: 0
|
|
131
|
+
property bool parsing: false
|
|
132
|
+
// Parses that really ran (worker message or synchronous), so a suite counts one per event.
|
|
133
|
+
property int parseRuns: 0
|
|
134
|
+
// Loads of the shown file that landed, so a suite can tell a save the watcher read from one it never saw.
|
|
135
|
+
property int loadRuns: 0
|
|
136
|
+
// A worker reply landed for this file; the lazy suite asserts the parse left the UI thread.
|
|
137
|
+
property bool parsedOffThread: false
|
|
138
|
+
property string parseError: ""
|
|
139
|
+
// Worker liveness for the quicklook-firstframe watchdog line: last seq of each message kind (-1 none), beats, fallback fires.
|
|
140
|
+
property int ackSeq: -1
|
|
141
|
+
property int beatSeq: -1
|
|
142
|
+
property int beatCount: 0
|
|
143
|
+
property int headSeq: -1
|
|
144
|
+
property int replySeq: -1
|
|
145
|
+
property int fallbackFires: 0
|
|
146
|
+
readonly property bool fallbackRunning: parseFallback.running
|
|
147
|
+
// Give the worker ten seconds to answer before the synchronous recovery parse.
|
|
148
|
+
readonly property int parseFallbackMs: 10000
|
|
149
|
+
// Keep this many pixels of blocks warm beyond the visible ListView window.
|
|
150
|
+
readonly property int blockCachePixels: 600
|
|
151
|
+
readonly property bool blocksReady: root.appliedSeq === root.parseSeq && !root.parsing
|
|
152
|
+
readonly property bool sourceRefused: root.shownView === Markdown.SOURCE && sourceList.refused
|
|
153
|
+
readonly property bool loading: root.active && !root.sourceRefused && !root.readFailed && !root.tooLarge && root.parseError === ""
|
|
154
|
+
&& (!file.loaded || !root.blocksReady || root.coloursWaiting)
|
|
155
|
+
readonly property string status: {
|
|
156
|
+
if (root.sourceRefused) return sourceList.status
|
|
157
|
+
if (root.tooLarge) return "This file is too large to preview."
|
|
158
|
+
if (root.readFailed || root.parseError !== "") return "This file could not be read."
|
|
159
|
+
return root.blocksReady && file.loaded && !root.coloursWaiting ? "ready" : "loading"
|
|
160
|
+
}
|
|
161
|
+
readonly property string lineLabel: Markdown.countLine(Markdown.lineCount(root.rawText))
|
|
162
|
+
// The bar's line count reads only once there is a file behind it, never "0 lines" first.
|
|
163
|
+
readonly property bool contentReady: file.loaded && root.blocksReady
|
|
164
|
+
&& !root.sourceRefused && !root.tooLarge && !root.readFailed && root.parseError === ""
|
|
165
|
+
// Visible Source rows and fences hold the first screen until their colours arrive.
|
|
166
|
+
readonly property bool sourceWaiting: root.shownView === Markdown.SOURCE && !sourceList.firstScreen
|
|
167
|
+
readonly property bool coloursWaiting: root.fenceWaits > 0 || root.sourceWaiting
|
|
168
|
+
// A first screen is drawn: blocks are in the list, the head of a parse still running or a whole list, and the swap counts either as shown.
|
|
169
|
+
readonly property bool firstScreen: root.sourceRefused || (file.loaded && root.parseError === "" && root.blockList.length > 0 && !root.coloursWaiting)
|
|
170
|
+
// True when the reader has settled with nothing to put in the frame, the way PreviewLines.blank reads.
|
|
171
|
+
readonly property bool blank: root.tooLarge
|
|
172
|
+
|| (root.active && !root.readFailed && file.loaded && root.rawText.length === 0)
|
|
173
|
+
|
|
174
|
+
// What the Source text holds, so a suite sees that Rendered lays none out.
|
|
175
|
+
readonly property int sourceChars: sourceList.laidChars
|
|
176
|
+
readonly property Item bodyItem: body
|
|
177
|
+
// The route a sideways stroke takes to a table wider than the document, which each such table joins.
|
|
178
|
+
readonly property Item tableWheel: tableRoute
|
|
179
|
+
// The first live table drawn wider than the document, which Quick Look's IPC reads for the sideways capture.
|
|
180
|
+
function tableScroller() { return tableRoute.scrollers.filter(function (s) { return s })[0] || null }
|
|
181
|
+
// The offset the wheel moved, in whichever view shows, for Quick Look's IPC.
|
|
182
|
+
readonly property real scrollY: root.shownView === Markdown.SOURCE ? (root.sourceItem !== null ? root.sourceItem.contentY : 0) : body.contentY
|
|
183
|
+
// The render suite reads live delegate geometry; only visible blocks plus the cache exist, so offscreen blocks answer null.
|
|
184
|
+
function blockItem(i) {
|
|
185
|
+
var kids = body.contentItem.children
|
|
186
|
+
for (var k = 0; k < kids.length; k++) {
|
|
187
|
+
if (kids[k].blockIndex === i)
|
|
188
|
+
return kids[k]
|
|
189
|
+
}
|
|
190
|
+
return null
|
|
191
|
+
}
|
|
192
|
+
// Instantiated delegates only: the lazy suite asserts this stays bounded.
|
|
193
|
+
function delegateCount() { return body.contentItem.children.length }
|
|
194
|
+
// An absent figure delegate answers null to the render probe.
|
|
195
|
+
function figureInfo(i) {
|
|
196
|
+
var d = blockItem(i)
|
|
197
|
+
if (!d)
|
|
198
|
+
return null
|
|
199
|
+
var box = null
|
|
200
|
+
var kids = d.children
|
|
201
|
+
for (var k = 0; k < kids.length; k++)
|
|
202
|
+
if (kids[k].objectName === "figureBox" && kids[k].visible)
|
|
203
|
+
box = kids[k]
|
|
204
|
+
if (!box)
|
|
205
|
+
return null
|
|
206
|
+
var fig = null
|
|
207
|
+
var inner = box.children
|
|
208
|
+
for (var m = 0; m < inner.length; m++)
|
|
209
|
+
if (inner[m].objectName === "figureItem")
|
|
210
|
+
fig = inner[m]
|
|
211
|
+
if (!fig)
|
|
212
|
+
return null
|
|
213
|
+
return { ready: fig.ready, failed: fig.failed, working: fig.working, boxW: box.width,
|
|
214
|
+
imgW: fig.fitWidth, imgH: fig.fitHeight }
|
|
215
|
+
}
|
|
216
|
+
readonly property real flickContentHeight: sourceList.visible
|
|
217
|
+
? (root.sourceItem !== null ? root.sourceItem.contentHeight : 0) : body.contentHeight
|
|
218
|
+
|
|
219
|
+
visible: root.active
|
|
220
|
+
|
|
221
|
+
FileView {
|
|
222
|
+
id: file
|
|
223
|
+
printErrors: false
|
|
224
|
+
// The one watcher is on the shown file; a path change re-points it, so an old file never reloads here.
|
|
225
|
+
watchChanges: true
|
|
226
|
+
// The first event opens the window and the rest land inside it: a restart would starve a file written without pause.
|
|
227
|
+
onFileChanged: if (!reloadCoalesce.running) reloadCoalesce.start()
|
|
228
|
+
onLoaded: {
|
|
229
|
+
root.loadedText = file.text()
|
|
230
|
+
// Only the first read of a path blocks; a reload after a save never does, whatever the file grew to.
|
|
231
|
+
file.blockLoading = false
|
|
232
|
+
root.loadRuns++
|
|
233
|
+
// A save that unlinks and recreates the file can fail one reload; the next good load clears it.
|
|
234
|
+
root.readFailed = false
|
|
235
|
+
root.askParse()
|
|
236
|
+
root.askWeb()
|
|
237
|
+
}
|
|
238
|
+
onLoadFailed: {
|
|
239
|
+
root.loadedText = ""
|
|
240
|
+
file.blockLoading = false
|
|
241
|
+
root.keepScroll = false
|
|
242
|
+
root.readFailed = true
|
|
243
|
+
}
|
|
244
|
+
onPathChanged: root.readFailed = false
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// One step moves the path and the blocking flag together, since a read inside the path change takes the flag as it stands then.
|
|
248
|
+
function pointFile() {
|
|
249
|
+
var want = (root.active && !root.tooLarge) ? root.path : ""
|
|
250
|
+
// A pane built before the path moved sees the last file's path, which an open that named its file must not read first.
|
|
251
|
+
if ((want === file.path) || (want !== "" && root.blockPath !== "" && want !== root.blockPath))
|
|
252
|
+
return
|
|
253
|
+
var blocking = want !== "" && want === root.blockPath
|
|
254
|
+
file.blockLoading = blocking
|
|
255
|
+
if (blocking) {
|
|
256
|
+
root.blockedReads++
|
|
257
|
+
// A view that holds another file takes a new path asynchronously, so the blocking read starts from none.
|
|
258
|
+
file.path = ""
|
|
259
|
+
}
|
|
260
|
+
file.path = want
|
|
261
|
+
// blockLoading gates only text(), so the blocking first read is taken here, in the first frame, not inside a binding.
|
|
262
|
+
if (blocking) root.loadedText = file.text()
|
|
263
|
+
else if (want === "") root.loadedText = ""
|
|
264
|
+
}
|
|
265
|
+
Component.onCompleted: root.pointFile()
|
|
266
|
+
// The list builds its cache asynchronously, so a teardown mid-build drops the model first and no incubation outlives its context.
|
|
267
|
+
Component.onDestruction: body.model = null
|
|
268
|
+
onTooLargeChanged: root.pointFile()
|
|
269
|
+
|
|
270
|
+
// One reload per save: an editor's truncate, write and rename raise events within a few ms, and 50 ms is under what a reader notices.
|
|
271
|
+
readonly property int reloadCoalesceMs: 50
|
|
272
|
+
Timer {
|
|
273
|
+
id: reloadCoalesce
|
|
274
|
+
interval: root.reloadCoalesceMs
|
|
275
|
+
repeat: false
|
|
276
|
+
onTriggered: root.reloadFromDisk()
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// A reparse of the shown file (disk edit, theme change) puts the reader back where they were, by block or else by pixels.
|
|
280
|
+
property real savedY: 0
|
|
281
|
+
// The place by block: the block at the view's top and the pixels past its top edge, -1 when none is built there.
|
|
282
|
+
property int savedIndex: -1
|
|
283
|
+
property real savedOffset: 0
|
|
284
|
+
property bool keepScroll: false
|
|
285
|
+
// Where a restore left the view when the content was too short for the saved place, NaN when none waits.
|
|
286
|
+
property real heldY: NaN
|
|
287
|
+
// Two positions this close are the same place: the list stores contentY as a float.
|
|
288
|
+
readonly property real samePlacePx: 1
|
|
289
|
+
// True while the model is replaced: the list moves itself to its top then, and restoreScroll puts the view back.
|
|
290
|
+
property bool settingBlocks: false
|
|
291
|
+
// A place waiting for taller content ends the moment the reader moves the view away from it.
|
|
292
|
+
function releaseHeldPlace() {
|
|
293
|
+
if (root.settingBlocks || isNaN(root.heldY) || Math.abs(body.contentY - root.heldY) < root.samePlacePx)
|
|
294
|
+
return
|
|
295
|
+
root.keepScroll = false
|
|
296
|
+
root.heldY = NaN
|
|
297
|
+
}
|
|
298
|
+
// A place waiting for taller content is kept; otherwise the reader's present place is saved (each landing asks first).
|
|
299
|
+
function rememberScroll() {
|
|
300
|
+
if (root.keepScroll)
|
|
301
|
+
return
|
|
302
|
+
root.savedY = body.contentY
|
|
303
|
+
root.keepScroll = true
|
|
304
|
+
// A path change or a failed load ends a hold without clearing its place, so a new place starts with none.
|
|
305
|
+
root.heldY = NaN
|
|
306
|
+
var item = root.topBlockItem()
|
|
307
|
+
root.savedIndex = item === null ? -1 : item.blockIndex
|
|
308
|
+
root.savedOffset = item === null ? 0 : body.contentY - item.y
|
|
309
|
+
}
|
|
310
|
+
// The first built block that ends below the view's top, so a view in a gap or above the first block still has one.
|
|
311
|
+
function topBlockItem() {
|
|
312
|
+
var kids = body.contentItem.children
|
|
313
|
+
var found = null
|
|
314
|
+
for (var k = 0; k < kids.length; k++) {
|
|
315
|
+
var kid = kids[k]
|
|
316
|
+
if (kid.blockIndex === undefined || kid.y + kid.height <= body.contentY)
|
|
317
|
+
continue
|
|
318
|
+
if (found === null || kid.blockIndex < found.blockIndex)
|
|
319
|
+
found = kid
|
|
320
|
+
}
|
|
321
|
+
return found
|
|
322
|
+
}
|
|
323
|
+
// A place by block is restored by block: the list estimates an unbuilt document, and only a built end may clamp it.
|
|
324
|
+
function restoreScroll() {
|
|
325
|
+
if (!root.keepScroll)
|
|
326
|
+
return
|
|
327
|
+
var byBlock = root.savedIndex >= 0 && root.savedIndex < root.blockList.length
|
|
328
|
+
if (byBlock)
|
|
329
|
+
body.positionViewAtIndex(root.savedIndex, ListView.Beginning)
|
|
330
|
+
var item = byBlock ? root.blockItem(root.savedIndex) : null
|
|
331
|
+
var top = body.originY - body.topMargin
|
|
332
|
+
var end = Math.max(top, body.originY + body.contentHeight - body.height + body.bottomMargin)
|
|
333
|
+
var place = item === null ? root.savedY : item.y + root.savedOffset
|
|
334
|
+
var endExact = item === null || root.blockItem(root.blockList.length - 1) !== null
|
|
335
|
+
var at = Math.max(top, endExact ? Math.min(place, end) : place)
|
|
336
|
+
var settled = !endExact || place <= end
|
|
337
|
+
// The hold is recorded before the move, so the move itself reads as the same place.
|
|
338
|
+
root.heldY = settled ? NaN : at
|
|
339
|
+
body.contentY = at
|
|
340
|
+
if (settled)
|
|
341
|
+
root.keepScroll = false
|
|
342
|
+
}
|
|
343
|
+
// Where the list's end last was, origin and height together: a layout that re-estimates the unbuilt blocks moves the two apart.
|
|
344
|
+
property real seenEnd: 0
|
|
345
|
+
// Whether the last block had a delegate at the last end change or move, so the end then was drawn, not estimated.
|
|
346
|
+
property bool endBuilt: false
|
|
347
|
+
// The snap below sets contentY itself, and the end can settle again under it.
|
|
348
|
+
property bool snappingToEnd: false
|
|
349
|
+
function noteEnd() {
|
|
350
|
+
root.endBuilt = root.blockItem(root.blockList.length - 1) !== null
|
|
351
|
+
}
|
|
352
|
+
// A picture decodes after its block was built at no height; only a reader at the drawn end follows it, never one in unbuilt blocks.
|
|
353
|
+
function holdEnd() {
|
|
354
|
+
var was = root.seenEnd
|
|
355
|
+
var builtBefore = root.endBuilt
|
|
356
|
+
root.seenEnd = body.originY + body.contentHeight
|
|
357
|
+
root.noteEnd()
|
|
358
|
+
if (root.snappingToEnd || !builtBefore || !(root.seenEnd > was))
|
|
359
|
+
return
|
|
360
|
+
var wasEnd = was - body.height + body.bottomMargin
|
|
361
|
+
var tallerThanView = wasEnd > body.originY - body.topMargin
|
|
362
|
+
if (!tallerThanView || body.contentY < wasEnd - root.samePlacePx)
|
|
363
|
+
return
|
|
364
|
+
root.snappingToEnd = true
|
|
365
|
+
body.contentY = root.seenEnd - body.height + body.bottomMargin
|
|
366
|
+
root.snappingToEnd = false
|
|
367
|
+
}
|
|
368
|
+
// How far the last block's bottom and the inset under it lie past the viewport, 0 when whole, -1 when the last block is not built.
|
|
369
|
+
function endGap() {
|
|
370
|
+
var last = root.blockItem(root.blockList.length - 1)
|
|
371
|
+
return last === null ? -1 : Math.max(0, Math.round(last.mapToItem(body, 0, last.height).y + body.bottomMargin - body.height))
|
|
372
|
+
}
|
|
373
|
+
function reloadFromDisk() {
|
|
374
|
+
if (!root.active || root.tooLarge)
|
|
375
|
+
return
|
|
376
|
+
file.reload()
|
|
377
|
+
}
|
|
378
|
+
// Link ink and code chrome are parsed into the runs, so a theme change reparses the loaded file.
|
|
379
|
+
function reparseForTheme() {
|
|
380
|
+
if (!root.active || !file.loaded)
|
|
381
|
+
return
|
|
382
|
+
root.askWeb()
|
|
383
|
+
root.askParse()
|
|
384
|
+
}
|
|
385
|
+
// A theme switch moves ink and chrome in one turn, so both ask through one callLater and the parse sees both.
|
|
386
|
+
onInkHexChanged: Qt.callLater(root.reparseForTheme)
|
|
387
|
+
onChromeHexChanged: Qt.callLater(root.reparseForTheme)
|
|
388
|
+
|
|
389
|
+
// Large files require synchronous worker activation before their parse request.
|
|
390
|
+
readonly property int workerThreshold: 65536
|
|
391
|
+
Loader {
|
|
392
|
+
id: parserLoader
|
|
393
|
+
active: false
|
|
394
|
+
sourceComponent: parserComponent
|
|
395
|
+
}
|
|
396
|
+
Component {
|
|
397
|
+
id: parserComponent
|
|
398
|
+
CountedWorker {
|
|
399
|
+
source: "MarkdownWorker.js"
|
|
400
|
+
onMessage: function (messageObject) { root.landed(messageObject) }
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function landed(messageObject) {
|
|
404
|
+
if (messageObject.seq !== root.parseSeq)
|
|
405
|
+
return
|
|
406
|
+
// A live worker proves it with messages, so the fallback below fires only after 10 s of none, never for slowness.
|
|
407
|
+
if (messageObject.yielded === true) {
|
|
408
|
+
// One slice a message: only the live request asks for the next, so a newer request is read first.
|
|
409
|
+
parseFallback.restart()
|
|
410
|
+
parserLoader.item.sendMessage({ seq: messageObject.seq, cont: true })
|
|
411
|
+
return
|
|
412
|
+
}
|
|
413
|
+
if (messageObject.ack === true || messageObject.progress === true) {
|
|
414
|
+
if (messageObject.ack === true) root.ackSeq = messageObject.seq
|
|
415
|
+
else { root.beatSeq = messageObject.seq; root.beatCount++ }
|
|
416
|
+
parseFallback.restart()
|
|
417
|
+
return
|
|
418
|
+
}
|
|
419
|
+
// The head of a first parse draws the first screen; the parse goes on, and the whole list replaces it when it lands.
|
|
420
|
+
if (messageObject.partial === true) {
|
|
421
|
+
root.headSeq = messageObject.seq
|
|
422
|
+
parseFallback.restart()
|
|
423
|
+
root.settingBlocks = true
|
|
424
|
+
root.blockList = messageObject.blocks
|
|
425
|
+
root.settingBlocks = false
|
|
426
|
+
return
|
|
427
|
+
}
|
|
428
|
+
root.parsing = false
|
|
429
|
+
root.appliedSeq = messageObject.seq
|
|
430
|
+
root.replySeq = messageObject.seq
|
|
431
|
+
if (messageObject.error !== "") {
|
|
432
|
+
root.parseError = messageObject.error
|
|
433
|
+
root.askedAny = false
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
root.parseError = ""
|
|
437
|
+
// The reader's present place is taken before the model reset moves the list to its top; a place that waits is kept.
|
|
438
|
+
root.rememberScroll()
|
|
439
|
+
root.settingBlocks = true
|
|
440
|
+
root.blockList = messageObject.blocks
|
|
441
|
+
root.settingBlocks = false
|
|
442
|
+
// A reply that changed nothing the list sees raises no model change, so the saved place is released here.
|
|
443
|
+
root.restoreScroll()
|
|
444
|
+
root.parsedOffThread = true
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// The worker parses only above workerThreshold; this timer recovers a worker request whose reply never settles.
|
|
448
|
+
Timer {
|
|
449
|
+
id: parseFallback
|
|
450
|
+
interval: root.parseFallbackMs
|
|
451
|
+
repeat: false
|
|
452
|
+
onTriggered: {
|
|
453
|
+
if (!root.parsing)
|
|
454
|
+
return
|
|
455
|
+
root.fallbackFires++
|
|
456
|
+
// A late worker reply for the request being recovered is voided by the new number.
|
|
457
|
+
root.parseSeq++
|
|
458
|
+
root.releaseWorker()
|
|
459
|
+
root.parseNow(root.askedText, root.askedDir, root.askedChrome, root.askedInk)
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// The last parsed request's text, folder, chrome and ink; a reload's second trigger (onRawTextChanged after onLoaded) is skipped.
|
|
464
|
+
property string askedText: ""
|
|
465
|
+
property string askedDir: ""
|
|
466
|
+
property string askedChrome: ""
|
|
467
|
+
property string askedInk: ""
|
|
468
|
+
property bool askedAny: false
|
|
469
|
+
function releaseWorker() {
|
|
470
|
+
// The worker holds a live request's parse between slices; a cancel frees it.
|
|
471
|
+
if (parserLoader.item !== null)
|
|
472
|
+
parserLoader.item.sendMessage({ seq: root.parseSeq, cancel: true })
|
|
473
|
+
}
|
|
474
|
+
// Forget the last request and void any worker reply in flight, so the next ask always parses.
|
|
475
|
+
function dropParse() {
|
|
476
|
+
root.parseSeq++
|
|
477
|
+
root.releaseWorker()
|
|
478
|
+
root.parsing = false
|
|
479
|
+
root.askedAny = false
|
|
480
|
+
root.askedText = ""
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// The synchronous parse of one request, landed like a worker reply: the small-file path and the worker's recovery both end here.
|
|
484
|
+
function parseNow(text, dir, chrome, ink, deep) {
|
|
485
|
+
var blocks = root.shareParse && !deep ? Prepared.take(root.path, text, dir, chrome, ink) : null
|
|
486
|
+
if (blocks !== null)
|
|
487
|
+
root.reusedParses++
|
|
488
|
+
try {
|
|
489
|
+
if (blocks === null)
|
|
490
|
+
blocks = deep ? Markdown.deepBlocks() : Markdown.blocks(text, dir, chrome, ink)
|
|
491
|
+
} catch (e) {
|
|
492
|
+
root.parseError = String(e.message || e)
|
|
493
|
+
root.appliedSeq = root.parseSeq
|
|
494
|
+
root.parsing = false
|
|
495
|
+
root.askedAny = false
|
|
496
|
+
return
|
|
497
|
+
}
|
|
498
|
+
if (root.shareParse && !deep)
|
|
499
|
+
Prepared.store(root.path, text, dir, chrome, ink, blocks)
|
|
500
|
+
// Taken once the parse is good and before the model reset, like the worker landing: a parse that throws takes no place.
|
|
501
|
+
root.rememberScroll()
|
|
502
|
+
root.settingBlocks = true
|
|
503
|
+
root.blockList = blocks
|
|
504
|
+
root.settingBlocks = false
|
|
505
|
+
root.parseError = ""
|
|
506
|
+
root.appliedSeq = root.parseSeq
|
|
507
|
+
root.parsing = false
|
|
508
|
+
root.restoreScroll()
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Resolve images before Qt sees text: remote images become placeholders; only files beside the document load.
|
|
512
|
+
function askParse() {
|
|
513
|
+
if (!root.active || root.tooLarge || !file.loaded) {
|
|
514
|
+
root.parseError = ""
|
|
515
|
+
root.dropParse()
|
|
516
|
+
return
|
|
517
|
+
}
|
|
518
|
+
// Read the file's own text: onLoaded can run before the rawText binding has caught up.
|
|
519
|
+
var text = file.text()
|
|
520
|
+
var dir = Markdown.dirOf(root.path)
|
|
521
|
+
if (root.askedAny && text === root.askedText && dir === root.askedDir
|
|
522
|
+
&& root.chromeHex === root.askedChrome && root.inkHex === root.askedInk) {
|
|
523
|
+
return
|
|
524
|
+
}
|
|
525
|
+
// Only a request that goes on to parse clears an error; a skipped one has nothing to replace it with.
|
|
526
|
+
root.parseError = ""
|
|
527
|
+
root.askedAny = true
|
|
528
|
+
root.askedText = text
|
|
529
|
+
root.askedDir = dir
|
|
530
|
+
root.askedChrome = root.chromeHex
|
|
531
|
+
root.askedInk = root.inkHex
|
|
532
|
+
root.parseSeq++
|
|
533
|
+
root.parseRuns++
|
|
534
|
+
root.parsing = true
|
|
535
|
+
// The live text length decides worker activation before bindings update; a big text with a deep head lands the sentinel unparsed.
|
|
536
|
+
var big = text.length > root.workerThreshold
|
|
537
|
+
var deep = big && Markdown.deepHead(text).deep
|
|
538
|
+
var wantWorker = big && !deep
|
|
539
|
+
parserLoader.active = wantWorker
|
|
540
|
+
var w = parserLoader.item
|
|
541
|
+
if (wantWorker && w) {
|
|
542
|
+
parseFallback.restart()
|
|
543
|
+
// Only a file with nothing drawn yet sends a head: a reparse keeps the list and the reader's place until the whole one lands.
|
|
544
|
+
w.sendMessage({ seq: root.parseSeq, source: text, dir: dir, chrome: root.chromeHex, ink: root.inkHex, head: root.blockList.length === 0 ? Markdown.HEAD_BLOCKS : 0 })
|
|
545
|
+
return
|
|
546
|
+
}
|
|
547
|
+
parserLoader.active = false
|
|
548
|
+
parseFallback.stop()
|
|
549
|
+
root.parseNow(text, dir, root.chromeHex, root.inkHex, deep)
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
onRawTextChanged: root.askParse()
|
|
553
|
+
onActiveChanged: {
|
|
554
|
+
root.pointFile()
|
|
555
|
+
root.askParse()
|
|
556
|
+
}
|
|
557
|
+
onPathChanged: {
|
|
558
|
+
// A save's pending reload belongs to the old file.
|
|
559
|
+
reloadCoalesce.stop()
|
|
560
|
+
root.keepScroll = false
|
|
561
|
+
root.parseError = ""
|
|
562
|
+
root.blockList = []
|
|
563
|
+
tableRoute.reset()
|
|
564
|
+
root.parsedOffThread = false
|
|
565
|
+
// The new file's load asks; asking now would parse the old file's text under the new path.
|
|
566
|
+
root.dropParse()
|
|
567
|
+
root.pointFile()
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Warming both view heights prevents a contentHeight binding loop on Rendered/Source changes.
|
|
571
|
+
onViewChanged: {
|
|
572
|
+
body.contentHeight
|
|
573
|
+
if (root.sourceItem !== null)
|
|
574
|
+
root.sourceItem.contentHeight
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// Only the shown Source (a too-deep one too) asks for lines, a screen at a time: an unseen 1 MiB Source held the UI thread 100 ms.
|
|
578
|
+
Flea.MarkdownSource {
|
|
579
|
+
id: sourceList
|
|
580
|
+
anchors.fill: parent
|
|
581
|
+
visible: root.shownView === Markdown.SOURCE && (root.parseError === "" || root.sourceRefused)
|
|
582
|
+
text: root.shownView === Markdown.SOURCE ? root.rawText : ""
|
|
583
|
+
path: root.path
|
|
584
|
+
truncate: root.truncate
|
|
585
|
+
backend: root.backend
|
|
586
|
+
slot: root.slot
|
|
587
|
+
active: root.active && root.shownView === Markdown.SOURCE
|
|
588
|
+
&& (file.loaded || root.tooLarge || root.readFailed || (sourceList.engine && !root.truncate))
|
|
589
|
+
tooLarge: root.tooLarge
|
|
590
|
+
readFailed: root.readFailed
|
|
591
|
+
wrap: root.wrap
|
|
592
|
+
notice: root.tooDeep ? Markdown.deepNotice() : ""
|
|
593
|
+
insetX: root.insetX
|
|
594
|
+
insetY: root.insetY
|
|
595
|
+
blockGap: root.blockGap
|
|
596
|
+
bodyPx: root.bodyPx
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Where the runtime has a web view, the rendered view is one sandboxed page the backend builds
|
|
600
|
+
// (src/markdown-html.js): formulas are set, and scrolling is the browser's. The block list
|
|
601
|
+
// below stays the view everywhere else, and for the source view.
|
|
602
|
+
readonly property bool useWeb: web.available && !root.tooLarge && !root.readFailed
|
|
603
|
+
&& root.shownView === Markdown.RENDERED
|
|
604
|
+
property int webToken: 0
|
|
605
|
+
function askWeb() {
|
|
606
|
+
if (!root.useWeb || !root.active || root.path === "" || root.backend === null
|
|
607
|
+
|| typeof root.backend.askMarkdownHtml !== "function")
|
|
608
|
+
return
|
|
609
|
+
var figure = themeProbe.item ? themeProbe.item.hexTheme() : null
|
|
610
|
+
root.webToken = root.backend.askMarkdownHtml("markdown-" + root.slot, root.path, {
|
|
611
|
+
foreground: root.inkHex, background: root.hexOf(Theme.color.background), muted: root.mutedHex,
|
|
612
|
+
surface: root.surfaceHex, accent: root.accentHex, bodyPx: root.bodyPx,
|
|
613
|
+
font: Theme.font.family,
|
|
614
|
+
advances: figure ? figure.advances : [], boldAdvances: figure ? figure.boldAdvances : []
|
|
615
|
+
})
|
|
616
|
+
}
|
|
617
|
+
onUseWebChanged: root.askWeb()
|
|
618
|
+
Connections {
|
|
619
|
+
target: root.backend
|
|
620
|
+
ignoreUnknownSignals: true
|
|
621
|
+
function onMarkdownHtmlResult(message) {
|
|
622
|
+
if (message.token === root.webToken && message.state === "ready")
|
|
623
|
+
web.html = message.html
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
Flea.WebPreview {
|
|
627
|
+
id: web
|
|
628
|
+
anchors.fill: parent
|
|
629
|
+
visible: root.useWeb
|
|
630
|
+
// A link opens outside, under the same gate as the block view's links.
|
|
631
|
+
onLinkActivated: function (url) {
|
|
632
|
+
if (Markdown.isExternalLink(url))
|
|
633
|
+
Qt.openUrlExternally(url)
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// Render only visible blocks and a bounded cache, even for a 1 MiB document.
|
|
638
|
+
ListView {
|
|
639
|
+
id: body
|
|
640
|
+
anchors.fill: parent
|
|
641
|
+
anchors.leftMargin: root.insetX
|
|
642
|
+
anchors.rightMargin: root.insetX
|
|
643
|
+
clip: true
|
|
644
|
+
visible: (!root.tooLarge && !root.readFailed && root.parseError === "")
|
|
645
|
+
&& root.shownView !== Markdown.SOURCE && !root.useWeb
|
|
646
|
+
// The web page draws the document then, so no block delegates are built behind it.
|
|
647
|
+
model: root.useWeb ? [] : root.blockList
|
|
648
|
+
// A new model resets the view to its origin, so the saved place is restored once that reset is done.
|
|
649
|
+
onModelChanged: root.restoreScroll()
|
|
650
|
+
onContentYChanged: { root.releaseHeldPlace(); root.noteEnd() }
|
|
651
|
+
onContentHeightChanged: root.holdEnd()
|
|
652
|
+
onOriginYChanged: root.holdEnd()
|
|
653
|
+
spacing: root.blockGap
|
|
654
|
+
topMargin: root.insetY
|
|
655
|
+
bottomMargin: root.insetY
|
|
656
|
+
cacheBuffer: root.blockCachePixels
|
|
657
|
+
focus: false
|
|
658
|
+
|
|
659
|
+
// The wheel and the bar belong to the frame, not to the inset list, so both sit on the root.
|
|
660
|
+
FastScrollHandler {
|
|
661
|
+
parent: root
|
|
662
|
+
flickable: body
|
|
663
|
+
visible: body.visible
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
Flea.ViewportScrollBar {
|
|
667
|
+
parent: root
|
|
668
|
+
visible: !root.externalScrollBars && overflow && body.visible
|
|
669
|
+
anchors { top: parent.top; right: parent.right }
|
|
670
|
+
flickable: body
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// A sideways stroke over a table wider than the document goes to the table, above the handler that scrolls the document.
|
|
674
|
+
Flea.MarkdownTableWheel {
|
|
675
|
+
id: tableRoute
|
|
676
|
+
parent: root
|
|
677
|
+
visible: body.visible
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
delegate: Flea.MarkdownBlockView {
|
|
681
|
+
block: modelData
|
|
682
|
+
blockIndex: index
|
|
683
|
+
blockCount: root.blockList.length
|
|
684
|
+
siblings: root.blockList
|
|
685
|
+
preview: root
|
|
686
|
+
width: ListView.view.width
|
|
687
|
+
// Only a figure intersecting the viewport may send a render request.
|
|
688
|
+
inView: {
|
|
689
|
+
var v = ListView.view
|
|
690
|
+
if (!v)
|
|
691
|
+
return true
|
|
692
|
+
return (y + height >= v.contentY) && (y <= v.contentY + v.height)
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
Text {
|
|
698
|
+
anchors.centerIn: parent
|
|
699
|
+
visible: false // Failed previews remain blank.
|
|
700
|
+
text: root.status
|
|
701
|
+
color: Theme.color.muted
|
|
702
|
+
font.family: Theme.font.family
|
|
703
|
+
font.pixelSize: Theme.font.body
|
|
704
|
+
textFormat: Text.PlainText
|
|
705
|
+
}
|
|
706
|
+
}
|