bookish-press 0.4.45 → 0.4.47
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/.env.example +8 -0
- package/.firebaserc +8 -0
- package/.prettierignore +8 -0
- package/.prettierrc.json +5 -0
- package/_update-notifier-last-checked +0 -0
- package/firebase.json +46 -0
- package/firestore.indexes.json +4 -0
- package/firestore.rules +59 -0
- package/functions/.eslintrc.js +28 -0
- package/functions/package-lock.json +12595 -0
- package/functions/package.json +43 -0
- package/functions/src/index.ts +345 -0
- package/functions/tsconfig.dev.json +3 -0
- package/functions/tsconfig.json +15 -0
- package/package.json +53 -270
- package/scripts/claims.cjs +99 -0
- package/src/app.d.ts +9 -0
- package/src/app.html +24 -0
- package/src/lib/components/Auth.svelte +65 -0
- package/{components/Authentication.d.ts → src/lib/components/Authentication.ts} +2 -0
- package/{components → src/lib/components}/BookPreview.svelte +27 -22
- package/{components → src/lib/components}/External.svelte +2 -1
- package/src/lib/components/Link.svelte +58 -0
- package/{components → src/lib/components}/app/BookList.svelte +6 -3
- package/{components → src/lib/components}/app/Button.svelte +5 -4
- package/{components → src/lib/components}/app/Feedback.svelte +11 -7
- package/{components → src/lib/components}/app/Head.svelte +2 -1
- package/{components → src/lib/components}/app/Large.svelte +0 -0
- package/{components → src/lib/components}/app/Lead.svelte +0 -0
- package/{components → src/lib/components}/app/Link.svelte +4 -3
- package/{components → src/lib/components}/app/Options.svelte +5 -4
- package/{components → src/lib/components}/app/Paragraph.svelte +2 -1
- package/{components → src/lib/components}/app/Section.svelte +0 -0
- package/{components → src/lib/components}/app/Table.svelte +0 -0
- package/{components → src/lib/components}/app/TextInput.svelte +12 -9
- package/{components → src/lib/components}/chapter/Atom.svelte +18 -12
- package/src/lib/components/chapter/Block.svelte +42 -0
- package/{components → src/lib/components}/chapter/Callout.svelte +6 -3
- package/{components → src/lib/components}/chapter/CaptionedCode.svelte +21 -13
- package/{components → src/lib/components}/chapter/ChapterBody.svelte +13 -9
- package/{components → src/lib/components}/chapter/Citations.svelte +34 -33
- package/{components → src/lib/components}/chapter/Code.svelte +63 -58
- package/{components → src/lib/components}/chapter/Comment.svelte +30 -18
- package/{components → src/lib/components}/chapter/Definition.svelte +23 -17
- package/{components → src/lib/components}/chapter/Embed.svelte +97 -77
- package/src/lib/components/chapter/ErrorMessage.svelte +12 -0
- package/{components → src/lib/components}/chapter/ExtendedPrism.js +0 -0
- package/{components → src/lib/components}/chapter/Figure.svelte +34 -26
- package/{components → src/lib/components}/chapter/Footnote.svelte +32 -20
- package/{components → src/lib/components}/chapter/Format.svelte +39 -34
- package/{components → src/lib/components}/chapter/InlineCode.svelte +9 -5
- package/{components → src/lib/components}/chapter/Label.svelte +23 -14
- package/{components → src/lib/components}/chapter/Link.svelte +27 -21
- package/{components → src/lib/components}/chapter/List.svelte +5 -3
- package/{components → src/lib/components}/chapter/Marginal.svelte +54 -41
- package/{components → src/lib/components}/chapter/Paragraph.svelte +25 -20
- package/{components → src/lib/components}/chapter/Positioned.svelte +4 -1
- package/{components → src/lib/components}/chapter/Problem.svelte +0 -0
- package/src/lib/components/chapter/Python.svelte +144 -0
- package/{components → src/lib/components}/chapter/Quote.svelte +9 -5
- package/{components → src/lib/components}/chapter/Rule.svelte +4 -1
- package/{components → src/lib/components}/chapter/Table.svelte +11 -7
- package/src/lib/components/chapter/Text.svelte +109 -0
- package/src/lib/components/editor/BookishEditor.svelte +1101 -0
- package/src/lib/components/editor/CalloutEditor.svelte +14 -0
- package/{components → src/lib/components}/editor/CaptionedCodeEditor.svelte +10 -6
- package/src/lib/components/editor/CaretContext.ts +55 -0
- package/{components/editor/CaretState.d.ts → src/lib/components/editor/CaretState.ts} +6 -7
- package/{components/editor/CaretUtilities.d.ts → src/lib/components/editor/CaretUtilities.ts} +1 -0
- package/{components → src/lib/components}/editor/CaretView.svelte +25 -20
- package/src/lib/components/editor/CitationsEditor.svelte +64 -0
- package/{components/editor/Clipboard.d.ts → src/lib/components/editor/Clipboard.ts} +2 -1
- package/{components/editor/Command.d.ts → src/lib/components/editor/Command.ts} +8 -2
- package/{components/editor/Commands.js → src/lib/components/editor/Commands.ts} +730 -315
- package/src/lib/components/editor/ConfirmButton.svelte +51 -0
- package/src/lib/components/editor/DefinitionEditor.svelte +44 -0
- package/src/lib/components/editor/EmbedEditor.svelte +152 -0
- package/{components → src/lib/components}/editor/Icon.svelte +2 -1
- package/{components → src/lib/components}/editor/ImageChooser.svelte +24 -19
- package/src/lib/components/editor/InlineCodeEditor.svelte +16 -0
- package/{components → src/lib/components}/editor/LabelEditor.svelte +14 -9
- package/{components → src/lib/components}/editor/LanguageEditor.svelte +8 -5
- package/src/lib/components/editor/LinkEditor.svelte +110 -0
- package/{components → src/lib/components}/editor/Note.svelte +0 -0
- package/{components → src/lib/components}/editor/Permissions.svelte +43 -36
- package/src/lib/components/editor/PositionEditor.svelte +21 -0
- package/src/lib/components/editor/QuoteEditor.svelte +14 -0
- package/{components → src/lib/components}/editor/Switch.svelte +14 -11
- package/src/lib/components/editor/TableEditor.svelte +14 -0
- package/{components → src/lib/components}/editor/TextEditor.svelte +101 -89
- package/src/lib/components/editor/Toggle.svelte +47 -0
- package/src/lib/components/editor/Toolbar.svelte +297 -0
- package/{components → src/lib/components}/editor/ToolbarGroup.svelte +5 -3
- package/{components → src/lib/components}/editor/ToolbarSpacer.svelte +0 -0
- package/src/lib/components/editor/URLEditor.svelte +15 -0
- package/{components/editor/UndoState.d.ts → src/lib/components/editor/UndoState.ts} +3 -2
- package/{components → src/lib/components}/editor/icons/annotate.svg +0 -0
- package/{components → src/lib/components}/editor/icons/block.svg +0 -0
- package/{components → src/lib/components}/editor/icons/bold.svg +0 -0
- package/{components → src/lib/components}/editor/icons/bullets.svg +0 -0
- package/{components → src/lib/components}/editor/icons/callout.svg +0 -0
- package/{components → src/lib/components}/editor/icons/citation.svg +0 -0
- package/{components → src/lib/components}/editor/icons/clear.svg +0 -0
- package/{components → src/lib/components}/editor/icons/clipboard.svg +0 -0
- package/{components → src/lib/components}/editor/icons/code.svg +0 -0
- package/{components → src/lib/components}/editor/icons/columnafter.svg +0 -0
- package/{components → src/lib/components}/editor/icons/columnbefore.svg +0 -0
- package/{components → src/lib/components}/editor/icons/comment.svg +0 -0
- package/{components → src/lib/components}/editor/icons/copy.svg +0 -0
- package/{components → src/lib/components}/editor/icons/cut.svg +0 -0
- package/{components → src/lib/components}/editor/icons/define.svg +0 -0
- package/{components → src/lib/components}/editor/icons/deletecolumn.svg +0 -0
- package/{components → src/lib/components}/editor/icons/deleterow.svg +0 -0
- package/{components → src/lib/components}/editor/icons/footnote.svg +0 -0
- package/{components → src/lib/components}/editor/icons/header1.svg +0 -0
- package/{components → src/lib/components}/editor/icons/header2.svg +0 -0
- package/{components → src/lib/components}/editor/icons/header3.svg +0 -0
- package/{components → src/lib/components}/editor/icons/home.svg +0 -0
- package/{components → src/lib/components}/editor/icons/indent.svg +0 -0
- package/{components → src/lib/components}/editor/icons/italic.svg +0 -0
- package/{components → src/lib/components}/editor/icons/label.svg +0 -0
- package/{components → src/lib/components}/editor/icons/left.svg +0 -0
- package/{components → src/lib/components}/editor/icons/level.svg +0 -0
- package/{components → src/lib/components}/editor/icons/link.svg +0 -0
- package/{components → src/lib/components}/editor/icons/list.svg +0 -0
- package/{components → src/lib/components}/editor/icons/media.svg +0 -0
- package/{components → src/lib/components}/editor/icons/middle.svg +0 -0
- package/{components → src/lib/components}/editor/icons/numbers.svg +0 -0
- package/{components → src/lib/components}/editor/icons/paragraph.svg +0 -0
- package/{components → src/lib/components}/editor/icons/paste.svg +0 -0
- package/{components → src/lib/components}/editor/icons/quote.svg +0 -0
- package/{components → src/lib/components}/editor/icons/redo.svg +0 -0
- package/{components → src/lib/components}/editor/icons/right.svg +0 -0
- package/{components → src/lib/components}/editor/icons/rowabove.svg +0 -0
- package/{components → src/lib/components}/editor/icons/rowbelow.svg +0 -0
- package/{components → src/lib/components}/editor/icons/rule.svg +0 -0
- package/{components → src/lib/components}/editor/icons/sub.svg +0 -0
- package/{components → src/lib/components}/editor/icons/super.svg +0 -0
- package/{components → src/lib/components}/editor/icons/table.svg +0 -0
- package/{components → src/lib/components}/editor/icons/text.svg +0 -0
- package/{components → src/lib/components}/editor/icons/time.svg +0 -0
- package/{components → src/lib/components}/editor/icons/undo.svg +0 -0
- package/{components → src/lib/components}/editor/icons/unindent.svg +0 -0
- package/{components → src/lib/components}/editor/icons/unlink.svg +0 -0
- package/{components → src/lib/components}/page/Acknowledgements.svelte +19 -10
- package/src/lib/components/page/Authors.svelte +92 -0
- package/src/lib/components/page/BookLoader.svelte +77 -0
- package/src/lib/components/page/BulkReferenceEditor.svelte +86 -0
- package/src/lib/components/page/Chapter.svelte +449 -0
- package/src/lib/components/page/ChapterContext.ts +13 -0
- package/{components → src/lib/components}/page/ChapterNumber.svelte +0 -0
- package/{components → src/lib/components}/page/ChapterTitle.svelte +4 -2
- package/src/lib/components/page/Contexts.ts +176 -0
- package/{components → src/lib/components}/page/DefinitionView.svelte +52 -37
- package/{components → src/lib/components}/page/Description.svelte +15 -7
- package/src/lib/components/page/Edition.svelte +189 -0
- package/src/lib/components/page/EditionLoader.svelte +123 -0
- package/{components → src/lib/components}/page/Editions.svelte +22 -18
- package/{components → src/lib/components}/page/Glossary.svelte +33 -28
- package/{components → src/lib/components}/page/Header.svelte +59 -52
- package/{components → src/lib/components}/page/Index.svelte +48 -41
- package/{components → src/lib/components}/page/Instructions.svelte +2 -1
- package/{components → src/lib/components}/page/License.svelte +17 -9
- package/{components → src/lib/components}/page/Loading.svelte +0 -0
- package/{components → src/lib/components}/page/Media.svelte +44 -27
- package/{components → src/lib/components}/page/MediaPreview.svelte +3 -2
- package/{components → src/lib/components}/page/Muted.svelte +0 -0
- package/{components → src/lib/components}/page/Outline.svelte +140 -110
- package/src/lib/components/page/Page.svelte +94 -0
- package/{components → src/lib/components}/page/PageHeader.svelte +2 -1
- package/{components → src/lib/components}/page/PageParagraph.svelte +0 -0
- package/src/lib/components/page/PossibleChapter.svelte +16 -0
- package/src/lib/components/page/PossibleReference.svelte +14 -0
- package/{components → src/lib/components}/page/Print.svelte +5 -3
- package/{components → src/lib/components}/page/Publish.svelte +59 -52
- package/{components → src/lib/components}/page/Reference.svelte +39 -30
- package/{components → src/lib/components}/page/References.svelte +18 -14
- package/{components → src/lib/components}/page/Rows.svelte +0 -0
- package/src/lib/components/page/Search.svelte +153 -0
- package/{components → src/lib/components}/page/Status.svelte +5 -3
- package/{components → src/lib/components}/page/SubdomainEditor.svelte +16 -13
- package/{components → src/lib/components}/page/TableOfContents.svelte +79 -68
- package/src/lib/components/page/TableOfContentsImage.svelte +22 -0
- package/{components → src/lib/components}/page/TableOfContentsRow.svelte +34 -24
- package/{components → src/lib/components}/page/ThemeEditor.svelte +44 -33
- package/{components → src/lib/components}/page/ThemeEditorPreview.svelte +21 -12
- package/src/lib/components/page/ThemeSetEditor.svelte +21 -0
- package/{components → src/lib/components}/page/ThemeVariableEditor.svelte +18 -14
- package/{components → src/lib/components}/page/Title.svelte +0 -0
- package/{components → src/lib/components}/page/Unknown.svelte +10 -8
- package/{components/page/margins.js → src/lib/components/page/margins.ts} +79 -46
- package/{index.js → src/lib/index.js} +0 -0
- package/src/lib/models/CRUD.ts +469 -0
- package/{models/Firebase.js → src/lib/models/Firebase.ts} +26 -16
- package/src/lib/models/book/Book.ts +283 -0
- package/src/lib/models/book/BookMedia.ts +182 -0
- package/src/lib/models/book/BookSaveStatus.ts +8 -0
- package/src/lib/models/book/Chapter.ts +462 -0
- package/{models/book/ChapterID.js → src/lib/models/book/ChapterID.ts} +1 -0
- package/src/lib/models/book/Definition.ts +2 -0
- package/src/lib/models/book/Edition.ts +1216 -0
- package/src/lib/models/book/Reference.ts +171 -0
- package/{models/book/Schema.js → src/lib/models/book/Schema.ts} +1 -0
- package/{models/book/Theme.js → src/lib/models/book/Theme.ts} +111 -6
- package/{models/book/ThemeColors.d.ts → src/lib/models/book/ThemeColors.ts} +6 -0
- package/{models/book/Words.js → src/lib/models/book/Words.ts} +1 -0
- package/{models/chapter/AtomNode.js → src/lib/models/chapter/AtomNode.ts} +30 -10
- package/{models/chapter/BlockNode.js → src/lib/models/chapter/BlockNode.ts} +80 -47
- package/src/lib/models/chapter/BlocksNode.test.ts +867 -0
- package/{models/chapter/BlocksNode.js → src/lib/models/chapter/BlocksNode.ts} +571 -359
- package/{models/chapter/Bookkeeping.d.ts → src/lib/models/chapter/Bookkeeping.ts} +0 -0
- package/src/lib/models/chapter/CalloutNode.ts +79 -0
- package/{models/chapter/Caret.js → src/lib/models/chapter/Caret.ts} +50 -26
- package/src/lib/models/chapter/ChapterNode.ts +169 -0
- package/{models/chapter/CitationsNode.js → src/lib/models/chapter/CitationsNode.ts} +17 -10
- package/{models/chapter/CodeNode.js → src/lib/models/chapter/CodeNode.ts} +125 -62
- package/src/lib/models/chapter/CommentNode.ts +61 -0
- package/{models/chapter/DefinitionNode.js → src/lib/models/chapter/DefinitionNode.ts} +14 -8
- package/src/lib/models/chapter/Edit.ts +6 -0
- package/src/lib/models/chapter/EmbedNode.ts +257 -0
- package/{models/chapter/ErrorNode.js → src/lib/models/chapter/ErrorNode.ts} +15 -8
- package/src/lib/models/chapter/FootnoteNode.ts +59 -0
- package/src/lib/models/chapter/FormatNode.test.ts +137 -0
- package/{models/chapter/FormatNode.js → src/lib/models/chapter/FormatNode.ts} +443 -262
- package/{models/chapter/InlineCodeNode.js → src/lib/models/chapter/InlineCodeNode.ts} +17 -9
- package/{models/chapter/LabelNode.js → src/lib/models/chapter/LabelNode.ts} +26 -10
- package/{models/chapter/LinkNode.js → src/lib/models/chapter/LinkNode.ts} +12 -7
- package/{models/chapter/ListNode.test.js → src/lib/models/chapter/ListNode.test.ts} +57 -20
- package/{models/chapter/ListNode.js → src/lib/models/chapter/ListNode.ts} +277 -200
- package/src/lib/models/chapter/MetadataNode.ts +44 -0
- package/{models → src/lib/models}/chapter/Node.test.js +0 -0
- package/{models/chapter/Node.js → src/lib/models/chapter/Node.ts} +155 -71
- package/src/lib/models/chapter/ParagraphNode.test.ts +54 -0
- package/{models/chapter/ParagraphNode.js → src/lib/models/chapter/ParagraphNode.ts} +95 -58
- package/{models/chapter/Parser.test.js → src/lib/models/chapter/Parser.test.ts} +7 -0
- package/{models/chapter/Parser.js → src/lib/models/chapter/Parser.ts} +369 -184
- package/{models/chapter/Position.d.ts → src/lib/models/chapter/Position.ts} +0 -0
- package/src/lib/models/chapter/QuoteNode.ts +135 -0
- package/{models/chapter/RootNode.d.ts → src/lib/models/chapter/RootNode.ts} +2 -0
- package/{models/chapter/RuleNode.js → src/lib/models/chapter/RuleNode.ts} +9 -6
- package/{models/chapter/TableNode.test.js → src/lib/models/chapter/TableNode.test.ts} +27 -10
- package/{models/chapter/TableNode.js → src/lib/models/chapter/TableNode.ts} +141 -82
- package/{models/chapter/TextNode.test.js → src/lib/models/chapter/TextNode.test.ts} +2 -0
- package/{models/chapter/TextNode.js → src/lib/models/chapter/TextNode.ts} +117 -65
- package/{util/getSubdomain.js → src/lib/util/getSubdomain.ts} +14 -8
- package/{util/isMobile.js → src/lib/util/isMobile.ts} +1 -0
- package/{util/mineReference.js → src/lib/util/mineReference.ts} +45 -25
- package/{util/scrollToEyeLevel.js → src/lib/util/scrollToEyeLevel.ts} +4 -2
- package/src/params/edition.ts +3 -0
- package/src/routes/+error.svelte +12 -0
- package/src/routes/+layout.svelte +241 -0
- package/src/routes/+page.svelte +43 -0
- package/src/routes/Footer.svelte +0 -0
- package/src/routes/Header.svelte +112 -0
- package/src/routes/[bookid]/+layout.svelte +5 -0
- package/src/routes/[bookid]/[[editionid=edition]]/+error.svelte +14 -0
- package/src/routes/[bookid]/[[editionid=edition]]/+layout.svelte +7 -0
- package/src/routes/[bookid]/[[editionid=edition]]/+page.svelte +5 -0
- package/src/routes/[bookid]/[[editionid=edition]]/[chapterid]/+page.svelte +5 -0
- package/src/routes/[bookid]/[[editionid=edition]]/glossary/+page.svelte +5 -0
- package/src/routes/[bookid]/[[editionid=edition]]/index/[[letter]]/+page.svelte +5 -0
- package/src/routes/[bookid]/[[editionid=edition]]/media/+page.svelte +5 -0
- package/src/routes/[bookid]/[[editionid=edition]]/print/+page.svelte +5 -0
- package/src/routes/[bookid]/[[editionid=edition]]/references/+page.svelte +5 -0
- package/src/routes/[bookid]/[[editionid=edition]]/search/+page.svelte +5 -0
- package/src/routes/[bookid]/editions/+page.svelte +20 -0
- package/src/routes/about/+page.svelte +102 -0
- package/src/routes/confirm/+page.svelte +62 -0
- package/src/routes/email/+page.svelte +99 -0
- package/src/routes/login/+page.svelte +66 -0
- package/src/routes/read/+page.svelte +38 -0
- package/src/routes/write/+error.svelte +10 -0
- package/src/routes/write/+layout.svelte +11 -0
- package/src/routes/write/+page.svelte +114 -0
- package/src/routes/write/[bookid]/+layout.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/+layout.svelte +7 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/+page.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/[chapterid]/+page.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/glossary/+page.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/index/[[letter]]/+page.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/media/+page.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/print/+page.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/references/+page.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/search/+page.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/theme/+page.svelte +5 -0
- package/src/routes/write/[bookid]/[[editionid=edition]]/unknown/+page.svelte +5 -0
- package/src/routes/write/[bookid]/editions/+page.svelte +20 -0
- package/src/vite-env.d.ts +1 -0
- package/static/icons/favicon.png +0 -0
- package/static/icons/icon.png +0 -0
- package/static/icons/ios-icon.png +0 -0
- package/storage.rules +9 -0
- package/svelte.config.js +19 -0
- package/tsconfig.json +18 -0
- package/tsconfig.node.json +9 -0
- package/vite.config.ts +8 -0
- package/vite.reader.config.ts +32 -0
- package/components/Auth.svelte +0 -55
- package/components/Auth.svelte.d.ts +0 -16
- package/components/Authentication.js +0 -1
- package/components/BookPreview.svelte.d.ts +0 -18
- package/components/External.svelte.d.ts +0 -18
- package/components/Link.svelte +0 -51
- package/components/Link.svelte.d.ts +0 -18
- package/components/app/BookList.svelte.d.ts +0 -18
- package/components/app/Button.svelte.d.ts +0 -22
- package/components/app/Feedback.svelte.d.ts +0 -18
- package/components/app/Head.svelte.d.ts +0 -18
- package/components/app/Large.svelte.d.ts +0 -27
- package/components/app/Lead.svelte.d.ts +0 -27
- package/components/app/Link.svelte.d.ts +0 -20
- package/components/app/Options.svelte.d.ts +0 -19
- package/components/app/Paragraph.svelte.d.ts +0 -18
- package/components/app/Section.svelte.d.ts +0 -27
- package/components/app/Table.svelte.d.ts +0 -27
- package/components/app/TextInput.svelte.d.ts +0 -22
- package/components/chapter/Atom.svelte.d.ts +0 -19
- package/components/chapter/Block.svelte +0 -37
- package/components/chapter/Block.svelte.d.ts +0 -17
- package/components/chapter/Callout.svelte.d.ts +0 -17
- package/components/chapter/CaptionedCode.svelte.d.ts +0 -17
- package/components/chapter/ChapterBody.svelte.d.ts +0 -19
- package/components/chapter/Citations.svelte.d.ts +0 -17
- package/components/chapter/Code.svelte.d.ts +0 -22
- package/components/chapter/Comment.svelte.d.ts +0 -17
- package/components/chapter/Definition.svelte.d.ts +0 -17
- package/components/chapter/Embed.svelte.d.ts +0 -20
- package/components/chapter/ErrorMessage.svelte +0 -9
- package/components/chapter/ErrorMessage.svelte.d.ts +0 -17
- package/components/chapter/ExtendedPrism.d.ts +0 -2
- package/components/chapter/Figure.svelte.d.ts +0 -24
- package/components/chapter/Footnote.svelte.d.ts +0 -19
- package/components/chapter/Format.svelte.d.ts +0 -19
- package/components/chapter/InlineCode.svelte.d.ts +0 -17
- package/components/chapter/Label.svelte.d.ts +0 -17
- package/components/chapter/Link.svelte.d.ts +0 -17
- package/components/chapter/List.svelte.d.ts +0 -17
- package/components/chapter/Marginal.svelte.d.ts +0 -22
- package/components/chapter/Paragraph.svelte.d.ts +0 -18
- package/components/chapter/Positioned.svelte.d.ts +0 -19
- package/components/chapter/Problem.svelte.d.ts +0 -27
- package/components/chapter/Python.svelte +0 -128
- package/components/chapter/Python.svelte.d.ts +0 -18
- package/components/chapter/Quote.svelte.d.ts +0 -17
- package/components/chapter/Rule.svelte.d.ts +0 -17
- package/components/chapter/Table.svelte.d.ts +0 -17
- package/components/chapter/Text.svelte +0 -87
- package/components/chapter/Text.svelte.d.ts +0 -18
- package/components/editor/BookishEditor.svelte +0 -884
- package/components/editor/BookishEditor.svelte.d.ts +0 -25
- package/components/editor/CalloutEditor.svelte +0 -10
- package/components/editor/CalloutEditor.svelte.d.ts +0 -17
- package/components/editor/CaptionedCodeEditor.svelte.d.ts +0 -17
- package/components/editor/CaretContext.d.ts +0 -50
- package/components/editor/CaretContext.js +0 -1
- package/components/editor/CaretState.js +0 -1
- package/components/editor/CaretUtilities.js +0 -1
- package/components/editor/CaretView.svelte.d.ts +0 -25
- package/components/editor/CitationsEditor.svelte +0 -53
- package/components/editor/CitationsEditor.svelte.d.ts +0 -17
- package/components/editor/Clipboard.js +0 -1
- package/components/editor/Command.js +0 -1
- package/components/editor/Commands.d.ts +0 -3
- package/components/editor/ConfirmButton.svelte +0 -49
- package/components/editor/ConfirmButton.svelte.d.ts +0 -19
- package/components/editor/DefinitionEditor.svelte +0 -36
- package/components/editor/DefinitionEditor.svelte.d.ts +0 -17
- package/components/editor/EmbedEditor.svelte +0 -137
- package/components/editor/EmbedEditor.svelte.d.ts +0 -17
- package/components/editor/Icon.svelte.d.ts +0 -16
- package/components/editor/ImageChooser.svelte.d.ts +0 -18
- package/components/editor/InlineCodeEditor.svelte +0 -12
- package/components/editor/InlineCodeEditor.svelte.d.ts +0 -17
- package/components/editor/LabelEditor.svelte.d.ts +0 -17
- package/components/editor/LanguageEditor.svelte.d.ts +0 -17
- package/components/editor/LinkEditor.svelte +0 -100
- package/components/editor/LinkEditor.svelte.d.ts +0 -17
- package/components/editor/Note.svelte.d.ts +0 -27
- package/components/editor/Permissions.svelte.d.ts +0 -20
- package/components/editor/PositionEditor.svelte +0 -17
- package/components/editor/PositionEditor.svelte.d.ts +0 -18
- package/components/editor/QuoteEditor.svelte +0 -10
- package/components/editor/QuoteEditor.svelte.d.ts +0 -17
- package/components/editor/Switch.svelte.d.ts +0 -20
- package/components/editor/TableEditor.svelte +0 -10
- package/components/editor/TableEditor.svelte.d.ts +0 -17
- package/components/editor/TextEditor.svelte.d.ts +0 -24
- package/components/editor/Toggle.svelte +0 -41
- package/components/editor/Toggle.svelte.d.ts +0 -19
- package/components/editor/Toolbar.svelte +0 -249
- package/components/editor/Toolbar.svelte.d.ts +0 -17
- package/components/editor/ToolbarGroup.svelte.d.ts +0 -18
- package/components/editor/ToolbarSpacer.svelte.d.ts +0 -23
- package/components/editor/URLEditor.svelte +0 -13
- package/components/editor/URLEditor.svelte.d.ts +0 -18
- package/components/editor/UndoState.js +0 -1
- package/components/page/Acknowledgements.svelte.d.ts +0 -14
- package/components/page/Authors.svelte +0 -85
- package/components/page/Authors.svelte.d.ts +0 -21
- package/components/page/BookLoader.svelte +0 -59
- package/components/page/BookLoader.svelte.d.ts +0 -16
- package/components/page/BulkReferenceEditor.svelte +0 -63
- package/components/page/BulkReferenceEditor.svelte.d.ts +0 -14
- package/components/page/Chapter.svelte +0 -392
- package/components/page/Chapter.svelte.d.ts +0 -18
- package/components/page/ChapterContext.d.ts +0 -10
- package/components/page/ChapterContext.js +0 -1
- package/components/page/ChapterNumber.svelte.d.ts +0 -27
- package/components/page/ChapterTitle.svelte.d.ts +0 -18
- package/components/page/Contexts.d.ts +0 -47
- package/components/page/Contexts.js +0 -133
- package/components/page/DefinitionView.svelte.d.ts +0 -18
- package/components/page/Description.svelte.d.ts +0 -14
- package/components/page/Edition.svelte +0 -161
- package/components/page/Edition.svelte.d.ts +0 -20
- package/components/page/EditionLoader.svelte +0 -99
- package/components/page/EditionLoader.svelte.d.ts +0 -18
- package/components/page/Editions.svelte.d.ts +0 -14
- package/components/page/Glossary.svelte.d.ts +0 -14
- package/components/page/Header.svelte.d.ts +0 -29
- package/components/page/Index.svelte.d.ts +0 -14
- package/components/page/Instructions.svelte.d.ts +0 -18
- package/components/page/License.svelte.d.ts +0 -14
- package/components/page/Loading.svelte.d.ts +0 -23
- package/components/page/Media.svelte.d.ts +0 -14
- package/components/page/MediaPreview.svelte.d.ts +0 -19
- package/components/page/Muted.svelte.d.ts +0 -27
- package/components/page/Outline.svelte.d.ts +0 -19
- package/components/page/Page.svelte +0 -84
- package/components/page/Page.svelte.d.ts +0 -19
- package/components/page/PageHeader.svelte.d.ts +0 -18
- package/components/page/PageParagraph.svelte.d.ts +0 -27
- package/components/page/PossibleChapter.svelte +0 -14
- package/components/page/PossibleChapter.svelte.d.ts +0 -14
- package/components/page/PossibleReference.svelte +0 -11
- package/components/page/PossibleReference.svelte.d.ts +0 -18
- package/components/page/Print.svelte.d.ts +0 -14
- package/components/page/Publish.svelte.d.ts +0 -14
- package/components/page/Reference.svelte.d.ts +0 -17
- package/components/page/References.svelte.d.ts +0 -14
- package/components/page/Rows.svelte.d.ts +0 -27
- package/components/page/Search.svelte +0 -133
- package/components/page/Search.svelte.d.ts +0 -14
- package/components/page/Status.svelte.d.ts +0 -14
- package/components/page/SubdomainEditor.svelte.d.ts +0 -14
- package/components/page/TableOfContents.svelte.d.ts +0 -14
- package/components/page/TableOfContentsImage.svelte +0 -18
- package/components/page/TableOfContentsImage.svelte.d.ts +0 -16
- package/components/page/TableOfContentsRow.svelte.d.ts +0 -24
- package/components/page/ThemeEditor.svelte.d.ts +0 -14
- package/components/page/ThemeEditorPreview.svelte.d.ts +0 -17
- package/components/page/ThemeSetEditor.svelte +0 -19
- package/components/page/ThemeSetEditor.svelte.d.ts +0 -18
- package/components/page/ThemeVariableEditor.svelte.d.ts +0 -18
- package/components/page/Title.svelte.d.ts +0 -27
- package/components/page/Unknown.svelte.d.ts +0 -16
- package/components/page/margins.d.ts +0 -2
- package/index.d.ts +0 -15
- package/models/CRUD.d.ts +0 -27
- package/models/CRUD.js +0 -262
- package/models/Firebase.d.ts +0 -5
- package/models/book/Book.d.ts +0 -61
- package/models/book/Book.js +0 -135
- package/models/book/BookMedia.d.ts +0 -23
- package/models/book/BookMedia.js +0 -108
- package/models/book/BookSaveStatus.d.ts +0 -7
- package/models/book/BookSaveStatus.js +0 -8
- package/models/book/Chapter.d.ts +0 -81
- package/models/book/Chapter.js +0 -212
- package/models/book/ChapterID.d.ts +0 -10
- package/models/book/Definition.d.ts +0 -6
- package/models/book/Definition.js +0 -1
- package/models/book/Edition.d.ts +0 -139
- package/models/book/Edition.js +0 -620
- package/models/book/Reference.d.ts +0 -24
- package/models/book/Reference.js +0 -78
- package/models/book/Schema.d.ts +0 -174
- package/models/book/Theme.d.ts +0 -113
- package/models/book/ThemeColors.js +0 -1
- package/models/book/Words.d.ts +0 -2
- package/models/chapter/AtomNode.d.ts +0 -18
- package/models/chapter/BlockNode.d.ts +0 -20
- package/models/chapter/BlocksNode.d.ts +0 -50
- package/models/chapter/BlocksNode.test.d.ts +0 -1
- package/models/chapter/BlocksNode.test.js +0 -568
- package/models/chapter/Bookkeeping.js +0 -1
- package/models/chapter/CalloutNode.d.ts +0 -17
- package/models/chapter/CalloutNode.js +0 -58
- package/models/chapter/Caret.d.ts +0 -23
- package/models/chapter/ChapterNode.d.ts +0 -34
- package/models/chapter/ChapterNode.js +0 -117
- package/models/chapter/CitationsNode.d.ts +0 -16
- package/models/chapter/CodeNode.d.ts +0 -35
- package/models/chapter/CommentNode.d.ts +0 -18
- package/models/chapter/CommentNode.js +0 -48
- package/models/chapter/DefinitionNode.d.ts +0 -12
- package/models/chapter/Edit.d.ts +0 -7
- package/models/chapter/Edit.js +0 -1
- package/models/chapter/EmbedNode.d.ts +0 -45
- package/models/chapter/EmbedNode.js +0 -168
- package/models/chapter/ErrorNode.d.ts +0 -17
- package/models/chapter/FootnoteNode.d.ts +0 -18
- package/models/chapter/FootnoteNode.js +0 -47
- package/models/chapter/FormatNode.d.ts +0 -60
- package/models/chapter/FormatNode.test.d.ts +0 -1
- package/models/chapter/FormatNode.test.js +0 -96
- package/models/chapter/InlineCodeNode.d.ts +0 -12
- package/models/chapter/LabelNode.d.ts +0 -17
- package/models/chapter/LinkNode.d.ts +0 -12
- package/models/chapter/ListNode.d.ts +0 -51
- package/models/chapter/ListNode.test.d.ts +0 -1
- package/models/chapter/MetadataNode.d.ts +0 -17
- package/models/chapter/MetadataNode.js +0 -32
- package/models/chapter/Node.d.ts +0 -38
- package/models/chapter/Node.test.d.ts +0 -1
- package/models/chapter/ParagraphNode.d.ts +0 -33
- package/models/chapter/ParagraphNode.test.d.ts +0 -1
- package/models/chapter/ParagraphNode.test.js +0 -30
- package/models/chapter/Parser.d.ts +0 -75
- package/models/chapter/Parser.test.d.ts +0 -1
- package/models/chapter/Position.js +0 -1
- package/models/chapter/QuoteNode.d.ts +0 -25
- package/models/chapter/QuoteNode.js +0 -99
- package/models/chapter/RootNode.js +0 -1
- package/models/chapter/RuleNode.d.ts +0 -15
- package/models/chapter/TableNode.d.ts +0 -37
- package/models/chapter/TableNode.test.d.ts +0 -1
- package/models/chapter/TextNode.d.ts +0 -36
- package/models/chapter/TextNode.test.d.ts +0 -1
- package/util/getSubdomain.d.ts +0 -3
- package/util/isMobile.d.ts +0 -2
- package/util/mineReference.d.ts +0 -4
- package/util/scrollToEyeLevel.d.ts +0 -2
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
import Node from './Node';
|
|
2
|
+
import type ErrorNode from './ErrorNode';
|
|
2
3
|
import TextNode from './TextNode';
|
|
3
|
-
import
|
|
4
|
+
import type Caret from './Caret';
|
|
5
|
+
import {
|
|
6
|
+
caretRangeToIndexRange,
|
|
7
|
+
caretToIndex,
|
|
8
|
+
indexToCaret,
|
|
9
|
+
type CaretRange,
|
|
10
|
+
} from './Caret';
|
|
4
11
|
import MetadataNode from './MetadataNode';
|
|
5
12
|
import AtomNode from './AtomNode';
|
|
13
|
+
import type Edit from './Edit';
|
|
14
|
+
|
|
15
|
+
export type Format = '' | '*' | '_' | '^' | 'v';
|
|
16
|
+
export type FormatNodeSegmentType =
|
|
17
|
+
| FormatNode
|
|
18
|
+
| TextNode
|
|
19
|
+
| ErrorNode
|
|
20
|
+
| MetadataNode<any>
|
|
21
|
+
| AtomNode<any>;
|
|
22
|
+
|
|
6
23
|
export default class FormatNode extends Node {
|
|
7
|
-
#format;
|
|
8
|
-
#segments;
|
|
9
|
-
|
|
24
|
+
readonly #format: Format;
|
|
25
|
+
readonly #segments: FormatNodeSegmentType[];
|
|
26
|
+
|
|
27
|
+
constructor(format: Format, segments: FormatNodeSegmentType[]) {
|
|
10
28
|
super();
|
|
29
|
+
|
|
11
30
|
this.#format = format;
|
|
12
31
|
// Remove consecutive empty text nodes.
|
|
13
32
|
this.#segments = segments.filter((item, position, list) => {
|
|
14
|
-
if (
|
|
33
|
+
if (
|
|
34
|
+
position === 0 ||
|
|
15
35
|
!(item instanceof TextNode) ||
|
|
16
|
-
item.getLength() > 0
|
|
36
|
+
item.getLength() > 0
|
|
37
|
+
)
|
|
17
38
|
return true;
|
|
18
39
|
const previous = list[position - 1];
|
|
19
|
-
return !(
|
|
40
|
+
return !(
|
|
41
|
+
previous instanceof TextNode && previous.getLength() === 0
|
|
42
|
+
);
|
|
20
43
|
});
|
|
21
44
|
}
|
|
45
|
+
|
|
22
46
|
getType() {
|
|
23
47
|
return 'formatted';
|
|
24
48
|
}
|
|
@@ -32,100 +56,130 @@ export default class FormatNode extends Node {
|
|
|
32
56
|
return this.#segments.length === 0;
|
|
33
57
|
}
|
|
34
58
|
isEmptyText() {
|
|
35
|
-
return (
|
|
59
|
+
return (
|
|
60
|
+
this.#segments.length === 1 &&
|
|
36
61
|
this.#segments[0] instanceof TextNode &&
|
|
37
|
-
this.#segments[0].getText() === ''
|
|
62
|
+
this.#segments[0].getText() === ''
|
|
63
|
+
);
|
|
38
64
|
}
|
|
39
65
|
getLength() {
|
|
40
66
|
return this.#segments.length;
|
|
41
67
|
}
|
|
42
|
-
getParentOf(node) {
|
|
68
|
+
getParentOf(node: Node): Node | undefined {
|
|
43
69
|
return this.#segments
|
|
44
70
|
.map((b) => (b === node ? this : b.getParentOf(node)))
|
|
45
71
|
.find((b) => b !== undefined);
|
|
46
72
|
}
|
|
47
|
-
|
|
73
|
+
|
|
74
|
+
toText(): string {
|
|
48
75
|
return this.#segments.map((segment) => segment.toText()).join(' ');
|
|
49
76
|
}
|
|
50
|
-
toHTML() {
|
|
77
|
+
toHTML(): string {
|
|
51
78
|
const format = this.#format;
|
|
52
79
|
const segments = this.#segments.map((s) => s.toHTML()).join('');
|
|
53
|
-
if (format === '*')
|
|
54
|
-
|
|
55
|
-
else if (format === '
|
|
56
|
-
|
|
57
|
-
else
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
toBookdown() {
|
|
65
|
-
return ((this.#format === 'v' ? '^v' : this.#format) +
|
|
80
|
+
if (format === '*') return `<strong>${segments}</strong>`;
|
|
81
|
+
else if (format === '_') return `<em>${segments}</em>`;
|
|
82
|
+
else if (format === '^') return `<sup>${segments}</sup>`;
|
|
83
|
+
else if (format === 'v') return `<sub>${segments}</sub>`;
|
|
84
|
+
else return segments;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
toBookdown(): string {
|
|
88
|
+
return (
|
|
89
|
+
(this.#format === 'v' ? '^v' : this.#format) +
|
|
66
90
|
this.#segments
|
|
67
|
-
.map((s) =>
|
|
91
|
+
.map((s) =>
|
|
92
|
+
s instanceof AtomNode ? s.toBookdown(this) : s.toBookdown()
|
|
93
|
+
)
|
|
68
94
|
.join('') +
|
|
69
|
-
(this.#format === 'v' ? '^' : this.#format)
|
|
95
|
+
(this.#format === 'v' ? '^' : this.#format)
|
|
96
|
+
);
|
|
70
97
|
}
|
|
98
|
+
|
|
71
99
|
getChildren() {
|
|
72
100
|
return this.#segments;
|
|
73
101
|
}
|
|
74
|
-
|
|
102
|
+
|
|
103
|
+
getFirstTextNode(): TextNode {
|
|
75
104
|
const text = this.getTextNodes();
|
|
76
105
|
return text[0];
|
|
77
106
|
}
|
|
78
|
-
|
|
107
|
+
|
|
108
|
+
getLastTextNode(): TextNode {
|
|
79
109
|
const text = this.getTextNodes();
|
|
80
110
|
return text[text.length - 1];
|
|
81
111
|
}
|
|
82
|
-
|
|
83
|
-
|
|
112
|
+
|
|
113
|
+
copy(): this {
|
|
114
|
+
return new FormatNode(
|
|
115
|
+
this.#format,
|
|
116
|
+
this.#segments.map((s) => s.copy())
|
|
117
|
+
) as this;
|
|
84
118
|
}
|
|
85
|
-
|
|
86
|
-
|
|
119
|
+
|
|
120
|
+
getTextNodes(): TextNode[] {
|
|
121
|
+
return this.getNodes().filter(
|
|
122
|
+
(n) => n instanceof TextNode
|
|
123
|
+
) as TextNode[];
|
|
87
124
|
}
|
|
125
|
+
|
|
88
126
|
// Get all text or atom nodes in this format, except for any inside an atom node,
|
|
89
127
|
// as this is used for navigation and editing, and they should be isolated from that.
|
|
90
|
-
getTextAndAtomNodes() {
|
|
91
|
-
return this.getNodes().filter(
|
|
92
|
-
|
|
93
|
-
|
|
128
|
+
getTextAndAtomNodes(): (TextNode | AtomNode<any>)[] {
|
|
129
|
+
return this.getNodes().filter(
|
|
130
|
+
(n) => n instanceof TextNode || n instanceof AtomNode
|
|
131
|
+
) as (TextNode | AtomNode<any>)[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
getAdjacentTextOrAtom(
|
|
135
|
+
node: TextNode | AtomNode<any>,
|
|
136
|
+
next: boolean
|
|
137
|
+
): TextNode | AtomNode<any> | undefined {
|
|
94
138
|
// Find all of the text and atom nodes not in atom nodes in this node.
|
|
95
139
|
const text = this.getTextAndAtomNodes().filter((n) => {
|
|
96
140
|
const atomAncestor = n.getClosestParentOfType(this, AtomNode);
|
|
97
|
-
return (
|
|
141
|
+
return (
|
|
142
|
+
atomAncestor === undefined ||
|
|
98
143
|
(atomAncestor instanceof AtomNode &&
|
|
99
|
-
atomAncestor.getMeta() === this)
|
|
144
|
+
atomAncestor.getMeta() === this)
|
|
145
|
+
);
|
|
100
146
|
});
|
|
101
147
|
const index = text.indexOf(node);
|
|
102
148
|
return index === undefined
|
|
103
149
|
? undefined
|
|
104
150
|
: next
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
151
|
+
? index >= 0 && index < text.length - 1
|
|
152
|
+
? text[index + 1]
|
|
153
|
+
: undefined
|
|
154
|
+
: index > 0 && index <= text.length
|
|
155
|
+
? text[index - 1]
|
|
156
|
+
: undefined;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
getNextTextOrAtom(
|
|
160
|
+
node: TextNode | AtomNode<any>
|
|
161
|
+
): TextNode | AtomNode<any> | undefined {
|
|
113
162
|
return this.getAdjacentTextOrAtom(node, true);
|
|
114
163
|
}
|
|
115
|
-
|
|
164
|
+
|
|
165
|
+
getPreviousTextOrAtom(
|
|
166
|
+
node: TextNode | AtomNode<any>
|
|
167
|
+
): TextNode | AtomNode<any> | undefined {
|
|
116
168
|
return this.getAdjacentTextOrAtom(node, false);
|
|
117
169
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
170
|
+
|
|
171
|
+
getAdjacentCaret(caret: Caret, next: boolean): Caret | undefined {
|
|
172
|
+
if (
|
|
173
|
+
!(caret.node instanceof TextNode) &&
|
|
174
|
+
!(caret.node instanceof AtomNode)
|
|
175
|
+
)
|
|
121
176
|
return;
|
|
122
177
|
// Is there an adjascent caret in the current text node? If so, return it.
|
|
123
178
|
if (caret.node instanceof TextNode) {
|
|
124
179
|
const adjacentText = next
|
|
125
180
|
? caret.node.getNextCaret(caret.index)
|
|
126
181
|
: caret.node.getPreviousCaret(caret.index);
|
|
127
|
-
if (adjacentText !== undefined)
|
|
128
|
-
return adjacentText;
|
|
182
|
+
if (adjacentText !== undefined) return adjacentText;
|
|
129
183
|
}
|
|
130
184
|
// If there's not, is there an adjacent caret in the sequence of text and atom nodes?
|
|
131
185
|
const adjacentNode = this.getAdjacentTextOrAtom(caret.node, next);
|
|
@@ -141,29 +195,30 @@ export default class FormatNode extends Node {
|
|
|
141
195
|
: 1
|
|
142
196
|
: 0
|
|
143
197
|
: adjacentNode instanceof TextNode
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
198
|
+
? adjacentNode.isEmpty()
|
|
199
|
+
? 0
|
|
200
|
+
: adjacentNode.getLength() - 1
|
|
201
|
+
: 0,
|
|
148
202
|
};
|
|
149
203
|
}
|
|
150
204
|
// Otherwise, there is no adjascent caret.
|
|
151
205
|
return undefined;
|
|
152
206
|
}
|
|
153
|
-
|
|
207
|
+
|
|
208
|
+
getFirstCaret(): Caret | undefined {
|
|
154
209
|
const text = this.getTextNodes();
|
|
155
|
-
if (text.length === 0)
|
|
156
|
-
return undefined;
|
|
210
|
+
if (text.length === 0) return undefined;
|
|
157
211
|
return { node: this.getTextNodes()[0], index: 0 };
|
|
158
212
|
}
|
|
159
|
-
|
|
213
|
+
|
|
214
|
+
getLastCaret(): Caret | undefined {
|
|
160
215
|
const text = this.getTextNodes();
|
|
161
|
-
if (text.length === 0)
|
|
162
|
-
return undefined;
|
|
216
|
+
if (text.length === 0) return undefined;
|
|
163
217
|
const last = text[text.length - 1];
|
|
164
218
|
return { node: last, index: last.getLength() };
|
|
165
219
|
}
|
|
166
|
-
|
|
220
|
+
|
|
221
|
+
getSelection(): CaretRange {
|
|
167
222
|
const first = this.getFirstTextNode();
|
|
168
223
|
const last = this.getLastTextNode();
|
|
169
224
|
return {
|
|
@@ -171,117 +226,159 @@ export default class FormatNode extends Node {
|
|
|
171
226
|
end: { node: last, index: last.getLength() },
|
|
172
227
|
};
|
|
173
228
|
}
|
|
174
|
-
|
|
229
|
+
|
|
230
|
+
getIndexOfTextNode(node: TextNode): number | undefined {
|
|
175
231
|
const text = this.getTextNodes();
|
|
176
232
|
return text.indexOf(node);
|
|
177
233
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
234
|
+
|
|
235
|
+
getSelectedText(range: CaretRange): string | undefined {
|
|
236
|
+
if (
|
|
237
|
+
!(range.start.node instanceof TextNode) ||
|
|
238
|
+
!(range.end.node instanceof TextNode)
|
|
239
|
+
)
|
|
181
240
|
return undefined;
|
|
241
|
+
|
|
182
242
|
const start = this.getIndexOfTextNode(range.start.node);
|
|
183
243
|
const end = this.getIndexOfTextNode(range.end.node);
|
|
184
|
-
|
|
185
|
-
|
|
244
|
+
|
|
245
|
+
if (start === undefined || end === undefined) return undefined;
|
|
246
|
+
|
|
186
247
|
return this.getTextNodes()
|
|
187
248
|
.map((current, index) => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
249
|
+
return current === range.start.node
|
|
250
|
+
? current === range.end.node
|
|
251
|
+
? current
|
|
252
|
+
.getText()
|
|
253
|
+
.substring(range.start.index, range.end.index)
|
|
254
|
+
: current.getText().substring(range.start.index)
|
|
255
|
+
: index > start && index < end
|
|
195
256
|
? current.getText()
|
|
196
257
|
: current === range.end.node
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
258
|
+
? current.getText().substring(0, range.end.index)
|
|
259
|
+
: '';
|
|
260
|
+
})
|
|
200
261
|
.join('');
|
|
201
262
|
}
|
|
263
|
+
|
|
202
264
|
withTextIfEmpty() {
|
|
203
265
|
return this.isEmpty() ? this.withSegmentAppended(new TextNode()) : this;
|
|
204
266
|
}
|
|
205
|
-
|
|
267
|
+
|
|
268
|
+
withSegmentPrepended(segment: FormatNodeSegmentType): FormatNode {
|
|
206
269
|
return new FormatNode(this.#format, [segment, ...this.#segments]);
|
|
207
270
|
}
|
|
208
|
-
|
|
271
|
+
|
|
272
|
+
withSegmentAppended(segment: FormatNodeSegmentType): FormatNode {
|
|
209
273
|
return new FormatNode(this.#format, [...this.#segments, segment]);
|
|
210
274
|
}
|
|
211
|
-
|
|
275
|
+
|
|
276
|
+
withSegmentReplaced(
|
|
277
|
+
segment: FormatNodeSegmentType,
|
|
278
|
+
replacement: FormatNodeSegmentType
|
|
279
|
+
): this | undefined {
|
|
212
280
|
const index = this.#segments.indexOf(segment);
|
|
213
|
-
if (index < 0)
|
|
214
|
-
|
|
281
|
+
if (index < 0) return undefined;
|
|
282
|
+
|
|
215
283
|
const segments = this.#segments.slice();
|
|
216
284
|
segments[index] = replacement;
|
|
217
|
-
|
|
285
|
+
|
|
286
|
+
return new FormatNode(this.#format, segments) as this;
|
|
218
287
|
}
|
|
219
|
-
|
|
288
|
+
|
|
289
|
+
withoutSegment(segment: FormatNodeSegmentType): this | undefined {
|
|
220
290
|
const index = this.#segments.indexOf(segment);
|
|
221
|
-
if (index < 0)
|
|
222
|
-
return undefined;
|
|
291
|
+
if (index < 0) return undefined;
|
|
223
292
|
const newSegments = this.#segments.slice();
|
|
224
293
|
newSegments.splice(index, 1);
|
|
225
|
-
return new FormatNode(this.#format, newSegments);
|
|
294
|
+
return new FormatNode(this.#format, newSegments) as this;
|
|
226
295
|
}
|
|
227
|
-
|
|
296
|
+
|
|
297
|
+
withChildReplaced(
|
|
298
|
+
node: FormatNodeSegmentType,
|
|
299
|
+
replacement: FormatNodeSegmentType | undefined
|
|
300
|
+
) {
|
|
228
301
|
return replacement === undefined
|
|
229
|
-
? this.withoutSegment(node)
|
|
230
|
-
: this.withSegmentReplaced(node, replacement);
|
|
302
|
+
? (this.withoutSegment(node) as this)
|
|
303
|
+
: (this.withSegmentReplaced(node, replacement) as this);
|
|
231
304
|
}
|
|
305
|
+
|
|
232
306
|
// Creates two formatted nodes that split this node at the given caret location.
|
|
233
|
-
split(caret) {
|
|
307
|
+
split(caret: Caret): [FormatNode, FormatNode] | undefined {
|
|
234
308
|
// We can only copy if
|
|
235
309
|
// ... this has a parent.
|
|
236
310
|
// ... the given caret is in this formatted node.
|
|
237
311
|
// ... the caret is on a text node.
|
|
238
312
|
if (!(caret.node instanceof TextNode) || !this.contains(caret.node))
|
|
239
313
|
return undefined;
|
|
314
|
+
|
|
240
315
|
const firstCaret = this.getFirstCaret();
|
|
241
316
|
const lastCaret = this.getLastCaret();
|
|
242
317
|
if (firstCaret === undefined || lastCaret === undefined)
|
|
243
318
|
return undefined;
|
|
319
|
+
|
|
244
320
|
// Delete everything after in the first, everything before in the second.
|
|
245
321
|
const first = this.withoutRange({ start: caret, end: lastCaret });
|
|
246
322
|
const second = this.withoutRange({ start: firstCaret, end: caret });
|
|
247
|
-
|
|
248
|
-
|
|
323
|
+
|
|
324
|
+
if (first !== undefined && second !== undefined) return [first, second];
|
|
249
325
|
}
|
|
250
|
-
|
|
326
|
+
|
|
327
|
+
withoutRange(range: CaretRange): FormatNode | undefined {
|
|
251
328
|
return this.withFormat(range, undefined);
|
|
252
329
|
}
|
|
330
|
+
|
|
253
331
|
// This function takes the given range, and if it's within the bounds of this FormatNode,
|
|
254
332
|
// produces a new FormatNode that either formats the given range with the given format or deletes the range if the format is undefined.
|
|
255
333
|
// It's approach is to scan through every text, meta, and atom node build a new format based on the requested format.
|
|
256
|
-
withFormat(
|
|
334
|
+
withFormat(
|
|
335
|
+
range: CaretRange,
|
|
336
|
+
format: Format | undefined
|
|
337
|
+
): FormatNode | undefined {
|
|
257
338
|
// This only transforms ranges that start and end with text/atom nodes in this format node.
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
range.
|
|
262
|
-
|
|
339
|
+
if (
|
|
340
|
+
!(
|
|
341
|
+
range.start.node instanceof TextNode ||
|
|
342
|
+
range.start.node instanceof AtomNode
|
|
343
|
+
) ||
|
|
344
|
+
!(
|
|
345
|
+
range.end.node instanceof TextNode ||
|
|
346
|
+
range.end.node instanceof AtomNode
|
|
347
|
+
) ||
|
|
348
|
+
!(this.contains(range.start.node) && this.contains(range.end.node))
|
|
349
|
+
)
|
|
263
350
|
return;
|
|
351
|
+
|
|
264
352
|
const sortedRange = this.sortRange(range);
|
|
353
|
+
|
|
265
354
|
// Remember the text positions so we can return a new range in the new tree.
|
|
266
355
|
const selectionStartIndex = caretToIndex(this, sortedRange.start);
|
|
267
356
|
const selectionEndIndex = caretToIndex(this, sortedRange.end);
|
|
268
|
-
|
|
269
|
-
|
|
357
|
+
|
|
358
|
+
if (
|
|
359
|
+
selectionStartIndex === undefined ||
|
|
360
|
+
selectionEndIndex === undefined
|
|
361
|
+
)
|
|
270
362
|
return;
|
|
363
|
+
|
|
271
364
|
// Remember if the selection is zero width.
|
|
272
365
|
let zeroWidthSelection = selectionStartIndex === selectionEndIndex;
|
|
366
|
+
|
|
273
367
|
// Find all of the content in the node, except for format nodes and decendants of atom nodes that have format nodes,
|
|
274
368
|
// to construct a new format tree with the old content.
|
|
275
|
-
const everythingButFormats = this.getNodes().filter(
|
|
369
|
+
const everythingButFormats = this.getNodes().filter(
|
|
370
|
+
(n) => !(n instanceof FormatNode)
|
|
371
|
+
);
|
|
372
|
+
|
|
276
373
|
// Check if all of the selected content has the requested format so we can toggle it if so.
|
|
277
374
|
let checkIndex = 0; // This tracks the current location in our scan.
|
|
278
375
|
let editingEmptyNode = false; // This remembers the special case of the caret being inside an empty text node.
|
|
279
376
|
let alreadyApplied = false; // We assume it's not applied until proven otherwise.
|
|
280
377
|
let nodeCount = 0;
|
|
281
378
|
let nodesWithFormat = 0;
|
|
379
|
+
|
|
282
380
|
// It's already applied if we're deleting (in which case this doesn't apply).
|
|
283
|
-
if (format === undefined)
|
|
284
|
-
alreadyApplied = true;
|
|
381
|
+
if (format === undefined) alreadyApplied = true;
|
|
285
382
|
// Otherwise, formatting is already applied if all of the non-format nodes already have this format.
|
|
286
383
|
// We need to know this so we can toggle the format off.
|
|
287
384
|
else {
|
|
@@ -294,8 +391,10 @@ export default class FormatNode extends Node {
|
|
|
294
391
|
}
|
|
295
392
|
// If this node is empty but contains a zero-width selection, remember it, since this is the only node for which formats are relevant.
|
|
296
393
|
else if (node.getText().length === 0) {
|
|
297
|
-
if (
|
|
298
|
-
|
|
394
|
+
if (
|
|
395
|
+
checkIndex === selectionStartIndex &&
|
|
396
|
+
zeroWidthSelection
|
|
397
|
+
) {
|
|
299
398
|
editingEmptyNode = true;
|
|
300
399
|
alreadyApplied = parent
|
|
301
400
|
.getFormats(this)
|
|
@@ -308,41 +407,46 @@ export default class FormatNode extends Node {
|
|
|
308
407
|
const parentIsFormatted = parent
|
|
309
408
|
.getFormats(this)
|
|
310
409
|
.includes(format);
|
|
311
|
-
const selectionContainsNode =
|
|
312
|
-
selectionStartIndex
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
410
|
+
const selectionContainsNode =
|
|
411
|
+
(selectionStartIndex > checkIndex &&
|
|
412
|
+
selectionStartIndex <
|
|
413
|
+
checkIndex +
|
|
414
|
+
node.getCaretPositionCount() -
|
|
415
|
+
1) ||
|
|
316
416
|
(selectionEndIndex > checkIndex &&
|
|
317
417
|
selectionEndIndex <
|
|
318
418
|
checkIndex +
|
|
319
419
|
node.getCaretPositionCount() -
|
|
320
420
|
1);
|
|
321
|
-
const nodeContainsSelection =
|
|
421
|
+
const nodeContainsSelection =
|
|
422
|
+
selectionStartIndex >= checkIndex &&
|
|
322
423
|
selectionEndIndex <=
|
|
323
424
|
checkIndex + node.getCaretPositionCount();
|
|
324
425
|
checkIndex += node.getCaretPositionCount();
|
|
325
426
|
if (nodeContainsSelection || selectionContainsNode) {
|
|
326
427
|
nodeCount++;
|
|
327
|
-
if (parentIsFormatted)
|
|
328
|
-
nodesWithFormat++;
|
|
428
|
+
if (parentIsFormatted) nodesWithFormat++;
|
|
329
429
|
}
|
|
330
430
|
}
|
|
331
431
|
}
|
|
332
432
|
// Treat all non-text as containing the requested format.
|
|
333
|
-
else
|
|
334
|
-
return true;
|
|
433
|
+
else return true;
|
|
335
434
|
});
|
|
336
435
|
if (nodeCount > 0 && nodesWithFormat === nodeCount)
|
|
337
436
|
alreadyApplied = true;
|
|
338
437
|
}
|
|
438
|
+
|
|
339
439
|
// Reformat everything. The strategy is to step through each character, atom node, and metadata node in this format node
|
|
340
440
|
// and create a new series of formats that preserve existing formatting while applying new formatting to the selection.
|
|
341
|
-
let newFormats
|
|
441
|
+
let newFormats: {
|
|
442
|
+
format: Format;
|
|
443
|
+
segments: FormatNodeSegmentType[];
|
|
444
|
+
}[] = [{ format: '', segments: [] }]; // A stack of formats we're constructing.
|
|
342
445
|
let textIndex = 0;
|
|
343
446
|
let currentText = ''; // The current text we've accumulated, inserted before each format change and at the end.
|
|
344
447
|
let formattingEmptyNode = false;
|
|
345
448
|
let emptyNode = undefined;
|
|
449
|
+
|
|
346
450
|
function saveText() {
|
|
347
451
|
// If there's some text, update the current format with the current text, then reset it.
|
|
348
452
|
if (currentText.length > 0) {
|
|
@@ -350,45 +454,60 @@ export default class FormatNode extends Node {
|
|
|
350
454
|
currentText = '';
|
|
351
455
|
}
|
|
352
456
|
}
|
|
457
|
+
|
|
353
458
|
function inRange() {
|
|
354
|
-
return (
|
|
459
|
+
return (
|
|
460
|
+
selectionStartIndex !== undefined &&
|
|
355
461
|
selectionEndIndex !== undefined &&
|
|
356
462
|
textIndex >= selectionStartIndex &&
|
|
357
|
-
textIndex < selectionEndIndex
|
|
463
|
+
textIndex < selectionEndIndex
|
|
464
|
+
);
|
|
358
465
|
}
|
|
466
|
+
|
|
359
467
|
function getFormats() {
|
|
360
468
|
// We don't include non-formatted text in the list of formats applied.
|
|
361
469
|
return newFormats.map((f) => f.format).filter((f) => f !== '');
|
|
362
470
|
}
|
|
471
|
+
|
|
363
472
|
function finishFormat() {
|
|
364
473
|
const formatSpec = newFormats[0];
|
|
365
474
|
newFormats.shift();
|
|
366
475
|
// Keep the new format clean by only adding the format node if it's not empty, or if it's a zero width selection.
|
|
367
|
-
if (
|
|
368
|
-
|
|
369
|
-
|
|
476
|
+
if (
|
|
477
|
+
formatSpec.segments.length > 0 ||
|
|
478
|
+
(zeroWidthSelection && textIndex === selectionStartIndex)
|
|
479
|
+
)
|
|
480
|
+
newFormats[0].segments.push(
|
|
481
|
+
new FormatNode(formatSpec.format, formatSpec.segments)
|
|
482
|
+
);
|
|
370
483
|
}
|
|
484
|
+
|
|
371
485
|
everythingButFormats.forEach((node) => {
|
|
372
486
|
const parent = this.getParentOf(node);
|
|
373
487
|
if (node instanceof TextNode) {
|
|
374
488
|
// If this is a text node in an atom node we're not formatting the atom node's format, then just
|
|
375
489
|
// account for it's length, but do nothing else.
|
|
376
|
-
const atomAncestor = node.getClosestParentOfType(
|
|
377
|
-
|
|
490
|
+
const atomAncestor = node.getClosestParentOfType(
|
|
491
|
+
this,
|
|
492
|
+
AtomNode
|
|
493
|
+
);
|
|
494
|
+
if (
|
|
495
|
+
atomAncestor instanceof AtomNode &&
|
|
378
496
|
atomAncestor.getMeta() !== this &&
|
|
379
|
-
atomAncestor.getMeta() instanceof FormatNode
|
|
497
|
+
atomAncestor.getMeta() instanceof FormatNode
|
|
498
|
+
) {
|
|
380
499
|
textIndex += node.getCaretPositionCount();
|
|
381
|
-
}
|
|
382
|
-
else if (parent instanceof FormatNode) {
|
|
500
|
+
} else if (parent instanceof FormatNode) {
|
|
383
501
|
// Remember we found an empty node so that we don't insert an extra one later.
|
|
384
502
|
if (node.getText().length === 0) {
|
|
385
|
-
if (
|
|
386
|
-
|
|
503
|
+
if (
|
|
504
|
+
textIndex === selectionStartIndex &&
|
|
505
|
+
zeroWidthSelection
|
|
506
|
+
) {
|
|
387
507
|
formattingEmptyNode = true;
|
|
388
508
|
textIndex++;
|
|
389
509
|
}
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
510
|
+
} else {
|
|
392
511
|
// Process each character in the node, including the very last position.
|
|
393
512
|
for (let i = 0; i <= node.getText().length; i++) {
|
|
394
513
|
// Determine the desired format for this character. Start with the current formats
|
|
@@ -398,22 +517,31 @@ export default class FormatNode extends Node {
|
|
|
398
517
|
let desiredFormats = formatter
|
|
399
518
|
? formatter.getFormats(this)
|
|
400
519
|
: [];
|
|
401
|
-
if (
|
|
520
|
+
if (
|
|
521
|
+
format !== undefined &&
|
|
402
522
|
((textIndex === selectionStartIndex &&
|
|
403
523
|
zeroWidthSelection) ||
|
|
404
|
-
inRange())
|
|
524
|
+
inRange())
|
|
525
|
+
) {
|
|
405
526
|
// Remove all formatting if we were asked to.
|
|
406
|
-
if (format === '')
|
|
407
|
-
desiredFormats = [];
|
|
527
|
+
if (format === '') desiredFormats = [];
|
|
408
528
|
// Apply the formatting if it's not already applied.
|
|
409
|
-
else if (
|
|
410
|
-
!
|
|
529
|
+
else if (
|
|
530
|
+
!alreadyApplied &&
|
|
531
|
+
!desiredFormats.includes(format)
|
|
532
|
+
)
|
|
411
533
|
desiredFormats.push(format);
|
|
412
534
|
// Remove the formatting if it's already applied in the selection.
|
|
413
|
-
else if (
|
|
414
|
-
|
|
415
|
-
desiredFormats.
|
|
535
|
+
else if (
|
|
536
|
+
alreadyApplied &&
|
|
537
|
+
desiredFormats.includes(format)
|
|
538
|
+
)
|
|
539
|
+
desiredFormats.splice(
|
|
540
|
+
desiredFormats.indexOf(format),
|
|
541
|
+
1
|
|
542
|
+
);
|
|
416
543
|
}
|
|
544
|
+
|
|
417
545
|
// Remove undesired formats.
|
|
418
546
|
getFormats().forEach((activeFormat) => {
|
|
419
547
|
// If the current format is not in the desired list, close the text
|
|
@@ -421,16 +549,22 @@ export default class FormatNode extends Node {
|
|
|
421
549
|
if (!desiredFormats.includes(activeFormat)) {
|
|
422
550
|
// Save any text that we've accumulated.
|
|
423
551
|
saveText();
|
|
552
|
+
|
|
424
553
|
// Not sure this loop is necessary; we should always remove in the order we added.
|
|
425
|
-
while (
|
|
554
|
+
while (
|
|
555
|
+
newFormats[0].format !== activeFormat
|
|
556
|
+
)
|
|
426
557
|
finishFormat();
|
|
427
558
|
// Do it one more time to close out the undesired format.
|
|
428
559
|
finishFormat();
|
|
560
|
+
|
|
429
561
|
// If we have unformatted something at a zero-width range, create empty format node, add a text node in it and remember it so
|
|
430
562
|
// we can place the caret in it.
|
|
431
|
-
if (
|
|
563
|
+
if (
|
|
564
|
+
!formattingEmptyNode &&
|
|
432
565
|
textIndex === selectionStartIndex &&
|
|
433
|
-
zeroWidthSelection
|
|
566
|
+
zeroWidthSelection
|
|
567
|
+
) {
|
|
434
568
|
// Remember the node for later, so we can place the caret in it.
|
|
435
569
|
emptyNode = new TextNode();
|
|
436
570
|
// Append the empty node to the current format.
|
|
@@ -443,6 +577,7 @@ export default class FormatNode extends Node {
|
|
|
443
577
|
}
|
|
444
578
|
}
|
|
445
579
|
});
|
|
580
|
+
|
|
446
581
|
// Ensure the desired formats.
|
|
447
582
|
desiredFormats.forEach((desiredFormat) => {
|
|
448
583
|
// If the current format does not yet include the desired format,
|
|
@@ -450,22 +585,27 @@ export default class FormatNode extends Node {
|
|
|
450
585
|
if (!getFormats().includes(desiredFormat)) {
|
|
451
586
|
// Save any text that we've accumulated in the curent format.
|
|
452
587
|
saveText();
|
|
588
|
+
|
|
453
589
|
// Add a new format onto the stack to start adding to.
|
|
454
590
|
newFormats.unshift({
|
|
455
591
|
format: desiredFormat,
|
|
456
592
|
segments: [],
|
|
457
593
|
});
|
|
594
|
+
|
|
458
595
|
// If we inserted an empty format node, add a text node in it and remember it so
|
|
459
596
|
// we can place the caret in it.
|
|
460
|
-
if (
|
|
597
|
+
if (
|
|
598
|
+
!formattingEmptyNode &&
|
|
461
599
|
textIndex === selectionStartIndex &&
|
|
462
|
-
zeroWidthSelection
|
|
600
|
+
zeroWidthSelection
|
|
601
|
+
) {
|
|
463
602
|
emptyNode = new TextNode();
|
|
464
603
|
newFormats[0].segments.push(emptyNode);
|
|
465
604
|
finishFormat();
|
|
466
605
|
}
|
|
467
606
|
}
|
|
468
607
|
});
|
|
608
|
+
|
|
469
609
|
// If there's a format we're applying, or we're outside the deletion range, append the current character.
|
|
470
610
|
// We don't do this if we're checking the very last index of the node, since there is no character after it.
|
|
471
611
|
if (i < node.getLength()) {
|
|
@@ -481,16 +621,20 @@ export default class FormatNode extends Node {
|
|
|
481
621
|
else if (parent instanceof MetadataNode) {
|
|
482
622
|
// Save whatever text came before it.
|
|
483
623
|
saveText();
|
|
624
|
+
|
|
484
625
|
// Process each character in the node if we're formatting, and if we're deleting, skip anything in range of deletion.
|
|
485
626
|
for (let i = 0; i < node.getText().length; i++) {
|
|
486
627
|
if (format !== undefined || !inRange())
|
|
487
628
|
currentText += node.getText().charAt(i);
|
|
488
629
|
textIndex++;
|
|
489
630
|
}
|
|
631
|
+
|
|
490
632
|
// Duplicate the MetadataNode but with new text. Erase the MetadataNode if the text is empty
|
|
491
633
|
// by simply not adding one to this new format. Then, erase the text, since it was added in the metadata node.
|
|
492
634
|
if (currentText.length > 0) {
|
|
493
|
-
newFormats[0].segments.push(
|
|
635
|
+
newFormats[0].segments.push(
|
|
636
|
+
parent.withText(new TextNode(currentText))
|
|
637
|
+
);
|
|
494
638
|
currentText = '';
|
|
495
639
|
}
|
|
496
640
|
}
|
|
@@ -500,35 +644,52 @@ export default class FormatNode extends Node {
|
|
|
500
644
|
else if (node instanceof AtomNode) {
|
|
501
645
|
// Before adding the atom, create a text node and reset the accumulator.
|
|
502
646
|
saveText();
|
|
647
|
+
|
|
503
648
|
// Add the atom immediately after, unless it's in the deletion range.
|
|
504
649
|
// We include the start index since AtomNode's text index is on the left.
|
|
505
|
-
if (
|
|
650
|
+
if (
|
|
651
|
+
format !== undefined ||
|
|
506
652
|
textIndex < selectionStartIndex ||
|
|
507
|
-
textIndex > selectionEndIndex
|
|
653
|
+
textIndex > selectionEndIndex
|
|
654
|
+
) {
|
|
508
655
|
// Does the atom node have a format? Format it!
|
|
509
656
|
let newAtom = node;
|
|
510
657
|
const atomMeta = node.getMeta();
|
|
511
658
|
if (atomMeta instanceof FormatNode) {
|
|
512
|
-
if (
|
|
513
|
-
atomMeta.contains(range.
|
|
514
|
-
|
|
659
|
+
if (
|
|
660
|
+
atomMeta.contains(range.start.node) &&
|
|
661
|
+
atomMeta.contains(range.end.node)
|
|
662
|
+
) {
|
|
663
|
+
const newFormat = atomMeta.withFormat(
|
|
664
|
+
range,
|
|
665
|
+
format
|
|
666
|
+
);
|
|
515
667
|
newAtom = node.withMeta(newFormat);
|
|
516
668
|
}
|
|
517
669
|
}
|
|
518
670
|
// Add the formatted atom if there is one.
|
|
519
|
-
newFormats[0].segments.push(
|
|
671
|
+
newFormats[0].segments.push(
|
|
672
|
+
newAtom !== undefined ? newAtom : node
|
|
673
|
+
);
|
|
520
674
|
}
|
|
675
|
+
|
|
521
676
|
// Increment the text index; atoms count for one character.
|
|
522
677
|
textIndex++;
|
|
523
678
|
}
|
|
524
679
|
});
|
|
680
|
+
|
|
525
681
|
// Save any remaining text that we've accumulated.
|
|
526
682
|
saveText();
|
|
683
|
+
|
|
527
684
|
// Keep finishing formats until we get to the original we created.
|
|
528
|
-
while (newFormats.length > 1)
|
|
529
|
-
|
|
685
|
+
while (newFormats.length > 1) finishFormat();
|
|
686
|
+
|
|
530
687
|
// Create the final format.
|
|
531
|
-
let newFormat = new FormatNode(
|
|
688
|
+
let newFormat = new FormatNode(
|
|
689
|
+
newFormats[0].format,
|
|
690
|
+
newFormats[0].segments
|
|
691
|
+
);
|
|
692
|
+
|
|
532
693
|
// If after all that, it's empty, make sure there's one empty text node to type in.
|
|
533
694
|
if (newFormat.getTextAndAtomNodes().length === 0)
|
|
534
695
|
newFormat = new FormatNode('', [new TextNode()]);
|
|
@@ -536,210 +697,230 @@ export default class FormatNode extends Node {
|
|
|
536
697
|
else {
|
|
537
698
|
if (newFormat.#segments[0] instanceof AtomNode)
|
|
538
699
|
newFormat = newFormat.withSegmentPrepended(new TextNode());
|
|
539
|
-
if (
|
|
540
|
-
|
|
700
|
+
if (
|
|
701
|
+
newFormat.#segments[newFormat.getLength() - 1] instanceof
|
|
702
|
+
AtomNode
|
|
703
|
+
)
|
|
541
704
|
newFormat = newFormat.withSegmentAppended(new TextNode());
|
|
542
705
|
}
|
|
706
|
+
|
|
543
707
|
return newFormat;
|
|
544
708
|
}
|
|
545
|
-
|
|
709
|
+
|
|
710
|
+
withRangeFormatted(range: CaretRange, format: Format | undefined): Edit {
|
|
546
711
|
// Convert the range to text indices.
|
|
547
712
|
const text = caretRangeToIndexRange(this, range);
|
|
548
|
-
if (text === undefined)
|
|
549
|
-
return;
|
|
713
|
+
if (text === undefined) return;
|
|
550
714
|
const newFormat = this.withFormat(range, format);
|
|
551
|
-
if (newFormat === undefined)
|
|
552
|
-
return;
|
|
715
|
+
if (newFormat === undefined) return;
|
|
553
716
|
const newStart = indexToCaret(newFormat, text.start);
|
|
554
|
-
const newEnd =
|
|
555
|
-
|
|
556
|
-
|
|
717
|
+
const newEnd =
|
|
718
|
+
format === undefined ? newStart : indexToCaret(newFormat, text.end);
|
|
719
|
+
if (newStart === undefined || newEnd === undefined) return;
|
|
557
720
|
return { root: newFormat, range: { start: newStart, end: newEnd } };
|
|
558
721
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
722
|
+
|
|
723
|
+
getFormats(root: Node): Format[] {
|
|
724
|
+
let format: Node | undefined = this;
|
|
725
|
+
const formats: Format[] = [];
|
|
562
726
|
while (format instanceof FormatNode) {
|
|
563
|
-
if (format.#format !== '')
|
|
564
|
-
formats.push(format.#format);
|
|
727
|
+
if (format.#format !== '') formats.push(format.#format);
|
|
565
728
|
format = format.getParent(root);
|
|
566
729
|
}
|
|
567
730
|
return formats;
|
|
568
731
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
732
|
+
|
|
733
|
+
withSegmentAt(
|
|
734
|
+
segment: FormatNodeSegmentType,
|
|
735
|
+
caret: Caret
|
|
736
|
+
): FormatNode | undefined {
|
|
737
|
+
if (!(caret.node instanceof TextNode)) return;
|
|
738
|
+
|
|
572
739
|
// Verify that the caret's node is a segment in this node.
|
|
573
740
|
const index = this.#segments.indexOf(caret.node);
|
|
574
|
-
if (index < 0)
|
|
575
|
-
|
|
741
|
+
if (index < 0) return;
|
|
742
|
+
|
|
576
743
|
// Splice the text node.
|
|
577
|
-
const left = new TextNode(
|
|
744
|
+
const left = new TextNode(
|
|
745
|
+
caret.node.getText().substring(0, caret.index)
|
|
746
|
+
);
|
|
578
747
|
const right = new TextNode(caret.node.getText().substring(caret.index));
|
|
748
|
+
|
|
579
749
|
// Insert the new left, right and middle
|
|
580
750
|
const newSegments = this.#segments.slice();
|
|
581
751
|
newSegments.splice(index, 1, left, segment, right);
|
|
582
752
|
return new FormatNode(this.#format, newSegments);
|
|
583
753
|
}
|
|
584
|
-
|
|
754
|
+
|
|
755
|
+
withSegmentAtSelection(
|
|
756
|
+
range: CaretRange,
|
|
757
|
+
nodeCreator: (text: string) => FormatNodeSegmentType
|
|
758
|
+
): Edit {
|
|
585
759
|
// If there's a selection, grab it's text and then remove the text and update the root and text being edited.
|
|
586
760
|
let selectedText = this.getSelectedText(range);
|
|
587
|
-
let newFormat = this;
|
|
761
|
+
let newFormat: FormatNode | undefined = this;
|
|
588
762
|
const sortedRange = this.sortRange(range);
|
|
589
763
|
let caret = sortedRange.start;
|
|
590
|
-
if (
|
|
591
|
-
sortedRange.start.
|
|
764
|
+
if (
|
|
765
|
+
sortedRange.start.node !== sortedRange.end.node ||
|
|
766
|
+
sortedRange.start.index !== sortedRange.end.index
|
|
767
|
+
) {
|
|
592
768
|
// Try to remove the selected text. Bail on fail.
|
|
593
769
|
const textIndex = caretToIndex(this, sortedRange.start);
|
|
594
|
-
if (textIndex === undefined)
|
|
595
|
-
return;
|
|
770
|
+
if (textIndex === undefined) return;
|
|
596
771
|
newFormat = this.withoutRange(sortedRange);
|
|
597
|
-
if (newFormat === undefined)
|
|
598
|
-
return;
|
|
772
|
+
if (newFormat === undefined) return;
|
|
599
773
|
const newCaret = indexToCaret(newFormat, textIndex);
|
|
600
|
-
if (newCaret === undefined)
|
|
601
|
-
return;
|
|
774
|
+
if (newCaret === undefined) return;
|
|
602
775
|
caret = newCaret;
|
|
603
776
|
}
|
|
777
|
+
|
|
604
778
|
// Create and insert the into the formatted node.
|
|
605
|
-
const newNode = nodeCreator.call(
|
|
779
|
+
const newNode = nodeCreator.call(
|
|
780
|
+
undefined,
|
|
781
|
+
selectedText ? selectedText : ''
|
|
782
|
+
);
|
|
606
783
|
const revisedFormat = newFormat.withSegmentAt(newNode, caret);
|
|
607
|
-
if (revisedFormat === undefined)
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
784
|
+
if (revisedFormat === undefined) return;
|
|
785
|
+
const newCaret =
|
|
786
|
+
newNode instanceof AtomNode
|
|
787
|
+
? newNode.getDefaultCaret()
|
|
788
|
+
: newNode instanceof FormatNode
|
|
612
789
|
? newNode.getFirstCaret()
|
|
613
790
|
: newNode instanceof MetadataNode
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
791
|
+
? { node: newNode.getText(), index: 0 }
|
|
792
|
+
: newNode instanceof TextNode
|
|
793
|
+
? { node: newNode, index: 0 }
|
|
794
|
+
: undefined;
|
|
795
|
+
|
|
796
|
+
if (newCaret === undefined) return;
|
|
620
797
|
return {
|
|
621
798
|
root: revisedFormat,
|
|
622
799
|
range: { start: newCaret, end: newCaret },
|
|
623
800
|
};
|
|
624
801
|
}
|
|
625
|
-
|
|
802
|
+
|
|
803
|
+
withoutContentBefore(caret: Caret): FormatNode | undefined {
|
|
626
804
|
return this.withContentAt(caret, false);
|
|
627
805
|
}
|
|
628
|
-
|
|
806
|
+
|
|
807
|
+
withoutContentAfter(caret: Caret): FormatNode | undefined {
|
|
629
808
|
return this.withContentAt(caret, true);
|
|
630
809
|
}
|
|
631
|
-
|
|
810
|
+
|
|
811
|
+
withContentAt(caret: Caret, before: boolean): FormatNode | undefined {
|
|
632
812
|
let range = undefined;
|
|
633
813
|
if (before) {
|
|
634
814
|
const lastCaret = this.getLastCaret();
|
|
635
|
-
if (lastCaret === undefined)
|
|
636
|
-
return;
|
|
815
|
+
if (lastCaret === undefined) return;
|
|
637
816
|
range = { start: caret, end: lastCaret };
|
|
638
|
-
}
|
|
639
|
-
else {
|
|
817
|
+
} else {
|
|
640
818
|
const firstCaret = this.getFirstCaret();
|
|
641
|
-
if (firstCaret === undefined)
|
|
642
|
-
return;
|
|
819
|
+
if (firstCaret === undefined) return;
|
|
643
820
|
range = { start: firstCaret, end: caret };
|
|
644
821
|
}
|
|
645
822
|
return this.withoutRange(range);
|
|
646
823
|
}
|
|
647
|
-
|
|
824
|
+
|
|
825
|
+
withContentInRange(range: CaretRange): this | undefined {
|
|
648
826
|
const containsStart = this.contains(range.start.node);
|
|
649
827
|
const containsEnd = this.contains(range.end.node);
|
|
650
|
-
if (!containsStart && !containsEnd)
|
|
651
|
-
return this.copy();
|
|
828
|
+
if (!containsStart && !containsEnd) return this.copy();
|
|
652
829
|
const startCaret = containsStart ? range.start : this.getFirstCaret();
|
|
653
830
|
const endCaret = containsEnd ? range.end : this.getLastCaret();
|
|
654
|
-
if (startCaret === undefined || endCaret === undefined)
|
|
655
|
-
return;
|
|
831
|
+
if (startCaret === undefined || endCaret === undefined) return;
|
|
656
832
|
const startIndex = caretToIndex(this, startCaret);
|
|
657
833
|
const endIndex = caretToIndex(this, endCaret);
|
|
658
|
-
if (startIndex === undefined || endIndex === undefined)
|
|
659
|
-
return;
|
|
834
|
+
if (startIndex === undefined || endIndex === undefined) return;
|
|
660
835
|
const withoutBefore = this.withoutContentBefore(startCaret);
|
|
661
|
-
if (withoutBefore === undefined)
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
836
|
+
if (withoutBefore === undefined) return;
|
|
837
|
+
const revisedEndCaret = indexToCaret(
|
|
838
|
+
withoutBefore,
|
|
839
|
+
endIndex - startIndex
|
|
840
|
+
);
|
|
841
|
+
if (revisedEndCaret === undefined) return;
|
|
842
|
+
return withoutBefore.withoutContentAfter(revisedEndCaret) as this;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
withSegmentsAppended(format: FormatNode): FormatNode {
|
|
669
846
|
return new FormatNode(this.#format, [
|
|
670
847
|
...this.#segments,
|
|
671
848
|
...format.getSegments(),
|
|
672
849
|
]);
|
|
673
850
|
}
|
|
674
|
-
|
|
851
|
+
|
|
852
|
+
withoutAdjacentContent(caret: Caret, next: boolean): Edit | undefined {
|
|
675
853
|
return this.withoutCharacter(caret, next);
|
|
676
854
|
}
|
|
677
|
-
|
|
855
|
+
|
|
856
|
+
withoutCharacter(caret: Caret, next: boolean): Edit | undefined {
|
|
678
857
|
// Confirm that this caret is in this format.
|
|
679
|
-
if (!this.contains(caret.node))
|
|
680
|
-
return;
|
|
858
|
+
if (!this.contains(caret.node)) return;
|
|
681
859
|
// Is there an adjascent caret? Return nothing if not.
|
|
682
860
|
const adjacentCaret = this.getAdjacentCaret(caret, next);
|
|
683
|
-
if (adjacentCaret === undefined)
|
|
684
|
-
|
|
861
|
+
if (adjacentCaret === undefined) return;
|
|
862
|
+
|
|
685
863
|
// Handle each case differently
|
|
686
864
|
if (caret.node instanceof AtomNode) {
|
|
687
865
|
const newFormat = this.withNodeReplaced(caret.node, undefined);
|
|
688
|
-
if (newFormat === undefined)
|
|
689
|
-
return;
|
|
866
|
+
if (newFormat === undefined) return;
|
|
690
867
|
return {
|
|
691
868
|
root: newFormat,
|
|
692
869
|
range: { start: adjacentCaret, end: adjacentCaret },
|
|
693
870
|
};
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
871
|
+
} else if (adjacentCaret.node instanceof AtomNode) {
|
|
872
|
+
const newFormat = this.withNodeReplaced(
|
|
873
|
+
adjacentCaret.node,
|
|
874
|
+
undefined
|
|
875
|
+
);
|
|
876
|
+
if (newFormat === undefined) return;
|
|
699
877
|
return { root: newFormat, range: { start: caret, end: caret } };
|
|
700
|
-
}
|
|
701
|
-
else {
|
|
878
|
+
} else {
|
|
702
879
|
// If next, keep the caret in place, otherwise go to the adjacent caret position.
|
|
703
880
|
const textIndex = caretToIndex(this, next ? caret : adjacentCaret);
|
|
704
|
-
if (textIndex === undefined)
|
|
705
|
-
return;
|
|
881
|
+
if (textIndex === undefined) return;
|
|
706
882
|
// If there is one, try removing everything between this and the adjascent caret.
|
|
707
883
|
const newFormat = this.withoutRange({
|
|
708
884
|
start: caret,
|
|
709
885
|
end: adjacentCaret,
|
|
710
886
|
});
|
|
711
|
-
if (newFormat === undefined)
|
|
712
|
-
return;
|
|
887
|
+
if (newFormat === undefined) return;
|
|
713
888
|
const newCaret = indexToCaret(newFormat, textIndex);
|
|
714
|
-
if (newCaret === undefined)
|
|
715
|
-
return;
|
|
889
|
+
if (newCaret === undefined) return;
|
|
716
890
|
return {
|
|
717
891
|
root: newFormat,
|
|
718
892
|
range: { start: newCaret, end: newCaret },
|
|
719
893
|
};
|
|
720
894
|
}
|
|
721
895
|
}
|
|
722
|
-
|
|
896
|
+
|
|
897
|
+
withNodeInserted(caret: Caret, node: Node): Edit {
|
|
723
898
|
// The caret node has to be one of the nodes in this format to insert.
|
|
724
|
-
const index = this.#segments.indexOf(
|
|
725
|
-
|
|
726
|
-
|
|
899
|
+
const index = this.#segments.indexOf(
|
|
900
|
+
caret.node as FormatNodeSegmentType
|
|
901
|
+
);
|
|
902
|
+
if (index < 0) return;
|
|
727
903
|
// The inserted node has to be a segment type.
|
|
728
|
-
if (
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
904
|
+
if (
|
|
905
|
+
!(
|
|
906
|
+
node instanceof FormatNode ||
|
|
907
|
+
node instanceof TextNode ||
|
|
908
|
+
node instanceof MetadataNode ||
|
|
909
|
+
node instanceof AtomNode
|
|
910
|
+
)
|
|
911
|
+
)
|
|
732
912
|
return;
|
|
913
|
+
|
|
733
914
|
const newFormat = this.withSegmentAt(node, caret);
|
|
734
|
-
const newCaret =
|
|
735
|
-
|
|
736
|
-
|
|
915
|
+
const newCaret =
|
|
916
|
+
node instanceof AtomNode
|
|
917
|
+
? node.getDefaultCaret()
|
|
918
|
+
: node instanceof FormatNode
|
|
737
919
|
? node.getLastCaret()
|
|
738
920
|
: node instanceof MetadataNode
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
if (newFormat === undefined || newCaret === undefined)
|
|
742
|
-
return;
|
|
921
|
+
? { node: node.getText(), index: node.getText().getLength() }
|
|
922
|
+
: { node: node, index: node.getLength() };
|
|
923
|
+
if (newFormat === undefined || newCaret === undefined) return;
|
|
743
924
|
return { root: newFormat, range: { start: newCaret, end: newCaret } };
|
|
744
925
|
}
|
|
745
926
|
}
|