flea-qml 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +511 -2
- package/THIRD-PARTY-NOTICES.md +29 -0
- package/demos/App.java +5 -0
- package/demos/Dockerfile +4 -0
- package/demos/Main.kt +3 -0
- package/demos/Program.cs +1 -0
- package/demos/README.md +12 -0
- package/demos/app.dart +3 -0
- package/demos/app.deb +0 -0
- package/demos/app.js +1 -0
- package/demos/backup.tar +0 -0
- package/demos/budget.xlsx +0 -0
- package/demos/build.sh +2 -0
- package/demos/bundle.zip +0 -0
- package/demos/clip.mp4 +0 -0
- package/demos/data.sqlite +0 -0
- package/demos/disk.iso +0 -0
- package/demos/engine.cpp +5 -0
- package/demos/firmware.bin +0 -0
- package/demos/flake.nix +4 -0
- package/demos/folder/inside.txt +1 -0
- package/demos/font.ttf +0 -0
- package/demos/index.html +5 -0
- package/demos/index.php +2 -0
- package/demos/init.lua +1 -0
- package/demos/letter.docx +0 -0
- package/demos/lib.rs +3 -0
- package/demos/main.c +6 -0
- package/demos/main.h +3 -0
- package/demos/math-and-diagrams.md +200 -0
- package/demos/notes.tar.gz +0 -0
- package/demos/notes.txt +3 -0
- package/demos/photo.png +0 -0
- package/demos/program +2 -0
- package/demos/report.pdf +32 -0
- package/demos/script.py +1 -0
- package/demos/server.go +7 -0
- package/demos/settings.json +4 -0
- package/demos/slides.pptx +0 -0
- package/demos/song.mp3 +0 -0
- package/demos/style.css +4 -0
- package/demos/tool.rb +1 -0
- package/demos/types.ts +2 -0
- package/docs/pele.md +23 -0
- package/docs/protocol.md +3420 -0
- package/docs/temml.md +63 -0
- package/index.js +107 -0
- package/package.json +34 -4
- package/src/archive.js +407 -0
- package/src/archiveops.js +728 -0
- package/src/backend.js +369 -0
- package/src/bulkrename.js +95 -0
- package/src/clip-host.js +76 -0
- package/src/clip.js +462 -0
- package/src/code.js +168 -0
- package/src/compare.js +74 -0
- package/src/create.js +128 -0
- package/src/dirsize.js +147 -0
- package/src/figure-svg.js +530 -0
- package/src/figure-thread.js +23 -0
- package/src/figure.js +132 -0
- package/src/find.js +55 -0
- package/src/flea.js +39 -0
- package/src/fsinfo.js +39 -0
- package/src/highlight.js +141 -0
- package/src/html.js +52 -0
- package/src/kinds.js +89 -0
- package/src/listing.js +130 -0
- package/src/markdown-html.js +317 -0
- package/src/mathml.js +186 -0
- package/src/menu.js +180 -0
- package/src/meta.js +135 -0
- package/src/office.js +810 -0
- package/src/order.js +100 -0
- package/src/peek.js +49 -0
- package/src/pele-wrapper.js +695 -0
- package/src/permissions.js +180 -0
- package/src/places.js +313 -0
- package/src/preview-language.js +10 -0
- package/src/terminal-server.js +95 -0
- package/src/terminal-shell.js +26 -0
- package/src/transfer.js +669 -0
- package/src/trash-record.js +41 -0
- package/src/trash.js +210 -0
- package/src/trashbrowse.js +327 -0
- package/src/uistate.js +393 -0
- package/src/uistore.js +168 -0
- package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
- package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
- package/src/vendor/LICENSES/MIT-katex.txt +21 -0
- package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
- package/src/vendor/LICENSES/MIT-pele.txt +40 -0
- package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
- package/src/vendor/LICENSES/MIT-temml.txt +21 -0
- package/src/vendor/pele.js +145 -0
- package/src/vendor/temml.mjs +14708 -0
- package/src/watch.js +98 -0
- package/src/wayland/client.js +109 -0
- package/src/wayland/protocol.js +55 -0
- package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
- package/src/wayland/protocols/wayland.xml +3248 -0
- package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
- package/src/wayland/resource-io.js +6 -0
- package/src/wayland/socket-discovery.js +26 -0
- package/src/wayland/transport-posix.js +120 -0
- package/src/wayland/transport-win32.js +11 -0
- package/src/wayland/transport.js +3 -0
- package/src/wayland/win32-resources.js +80 -0
- package/src/wayland/win32-wire.js +62 -0
- package/test/archive.test.js +80 -0
- package/test/bench-markdown-scroll.mjs +190 -0
- package/test/clip-host.test.js +113 -0
- package/test/code-preview.test.js +35 -0
- package/test/compare-ui-paths.test.js +24 -0
- package/test/compare.test.js +54 -0
- package/test/delete-trash.test.js +67 -0
- package/test/dirsize.test.js +138 -0
- package/test/file-ops.test.js +307 -0
- package/test/file-url.test.js +24 -0
- package/test/find-contents.test.js +161 -0
- package/test/find-input.test.js +66 -0
- package/test/fixtures/pele-parity.json +1006 -0
- package/test/highlight-launcher.test.js +35 -0
- package/test/html-preview.test.js +22 -0
- package/test/input.test.js +15 -0
- package/test/keymap.test.js +26 -0
- package/test/language-icons.test.js +36 -0
- package/test/launcher.test.js +51 -0
- package/test/manual-archive-here-ui.mjs +47 -0
- package/test/manual-code-scroll.mjs +28 -0
- package/test/manual-column-scroll.mjs +24 -0
- package/test/manual-compare-ui.mjs +20 -0
- package/test/manual-find-status.mjs +37 -0
- package/test/manual-folder-focus.mjs +63 -0
- package/test/manual-html-security.mjs +23 -0
- package/test/manual-html-ui.mjs +30 -0
- package/test/manual-syntax-preview.mjs +26 -0
- package/test/manual-terminal-lifecycle.mjs +42 -0
- package/test/manual-terminal-navigation.mjs +48 -0
- package/test/manual-terminal-ui.mjs +47 -0
- package/test/manual-trash-ui.mjs +86 -0
- package/test/markdown-diagrams.test.js +93 -0
- package/test/markdown-html.test.js +105 -0
- package/test/mathml.test.js +92 -0
- package/test/menu-transfer.test.js +57 -0
- package/test/office-preview.test.js +154 -0
- package/test/pele-parity.test.js +28 -0
- package/test/places.test.js +134 -0
- package/test/preview-keys.test.js +60 -0
- package/test/preview-language.test.js +22 -0
- package/test/status-filename.test.js +20 -0
- package/test/transfer-replace-merge.test.js +187 -0
- package/test/trash-address.test.js +23 -0
- package/test/trash-view.test.js +37 -0
- package/test/trashbrowse.test.js +135 -0
- package/ui/AboutFacts.qml +78 -0
- package/ui/ArchiveCards.qml +95 -0
- package/ui/ArchiveCompressDialog.qml +378 -0
- package/ui/ArchiveHereConfirm.qml +127 -0
- package/ui/ArchivePasswordDialog.qml +257 -0
- package/ui/Backend.qml +775 -0
- package/ui/BulkOldNames.qml +47 -0
- package/ui/BulkRenameDialog.qml +380 -0
- package/ui/CardFrame.qml +67 -0
- package/ui/CardScroll.qml +79 -0
- package/ui/CheckBox.qml +73 -0
- package/ui/ChromeBar.qml +360 -0
- package/ui/ChromeButton.qml +131 -0
- package/ui/ChromeModes.qml +43 -0
- package/ui/CodeLines.qml +256 -0
- package/ui/CodeRefusal.qml +52 -0
- package/ui/CollideConfirm.qml +147 -0
- package/ui/CollideHost.qml +167 -0
- package/ui/ColumnPane.qml +525 -0
- package/ui/ColumnRow.qml +380 -0
- package/ui/ColumnsArea.qml +594 -0
- package/ui/ColumnsLanding.qml +147 -0
- package/ui/CompareView.qml +321 -0
- package/ui/ContextMenu.qml +743 -0
- package/ui/ConvertDialog.qml +456 -0
- package/ui/CountedWorker.qml +7 -0
- package/ui/Crumb.qml +64 -0
- package/ui/CrumbDrop.qml +25 -0
- package/ui/CsvTable.qml +394 -0
- package/ui/CursorMark.qml +41 -0
- package/ui/DefaultClaim.qml +130 -0
- package/ui/DeviceLock.qml +47 -0
- package/ui/DeviceMounts.qml +540 -0
- package/ui/DialogButton.qml +150 -0
- package/ui/DialogField.qml +147 -0
- package/ui/DialogHeader.qml +31 -0
- package/ui/DialogScrim.qml +20 -0
- package/ui/DialogTitle.qml +37 -0
- package/ui/Divider.qml +9 -0
- package/ui/DropInto.qml +126 -0
- package/ui/DropTarget.qml +35 -0
- package/ui/DropboxMark.qml +60 -0
- package/ui/EmptyState.qml +150 -0
- package/ui/EscapeHint.qml +11 -0
- package/ui/FactsTable.qml +54 -0
- package/ui/FastScrollHandler.qml +476 -0
- package/ui/FatNamesConfirm.qml +157 -0
- package/ui/Favourites.qml +143 -0
- package/ui/FigureService.qml +120 -0
- package/ui/FileDrag.qml +267 -0
- package/ui/FilterStrip.qml +133 -0
- package/ui/FitMetrics.qml +22 -0
- package/ui/FlashDriveRows.qml +137 -0
- package/ui/FlashHost.qml +72 -0
- package/ui/FlashImageRow.qml +104 -0
- package/ui/FlashRunner.qml +119 -0
- package/ui/FlashStepRow.qml +172 -0
- package/ui/FlashStrip.qml +38 -0
- package/ui/FlashView.qml +397 -0
- package/ui/FleaMark.qml +88 -0
- package/ui/FlyoutFade.qml +23 -0
- package/ui/FontPane.qml +170 -0
- package/ui/Glass.qml +114 -0
- package/ui/GlassTagger.qml +59 -0
- package/ui/Glyph.qml +64 -0
- package/ui/GlyphSolid.qml +22 -0
- package/ui/GridArea.qml +664 -0
- package/ui/GridTile.qml +325 -0
- package/ui/GvfsBridge.qml +164 -0
- package/ui/Header.qml +433 -0
- package/ui/HoverTimers.qml +39 -0
- package/ui/HtmlClip.qml +30 -0
- package/ui/HtmlPane.qml +63 -0
- package/ui/HyprlandMark.qml +45 -0
- package/ui/Ipc.qml +1005 -0
- package/ui/IpcControls.qml +7 -0
- package/ui/IpcMenuState.qml +48 -0
- package/ui/IpcPreviewState.qml +185 -0
- package/ui/JumpPath.qml +51 -0
- package/ui/KeymapSheet.qml +561 -0
- package/ui/KeymapSheetResult.qml +89 -0
- package/ui/KindStack.qml +40 -0
- package/ui/LangMark.qml +51 -0
- package/ui/LangMarkLoader.qml +26 -0
- package/ui/List.qml +480 -0
- package/ui/LoadingState.qml +54 -0
- package/ui/LocalSend.qml +56 -0
- package/ui/LocalSendMark.qml +73 -0
- package/ui/MarkdownBlockView.qml +311 -0
- package/ui/MarkdownBlocks.qml +35 -0
- package/ui/MarkdownFigure.qml +254 -0
- package/ui/MarkdownImages.qml +72 -0
- package/ui/MarkdownList.qml +81 -0
- package/ui/MarkdownMathsText.qml +97 -0
- package/ui/MarkdownPane.qml +83 -0
- package/ui/MarkdownPictures.qml +41 -0
- package/ui/MarkdownQuote.qml +52 -0
- package/ui/MarkdownRemote.qml +82 -0
- package/ui/MarkdownSource.qml +155 -0
- package/ui/MarkdownTable.qml +222 -0
- package/ui/MarkdownTableScroll.qml +64 -0
- package/ui/MarkdownTableWheel.qml +126 -0
- package/ui/MarkdownText.qml +87 -0
- package/ui/MarkdownWorker.js +132 -0
- package/ui/MatchText.qml +99 -0
- package/ui/MediaSession.qml +38 -0
- package/ui/MediaSound.qml +26 -0
- package/ui/MediaStrip.qml +191 -0
- package/ui/MediaTrack.qml +36 -0
- package/ui/MediaVolume.qml +54 -0
- package/ui/MenuActionDialog.qml +396 -0
- package/ui/MenuEdgeFade.qml +24 -0
- package/ui/MenuHost.qml +227 -0
- package/ui/MenuRow.qml +351 -0
- package/ui/MountListing.qml +100 -0
- package/ui/NetworkDialog.qml +435 -0
- package/ui/NetworkForm.qml +426 -0
- package/ui/NetworkMounts.qml +913 -0
- package/ui/NetworkPlaces.qml +127 -0
- package/ui/OpenWithDialog.qml +613 -0
- package/ui/Opener.qml +95 -0
- package/ui/Pane.qml +1320 -0
- package/ui/PaneMenuActions.qml +527 -0
- package/ui/PanePath.qml +90 -0
- package/ui/PaneRail.qml +268 -0
- package/ui/PaneStates.qml +88 -0
- package/ui/PaneSwap.qml +339 -0
- package/ui/PaneWire.qml +601 -0
- package/ui/ParkedWait.qml +9 -0
- package/ui/PathEntry.qml +186 -0
- package/ui/PathJump.qml +400 -0
- package/ui/PdfViewer.qml +297 -0
- package/ui/PermissionsDialog.qml +658 -0
- package/ui/PermissionsHeadings.qml +31 -0
- package/ui/PhoneMounts.qml +67 -0
- package/ui/PickerAnswers.qml +75 -0
- package/ui/PickerBox.qml +26 -0
- package/ui/PickerChrome.qml +295 -0
- package/ui/PickerFilter.qml +97 -0
- package/ui/PickerGrid.qml +308 -0
- package/ui/PickerHeader.qml +28 -0
- package/ui/PickerLifecycle.qml +27 -0
- package/ui/PickerList.qml +218 -0
- package/ui/PickerListing.qml +149 -0
- package/ui/PickerPathBar.qml +127 -0
- package/ui/PickerPlaces.qml +189 -0
- package/ui/PickerRecent.qml +92 -0
- package/ui/PickerSave.qml +101 -0
- package/ui/PickerSelection.qml +155 -0
- package/ui/PickerWindow.qml +846 -0
- package/ui/PowerSectorsReader.qml +10 -0
- package/ui/PrebuildDriver.qml +146 -0
- package/ui/Preview.qml +1005 -0
- package/ui/PreviewAnimation.qml +24 -0
- package/ui/PreviewArchive.qml +91 -0
- package/ui/PreviewColumn.qml +553 -0
- package/ui/PreviewEdge.qml +63 -0
- package/ui/PreviewFacts.qml +30 -0
- package/ui/PreviewFactsLine.qml +34 -0
- package/ui/PreviewHtml.qml +233 -0
- package/ui/PreviewImage.qml +253 -0
- package/ui/PreviewImagePan.qml +13 -0
- package/ui/PreviewImageSharp.qml +32 -0
- package/ui/PreviewLines.qml +106 -0
- package/ui/PreviewMarkdown.qml +706 -0
- package/ui/PreviewMedia.qml +250 -0
- package/ui/PreviewPdf.qml +482 -0
- package/ui/PreviewScroll.qml +201 -0
- package/ui/PreviewSwap.qml +335 -0
- package/ui/PreviewText.qml +149 -0
- package/ui/ProtocolChip.qml +18 -0
- package/ui/QuickLookArchive.qml +41 -0
- package/ui/QuickLookBar.qml +103 -0
- package/ui/QuickLookPrepare.qml +355 -0
- package/ui/QuickLookSwap.qml +10 -0
- package/ui/QuickLookWarm.qml +65 -0
- package/ui/RailDrop.qml +155 -0
- package/ui/RailHeading.qml +19 -0
- package/ui/RailPlaces.qml +38 -0
- package/ui/RailTrashRow.qml +67 -0
- package/ui/RenameField.qml +353 -0
- package/ui/RendererRetry.qml +11 -0
- package/ui/ResizeHandle.qml +52 -0
- package/ui/Reveal.qml +54 -0
- package/ui/Row.qml +476 -0
- package/ui/RowDrag.qml +213 -0
- package/ui/RowDropTarget.qml +27 -0
- package/ui/RunCard.qml +286 -0
- package/ui/Scripts.qml +65 -0
- package/ui/SearchStrip.qml +232 -0
- package/ui/SelectionBand.qml +140 -0
- package/ui/SelectionPreview.qml +370 -0
- package/ui/SettingsFavourite.qml +122 -0
- package/ui/SettingsGroup.qml +96 -0
- package/ui/SettingsHint.qml +12 -0
- package/ui/SettingsMetrics.qml +29 -0
- package/ui/SettingsPane.qml +178 -0
- package/ui/SettingsPanel.qml +547 -0
- package/ui/SettingsRail.qml +128 -0
- package/ui/SettingsRow.qml +409 -0
- package/ui/SettingsRuler.qml +85 -0
- package/ui/SettingsSegment.qml +85 -0
- package/ui/ShareBrowser.qml +113 -0
- package/ui/ShareLink.qml +67 -0
- package/ui/ShelfPins.qml +101 -0
- package/ui/Sidebar.qml +728 -0
- package/ui/SidebarRow.qml +358 -0
- package/ui/Spinner.qml +60 -0
- package/ui/StableModel.qml +89 -0
- package/ui/StateMessage.qml +84 -0
- package/ui/StatusBar.qml +512 -0
- package/ui/StatusFileName.qml +27 -0
- package/ui/TabBar.qml +673 -0
- package/ui/TabDragGeometry.qml +60 -0
- package/ui/TagMenuMark.qml +52 -0
- package/ui/TagRailSection.qml +53 -0
- package/ui/TagSlot.qml +40 -0
- package/ui/TagState.qml +150 -0
- package/ui/TagSwatch.qml +28 -0
- package/ui/Taildrop.qml +86 -0
- package/ui/TailscaleMark.qml +50 -0
- package/ui/TerminalService.qml +69 -0
- package/ui/TerminalTab.qml +48 -0
- package/ui/TerminalTabs.qml +27 -0
- package/ui/Theme.qml +460 -0
- package/ui/ThemeColors.qml +43 -0
- package/ui/TransferCard.qml +239 -0
- package/ui/TrashConfirm.qml +129 -0
- package/ui/TrashDropHandler.qml +11 -0
- package/ui/TrashHost.qml +202 -0
- package/ui/TrashMonitor.qml +30 -0
- package/ui/TrashToolbar.qml +19 -0
- package/ui/TrashView.qml +492 -0
- package/ui/UnlockDialog.qml +450 -0
- package/ui/UnlockHost.qml +206 -0
- package/ui/UpdateCheck.qml +97 -0
- package/ui/UserDirs.qml +25 -0
- package/ui/ViewState.qml +565 -0
- package/ui/ViewportScrollBar.qml +195 -0
- package/ui/ViewportScrollBars.qml +25 -0
- package/ui/WebPreview.qml +33 -0
- package/ui/WebPreviewView.qml +26 -0
- package/ui/WindowBody.qml +829 -0
- package/ui/WindowDrag.qml +35 -0
- package/ui/boot/Commons/AudioNodes.qml +50 -0
- package/ui/boot/Commons/AudioNodesModel.js +96 -0
- package/ui/boot/Commons/Border.qml +243 -0
- package/ui/boot/Commons/BorderGeometry.js +373 -0
- package/ui/boot/Commons/Color.qml +258 -0
- package/ui/boot/Commons/I18n.qml +118 -0
- package/ui/boot/Commons/InputDevices.qml +112 -0
- package/ui/boot/Commons/InputMethodState.qml +38 -0
- package/ui/boot/Commons/IpcRegistry.qml +77 -0
- package/ui/boot/Commons/Numbers.js +19 -0
- package/ui/boot/Commons/Plural.js +91 -0
- package/ui/boot/Commons/ShellIpc.qml +12 -0
- package/ui/boot/Commons/Style.qml +561 -0
- package/ui/boot/Commons/Translations.qml +100 -0
- package/ui/boot/Commons/UntypedInput.qml +152 -0
- package/ui/boot/Commons/Util.qml +188 -0
- package/ui/boot/Commons/qmldir +13 -0
- package/ui/boot/LICENSE-omarchy +20 -0
- package/ui/boot/Ui/BackgroundMedia.qml +49 -0
- package/ui/boot/Ui/BarIconButton.qml +106 -0
- package/ui/boot/Ui/BarIconContent.qml +38 -0
- package/ui/boot/Ui/BarIndicator.qml +53 -0
- package/ui/boot/Ui/BarWidget.qml +50 -0
- package/ui/boot/Ui/BorderOverlay.qml +54 -0
- package/ui/boot/Ui/BorderSurface.qml +40 -0
- package/ui/boot/Ui/Button.qml +224 -0
- package/ui/boot/Ui/ButtonGroup.qml +131 -0
- package/ui/boot/Ui/ConfirmDialog.qml +134 -0
- package/ui/boot/Ui/CursorSurface.qml +42 -0
- package/ui/boot/Ui/Dropdown.qml +245 -0
- package/ui/boot/Ui/FilterInput.qml +26 -0
- package/ui/boot/Ui/IconContentBounds.qml +141 -0
- package/ui/boot/Ui/KeyboardPanel.qml +453 -0
- package/ui/boot/Ui/MultiSelect.qml +624 -0
- package/ui/boot/Ui/NumberField.qml +86 -0
- package/ui/boot/Ui/OpticalGlyph.qml +68 -0
- package/ui/boot/Ui/OverlayWindow.qml +102 -0
- package/ui/boot/Ui/Panel.qml +60 -0
- package/ui/boot/Ui/PanelActionButton.qml +105 -0
- package/ui/boot/Ui/PanelController.qml +16 -0
- package/ui/boot/Ui/PanelHero.qml +112 -0
- package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
- package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
- package/ui/boot/Ui/PanelSeparator.qml +19 -0
- package/ui/boot/Ui/PanelSlider.qml +156 -0
- package/ui/boot/Ui/PanelToolTip.qml +50 -0
- package/ui/boot/Ui/PluginBarApi.qml +89 -0
- package/ui/boot/Ui/PointerMoveGate.qml +54 -0
- package/ui/boot/Ui/PopupCard.qml +181 -0
- package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
- package/ui/boot/Ui/SearchableDropdown.qml +354 -0
- package/ui/boot/Ui/SizedImage.qml +125 -0
- package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
- package/ui/boot/Ui/TextField.qml +58 -0
- package/ui/boot/Ui/Toggle.qml +118 -0
- package/ui/boot/Ui/ToggleSwitch.qml +115 -0
- package/ui/boot/Ui/WidgetButton.qml +172 -0
- package/ui/boot/Ui/qmldir +41 -0
- package/ui/boot/fleatab.qml +50 -0
- package/ui/boot/picker.qml +39 -0
- package/ui/boot/shell.qml +131 -0
- package/ui/boot/tabtearoff.qml +51 -0
- package/ui/js/Anchor.js +379 -0
- package/ui/js/AnchorHold.js +162 -0
- package/ui/js/Archive.js +157 -0
- package/ui/js/ArchiveCard.js +44 -0
- package/ui/js/ArchiveOps.js +44 -0
- package/ui/js/BackReturn.js +118 -0
- package/ui/js/BulkRename.js +100 -0
- package/ui/js/Buttons.js +54 -0
- package/ui/js/ChromeKeys.js +116 -0
- package/ui/js/ClipMarks.js +73 -0
- package/ui/js/ClipSelection.js +67 -0
- package/ui/js/Clipboard.js +179 -0
- package/ui/js/Cloud.js +97 -0
- package/ui/js/CodeRuns.js +72 -0
- package/ui/js/Collide.js +212 -0
- package/ui/js/ColumnFit.js +28 -0
- package/ui/js/ColumnMenu.js +111 -0
- package/ui/js/Columns.js +298 -0
- package/ui/js/ColumnsCarry.js +103 -0
- package/ui/js/Compare.js +74 -0
- package/ui/js/Contrast.js +157 -0
- package/ui/js/ControlReader.js +42 -0
- package/ui/js/Convert.js +52 -0
- package/ui/js/CopyAs.js +52 -0
- package/ui/js/Crumbs.js +178 -0
- package/ui/js/Csv.js +231 -0
- package/ui/js/Density.js +44 -0
- package/ui/js/Devices.js +440 -0
- package/ui/js/DirSizes.js +180 -0
- package/ui/js/Drag.js +360 -0
- package/ui/js/DragOut.js +166 -0
- package/ui/js/DropDev.js +52 -0
- package/ui/js/Dropbox.js +41 -0
- package/ui/js/Eject.js +217 -0
- package/ui/js/Errors.js +188 -0
- package/ui/js/ExtThumbs.js +115 -0
- package/ui/js/Facts.js +402 -0
- package/ui/js/FigureDate.js +14 -0
- package/ui/js/Filter.js +285 -0
- package/ui/js/Find.js +46 -0
- package/ui/js/Flash.js +184 -0
- package/ui/js/FlashCard.js +79 -0
- package/ui/js/FlashEndings.js +125 -0
- package/ui/js/FlashPane.js +116 -0
- package/ui/js/FleaBin.js +12 -0
- package/ui/js/Focus.js +504 -0
- package/ui/js/FolderSorts.js +108 -0
- package/ui/js/FolderViews.js +44 -0
- package/ui/js/Format.js +314 -0
- package/ui/js/Fuzzy.js +141 -0
- package/ui/js/GlassTag.js +72 -0
- package/ui/js/Grid.js +33 -0
- package/ui/js/GridGeometry.js +90 -0
- package/ui/js/GridNames.js +153 -0
- package/ui/js/GvfsBridge.js +200 -0
- package/ui/js/HostClipboard.js +29 -0
- package/ui/js/Icons.js +218 -0
- package/ui/js/Input.js +50 -0
- package/ui/js/Jump.js +200 -0
- package/ui/js/KeyName.js +64 -0
- package/ui/js/Keymap.js +401 -0
- package/ui/js/Kinds.js +164 -0
- package/ui/js/LICENSES/ISC-lucide.txt +43 -0
- package/ui/js/LangMarkPaths.js +47 -0
- package/ui/js/LangMarks.js +120 -0
- package/ui/js/Lists.js +11 -0
- package/ui/js/LocalSend.js +39 -0
- package/ui/js/LockedMenu.js +63 -0
- package/ui/js/MakeDefault.js +186 -0
- package/ui/js/MarkBox.js +7 -0
- package/ui/js/Markdown.js +119 -0
- package/ui/js/MarkdownLists.js +86 -0
- package/ui/js/MarkdownMaths.js +58 -0
- package/ui/js/MarkdownPictures.js +32 -0
- package/ui/js/MarkdownPrepared.js +139 -0
- package/ui/js/MarkdownTableFit.js +34 -0
- package/ui/js/Marks.js +148 -0
- package/ui/js/Marquee.js +96 -0
- package/ui/js/Match.js +93 -0
- package/ui/js/Material.js +109 -0
- package/ui/js/MdBlocks.js +437 -0
- package/ui/js/MdBreak.js +71 -0
- package/ui/js/MdChunks.js +70 -0
- package/ui/js/MdContainer.js +137 -0
- package/ui/js/MdDocument.js +337 -0
- package/ui/js/MdEmph.js +97 -0
- package/ui/js/MdEntity.js +108 -0
- package/ui/js/MdEntityTable.js +223 -0
- package/ui/js/MdEscape.js +59 -0
- package/ui/js/MdFront.js +37 -0
- package/ui/js/MdHold.js +32 -0
- package/ui/js/MdHtml.js +307 -0
- package/ui/js/MdHtmlBlock.js +290 -0
- package/ui/js/MdHtmlHeading.js +53 -0
- package/ui/js/MdHtmlImage.js +179 -0
- package/ui/js/MdInline.js +154 -0
- package/ui/js/MdItems.js +212 -0
- package/ui/js/MdLeaf.js +309 -0
- package/ui/js/MdLink.js +196 -0
- package/ui/js/MdMath.js +67 -0
- package/ui/js/MdParagraphs.js +138 -0
- package/ui/js/MdRefs.js +232 -0
- package/ui/js/MdResolve.js +226 -0
- package/ui/js/MdRun.js +300 -0
- package/ui/js/MdUrl.js +226 -0
- package/ui/js/Menu.js +514 -0
- package/ui/js/MenuContext.js +85 -0
- package/ui/js/MenuFit.js +13 -0
- package/ui/js/MenuRefresh.js +74 -0
- package/ui/js/MenuWheel.js +35 -0
- package/ui/js/Messages.js +186 -0
- package/ui/js/Motion.js +16 -0
- package/ui/js/Mounts.js +320 -0
- package/ui/js/MouseNav.js +13 -0
- package/ui/js/Nav.js +329 -0
- package/ui/js/NetFs.js +26 -0
- package/ui/js/OpenWith.js +83 -0
- package/ui/js/Ops.js +585 -0
- package/ui/js/Palette.js +33 -0
- package/ui/js/PathBar.js +260 -0
- package/ui/js/Permissions.js +179 -0
- package/ui/js/Phones.js +112 -0
- package/ui/js/Picker.js +353 -0
- package/ui/js/PlaceMenu.js +96 -0
- package/ui/js/Places.js +265 -0
- package/ui/js/PreviewAsk.js +21 -0
- package/ui/js/PreviewKeys.js +155 -0
- package/ui/js/PreviewSettle.js +29 -0
- package/ui/js/PreviewSwap.js +101 -0
- package/ui/js/PropertyFacts.js +144 -0
- package/ui/js/Protocols.js +296 -0
- package/ui/js/QuickLookKinds.js +27 -0
- package/ui/js/QuickLookRect.js +24 -0
- package/ui/js/RailDrop.js +51 -0
- package/ui/js/RailKeys.js +87 -0
- package/ui/js/RailMenu.js +133 -0
- package/ui/js/Recent.js +135 -0
- package/ui/js/RecentMode.js +156 -0
- package/ui/js/Reload.js +60 -0
- package/ui/js/Renderer.js +9 -0
- package/ui/js/RunFile.js +143 -0
- package/ui/js/Scripts.js +28 -0
- package/ui/js/Scroll.js +304 -0
- package/ui/js/ScrollOff.js +69 -0
- package/ui/js/Search.js +478 -0
- package/ui/js/Selection.js +97 -0
- package/ui/js/Settings.js +476 -0
- package/ui/js/SettingsAbout.js +97 -0
- package/ui/js/SettingsShelf.js +52 -0
- package/ui/js/SheetKeys.js +42 -0
- package/ui/js/SheetQuery.js +281 -0
- package/ui/js/ShelfPile.js +27 -0
- package/ui/js/SlowClick.js +53 -0
- package/ui/js/SlowOp.js +6 -0
- package/ui/js/Sort.js +134 -0
- package/ui/js/Startup.js +63 -0
- package/ui/js/StateWords.js +17 -0
- package/ui/js/Status.js +238 -0
- package/ui/js/Swap.js +166 -0
- package/ui/js/TabMove.js +39 -0
- package/ui/js/Tabs.js +751 -0
- package/ui/js/Tags.js +134 -0
- package/ui/js/Taildrop.js +128 -0
- package/ui/js/Tap.js +180 -0
- package/ui/js/TextSize.js +107 -0
- package/ui/js/Thumbs.js +158 -0
- package/ui/js/Transfer.js +172 -0
- package/ui/js/Trash.js +84 -0
- package/ui/js/TrashDates.js +47 -0
- package/ui/js/TrashDrop.js +64 -0
- package/ui/js/UiState.js +438 -0
- package/ui/js/Unlock.js +152 -0
- package/ui/js/Update.js +130 -0
- package/ui/js/UserDirs.js +56 -0
- package/ui/qmldir +230 -0
package/ui/js/MdHtml.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// MdHtml: one forward scan allowlists raw tags; only sanitized markup reaches md4c.
|
|
4
|
+
.import "MdUrl.js" as MdUrl
|
|
5
|
+
.import "MdEscape.js" as MdEscape
|
|
6
|
+
.import "MdInline.js" as MdInline
|
|
7
|
+
|
|
8
|
+
var TOKEN_OPEN = 57346
|
|
9
|
+
var TOKEN_CLOSE = 57347
|
|
10
|
+
var MAX_TAG_LENGTH = 4096
|
|
11
|
+
|
|
12
|
+
// Sample input: "\uE0020\uE003" becomes "\uFFFD0\uFFFD" before document parsing reserves its token markers; "a\r\nb\rc" becomes "a\nb\nc", the line endings CommonMark names.
|
|
13
|
+
function documentText(text) {
|
|
14
|
+
return String(text).replace(/[\uE002\uE003]/g, "\uFFFD").replace(/\r\n?/g, "\n")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Held spans use private-use delimiters and one shared token table, restored after escaping.
|
|
18
|
+
function openToken() {
|
|
19
|
+
return String.fromCharCode(TOKEN_OPEN)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function closeToken() {
|
|
23
|
+
return String.fromCharCode(TOKEN_CLOSE)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function holdToken(tokens, html) {
|
|
27
|
+
var token = openToken() + tokens.length + closeToken()
|
|
28
|
+
tokens.push(html)
|
|
29
|
+
return token
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Tags whose content is dropped with them: active content and whole-document namespaces a preview must never instantiate.
|
|
33
|
+
var DROP_CONTENT = { script: 1, style: 1, iframe: 1, object: 1, embed: 1,
|
|
34
|
+
template: 1, noscript: 1, svg: 1, math: 1 }
|
|
35
|
+
|
|
36
|
+
// Tags re-emitted with the attributes below; any other tag is dropped and its content kept. font carries only the color the parser's own links wrap in.
|
|
37
|
+
var ALLOWED = { a: 1, b: 1, strong: 1, i: 1, em: 1, u: 1, s: 1, del: 1,
|
|
38
|
+
strike: 1, sub: 1, sup: 1, kbd: 1, code: 1, br: 1, small: 1, mark: 1,
|
|
39
|
+
span: 1, p: 1, div: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, hr: 1,
|
|
40
|
+
img: 1, picture: 1, source: 1, details: 1, summary: 1, table: 1,
|
|
41
|
+
thead: 1, tbody: 1, tr: 1, th: 1, td: 1, ul: 1, ol: 1, li: 1,
|
|
42
|
+
blockquote: 1, pre: 1, font: 1 }
|
|
43
|
+
|
|
44
|
+
// Attributes that survive on any allowed tag. Every style, class, id, background, srcset, poster, data-* and on* attribute is dropped.
|
|
45
|
+
var GLOBAL_ATTRS = { align: 1, alt: 1, width: 1, height: 1, title: 1,
|
|
46
|
+
colspan: 1, rowspan: 1 }
|
|
47
|
+
|
|
48
|
+
// Void tags never take a closing tag.
|
|
49
|
+
var VOID = { br: 1, hr: 1, img: 1, source: 1 }
|
|
50
|
+
|
|
51
|
+
// The chip kbd and code tags wear, the same recipe as an inline code span.
|
|
52
|
+
var CHROME_PATTERN = /^#[0-9a-f]{6}([0-9a-f]{2})?$/i
|
|
53
|
+
var DISCLOSURE_OPEN = "\u25be"
|
|
54
|
+
|
|
55
|
+
// Qt draws a raw s tag struck on every build but drops del and strike, so all three are emitted as s.
|
|
56
|
+
var STRIKE_AS = { del: "s", strike: "s" }
|
|
57
|
+
|
|
58
|
+
function isNameChar(c) {
|
|
59
|
+
return (c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || (c >= "0" && c <= "9")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function isHtmlWhitespace(c) {
|
|
63
|
+
return c === "\t" || c === "\n" || c === "\f" || c === "\r" || c === " "
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Sample: <img src="pic.png" alt="picture">. Quote-check only the candidate; a failed native search marks later openers dead, and oversized tags stay literal.
|
|
67
|
+
function readTag(text, i, dead) {
|
|
68
|
+
if (dead !== undefined && dead !== null && i < dead.tagDead)
|
|
69
|
+
return null
|
|
70
|
+
var cached = dead !== undefined && dead !== null && dead.tagClose > i
|
|
71
|
+
var gt = cached ? dead.tagClose : text.indexOf(">", i + 1)
|
|
72
|
+
if (dead !== undefined && dead !== null && gt >= 0)
|
|
73
|
+
dead.tagClose = gt
|
|
74
|
+
if (gt < 0) {
|
|
75
|
+
if (dead !== undefined && dead !== null)
|
|
76
|
+
dead.tagDead = text.length
|
|
77
|
+
return null
|
|
78
|
+
}
|
|
79
|
+
if (gt - i > MAX_TAG_LENGTH) {
|
|
80
|
+
if (dead !== undefined && dead !== null)
|
|
81
|
+
dead.tagDead = gt - MAX_TAG_LENGTH
|
|
82
|
+
return null
|
|
83
|
+
}
|
|
84
|
+
var candidate = text.slice(i, gt + 1)
|
|
85
|
+
var dq = candidate.indexOf('"')
|
|
86
|
+
var sq = candidate.indexOf("'")
|
|
87
|
+
if (dq < 0 && sq < 0)
|
|
88
|
+
return { tag: candidate, end: gt + 1 }
|
|
89
|
+
var quote = ""
|
|
90
|
+
var j = i + 1
|
|
91
|
+
while (j < gt) {
|
|
92
|
+
var c = text.charAt(j)
|
|
93
|
+
if (quote !== "") {
|
|
94
|
+
if (c === quote)
|
|
95
|
+
quote = ""
|
|
96
|
+
} else if (c === '"' || c === "'") {
|
|
97
|
+
quote = c
|
|
98
|
+
}
|
|
99
|
+
j++
|
|
100
|
+
}
|
|
101
|
+
if (quote !== "")
|
|
102
|
+
return null
|
|
103
|
+
return { tag: candidate, end: gt + 1 }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Sample input: ' a=b/' keeps the slash in b/; ' ==/' names '=' with value '/'; ' a="b"/' sets the self-closing flag.
|
|
107
|
+
function scanAttributes(rest) {
|
|
108
|
+
var i = 0
|
|
109
|
+
var attributes = []
|
|
110
|
+
var valid = true
|
|
111
|
+
var selfClose = false
|
|
112
|
+
while (i < rest.length) {
|
|
113
|
+
while (i < rest.length && isHtmlWhitespace(rest.charAt(i)))
|
|
114
|
+
i++
|
|
115
|
+
if (i >= rest.length)
|
|
116
|
+
break
|
|
117
|
+
if (rest.charAt(i) === "/") {
|
|
118
|
+
selfClose = i === rest.length - 1
|
|
119
|
+
i++
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
// Before an attribute name, even '=' starts the name; only a later '=' starts its value.
|
|
123
|
+
var aname = rest.charAt(i).toLowerCase()
|
|
124
|
+
i++
|
|
125
|
+
while (i < rest.length && !isHtmlWhitespace(rest.charAt(i))
|
|
126
|
+
&& rest.charAt(i) !== "=" && rest.charAt(i) !== "/" && rest.charAt(i) !== ">") {
|
|
127
|
+
aname += rest.charAt(i).toLowerCase()
|
|
128
|
+
i++
|
|
129
|
+
}
|
|
130
|
+
if (!/^[A-Za-z_:][-A-Za-z0-9_.:]*$/.test(aname))
|
|
131
|
+
valid = false
|
|
132
|
+
while (i < rest.length && isHtmlWhitespace(rest.charAt(i)))
|
|
133
|
+
i++
|
|
134
|
+
var value = null
|
|
135
|
+
if (rest.charAt(i) === "=") {
|
|
136
|
+
i++
|
|
137
|
+
while (i < rest.length && isHtmlWhitespace(rest.charAt(i)))
|
|
138
|
+
i++
|
|
139
|
+
var q = rest.charAt(i)
|
|
140
|
+
if (q === '"' || q === "'") {
|
|
141
|
+
i++
|
|
142
|
+
var start = i
|
|
143
|
+
while (i < rest.length && rest.charAt(i) !== q)
|
|
144
|
+
i++
|
|
145
|
+
value = rest.slice(start, i)
|
|
146
|
+
i++
|
|
147
|
+
} else {
|
|
148
|
+
var begin = i
|
|
149
|
+
while (i < rest.length && !isHtmlWhitespace(rest.charAt(i)) && rest.charAt(i) !== ">")
|
|
150
|
+
i++
|
|
151
|
+
value = rest.slice(begin, i)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
attributes.push({ name: aname, value: value })
|
|
155
|
+
}
|
|
156
|
+
return { attributes: attributes, valid: valid, selfClose: selfClose }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Sample input: '<img src="pic.png"/>' yields name "img", its attributes and a self-closing flag.
|
|
160
|
+
function tagHead(tag) {
|
|
161
|
+
var i = 1
|
|
162
|
+
var closing = false
|
|
163
|
+
if (tag.charAt(i) === "/") {
|
|
164
|
+
closing = true
|
|
165
|
+
i++
|
|
166
|
+
}
|
|
167
|
+
var name = ""
|
|
168
|
+
while (i < tag.length && (isNameChar(tag.charAt(i)) || tag.charAt(i) === "-")) {
|
|
169
|
+
name += tag.charAt(i).toLowerCase()
|
|
170
|
+
i++
|
|
171
|
+
}
|
|
172
|
+
var rest = tag.slice(i, tag.length - 1)
|
|
173
|
+
var slashFirst = rest.charAt(0) === "/"
|
|
174
|
+
var whitespaceEnd = slashFirst ? 1 : 0
|
|
175
|
+
while (whitespaceEnd < rest.length && isHtmlWhitespace(rest.charAt(whitespaceEnd)))
|
|
176
|
+
whitespaceEnd++
|
|
177
|
+
var validHead = /^[a-z]/.test(name)
|
|
178
|
+
&& (rest === "" || isHtmlWhitespace(rest.charAt(0)) || slashFirst)
|
|
179
|
+
&& (!closing || (!slashFirst && whitespaceEnd === rest.length))
|
|
180
|
+
&& (!slashFirst || whitespaceEnd === rest.length)
|
|
181
|
+
// Malformed dropped openers still suppress their bodies; malformed closers cannot end a dropped body.
|
|
182
|
+
if (!validHead && (closing || !DROP_CONTENT.hasOwnProperty(name)))
|
|
183
|
+
name = ""
|
|
184
|
+
var attrs = scanAttributes(rest)
|
|
185
|
+
return { name: name, closing: closing, rest: rest, selfClose: validHead && attrs.valid && attrs.selfClose,
|
|
186
|
+
attributes: attrs.attributes, validAttrs: attrs.valid }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Sample input: " \thttps://a.example/x\n " strips URL padding and embedded tab, CR and LF.
|
|
190
|
+
function normalizedTarget(value) {
|
|
191
|
+
return MdUrl.strippedTarget(value)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// One attribute value with entities decoded for the safety checks below.
|
|
195
|
+
function attrKept(name, value, tagName) {
|
|
196
|
+
var seen = normalizedTarget(MdUrl.canonicalUrl(value)).toLowerCase()
|
|
197
|
+
// CSS url() in any attribute loads, so the attribute goes.
|
|
198
|
+
if (/url\s*\(/i.test(seen))
|
|
199
|
+
return false
|
|
200
|
+
if (name === "href") {
|
|
201
|
+
if (tagName !== "a")
|
|
202
|
+
return false
|
|
203
|
+
// Links never fetch: http, https, mailto, relative and #anchor stay, through every decoding.
|
|
204
|
+
return MdUrl.targetAllowed(value)
|
|
205
|
+
}
|
|
206
|
+
if (name === "src")
|
|
207
|
+
return tagName === "img" || tagName === "source"
|
|
208
|
+
if (name === "color")
|
|
209
|
+
return tagName === "font"
|
|
210
|
+
return GLOBAL_ATTRS.hasOwnProperty(name)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// The opening of an inline code chip; an unusable chrome leaves a plain code tag.
|
|
214
|
+
function chipOpen(chrome) {
|
|
215
|
+
return CHROME_PATTERN.test(String(chrome || "")) ? '<code style="background-color:' + chrome + '">' + MdEscape.chipPad() : "<code>"
|
|
216
|
+
}
|
|
217
|
+
function chipClose(chrome) {
|
|
218
|
+
return CHROME_PATTERN.test(String(chrome || "")) ? MdEscape.chipPad() + "</code>" : "</code>"
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function escapeAttr(value) {
|
|
222
|
+
return String(value).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<")
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Sanitize one tag into {emit, drop}; held image tokens carry resolved URLs, and drop names content to skip. chrome fills the key cap, ink colours a link, inked.open counts the links wearing it.
|
|
226
|
+
function sanitizeTag(tag, dir, tokens, chrome, ink, inked) {
|
|
227
|
+
function hold(html) {
|
|
228
|
+
return holdToken(tokens, html)
|
|
229
|
+
}
|
|
230
|
+
var head = tagHead(tag)
|
|
231
|
+
var name = STRIKE_AS.hasOwnProperty(head.name) ? STRIKE_AS[head.name] : head.name
|
|
232
|
+
if (name.length === 0)
|
|
233
|
+
return { emit: "<", drop: null }
|
|
234
|
+
if (DROP_CONTENT.hasOwnProperty(name))
|
|
235
|
+
return { emit: "", drop: head.closing || head.selfClose ? null : name }
|
|
236
|
+
if (!ALLOWED.hasOwnProperty(name))
|
|
237
|
+
return { emit: "", drop: null }
|
|
238
|
+
// details is drawn open: its summary is a bold line led by the open disclosure mark, and its body follows.
|
|
239
|
+
if (name === "details")
|
|
240
|
+
return { emit: "", drop: null }
|
|
241
|
+
if (name === "summary")
|
|
242
|
+
return { emit: head.closing ? "</b>" : "<b>" + DISCLOSURE_OPEN + " ", drop: null }
|
|
243
|
+
// kbd and code are the inline code chip, never a bare tag.
|
|
244
|
+
if (name === "kbd" || name === "code")
|
|
245
|
+
return { emit: head.closing ? chipClose(chrome) : chipOpen(chrome), drop: null }
|
|
246
|
+
var wear = name === "a" ? MdInline.linkInk(ink) : null
|
|
247
|
+
// A closer takes off only ink its own opener put on, so a refused, self-closed or missing opener never ends an enclosing font.
|
|
248
|
+
if (head.closing) {
|
|
249
|
+
var worn = wear !== null && inked.open > 0
|
|
250
|
+
if (worn)
|
|
251
|
+
inked.open--
|
|
252
|
+
return { emit: (worn ? wear.close : "") + "</" + name + ">", drop: null }
|
|
253
|
+
}
|
|
254
|
+
if (!head.validAttrs)
|
|
255
|
+
return { emit: "", drop: null }
|
|
256
|
+
var kept = ""
|
|
257
|
+
var srcSeen = null
|
|
258
|
+
var srcsetSeen = null
|
|
259
|
+
var altSeen = null
|
|
260
|
+
for (var i = 0; i < head.attributes.length; i++) {
|
|
261
|
+
var aname = head.attributes[i].name
|
|
262
|
+
var value = head.attributes[i].value
|
|
263
|
+
// Every style, class, id, background, srcset, poster, data-* and on* attribute is dropped, whatever its value.
|
|
264
|
+
if (aname === "style" || aname === "class" || aname === "id"
|
|
265
|
+
|| aname === "background" || aname === "poster"
|
|
266
|
+
|| aname.indexOf("data-") === 0 || aname.indexOf("on") === 0)
|
|
267
|
+
continue
|
|
268
|
+
if (aname === "srcset") {
|
|
269
|
+
if (srcsetSeen === null)
|
|
270
|
+
srcsetSeen = value === null ? "" : value
|
|
271
|
+
continue
|
|
272
|
+
}
|
|
273
|
+
if (aname === "src" && (name === "img" || name === "source")) {
|
|
274
|
+
if (srcSeen === null)
|
|
275
|
+
srcSeen = value === null ? "" : value
|
|
276
|
+
continue
|
|
277
|
+
}
|
|
278
|
+
if (aname === "alt") {
|
|
279
|
+
if (altSeen !== null)
|
|
280
|
+
continue
|
|
281
|
+
altSeen = value === null ? "" : value
|
|
282
|
+
}
|
|
283
|
+
if (aname === "href" && value !== null)
|
|
284
|
+
value = normalizedTarget(value)
|
|
285
|
+
if (value === null || attrKept(aname, value, name))
|
|
286
|
+
kept += " " + aname + (value === null ? "" : '="' + escapeAttr(value) + '"')
|
|
287
|
+
}
|
|
288
|
+
if (name === "img" || name === "source") {
|
|
289
|
+
var picked = null
|
|
290
|
+
if (srcSeen !== null)
|
|
291
|
+
picked = MdUrl.classifyImage(srcSeen, dir)
|
|
292
|
+
else if (srcsetSeen !== null)
|
|
293
|
+
picked = MdUrl.srcsetPick(srcsetSeen, dir)
|
|
294
|
+
// The importer drops everything after a raw img tag, so a local picture reaches it as a Markdown image.
|
|
295
|
+
if (picked !== null && picked.kind === "local")
|
|
296
|
+
return { emit: hold(".replace(/\)/g, "%29") + ")"), drop: null }
|
|
298
|
+
if (picked !== null && picked.kind === "remote")
|
|
299
|
+
return { emit: "\n\n" + MdUrl.placeholder(MdEscape.escapeText(picked.host)) + "\n\n", drop: null }
|
|
300
|
+
return { emit: MdUrl.canonicalUrl(altSeen).length > 0 ? MdEscape.escapeText(altSeen) : "", drop: null }
|
|
301
|
+
}
|
|
302
|
+
var close = (head.selfClose || VOID.hasOwnProperty(name)) ? " /" : ""
|
|
303
|
+
var wears = wear !== null && close === ""
|
|
304
|
+
if (wears)
|
|
305
|
+
inked.open++
|
|
306
|
+
return { emit: "<" + name + kept + close + ">" + (wears ? wear.open : ""), drop: null }
|
|
307
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// MdHtmlBlock: images leave an HTML block as image blocks, and top-level HTML blocks start their own lines.
|
|
4
|
+
.import "MdHtml.js" as MdHtml
|
|
5
|
+
.import "MdHtmlImage.js" as HtmlImage
|
|
6
|
+
|
|
7
|
+
// The names CommonMark starts an HTML block with, and one complete tag alone on its line, which starts one only outside a paragraph.
|
|
8
|
+
var BLOCK_NAMES = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul"
|
|
9
|
+
// Sample input: '<div align="center">' and ' </table>' start an HTML block; '<span>x</span>' and 'text <div>' do not.
|
|
10
|
+
var BLOCK_START = new RegExp("^ {0,3}<\\/?(?:" + BLOCK_NAMES + ")(?:[\\s>]|\\/>|$)", "i")
|
|
11
|
+
// Sample input: '<a href="x">' and '</span>' alone on a line are complete tags; '<a href="x">text' is not.
|
|
12
|
+
var COMPLETE_TAG = /^ {0,3}(?:<[A-Za-z][A-Za-z0-9-]*(?:\s[^<>]*)?\/?>|<\/[A-Za-z][A-Za-z0-9-]*\s*>)\s*$/
|
|
13
|
+
// Sample input: 'x <a href="https://y">' ends with a link opener, which the text before an image holds when the image sits in a link.
|
|
14
|
+
var LINK_BEFORE = /<a\b[^<>]*>\s*$/i
|
|
15
|
+
// Sample input: '</a>' and '</A>' close the link around an image; the four characters after the image are tested against it.
|
|
16
|
+
var LINK_CLOSE = /^<\/a>$/i
|
|
17
|
+
var LINK_CLOSE_LENGTH = "</a>".length
|
|
18
|
+
// Sample input: 'A<IMG' holds the capital letters asciiLower lowers, by their distance from lower case.
|
|
19
|
+
var UPPER_ASCII = /[A-Z]/g
|
|
20
|
+
var CASE_OFFSET = "a".charCodeAt(0) - "A".charCodeAt(0)
|
|
21
|
+
// Sample input: '<p align="center"><b>x</b>' and '<center>' open a block that may centre; '<span>' and 'text' do not.
|
|
22
|
+
var CENTRED_OPEN = /^\s*<(?:p|div|center)\b[^<>]*>/i
|
|
23
|
+
// Sample input: 'a <div>b</div>' and '<h1 align="center">' hold a block tag that centres itself; '<b>x</b>' holds none.
|
|
24
|
+
var BLOCK_TAG = /<(?:p|div|h[1-6]|table|ul|ol|blockquote|pre)\b/i
|
|
25
|
+
// Sample input: '</p><p>' and '<div align="center">' open or close a block, so pictures either side of them sit on lines of their own; '<b>' and '</td><td>' do not.
|
|
26
|
+
var BLOCK_BOUNDARY = /<\/?(?:p|div|h[1-6]|table|tr|ul|ol|li|blockquote|pre)\b/i
|
|
27
|
+
// Sample input: '<br>' and '<BR />' break a line.
|
|
28
|
+
var BREAK_TAG = /<br\b[^<>]*>/i
|
|
29
|
+
// The most pictures one images block holds.
|
|
30
|
+
var ROW_IMAGE_CAP = 64
|
|
31
|
+
var CENTRED_WRAP = '<p align="center">'
|
|
32
|
+
// The elements that start their own line, and the ones that nest and so are counted open and closed.
|
|
33
|
+
// Sample input: '<h1 align="center">Flea</h1>' and ' <details open>' start a line of their own; '<b>x</b>' does not.
|
|
34
|
+
var LINE_OPENER = /^ {0,3}<(?:p|div|h[1-6]|details|summary|hr|table|ul|ol|blockquote|pre)(?=[\s>\/])/i
|
|
35
|
+
// Sample input: '<div class="x">' answers slash "" and '</div>' answers "/"; '<b>' and '<divider>' match nothing.
|
|
36
|
+
var NESTING_TAG = /<(\/?)(?:p|div|h[1-6]|details|summary|table|ul|ol|blockquote|pre)(?=[\s>\/])[^<>]*>/gi
|
|
37
|
+
// Sample input: '<b>' answers slash "" and name "b"; '</p>' answers "/" and "p"; text with no angle bracket matches nothing.
|
|
38
|
+
var ANY_TAG = /<(\/?)([A-Za-z][A-Za-z0-9]*)[^<>]*>/g
|
|
39
|
+
|
|
40
|
+
// Sample input: '<IMG SRC>' after a U+0130 answers '<img src>'; only A to Z change, so an index in the answer is an index in the text.
|
|
41
|
+
function asciiLower(text) {
|
|
42
|
+
return text.replace(UPPER_ASCII, function (letter) { return String.fromCharCode(letter.charCodeAt(0) + CASE_OFFSET) })
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Sample input: '<td><img src="a.png"></td>' from 0 answers { start: 4, end: 24, block }; remote and unreadable images answer null.
|
|
46
|
+
// lower is the line in asciiLower form and dead its tag cache, made once per line, so a row of many images costs one pass.
|
|
47
|
+
function findImage(line, lower, from, dead, dir) {
|
|
48
|
+
var at = lower.indexOf("<img", from)
|
|
49
|
+
while (at >= 0) {
|
|
50
|
+
var tag = MdHtml.readTag(line, at, dead)
|
|
51
|
+
var block = tag === null ? null : HtmlImage.rawImage(tag.tag, dir)
|
|
52
|
+
if (block !== null && block.type === "image")
|
|
53
|
+
return { start: at, end: tag.end, block: block }
|
|
54
|
+
at = lower.indexOf("<img", at + 1)
|
|
55
|
+
}
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Sample input: '<td>a</p>' drops the closer no opener in the text matches; text with its own pairs is unchanged.
|
|
60
|
+
function withoutStrayClosers(text) {
|
|
61
|
+
var open = {}
|
|
62
|
+
return text.replace(ANY_TAG, function (tag, slash, name) {
|
|
63
|
+
var key = name.toLowerCase()
|
|
64
|
+
if (slash === "") {
|
|
65
|
+
open[key] = (open[key] || 0) + 1
|
|
66
|
+
return tag
|
|
67
|
+
}
|
|
68
|
+
if (open[key] > 0) {
|
|
69
|
+
open[key]--
|
|
70
|
+
return tag
|
|
71
|
+
}
|
|
72
|
+
return ""
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// What stays of the lines around an extracted image: lines with visible text, their stray closers gone, centred when its block was.
|
|
77
|
+
function remainder(kept, centred) {
|
|
78
|
+
var split = withoutStrayClosers(kept.join("\n")).split("\n")
|
|
79
|
+
var lines = []
|
|
80
|
+
// A line that holds a block tag of its own centres itself; wrapping it would nest the paragraphs.
|
|
81
|
+
var nests = false
|
|
82
|
+
for (var i = 0; i < split.length; i++) {
|
|
83
|
+
// A line holding an image the splitter did not take (a remote one) draws its placeholder, so it stays.
|
|
84
|
+
if (split[i].replace(ANY_TAG, "").trim().length === 0 && !/<(?:hr|img)\b/i.test(split[i]))
|
|
85
|
+
continue
|
|
86
|
+
lines.push(split[i])
|
|
87
|
+
nests = nests || BLOCK_TAG.test(split[i])
|
|
88
|
+
}
|
|
89
|
+
if (lines.length > 0)
|
|
90
|
+
lines[0] = lines[0].replace(HtmlImage.LEADING_BREAK, "")
|
|
91
|
+
return lines.length === 0 ? [] : centred && !nests ? [CENTRED_WRAP + lines.join("\n") + "</p>"] : lines
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Sample input: images a and b with nothing between them answer [{ block: { type: "images", items: [a, b] } }]; one image, text or a row break keeps them apart.
|
|
95
|
+
// A row longer than ROW_IMAGE_CAP continues in the next block, so no block builds an unbounded number of pictures at once.
|
|
96
|
+
function imageRows(parts) {
|
|
97
|
+
var out = []
|
|
98
|
+
var row = []
|
|
99
|
+
function close() {
|
|
100
|
+
for (var at = 0; at < row.length; at += ROW_IMAGE_CAP) {
|
|
101
|
+
var items = row.slice(at, at + ROW_IMAGE_CAP)
|
|
102
|
+
if (items.length === 1) {
|
|
103
|
+
out.push({ block: items[0] })
|
|
104
|
+
continue
|
|
105
|
+
}
|
|
106
|
+
var rows = { type: "images", items: items }
|
|
107
|
+
if (items[0].align !== undefined)
|
|
108
|
+
rows.align = items[0].align
|
|
109
|
+
for (var r = 0; r < items.length; r++)
|
|
110
|
+
delete items[r].align
|
|
111
|
+
out.push({ block: rows })
|
|
112
|
+
}
|
|
113
|
+
row = []
|
|
114
|
+
}
|
|
115
|
+
for (var i = 0; i < parts.length; i++) {
|
|
116
|
+
if (parts[i].block !== undefined) {
|
|
117
|
+
row.push(parts[i].block)
|
|
118
|
+
} else {
|
|
119
|
+
close()
|
|
120
|
+
if (parts[i].lines !== undefined)
|
|
121
|
+
out.push(parts[i])
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
close()
|
|
125
|
+
return out
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// One HTML block's lines as parts, each a { lines } to parse or a { block } image; the block's wrappers do not outlive its image.
|
|
129
|
+
function splitBlock(group, dir) {
|
|
130
|
+
var centred = CENTRED_OPEN.test(group[0]) && (/^\s*<center\b/i.test(group[0]) || HtmlImage.isCentred(CENTRED_OPEN.exec(group[0])[0]))
|
|
131
|
+
var parts = []
|
|
132
|
+
var kept = []
|
|
133
|
+
var found = false
|
|
134
|
+
function flush() {
|
|
135
|
+
var lines = remainder(kept, centred)
|
|
136
|
+
// A line break or a block boundary between two images starts the next row.
|
|
137
|
+
var between = kept.join("\n")
|
|
138
|
+
var broke = BREAK_TAG.test(between) || BLOCK_BOUNDARY.test(between)
|
|
139
|
+
kept = []
|
|
140
|
+
if (lines.length > 0)
|
|
141
|
+
parts.push({ lines: lines })
|
|
142
|
+
else if (broke)
|
|
143
|
+
parts.push({ rowBreak: true })
|
|
144
|
+
}
|
|
145
|
+
for (var i = 0; i < group.length; i++) {
|
|
146
|
+
var line = group[i]
|
|
147
|
+
var lower = asciiLower(line)
|
|
148
|
+
var dead = { tagDead: -1 }
|
|
149
|
+
// The scan walks the line by position, so a line of many images is cut once, never once per image.
|
|
150
|
+
var from = 0
|
|
151
|
+
for (var hit = findImage(line, lower, from, dead, dir); hit !== null; hit = findImage(line, lower, from, dead, dir)) {
|
|
152
|
+
var before = line.slice(from, hit.start)
|
|
153
|
+
var wrap = LINK_BEFORE.exec(before)
|
|
154
|
+
// The link closer follows the image after optional whitespace.
|
|
155
|
+
var next = hit.end
|
|
156
|
+
while (next < line.length && /\s/.test(line.charAt(next)))
|
|
157
|
+
next++
|
|
158
|
+
from = hit.end
|
|
159
|
+
if (wrap !== null && LINK_CLOSE.test(line.slice(next, next + LINK_CLOSE_LENGTH))) {
|
|
160
|
+
if (HtmlImage.linkOf(wrap[0]) !== null)
|
|
161
|
+
hit.block.link = HtmlImage.linkOf(wrap[0])
|
|
162
|
+
before = before.slice(0, wrap.index)
|
|
163
|
+
from = next + LINK_CLOSE_LENGTH
|
|
164
|
+
}
|
|
165
|
+
kept.push(before)
|
|
166
|
+
flush()
|
|
167
|
+
if (centred)
|
|
168
|
+
hit.block.align = "center"
|
|
169
|
+
parts.push({ block: hit.block })
|
|
170
|
+
found = true
|
|
171
|
+
}
|
|
172
|
+
kept.push(line.slice(from))
|
|
173
|
+
}
|
|
174
|
+
flush()
|
|
175
|
+
return found ? imageRows(parts) : [{ lines: group }]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Sample input: ['<table><tr><td><img src="a.png"></td></tr></table>'] answers [{ block }]; a paragraph's inline image stays in its lines.
|
|
179
|
+
// The importer draws no Markdown inside an HTML block and drops a raw img with all that follows it, so a block's images leave it.
|
|
180
|
+
function splitHtmlImages(lines, dir) {
|
|
181
|
+
var parts = []
|
|
182
|
+
var text = []
|
|
183
|
+
var group = null
|
|
184
|
+
var paragraph = false
|
|
185
|
+
function closeGroup() {
|
|
186
|
+
if (group !== null) {
|
|
187
|
+
var split = splitBlock(group, dir)
|
|
188
|
+
for (var s = 0; s < split.length; s++)
|
|
189
|
+
parts.push(split[s])
|
|
190
|
+
}
|
|
191
|
+
group = null
|
|
192
|
+
}
|
|
193
|
+
function closeText() {
|
|
194
|
+
if (text.length > 0)
|
|
195
|
+
parts.push({ lines: text })
|
|
196
|
+
text = []
|
|
197
|
+
}
|
|
198
|
+
for (var i = 0; i < lines.length; i++) {
|
|
199
|
+
var line = lines[i]
|
|
200
|
+
if (line.trim().length === 0) {
|
|
201
|
+
closeGroup()
|
|
202
|
+
text.push(line)
|
|
203
|
+
paragraph = false
|
|
204
|
+
} else if (group !== null) {
|
|
205
|
+
group.push(line)
|
|
206
|
+
} else if (BLOCK_START.test(line) || (!paragraph && COMPLETE_TAG.test(line))) {
|
|
207
|
+
closeText()
|
|
208
|
+
group = [line]
|
|
209
|
+
} else {
|
|
210
|
+
paragraph = true
|
|
211
|
+
text.push(line)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
closeGroup()
|
|
215
|
+
closeText()
|
|
216
|
+
// Lines the split left alone stay one run, as the importer joins an HTML block with the paragraph after it.
|
|
217
|
+
var merged = []
|
|
218
|
+
for (var k = 0; k < parts.length; k++) {
|
|
219
|
+
var last = merged.length - 1
|
|
220
|
+
if (last >= 0 && merged[last].lines !== undefined && parts[k].lines !== undefined) {
|
|
221
|
+
for (var m = 0; m < parts[k].lines.length; m++)
|
|
222
|
+
merged[last].lines.push(parts[k].lines[m])
|
|
223
|
+
} else {
|
|
224
|
+
merged.push(parts[k].lines === undefined ? parts[k] : { lines: parts[k].lines.slice(0) })
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return merged
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Sample input: ['<h1>A</h1>', '<p>B</p>'] answers ['<h1>A</h1>', '', '<p>B</p>']; a block nested in an open one stays on its line.
|
|
231
|
+
// The importer draws adjacent HTML block lines as one line, so each top-level block starts after a blank line.
|
|
232
|
+
function separateBlocks(lines) {
|
|
233
|
+
var out = []
|
|
234
|
+
var depth = 0
|
|
235
|
+
for (var i = 0; i < lines.length; i++) {
|
|
236
|
+
var line = lines[i]
|
|
237
|
+
if (line.trim().length === 0)
|
|
238
|
+
depth = 0
|
|
239
|
+
else if (depth === 0 && out.length > 0 && out[out.length - 1].trim().length > 0 && LINE_OPENER.test(line))
|
|
240
|
+
out.push("")
|
|
241
|
+
out.push(line)
|
|
242
|
+
line.replace(NESTING_TAG, function (tag, slash) {
|
|
243
|
+
depth = slash === "/" ? Math.max(0, depth - 1) : depth + 1
|
|
244
|
+
return tag
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
return out
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// The six heading levels by tag name, so an HTML heading maps to its Markdown level.
|
|
251
|
+
var HEADING_LEVEL = { h1: 1, h2: 2, h3: 3, h4: 4, h5: 5, h6: 6 }
|
|
252
|
+
// The shortest heading line that holds text, "<h1>x</h1>": anything shorter is never one.
|
|
253
|
+
var HEADING_SHORTEST = 10
|
|
254
|
+
// Sample input: '<h1 align="center">Flea</h1>' answers level 1 with centre and inner Flea; '<h2>x</h2> tail' answers null.
|
|
255
|
+
function htmlHeading(line) {
|
|
256
|
+
var text = String(line).trim()
|
|
257
|
+
if (text.length < HEADING_SHORTEST)
|
|
258
|
+
return null
|
|
259
|
+
var open = MdHtml.readTag(text, 0, null)
|
|
260
|
+
if (open === null || open.end <= 0)
|
|
261
|
+
return null
|
|
262
|
+
var head = MdHtml.tagHead(open.tag)
|
|
263
|
+
var level = HEADING_LEVEL[head.name]
|
|
264
|
+
if (level === undefined || head.closing)
|
|
265
|
+
return null
|
|
266
|
+
var rest = text.slice(open.end)
|
|
267
|
+
var lower = asciiLower(rest)
|
|
268
|
+
var closeName = "</h" + level
|
|
269
|
+
var closeAt = lower.indexOf(closeName)
|
|
270
|
+
if (closeAt < 0)
|
|
271
|
+
return null
|
|
272
|
+
var close = MdHtml.readTag(text, open.end + closeAt, null)
|
|
273
|
+
if (close === null || close.end !== text.length)
|
|
274
|
+
return null
|
|
275
|
+
var closeHead = MdHtml.tagHead(close.tag)
|
|
276
|
+
if (closeHead.name !== head.name || !closeHead.closing)
|
|
277
|
+
return null
|
|
278
|
+
var inner = rest.slice(0, closeAt)
|
|
279
|
+
var align = null
|
|
280
|
+
var aligned = false
|
|
281
|
+
for (var i = 0; i < head.attributes.length; i++) {
|
|
282
|
+
if (head.attributes[i].name === "align" && head.attributes[i].value !== null) {
|
|
283
|
+
aligned = true
|
|
284
|
+
var seen = head.attributes[i].value.toLowerCase()
|
|
285
|
+
if (seen === "center" || seen === "right")
|
|
286
|
+
align = seen
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return { level: level, align: align, aligned: aligned, inner: inner }
|
|
290
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// MdHtmlHeading: an HTML heading inside a wrapper or opening with a picture, lifted whole so no wrapper is split and no picture sits in a text line.
|
|
4
|
+
.import "MdHtml.js" as MdHtml
|
|
5
|
+
.import "MdHtmlImage.js" as HtmlImage
|
|
6
|
+
.import "MdHtmlBlock.js" as HtmlBlock
|
|
7
|
+
|
|
8
|
+
// Sample input: drawn heading text 'Flea' or '<img src="a.png">' holds a picture; 'Flea' and 'Wow!\[beta]' hold none.
|
|
9
|
+
var DRAWN_PICTURE = /<img\b|!\[(?:\\.|[^\]\\])*\]\(/i
|
|
10
|
+
|
|
11
|
+
// Sample input: ['<div align="center">', '<h1>Flea</h1>', '<p>x</p>', '</div>'] at 0 answers { head, end: 3, wrapper: ['<div align="center"><p>x</p></div>'] }; a heading with no lone wrapper before it, or a wrapper that cannot be matched, answers null.
|
|
12
|
+
// The heading lifts out with its own align, else the wrapper's centre; what the wrapper held after it is drawn centred as it was.
|
|
13
|
+
function headingUnit(lines, at) {
|
|
14
|
+
var open = String(lines[at]).trim()
|
|
15
|
+
if (!HtmlImage.WRAPPER_OPEN.test(open) || at + 1 >= lines.length)
|
|
16
|
+
return null
|
|
17
|
+
var head = HtmlBlock.htmlHeading(lines[at + 1])
|
|
18
|
+
if (head === null)
|
|
19
|
+
return null
|
|
20
|
+
var name = MdHtml.tagHead(open).name
|
|
21
|
+
var tail = HtmlImage.wrapperTail(lines, at + 2, name)
|
|
22
|
+
if (tail === null)
|
|
23
|
+
return null
|
|
24
|
+
if (!head.aligned && HtmlImage.isCentred(open))
|
|
25
|
+
head.align = "center"
|
|
26
|
+
var shown = tail.rest.filter(function (line) { return line.length > 0 })
|
|
27
|
+
return { head: head, end: tail.end, wrapper: shown.length === 0 ? [] : [open + shown.join("\n") + "</" + name + ">"] }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Sample input: ('<div>', 0) answers 1 and ('</div>', 1) answers 0; a line with no block tag leaves the depth as it was.
|
|
31
|
+
// The open block HTML a run holds after a line, so a heading is judged inside open HTML by what the lines before it left open.
|
|
32
|
+
function nestDepth(line, depth) {
|
|
33
|
+
line.replace(HtmlBlock.NESTING_TAG, function (tag, slash) {
|
|
34
|
+
depth = slash === "/" ? Math.max(0, depth - 1) : depth + 1
|
|
35
|
+
return tag
|
|
36
|
+
})
|
|
37
|
+
return depth
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Sample input: '<a href="https://x/"><img src="logo.png" width="120"></a><br>Flea' answers { block: the linked image, rest: 'Flea' }; text first answers null.
|
|
41
|
+
var HEADING_PICTURE = /^\s*(<a\b[^<>]*>)?\s*(<img\b[^<>]*>)\s*(<\/a>)?\s*(?:<br\s*\/?>\s*)*/i
|
|
42
|
+
// A picture opening a heading's text draws through the picture path, so it is sized and fetched there and never sits in a text line.
|
|
43
|
+
function headingPicture(inner, dir) {
|
|
44
|
+
var parts = HEADING_PICTURE.exec(inner)
|
|
45
|
+
if (parts === null || (parts[1] === undefined) !== (parts[3] === undefined))
|
|
46
|
+
return null
|
|
47
|
+
var block = HtmlImage.rawImage(parts[2], dir)
|
|
48
|
+
if (block === null)
|
|
49
|
+
return null
|
|
50
|
+
if (parts[1] !== undefined && block.type === "image" && HtmlImage.linkOf(parts[1]) !== null)
|
|
51
|
+
block.link = HtmlImage.linkOf(parts[1])
|
|
52
|
+
return { block: block, rest: inner.slice(parts[0].length) }
|
|
53
|
+
}
|