bookish-press 0.4.0 → 0.4.3
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/README.md +3 -1
- package/components/Auth.svelte +27 -24
- package/components/Auth.svelte.d.ts +4 -4
- package/components/Authentication.d.ts +2 -2
- package/components/BookPreview.svelte +75 -59
- package/components/BookPreview.svelte.d.ts +5 -5
- package/components/External.svelte +1 -1
- package/components/External.svelte.d.ts +3 -3
- package/components/Link.svelte +49 -3
- package/components/Link.svelte.d.ts +3 -4
- package/components/app/BookList.svelte +19 -0
- package/components/app/BookList.svelte.d.ts +18 -0
- package/components/app/Button.svelte +49 -0
- package/components/app/Button.svelte.d.ts +22 -0
- package/components/app/Feedback.svelte +47 -0
- package/components/app/Feedback.svelte.d.ts +18 -0
- package/components/app/Head.svelte +15 -0
- package/components/app/Head.svelte.d.ts +18 -0
- package/components/app/Large.svelte +8 -0
- package/components/app/Large.svelte.d.ts +27 -0
- package/components/app/Lead.svelte +12 -0
- package/components/app/Lead.svelte.d.ts +27 -0
- package/components/app/Link.svelte +24 -0
- package/components/app/Link.svelte.d.ts +20 -0
- package/components/app/Options.svelte +24 -0
- package/components/app/Options.svelte.d.ts +19 -0
- package/components/app/Paragraph.svelte +20 -0
- package/components/app/Paragraph.svelte.d.ts +18 -0
- package/components/app/Section.svelte +12 -0
- package/components/app/Section.svelte.d.ts +27 -0
- package/components/app/Table.svelte +32 -0
- package/components/app/Table.svelte.d.ts +27 -0
- package/components/app/TextInput.svelte +38 -0
- package/components/app/TextInput.svelte.d.ts +22 -0
- package/components/chapter/Atom.svelte +20 -6
- package/components/chapter/Atom.svelte.d.ts +3 -3
- package/components/chapter/Block.svelte +26 -21
- package/components/chapter/Block.svelte.d.ts +4 -4
- package/components/chapter/Callout.svelte +38 -7
- package/components/chapter/Callout.svelte.d.ts +4 -4
- package/components/chapter/CaptionedCode.svelte +67 -24
- package/components/chapter/CaptionedCode.svelte.d.ts +4 -4
- package/components/chapter/ChapterBody.svelte +62 -9
- package/components/chapter/ChapterBody.svelte.d.ts +5 -4
- package/components/chapter/Citations.svelte +86 -20
- package/components/chapter/Citations.svelte.d.ts +4 -4
- package/components/chapter/Code.svelte +152 -21
- package/components/chapter/Code.svelte.d.ts +3 -3
- package/components/chapter/Comment.svelte +39 -17
- package/components/chapter/Comment.svelte.d.ts +3 -3
- package/components/chapter/Definition.svelte +52 -18
- package/components/chapter/Definition.svelte.d.ts +5 -8
- package/components/chapter/Embed.svelte +155 -67
- package/components/chapter/Embed.svelte.d.ts +6 -4
- package/components/chapter/ErrorMessage.svelte +7 -2
- package/components/chapter/ErrorMessage.svelte.d.ts +4 -4
- package/components/chapter/ExtendedPrism.d.ts +2 -0
- package/components/chapter/ExtendedPrism.js +69 -0
- package/components/chapter/Figure.svelte +90 -0
- package/components/chapter/Figure.svelte.d.ts +24 -0
- package/components/chapter/Footnote.svelte +75 -12
- package/components/chapter/Footnote.svelte.d.ts +4 -4
- package/components/chapter/Format.svelte +63 -38
- package/components/chapter/Format.svelte.d.ts +5 -4
- package/components/chapter/InlineCode.svelte +16 -6
- package/components/chapter/InlineCode.svelte.d.ts +4 -4
- package/components/chapter/Label.svelte +38 -9
- package/components/chapter/Label.svelte.d.ts +4 -4
- package/components/chapter/Link.svelte +24 -19
- package/components/chapter/Link.svelte.d.ts +4 -4
- package/components/chapter/List.svelte +75 -8
- package/components/chapter/List.svelte.d.ts +4 -4
- package/components/chapter/Marginal.svelte +169 -27
- package/components/chapter/Marginal.svelte.d.ts +6 -3
- package/components/chapter/Paragraph.svelte +79 -6
- package/components/chapter/Paragraph.svelte.d.ts +4 -4
- package/components/chapter/Positioned.svelte +33 -0
- package/components/chapter/Positioned.svelte.d.ts +19 -0
- package/components/chapter/Problem.svelte +15 -0
- package/components/chapter/Problem.svelte.d.ts +27 -0
- package/components/chapter/Python.svelte +68 -21
- package/components/chapter/Python.svelte.d.ts +4 -4
- package/components/chapter/Quote.svelte +64 -11
- package/components/chapter/Quote.svelte.d.ts +4 -4
- package/components/chapter/Rule.svelte +12 -1
- package/components/chapter/Rule.svelte.d.ts +4 -4
- package/components/chapter/Table.svelte +36 -25
- package/components/chapter/Table.svelte.d.ts +4 -4
- package/components/chapter/Text.svelte +61 -36
- package/components/chapter/Text.svelte.d.ts +5 -4
- package/components/editor/BookishEditor.svelte +373 -244
- package/components/editor/BookishEditor.svelte.d.ts +9 -6
- package/components/editor/CalloutEditor.svelte +5 -5
- package/components/editor/CalloutEditor.svelte.d.ts +4 -4
- package/components/editor/CaptionedCodeEditor.svelte +16 -12
- package/components/editor/CaptionedCodeEditor.svelte.d.ts +4 -4
- package/components/editor/CaretContext.d.ts +48 -16
- package/components/editor/CaretState.d.ts +16 -44
- package/components/editor/CaretUtilities.d.ts +2 -2
- package/components/editor/CaretView.svelte +82 -0
- package/components/editor/CaretView.svelte.d.ts +25 -0
- package/components/editor/CitationsEditor.svelte +36 -25
- package/components/editor/CitationsEditor.svelte.d.ts +4 -4
- package/components/editor/Clipboard.d.ts +2 -2
- package/components/editor/Command.d.ts +13 -12
- package/components/editor/Commands.d.ts +1 -1
- package/components/editor/Commands.js +1114 -571
- package/components/editor/ConfirmButton.svelte +18 -12
- package/components/editor/ConfirmButton.svelte.d.ts +5 -4
- package/components/editor/DefinitionEditor.svelte +29 -21
- package/components/editor/DefinitionEditor.svelte.d.ts +4 -4
- package/components/editor/EmbedEditor.svelte +93 -43
- package/components/editor/EmbedEditor.svelte.d.ts +3 -3
- package/components/editor/Icon.svelte +17 -0
- package/components/editor/Icon.svelte.d.ts +16 -0
- package/components/editor/ImageChooser.svelte +53 -34
- package/components/editor/ImageChooser.svelte.d.ts +3 -3
- package/components/editor/InlineCodeEditor.svelte +7 -4
- package/components/editor/InlineCodeEditor.svelte.d.ts +4 -4
- package/components/editor/LabelEditor.svelte +20 -11
- package/components/editor/LabelEditor.svelte.d.ts +4 -4
- package/components/editor/LanguageEditor.svelte +10 -7
- package/components/editor/LanguageEditor.svelte.d.ts +3 -3
- package/components/editor/LinkEditor.svelte +64 -39
- package/components/editor/LinkEditor.svelte.d.ts +4 -4
- package/components/editor/Note.svelte +4 -3
- package/components/editor/Note.svelte.d.ts +6 -2
- package/components/editor/Permissions.svelte +95 -0
- package/components/editor/Permissions.svelte.d.ts +20 -0
- package/components/editor/PositionEditor.svelte +9 -6
- package/components/editor/PositionEditor.svelte.d.ts +4 -4
- package/components/editor/QuoteEditor.svelte +7 -2
- package/components/editor/QuoteEditor.svelte.d.ts +4 -4
- package/components/editor/Switch.svelte +55 -28
- package/components/editor/Switch.svelte.d.ts +4 -4
- package/components/editor/TableEditor.svelte +10 -0
- package/components/editor/TableEditor.svelte.d.ts +17 -0
- package/components/editor/TextEditor.svelte +83 -45
- package/components/editor/TextEditor.svelte.d.ts +5 -4
- package/components/editor/Toggle.svelte +11 -8
- package/components/editor/Toggle.svelte.d.ts +4 -4
- package/components/editor/Toolbar.svelte +191 -144
- package/components/editor/Toolbar.svelte.d.ts +5 -8
- package/components/editor/ToolbarGroup.svelte +17 -23
- package/components/editor/ToolbarGroup.svelte.d.ts +3 -4
- package/components/editor/ToolbarSpacer.svelte +8 -1
- package/components/editor/ToolbarSpacer.svelte.d.ts +6 -2
- package/components/editor/URLEditor.svelte +6 -8
- package/components/editor/URLEditor.svelte.d.ts +3 -3
- package/components/editor/UndoState.d.ts +3 -3
- package/components/editor/icons/annotate.svg +1 -0
- package/components/editor/icons/block.svg +1 -0
- package/components/editor/icons/bold.svg +1 -0
- package/components/editor/icons/bullets.svg +1 -0
- package/components/editor/icons/callout.svg +1 -0
- package/components/editor/icons/citation.svg +8 -0
- package/components/editor/icons/clear.svg +1 -0
- package/components/editor/icons/clipboard.svg +1 -0
- package/components/editor/icons/code.svg +1 -0
- package/components/editor/icons/columnafter.svg +1 -0
- package/components/editor/icons/columnbefore.svg +1 -0
- package/components/editor/icons/comment.svg +1 -0
- package/components/editor/icons/copy.svg +1 -0
- package/components/editor/icons/cut.svg +1 -0
- package/components/editor/icons/define.svg +7 -0
- package/components/editor/icons/deletecolumn.svg +1 -0
- package/components/editor/icons/deleterow.svg +1 -0
- package/components/editor/icons/footnote.svg +8 -0
- package/components/editor/icons/header1.svg +7 -0
- package/components/editor/icons/header2.svg +7 -0
- package/components/editor/icons/header3.svg +7 -0
- package/components/editor/icons/home.svg +1 -0
- package/components/editor/icons/indent.svg +1 -0
- package/components/editor/icons/italic.svg +1 -0
- package/components/editor/icons/label.svg +1 -0
- package/components/editor/icons/left.svg +1 -0
- package/components/editor/icons/level.svg +1 -0
- package/components/editor/icons/link.svg +1 -0
- package/components/editor/icons/list.svg +1 -0
- package/components/editor/icons/media.svg +1 -0
- package/components/editor/icons/middle.svg +1 -0
- package/components/editor/icons/numbers.svg +10 -0
- package/components/editor/icons/paragraph.svg +1 -0
- package/components/editor/icons/paste.svg +10 -0
- package/components/editor/icons/quote.svg +1 -0
- package/components/editor/icons/redo.svg +1 -0
- package/components/editor/icons/right.svg +1 -0
- package/components/editor/icons/rowabove.svg +1 -0
- package/components/editor/icons/rowbelow.svg +1 -0
- package/components/editor/icons/rule.svg +1 -0
- package/components/editor/icons/sub.svg +1 -0
- package/components/editor/icons/super.svg +1 -0
- package/components/editor/icons/table.svg +1 -0
- package/components/editor/icons/text.svg +1 -0
- package/components/editor/icons/time.svg +1 -0
- package/components/editor/icons/undo.svg +1 -0
- package/components/editor/icons/unindent.svg +1 -0
- package/components/editor/icons/unlink.svg +1 -0
- package/components/page/Acknowledgements.svelte +35 -24
- package/components/page/Acknowledgements.svelte.d.ts +4 -4
- package/components/page/Authors.svelte +34 -17
- package/components/page/Authors.svelte.d.ts +7 -6
- package/components/page/BookLoader.svelte +59 -0
- package/components/page/BookLoader.svelte.d.ts +16 -0
- package/components/page/BulkReferenceEditor.svelte +54 -23
- package/components/page/BulkReferenceEditor.svelte.d.ts +4 -4
- package/components/page/Chapter.svelte +234 -143
- package/components/page/Chapter.svelte.d.ts +3 -3
- package/components/page/ChapterContext.d.ts +4 -4
- package/components/page/ChapterNumber.svelte +9 -0
- package/components/page/ChapterNumber.svelte.d.ts +27 -0
- package/components/page/ChapterTitle.svelte +16 -0
- package/components/page/ChapterTitle.svelte.d.ts +18 -0
- package/components/page/Contexts.d.ts +42 -22
- package/components/page/Contexts.js +129 -17
- package/components/page/DefinitionView.svelte +129 -90
- package/components/page/DefinitionView.svelte.d.ts +3 -3
- package/components/page/Description.svelte +31 -19
- package/components/page/Description.svelte.d.ts +4 -4
- package/components/page/Edition.svelte +135 -80
- package/components/page/Edition.svelte.d.ts +5 -6
- package/components/page/EditionLoader.svelte +99 -0
- package/components/page/EditionLoader.svelte.d.ts +18 -0
- package/components/page/Editions.svelte +106 -0
- package/components/page/Editions.svelte.d.ts +14 -0
- package/components/page/Glossary.svelte +65 -49
- package/components/page/Glossary.svelte.d.ts +4 -4
- package/components/page/Header.svelte +143 -56
- package/components/page/Header.svelte.d.ts +8 -6
- package/components/page/Index.svelte +116 -80
- package/components/page/Index.svelte.d.ts +4 -4
- package/components/page/Instructions.svelte +18 -17
- package/components/page/Instructions.svelte.d.ts +6 -4
- package/components/page/License.svelte +39 -23
- package/components/page/License.svelte.d.ts +4 -4
- package/components/page/Loading.svelte +102 -12
- package/components/page/Loading.svelte.d.ts +6 -2
- package/components/page/Media.svelte +81 -53
- package/components/page/Media.svelte.d.ts +4 -4
- package/components/page/MediaPreview.svelte +26 -8
- package/components/page/MediaPreview.svelte.d.ts +3 -3
- package/components/page/Muted.svelte +10 -0
- package/components/page/Muted.svelte.d.ts +27 -0
- package/components/page/Outline.svelte +279 -59
- package/components/page/Outline.svelte.d.ts +3 -3
- package/components/page/Page.svelte +40 -9
- package/components/page/Page.svelte.d.ts +3 -3
- package/components/page/PageHeader.svelte +14 -0
- package/components/page/PageHeader.svelte.d.ts +18 -0
- package/components/page/PageParagraph.svelte +18 -0
- package/components/page/PageParagraph.svelte.d.ts +27 -0
- package/components/page/PossibleChapter.svelte +7 -7
- package/components/page/PossibleChapter.svelte.d.ts +4 -4
- package/components/page/PossibleReference.svelte +6 -11
- package/components/page/PossibleReference.svelte.d.ts +6 -7
- package/components/page/Print.svelte +27 -3
- package/components/page/Print.svelte.d.ts +4 -4
- package/components/page/Publish.svelte +134 -0
- package/components/page/Publish.svelte.d.ts +14 -0
- package/components/page/Reference.svelte +259 -117
- package/components/page/Reference.svelte.d.ts +5 -5
- package/components/page/References.svelte +45 -48
- package/components/page/References.svelte.d.ts +4 -4
- package/components/page/Rows.svelte +54 -0
- package/components/page/Rows.svelte.d.ts +27 -0
- package/components/page/Search.svelte +88 -63
- package/components/page/Search.svelte.d.ts +4 -4
- package/components/page/Status.svelte +46 -39
- package/components/page/Status.svelte.d.ts +4 -9
- package/components/page/SubdomainEditor.svelte +41 -27
- package/components/page/SubdomainEditor.svelte.d.ts +4 -4
- package/components/page/TableOfContents.svelte +264 -191
- package/components/page/TableOfContents.svelte.d.ts +4 -4
- package/components/page/TableOfContentsImage.svelte +8 -8
- package/components/page/TableOfContentsImage.svelte.d.ts +3 -3
- package/components/page/TableOfContentsRow.svelte +97 -34
- package/components/page/TableOfContentsRow.svelte.d.ts +4 -4
- package/components/page/ThemeEditor.svelte +177 -39
- package/components/page/ThemeEditor.svelte.d.ts +4 -4
- package/components/page/ThemeEditorPreview.svelte +35 -23
- package/components/page/ThemeEditorPreview.svelte.d.ts +5 -5
- package/components/page/ThemeSetEditor.svelte +15 -13
- package/components/page/ThemeSetEditor.svelte.d.ts +4 -4
- package/components/page/ThemeVariableEditor.svelte +24 -15
- package/components/page/ThemeVariableEditor.svelte.d.ts +3 -3
- package/components/page/Title.svelte +12 -0
- package/components/page/Title.svelte.d.ts +27 -0
- package/components/page/Unknown.svelte +28 -21
- package/components/page/Unknown.svelte.d.ts +4 -4
- package/components/page/margins.js +50 -33
- package/index.d.ts +13 -0
- package/index.js +14 -0
- package/models/CRUD.d.ts +27 -0
- package/models/CRUD.js +262 -0
- package/models/Firebase.d.ts +1 -0
- package/models/Firebase.js +26 -16
- package/models/book/Book.d.ts +40 -39
- package/models/book/Book.js +121 -121
- package/models/book/BookMedia.d.ts +3 -3
- package/models/book/BookMedia.js +22 -16
- package/models/book/BookSaveStatus.d.ts +7 -0
- package/models/book/BookSaveStatus.js +8 -0
- package/models/book/Chapter.d.ts +50 -39
- package/models/book/Chapter.js +189 -198
- package/models/book/ChapterID.js +7 -7
- package/models/book/Definition.d.ts +1 -1
- package/models/book/Edition.d.ts +87 -61
- package/models/book/Edition.js +460 -309
- package/models/book/Reference.d.ts +24 -0
- package/models/book/Reference.js +78 -0
- package/models/book/Schema.d.ts +168 -0
- package/models/book/Schema.js +115 -0
- package/models/book/Theme.d.ts +44 -37
- package/models/book/Theme.js +452 -52
- package/models/book/ThemeColors.d.ts +1 -1
- package/models/book/Words.d.ts +2 -0
- package/models/book/Words.js +110 -0
- package/models/chapter/AtomNode.d.ts +4 -4
- package/models/chapter/AtomNode.js +20 -13
- package/models/chapter/BlockNode.d.ts +9 -10
- package/models/chapter/BlockNode.js +32 -13
- package/models/chapter/BlocksNode.d.ts +10 -10
- package/models/chapter/BlocksNode.js +315 -120
- package/models/chapter/BlocksNode.test.js +494 -228
- package/models/chapter/Bookkeeping.d.ts +1 -1
- package/models/chapter/CalloutNode.d.ts +3 -3
- package/models/chapter/CalloutNode.js +34 -12
- package/models/chapter/Caret.d.ts +9 -7
- package/models/chapter/Caret.js +11 -6
- package/models/chapter/ChapterNode.d.ts +11 -11
- package/models/chapter/ChapterNode.js +70 -33
- package/models/chapter/CitationsNode.d.ts +3 -3
- package/models/chapter/CitationsNode.js +31 -12
- package/models/chapter/CodeNode.d.ts +11 -6
- package/models/chapter/CodeNode.js +143 -34
- package/models/chapter/CommentNode.d.ts +5 -5
- package/models/chapter/CommentNode.js +29 -13
- package/models/chapter/DefinitionNode.d.ts +2 -2
- package/models/chapter/DefinitionNode.js +15 -7
- package/models/chapter/Edit.d.ts +3 -3
- package/models/chapter/EmbedNode.d.ts +9 -5
- package/models/chapter/EmbedNode.js +108 -35
- package/models/chapter/ErrorNode.d.ts +2 -2
- package/models/chapter/ErrorNode.js +34 -12
- package/models/chapter/FootnoteNode.d.ts +5 -5
- package/models/chapter/FootnoteNode.js +34 -16
- package/models/chapter/FormatNode.d.ts +10 -10
- package/models/chapter/FormatNode.js +237 -106
- package/models/chapter/FormatNode.test.js +87 -45
- package/models/chapter/InlineCodeNode.d.ts +2 -2
- package/models/chapter/InlineCodeNode.js +22 -9
- package/models/chapter/LabelNode.d.ts +4 -4
- package/models/chapter/LabelNode.js +31 -13
- package/models/chapter/LinkNode.d.ts +2 -2
- package/models/chapter/LinkNode.js +21 -9
- package/models/chapter/ListNode.d.ts +8 -8
- package/models/chapter/ListNode.js +99 -38
- package/models/chapter/ListNode.test.js +29 -24
- package/models/chapter/MetadataNode.d.ts +3 -3
- package/models/chapter/MetadataNode.js +13 -5
- package/models/chapter/Node.d.ts +5 -3
- package/models/chapter/Node.js +76 -29
- package/models/chapter/Node.test.js +20 -18
- package/models/chapter/ParagraphNode.d.ts +6 -6
- package/models/chapter/ParagraphNode.js +84 -29
- package/models/chapter/ParagraphNode.test.js +22 -13
- package/models/chapter/Parser.d.ts +27 -27
- package/models/chapter/Parser.js +220 -206
- package/models/chapter/Parser.test.js +16 -16
- package/models/chapter/Position.d.ts +1 -1
- package/models/chapter/QuoteNode.d.ts +6 -6
- package/models/chapter/QuoteNode.js +61 -23
- package/models/chapter/RootNode.d.ts +4 -4
- package/models/chapter/RuleNode.d.ts +2 -2
- package/models/chapter/RuleNode.js +31 -11
- package/models/chapter/TableNode.d.ts +8 -6
- package/models/chapter/TableNode.js +89 -34
- package/models/chapter/TableNode.test.js +22 -24
- package/models/chapter/TextNode.d.ts +6 -6
- package/models/chapter/TextNode.js +72 -32
- package/models/chapter/TextNode.test.js +4 -4
- package/package.json +108 -26
- package/util/getSubdomain.js +8 -6
- package/util/isMobile.js +1 -1
- package/util/mineReference.d.ts +3 -2
- package/util/mineReference.js +67 -29
- package/util/scrollToEyeLevel.js +6 -1
- package/components/chapter/renderPosition.d.ts +0 -3
- package/components/chapter/renderPosition.js +0 -4
- package/components/editor/ToolbarIcon.svelte +0 -22
- package/components/editor/ToolbarIcon.svelte.d.ts +0 -16
- package/components/page/Alert.svelte +0 -11
- package/components/page/Alert.svelte.d.ts +0 -23
- package/components/page/Revisions.svelte +0 -124
- package/components/page/Revisions.svelte.d.ts +0 -14
- package/models/BookLoader.d.ts +0 -2
- package/models/BookLoader.js +0 -67
- package/models/Firestore.d.ts +0 -22
- package/models/Firestore.js +0 -194
- package/models/chapter/ReferenceNode.d.ts +0 -29
- package/models/chapter/ReferenceNode.js +0 -48
- package/models/loadEdition.d.ts +0 -5
- package/models/loadEdition.js +0 -16
|
@@ -1,38 +1,50 @@
|
|
|
1
|
-
import BlockNode from
|
|
2
|
-
import ListNode from
|
|
3
|
-
import { caretToIndex, indexToCaret } from
|
|
4
|
-
import ParagraphNode from
|
|
5
|
-
import FormatNode from
|
|
6
|
-
import TextNode from
|
|
7
|
-
import AtomNode from
|
|
8
|
-
import CodeNode from
|
|
1
|
+
import BlockNode from './BlockNode';
|
|
2
|
+
import ListNode from './ListNode';
|
|
3
|
+
import { caretToIndex, indexToCaret } from './Caret';
|
|
4
|
+
import ParagraphNode from './ParagraphNode';
|
|
5
|
+
import FormatNode from './FormatNode';
|
|
6
|
+
import TextNode from './TextNode';
|
|
7
|
+
import AtomNode from './AtomNode';
|
|
8
|
+
import CodeNode from './CodeNode';
|
|
9
|
+
import EmbedNode from './EmbedNode';
|
|
9
10
|
export default class BlocksNode extends BlockNode {
|
|
10
11
|
#blocks;
|
|
11
12
|
constructor(elements) {
|
|
12
13
|
super();
|
|
13
|
-
// Always ensure there's an empty paragraph before and after non-paragraph nodes to allow for insertions.
|
|
14
14
|
const adjustedElements = [];
|
|
15
15
|
for (let i = 0; i < elements.length; i++) {
|
|
16
16
|
const block = elements[i];
|
|
17
17
|
const previousBlock = i === 0 ? undefined : elements[i - 1];
|
|
18
18
|
// If this block and the previous one are lists of the same kind, merge them.
|
|
19
|
-
if (block instanceof ListNode &&
|
|
20
|
-
|
|
19
|
+
if (block instanceof ListNode &&
|
|
20
|
+
previousBlock instanceof ListNode &&
|
|
21
|
+
block.isNumbered() === previousBlock.isNumbered()) {
|
|
22
|
+
adjustedElements[adjustedElements.length - 1] =
|
|
23
|
+
previousBlock.withListAppended(block);
|
|
21
24
|
}
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
// Always ensure there's an empty paragraph before and after non-paragraph nodes to allow for insertions.
|
|
26
|
+
// // If the block isn't a paragraph and the last one isn't either or this is the first one, put a paragraph between them to allow for insertion.
|
|
27
|
+
// else {
|
|
28
|
+
// if(!(block instanceof ParagraphNode) && (i === 0 || !(previousBlock instanceof ParagraphNode)))
|
|
29
|
+
// adjustedElements.push(new ParagraphNode());
|
|
30
|
+
// }
|
|
31
|
+
else
|
|
26
32
|
adjustedElements.push(block);
|
|
27
|
-
}
|
|
28
33
|
}
|
|
29
34
|
// Check the last one.
|
|
30
|
-
if
|
|
31
|
-
|
|
35
|
+
// if(!(adjustedElements[adjustedElements.length - 1] instanceof ParagraphNode))
|
|
36
|
+
// adjustedElements.push(new ParagraphNode());
|
|
32
37
|
this.#blocks = adjustedElements;
|
|
38
|
+
// After all that, always ensure there's at least one empty paragraph block.
|
|
39
|
+
if (this.#blocks.length === 0)
|
|
40
|
+
this.#blocks.push(new ParagraphNode());
|
|
41
|
+
}
|
|
42
|
+
getBlocks() {
|
|
43
|
+
return this.#blocks;
|
|
44
|
+
}
|
|
45
|
+
getFormats() {
|
|
46
|
+
return this.getBlocks().reduce((prev, current) => prev.concat(current.getFormats()), []);
|
|
33
47
|
}
|
|
34
|
-
getBlocks() { return this.#blocks; }
|
|
35
|
-
getFormats() { return this.getBlocks().reduce((prev, current) => prev.concat(current.getFormats()), []); }
|
|
36
48
|
getIndexOf(block) {
|
|
37
49
|
const index = this.#blocks.indexOf(block);
|
|
38
50
|
return index < 0 ? undefined : index;
|
|
@@ -77,14 +89,18 @@ export default class BlocksNode extends BlockNode {
|
|
|
77
89
|
getBlocksInRange(range) {
|
|
78
90
|
// Find the start and end block the carets reside in. Bail on fail.
|
|
79
91
|
const startBlock = this.getBlockOfCaret(range.start);
|
|
80
|
-
const endBlock = range.end === range.start
|
|
92
|
+
const endBlock = range.end === range.start
|
|
93
|
+
? startBlock
|
|
94
|
+
: this.getBlockOfCaret(range.end);
|
|
81
95
|
if (startBlock === undefined || endBlock === undefined)
|
|
82
96
|
return;
|
|
83
97
|
// Find all of the blocks between the start and end blocks.
|
|
84
98
|
// Start tracking when we hit the start node. Stop tracking when we hit the end node.
|
|
85
99
|
const blocksToEdit = [];
|
|
86
100
|
let insideSelection = false;
|
|
87
|
-
this.getNodes()
|
|
101
|
+
this.getNodes()
|
|
102
|
+
.filter((n) => n instanceof BlockNode)
|
|
103
|
+
.forEach((node) => {
|
|
88
104
|
if (node === startBlock)
|
|
89
105
|
insideSelection = true;
|
|
90
106
|
if (insideSelection && node instanceof BlockNode)
|
|
@@ -98,16 +114,18 @@ export default class BlocksNode extends BlockNode {
|
|
|
98
114
|
return caret.node.getClosestParentOfType(this, BlockNode);
|
|
99
115
|
}
|
|
100
116
|
getParentOf(node) {
|
|
101
|
-
return this.#blocks
|
|
117
|
+
return this.#blocks
|
|
118
|
+
.map((b) => (b === node ? this : b.getParentOf(node)))
|
|
119
|
+
.find((b) => b !== undefined);
|
|
102
120
|
}
|
|
103
121
|
getTextNodes() {
|
|
104
|
-
return this.getNodes().filter(node => node instanceof TextNode);
|
|
122
|
+
return this.getNodes().filter((node) => node instanceof TextNode);
|
|
105
123
|
}
|
|
106
124
|
getAtomNodes() {
|
|
107
|
-
return this.getNodes().filter(node => node instanceof AtomNode);
|
|
125
|
+
return this.getNodes().filter((node) => node instanceof AtomNode);
|
|
108
126
|
}
|
|
109
127
|
getTextAndAtomNodes() {
|
|
110
|
-
return this.getNodes().filter(node => node instanceof TextNode || node instanceof AtomNode);
|
|
128
|
+
return this.getNodes().filter((node) => node instanceof TextNode || node instanceof AtomNode);
|
|
111
129
|
}
|
|
112
130
|
getIndexOfTextNode(node) {
|
|
113
131
|
const text = this.getTextNodes();
|
|
@@ -119,23 +137,30 @@ export default class BlocksNode extends BlockNode {
|
|
|
119
137
|
}
|
|
120
138
|
getLastCaret() {
|
|
121
139
|
const text = this.getTextNodes();
|
|
122
|
-
return text.length === 0
|
|
140
|
+
return text.length === 0
|
|
141
|
+
? undefined
|
|
142
|
+
: {
|
|
143
|
+
node: text[text.length - 1],
|
|
144
|
+
index: text[text.length - 1].getLength(),
|
|
145
|
+
};
|
|
123
146
|
}
|
|
124
147
|
getAdjacentCaret(caret, next) {
|
|
125
148
|
if (!this.contains(caret.node))
|
|
126
149
|
return;
|
|
127
150
|
// Navigate from code node.
|
|
128
|
-
const code = caret.node.getFarthestParentMatching(this, n => n instanceof CodeNode);
|
|
151
|
+
const code = caret.node.getFarthestParentMatching(this, (n) => n instanceof CodeNode);
|
|
129
152
|
if (code && caret.node === code.getCodeNode()) {
|
|
130
153
|
// Get the adjacent text node.
|
|
131
|
-
const newCaret = next
|
|
154
|
+
const newCaret = next
|
|
155
|
+
? caret.node.getNextCaret(caret.index)
|
|
156
|
+
: caret.node.getPreviousCaret(caret.index);
|
|
132
157
|
if (newCaret !== undefined)
|
|
133
158
|
return newCaret;
|
|
134
159
|
// Otherwise, get the adjacent format's first/last caret.
|
|
135
160
|
if (next)
|
|
136
161
|
return code.getCaption().getFirstCaret();
|
|
137
162
|
// If there's no adjacent caret, find the adjacent root format.
|
|
138
|
-
const blocks = this.getNodes().filter(n => n instanceof BlockNode);
|
|
163
|
+
const blocks = this.getNodes().filter((n) => n instanceof BlockNode);
|
|
139
164
|
const codeIndex = blocks.indexOf(code);
|
|
140
165
|
if (codeIndex <= 0)
|
|
141
166
|
return;
|
|
@@ -144,7 +169,7 @@ export default class BlocksNode extends BlockNode {
|
|
|
144
169
|
const adjacentFormat = adjacentFormats[adjacentFormats.length - 1];
|
|
145
170
|
return adjacentFormat.getLastCaret();
|
|
146
171
|
}
|
|
147
|
-
const format = caret.node.getFarthestParentMatching(this, n => n instanceof FormatNode);
|
|
172
|
+
const format = caret.node.getFarthestParentMatching(this, (n) => n instanceof FormatNode);
|
|
148
173
|
if (format === undefined)
|
|
149
174
|
return;
|
|
150
175
|
// Find the format that contains the caret and return the adjacent caret if there is one.
|
|
@@ -152,26 +177,34 @@ export default class BlocksNode extends BlockNode {
|
|
|
152
177
|
if (adjacentCaretInFormat !== undefined)
|
|
153
178
|
return adjacentCaretInFormat;
|
|
154
179
|
// If there's no adjacent caret in the root format, find the adjacent format or code.
|
|
155
|
-
const formats = this.getNodes().filter(n => {
|
|
180
|
+
const formats = this.getNodes().filter((n) => {
|
|
156
181
|
const parent = n.getParent(this);
|
|
157
|
-
return (n instanceof TextNode && parent instanceof CodeNode) ||
|
|
182
|
+
return ((n instanceof TextNode && parent instanceof CodeNode) ||
|
|
183
|
+
(n instanceof FormatNode &&
|
|
184
|
+
!(parent instanceof AtomNode) &&
|
|
185
|
+
!(parent instanceof FormatNode)));
|
|
158
186
|
});
|
|
159
187
|
const index = formats.indexOf(format);
|
|
160
|
-
const adjacentFormat = index < 0 || formats.length === 0
|
|
188
|
+
const adjacentFormat = index < 0 || formats.length === 0
|
|
189
|
+
? undefined
|
|
190
|
+
: formats[index + (next ? 1 : -1)];
|
|
161
191
|
if (adjacentFormat === undefined)
|
|
162
192
|
return;
|
|
163
|
-
return next
|
|
193
|
+
return next
|
|
194
|
+
? adjacentFormat.getFirstCaret()
|
|
195
|
+
: adjacentFormat.getLastCaret();
|
|
164
196
|
}
|
|
165
197
|
getSelectedFormatRange(format, range) {
|
|
166
198
|
// Find all of the formats.
|
|
167
|
-
const formats = this.getNodes().filter(n => n instanceof FormatNode &&
|
|
199
|
+
const formats = this.getNodes().filter((n) => n instanceof FormatNode &&
|
|
200
|
+
!(this.getParentOf(n) instanceof FormatNode));
|
|
168
201
|
// Find the given format index.
|
|
169
202
|
const formatIndex = formats.indexOf(format);
|
|
170
203
|
if (formatIndex < 0)
|
|
171
204
|
return undefined;
|
|
172
205
|
// Find the range start and end formats.
|
|
173
|
-
const startFormat = formats.find(f => f.contains(range.start.node));
|
|
174
|
-
const endFormat = formats.find(f => f.contains(range.end.node));
|
|
206
|
+
const startFormat = formats.find((f) => f.contains(range.start.node));
|
|
207
|
+
const endFormat = formats.find((f) => f.contains(range.end.node));
|
|
175
208
|
if (startFormat === undefined || endFormat === undefined)
|
|
176
209
|
return undefined;
|
|
177
210
|
const startIndex = formats.indexOf(startFormat);
|
|
@@ -225,7 +258,7 @@ export default class BlocksNode extends BlockNode {
|
|
|
225
258
|
return this.create(newBlocks);
|
|
226
259
|
}
|
|
227
260
|
withoutBlock(block) {
|
|
228
|
-
return this.create(this.#blocks.filter(n => n !== block));
|
|
261
|
+
return this.create(this.#blocks.filter((n) => n !== block));
|
|
229
262
|
}
|
|
230
263
|
withBlockInsertedBefore(anchor, block) {
|
|
231
264
|
return this.withBlockInserted(anchor, block, true);
|
|
@@ -237,48 +270,71 @@ export default class BlocksNode extends BlockNode {
|
|
|
237
270
|
let caret = range.start;
|
|
238
271
|
let blocks = this;
|
|
239
272
|
// If there's a selection, remove it before inserting.
|
|
240
|
-
if (range.start.node !== range.end.node ||
|
|
273
|
+
if (range.start.node !== range.end.node ||
|
|
274
|
+
range.start.index !== range.end.index) {
|
|
241
275
|
const edit = blocks.withoutRange(range);
|
|
242
276
|
if (edit === undefined || !(edit.root instanceof BlocksNode))
|
|
243
277
|
return;
|
|
244
278
|
blocks = edit.root;
|
|
245
279
|
caret = edit.range.start;
|
|
246
280
|
}
|
|
247
|
-
// Find what
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (paragraph === undefined)
|
|
251
|
-
return;
|
|
252
|
-
// Split the paragraph in two.
|
|
253
|
-
const split = paragraph.split(caret);
|
|
254
|
-
if (split === undefined)
|
|
281
|
+
// Find what block the caret is in.
|
|
282
|
+
const block = caret.node.getClosestParentOfType(blocks, BlockNode);
|
|
283
|
+
if (block === undefined)
|
|
255
284
|
return;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
285
|
+
// If it's a paragraph, split it.
|
|
286
|
+
if (block instanceof ParagraphNode) {
|
|
287
|
+
const paragraph = block;
|
|
288
|
+
// Split the paragraph in two.
|
|
289
|
+
const split = paragraph.split(caret);
|
|
290
|
+
if (split === undefined)
|
|
291
|
+
return;
|
|
292
|
+
const [first, last] = split;
|
|
293
|
+
const newCaret = last.getFirstCaret();
|
|
294
|
+
if (newCaret === undefined)
|
|
295
|
+
return;
|
|
296
|
+
// Find the paragraph's blocks node.
|
|
297
|
+
const paragraphBlocks = paragraph.getParent(blocks);
|
|
298
|
+
if (!(paragraphBlocks instanceof BlocksNode))
|
|
299
|
+
return;
|
|
300
|
+
const newBlocks = paragraphBlocks
|
|
301
|
+
.withBlockInsertedBefore(paragraph, first)
|
|
302
|
+
?.withBlockInsertedAfter(paragraph, last)
|
|
303
|
+
?.withoutBlock(paragraph);
|
|
304
|
+
if (newBlocks === undefined)
|
|
305
|
+
return;
|
|
306
|
+
// Replace the paragraphs blocks in these blocks.
|
|
307
|
+
const newRoot = blocks.withNodeReplaced(paragraphBlocks, newBlocks);
|
|
308
|
+
if (newRoot === undefined)
|
|
309
|
+
return;
|
|
310
|
+
return { root: newRoot, range: { start: newCaret, end: newCaret } };
|
|
311
|
+
}
|
|
312
|
+
// If any other kind of block, and an empty paragraph after the block.
|
|
313
|
+
else {
|
|
314
|
+
// Find the paragraph's blocks node.
|
|
315
|
+
const container = block.getParent(blocks);
|
|
316
|
+
if (!(container instanceof BlocksNode))
|
|
317
|
+
return;
|
|
318
|
+
const newParagraph = new ParagraphNode();
|
|
319
|
+
const newCaret = newParagraph.getFirstCaret();
|
|
320
|
+
if (newCaret === undefined)
|
|
321
|
+
return;
|
|
322
|
+
const newBlocks = container.withBlockInsertedAfter(block, newParagraph);
|
|
323
|
+
if (newBlocks === undefined)
|
|
324
|
+
return;
|
|
325
|
+
// Replace the paragraphs blocks in these blocks.
|
|
326
|
+
const newRoot = blocks.withNodeReplaced(container, newBlocks);
|
|
327
|
+
if (newRoot === undefined)
|
|
328
|
+
return;
|
|
329
|
+
return { root: newRoot, range: { start: newCaret, end: newCaret } };
|
|
330
|
+
}
|
|
275
331
|
}
|
|
276
332
|
withoutRange(range) {
|
|
277
333
|
return this.withRangeFormatted(range, undefined);
|
|
278
334
|
}
|
|
279
335
|
withoutAtom(atom) {
|
|
280
336
|
// Find the format that contains the atom.
|
|
281
|
-
const format = atom.getFarthestParentMatching(this, p => p instanceof FormatNode);
|
|
337
|
+
const format = atom.getFarthestParentMatching(this, (p) => p instanceof FormatNode);
|
|
282
338
|
if (format === undefined)
|
|
283
339
|
return;
|
|
284
340
|
// Find the text or atom node to the left and right of the atom to determine the new caret position.
|
|
@@ -286,11 +342,16 @@ export default class BlocksNode extends BlockNode {
|
|
|
286
342
|
const next = format.getNextTextOrAtom(atom);
|
|
287
343
|
const newText = new TextNode();
|
|
288
344
|
// If the format is otherwise empty, replace the atom with an empty text node
|
|
289
|
-
const newFormat = previous === undefined && next == undefined
|
|
290
|
-
format.withSegmentReplaced(atom, newText)
|
|
291
|
-
format.withoutSegment(atom);
|
|
345
|
+
const newFormat = previous === undefined && next == undefined
|
|
346
|
+
? format.withSegmentReplaced(atom, newText)
|
|
347
|
+
: format.withoutSegment(atom);
|
|
292
348
|
// New caret is left, or right, or empty text.
|
|
293
|
-
const newCaret = {
|
|
349
|
+
const newCaret = {
|
|
350
|
+
node: previous ? previous : next ? next : newText,
|
|
351
|
+
index: previous && previous instanceof TextNode
|
|
352
|
+
? previous.getLength()
|
|
353
|
+
: 0,
|
|
354
|
+
};
|
|
294
355
|
// No format? Fail.
|
|
295
356
|
if (newFormat === undefined)
|
|
296
357
|
return;
|
|
@@ -303,18 +364,27 @@ export default class BlocksNode extends BlockNode {
|
|
|
303
364
|
}
|
|
304
365
|
withRangeFormatted(range, format) {
|
|
305
366
|
// Only works on text nodes, atom nodes, and metadata nodes.
|
|
306
|
-
if (!(range.start.node instanceof TextNode ||
|
|
307
|
-
|
|
367
|
+
if (!(range.start.node instanceof TextNode ||
|
|
368
|
+
range.start.node instanceof AtomNode) ||
|
|
369
|
+
!(range.end.node instanceof TextNode ||
|
|
370
|
+
range.end.node instanceof AtomNode))
|
|
308
371
|
return;
|
|
309
372
|
// Have we selected a single atom node for removal? Remove it and place the caret in the adjacent word.
|
|
310
|
-
if (format === undefined &&
|
|
373
|
+
if (format === undefined &&
|
|
374
|
+
range.start.node instanceof AtomNode &&
|
|
375
|
+
range.end.node instanceof AtomNode &&
|
|
376
|
+
range.start.node === range.end.node) {
|
|
311
377
|
return this.withoutAtom(range.start.node);
|
|
312
378
|
}
|
|
313
379
|
// Preserve the original range, since there are a few cases where we adjust it.
|
|
314
380
|
let adjustedRange = range;
|
|
315
381
|
// If this a single point in format, and we're clearing formatting, adjust the selection to the whole format.
|
|
316
|
-
if (format ===
|
|
317
|
-
|
|
382
|
+
if (format === '' &&
|
|
383
|
+
range.start.node === range.end.node &&
|
|
384
|
+
range.start.index === range.end.index) {
|
|
385
|
+
const selection = range.start.node
|
|
386
|
+
.getFormatRoot(this)
|
|
387
|
+
?.getSelection();
|
|
318
388
|
if (selection === undefined)
|
|
319
389
|
return;
|
|
320
390
|
adjustedRange = selection;
|
|
@@ -337,8 +407,12 @@ export default class BlocksNode extends BlockNode {
|
|
|
337
407
|
if (containsStart || containsEnd || inRange) {
|
|
338
408
|
inRange = true;
|
|
339
409
|
// Compute a proper range based on containment.
|
|
340
|
-
const blockStart = containsStart
|
|
341
|
-
|
|
410
|
+
const blockStart = containsStart
|
|
411
|
+
? sortedRange.start
|
|
412
|
+
: block.getFirstCaret();
|
|
413
|
+
const blockEnd = containsEnd
|
|
414
|
+
? sortedRange.end
|
|
415
|
+
: block.getLastCaret();
|
|
342
416
|
if (blockStart === undefined || blockEnd === undefined)
|
|
343
417
|
return;
|
|
344
418
|
// If we're just going to delete it, then don't bother formatting it.
|
|
@@ -354,16 +428,40 @@ export default class BlocksNode extends BlockNode {
|
|
|
354
428
|
if (edit === undefined)
|
|
355
429
|
return;
|
|
356
430
|
// If we succeeded in formatting it, replace it, otherwise skip it.
|
|
431
|
+
let newBlock = edit.root;
|
|
432
|
+
// Finally, if the selection started before a list node, and we were deleting in the middle of some item,
|
|
433
|
+
// convert that item (which should now be the first item in the list) into a paragraph, since it's bullet was deleted, conceptually.
|
|
434
|
+
if (!newBlock.isEmpty() &&
|
|
435
|
+
newBlock instanceof ListNode &&
|
|
436
|
+
!containsStart &&
|
|
437
|
+
containsEnd) {
|
|
438
|
+
const firstItem = newBlock.getItem(0);
|
|
439
|
+
if (firstItem instanceof FormatNode) {
|
|
440
|
+
// Remove the item from the list.
|
|
441
|
+
const newListWithoutItem = newBlock.withoutItem(firstItem);
|
|
442
|
+
if (newListWithoutItem === undefined)
|
|
443
|
+
return;
|
|
444
|
+
newBlock = newListWithoutItem;
|
|
445
|
+
// Replace the revised list
|
|
446
|
+
const blocksWithList = newBlocks
|
|
447
|
+
.withChildReplaced(block, newBlock)
|
|
448
|
+
?.withBlockInsertedBefore(newBlock, new ParagraphNode(0, firstItem));
|
|
449
|
+
if (blocksWithList === undefined)
|
|
450
|
+
return;
|
|
451
|
+
newBlocks = blocksWithList;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
// Otherwise, just handle the new block in isolation.
|
|
357
455
|
else {
|
|
358
|
-
const newBlock = edit.root;
|
|
359
456
|
// Remember non-empty revised blocks so we can merge things after.
|
|
360
457
|
if (!newBlock.isEmpty())
|
|
361
458
|
formattedBlocks.push(newBlock);
|
|
362
459
|
// Replace the block, or delete it if it's empty.
|
|
363
460
|
newBlocks = newBlocks.withChildReplaced(block, newBlock.isEmpty() ? undefined : newBlock);
|
|
364
|
-
if (newBlocks === undefined)
|
|
365
|
-
return;
|
|
366
461
|
}
|
|
462
|
+
// If we failed to replace it, bail.
|
|
463
|
+
if (newBlocks === undefined)
|
|
464
|
+
return;
|
|
367
465
|
}
|
|
368
466
|
}
|
|
369
467
|
if (block.contains(sortedRange.end.node))
|
|
@@ -373,7 +471,8 @@ export default class BlocksNode extends BlockNode {
|
|
|
373
471
|
if (format === undefined && formattedBlocks.length >= 2) {
|
|
374
472
|
const first = formattedBlocks[0];
|
|
375
473
|
const last = formattedBlocks[formattedBlocks.length - 1];
|
|
376
|
-
if (first instanceof ParagraphNode &&
|
|
474
|
+
if (first instanceof ParagraphNode &&
|
|
475
|
+
last instanceof ParagraphNode) {
|
|
377
476
|
// Replace the first paragraph with the second merged.
|
|
378
477
|
newBlocks = newBlocks.withNodeReplaced(first, first.withContent(first.getFormat().withSegmentsAppended(last.getFormat())));
|
|
379
478
|
if (newBlocks === undefined)
|
|
@@ -386,7 +485,9 @@ export default class BlocksNode extends BlockNode {
|
|
|
386
485
|
}
|
|
387
486
|
const startCaret = indexToCaret(newBlocks, startTextIndex);
|
|
388
487
|
// If we deleted, then the end caret should be the same as the start.
|
|
389
|
-
const endCaret = format === undefined
|
|
488
|
+
const endCaret = format === undefined
|
|
489
|
+
? startCaret
|
|
490
|
+
: indexToCaret(newBlocks, endTextIndex);
|
|
390
491
|
if (startCaret === undefined || endCaret === undefined)
|
|
391
492
|
return;
|
|
392
493
|
// Return the new root and the start and end of the range.
|
|
@@ -417,13 +518,14 @@ export default class BlocksNode extends BlockNode {
|
|
|
417
518
|
if (blocksInRange === undefined)
|
|
418
519
|
return;
|
|
419
520
|
// Only format if every block selected is a paragraph node. Non-paragraphs can't be in lists.
|
|
420
|
-
if (!blocksInRange.every(b => b instanceof ParagraphNode))
|
|
521
|
+
if (!blocksInRange.every((b) => b instanceof ParagraphNode))
|
|
421
522
|
return;
|
|
422
523
|
// Split the blocks into groups with shared parents.
|
|
423
524
|
const sequences = [[]];
|
|
424
525
|
let previous = undefined;
|
|
425
|
-
blocksInRange.forEach(block => {
|
|
426
|
-
if (previous === undefined ||
|
|
526
|
+
blocksInRange.forEach((block) => {
|
|
527
|
+
if (previous === undefined ||
|
|
528
|
+
block.getParent(this) === previous.getParent(this))
|
|
427
529
|
sequences[sequences.length - 1].push(block);
|
|
428
530
|
else {
|
|
429
531
|
sequences.push([block]);
|
|
@@ -435,7 +537,7 @@ export default class BlocksNode extends BlockNode {
|
|
|
435
537
|
for (let i = 0; i < sequences.length; i++) {
|
|
436
538
|
const sequence = sequences[i];
|
|
437
539
|
// Make the new list
|
|
438
|
-
const newList = new ListNode(sequence.map(p => p.getFormat()), numbered);
|
|
540
|
+
const newList = new ListNode(sequence.map((p) => p.getFormat()), numbered);
|
|
439
541
|
// Insert the new list
|
|
440
542
|
const blocksParent = sequence[0].getParent(newBlocks);
|
|
441
543
|
if (blocksParent === undefined)
|
|
@@ -462,14 +564,23 @@ export default class BlocksNode extends BlockNode {
|
|
|
462
564
|
if (blocksInRange === undefined)
|
|
463
565
|
return;
|
|
464
566
|
// Convert all of the lists into their root lists, since we only convert entire lists, not parts of lists.
|
|
465
|
-
const listsInRange = blocksInRange.filter(l => l instanceof ListNode);
|
|
466
|
-
const listRootsInRange = [
|
|
567
|
+
const listsInRange = blocksInRange.filter((l) => l instanceof ListNode);
|
|
568
|
+
const listRootsInRange = [
|
|
569
|
+
...new Set(listsInRange
|
|
570
|
+
.map((l) => l.getParent(this) instanceof ListNode
|
|
571
|
+
? l.getFarthestParentMatching(this, (m) => m instanceof ListNode)
|
|
572
|
+
: l)
|
|
573
|
+
.filter((n) => n !== undefined)),
|
|
574
|
+
];
|
|
467
575
|
if (listRootsInRange.length === 0)
|
|
468
576
|
return undefined;
|
|
469
577
|
// For each list in the range, convert all items in range to paragraphs.
|
|
470
578
|
for (let i = 0; i < listRootsInRange.length; i++) {
|
|
471
579
|
const list = listRootsInRange[i];
|
|
472
|
-
const paragraphs = list
|
|
580
|
+
const paragraphs = list
|
|
581
|
+
.getNodes()
|
|
582
|
+
.filter((n) => n instanceof FormatNode)
|
|
583
|
+
.map((f) => new ParagraphNode(0, f));
|
|
473
584
|
// Insert in reverse order to keep them in order, since the list is our anchor.
|
|
474
585
|
for (let j = paragraphs.length - 1; j >= 0; j--) {
|
|
475
586
|
const paragraph = paragraphs[j];
|
|
@@ -490,10 +601,13 @@ export default class BlocksNode extends BlockNode {
|
|
|
490
601
|
// Find all of the formats in list nodes in the range and indent them.
|
|
491
602
|
const ancestor = range.start.node.getCommonAncestor(newBlocks, range.end.node);
|
|
492
603
|
const nodes = ancestor?.getNodes();
|
|
493
|
-
const formats = nodes?.filter(n => n instanceof FormatNode &&
|
|
604
|
+
const formats = nodes?.filter((n) => n instanceof FormatNode &&
|
|
605
|
+
newBlocks.getParentOf(n) instanceof ListNode);
|
|
494
606
|
const startIndex = nodes?.indexOf(range.start.node);
|
|
495
607
|
const endIndex = nodes?.indexOf(range.end.node);
|
|
496
|
-
if (formats === undefined ||
|
|
608
|
+
if (formats === undefined ||
|
|
609
|
+
startIndex === undefined ||
|
|
610
|
+
endIndex === undefined)
|
|
497
611
|
return;
|
|
498
612
|
// Loop through the formats in the range and indent or dedent them, constructing a new root.
|
|
499
613
|
const first = startIndex < endIndex ? range.start.node : range.end.node;
|
|
@@ -506,9 +620,11 @@ export default class BlocksNode extends BlockNode {
|
|
|
506
620
|
// If we're in the selection and the format is in a list, restructure it's list to indent/unindent it.
|
|
507
621
|
if (inside) {
|
|
508
622
|
// Find the root list node of the format.
|
|
509
|
-
const list = format.getFarthestParentMatching(newBlocks, n => n instanceof ListNode);
|
|
623
|
+
const list = format.getFarthestParentMatching(newBlocks, (n) => n instanceof ListNode);
|
|
510
624
|
if (list instanceof ListNode) {
|
|
511
|
-
const newList = indent
|
|
625
|
+
const newList = indent
|
|
626
|
+
? list.withItemIndented(format)
|
|
627
|
+
: list.withItemUnindented(format);
|
|
512
628
|
if (newList === undefined)
|
|
513
629
|
return;
|
|
514
630
|
const blocksWithIndent = newBlocks.withChildReplaced(list, newList);
|
|
@@ -534,6 +650,7 @@ export default class BlocksNode extends BlockNode {
|
|
|
534
650
|
return;
|
|
535
651
|
// Find the parents of the node.
|
|
536
652
|
const parents = this.getParentsOf(caret.node);
|
|
653
|
+
// Iterate through the ancestors, seeing if they'd like to handle the request for a deletion.
|
|
537
654
|
while (parents && parents.length > 0) {
|
|
538
655
|
const parent = parents.pop();
|
|
539
656
|
// Ask the format node it's in to edit it, and return if successful.
|
|
@@ -547,6 +664,32 @@ export default class BlocksNode extends BlockNode {
|
|
|
547
664
|
return { root: newBlocks, range: editedFormat.range };
|
|
548
665
|
}
|
|
549
666
|
}
|
|
667
|
+
// See if the CodeNode would like to handle it.
|
|
668
|
+
else if (parent instanceof CodeNode) {
|
|
669
|
+
const revisedCode = parent.getCodeNode().withoutRange({
|
|
670
|
+
start: caret,
|
|
671
|
+
end: {
|
|
672
|
+
node: caret.node,
|
|
673
|
+
index: caret.index + (next ? 1 : -1),
|
|
674
|
+
},
|
|
675
|
+
});
|
|
676
|
+
if (revisedCode === undefined)
|
|
677
|
+
return;
|
|
678
|
+
const revisedCodeNode = parent.withChildReplaced(parent.getCodeNode(), revisedCode);
|
|
679
|
+
if (revisedCodeNode === undefined)
|
|
680
|
+
return;
|
|
681
|
+
const newBlocks = this.withNodeReplaced(parent, revisedCodeNode);
|
|
682
|
+
const newCaret = {
|
|
683
|
+
node: revisedCode,
|
|
684
|
+
index: Math.max(0, caret.index + (next ? 0 : -1)),
|
|
685
|
+
};
|
|
686
|
+
return newBlocks === undefined
|
|
687
|
+
? undefined
|
|
688
|
+
: {
|
|
689
|
+
root: newBlocks,
|
|
690
|
+
range: { start: newCaret, end: newCaret },
|
|
691
|
+
};
|
|
692
|
+
}
|
|
550
693
|
// If it's a format in the list node, merge with the previous list item
|
|
551
694
|
else if (parent instanceof ListNode) {
|
|
552
695
|
const index = parent.getItemContaining(caret);
|
|
@@ -561,10 +704,14 @@ export default class BlocksNode extends BlockNode {
|
|
|
561
704
|
const newBlocks = this.withNodeReplaced(parent, newList);
|
|
562
705
|
if (newBlocks === undefined)
|
|
563
706
|
return;
|
|
564
|
-
return {
|
|
707
|
+
return {
|
|
708
|
+
root: newBlocks,
|
|
709
|
+
range: { start: newCaret, end: newCaret },
|
|
710
|
+
};
|
|
565
711
|
}
|
|
566
712
|
// Convert the remaining list item into a paragraph.
|
|
567
|
-
else if (parents.length > 0 &&
|
|
713
|
+
else if (parents.length > 0 &&
|
|
714
|
+
parents[parents.length - 1] instanceof BlocksNode) {
|
|
568
715
|
const item = parent.getItem(0);
|
|
569
716
|
if (!(item instanceof FormatNode))
|
|
570
717
|
return;
|
|
@@ -573,36 +720,56 @@ export default class BlocksNode extends BlockNode {
|
|
|
573
720
|
const newCaret = newParagraph.getFirstCaret();
|
|
574
721
|
if (newBlocks === undefined || newCaret === undefined)
|
|
575
722
|
return;
|
|
576
|
-
return {
|
|
723
|
+
return {
|
|
724
|
+
root: newBlocks,
|
|
725
|
+
range: { start: newCaret, end: newCaret },
|
|
726
|
+
};
|
|
577
727
|
}
|
|
578
728
|
}
|
|
579
729
|
// If it's at the beginning of the paragraph, and there's a previous paragraph, merge with the previous paragraph.
|
|
580
730
|
else if (parent instanceof ParagraphNode) {
|
|
581
|
-
const firstCaret = next
|
|
731
|
+
const firstCaret = next
|
|
732
|
+
? parent.getLastCaret()
|
|
733
|
+
: parent.getFirstCaret();
|
|
582
734
|
if (firstCaret === undefined)
|
|
583
735
|
return;
|
|
584
736
|
const blocks = parents[parents.length - 1];
|
|
585
|
-
const adjacentBlock = next
|
|
737
|
+
const adjacentBlock = next
|
|
738
|
+
? blocks.getBlockAfter(parent)
|
|
739
|
+
: blocks.getBlockBefore(parent);
|
|
586
740
|
// Is this the first/last caret of the paragraph and there's an adjascent block? Try deleting something.
|
|
587
|
-
if (firstCaret.node === caret.node &&
|
|
741
|
+
if (firstCaret.node === caret.node &&
|
|
742
|
+
firstCaret.index === caret.index &&
|
|
743
|
+
adjacentBlock !== undefined) {
|
|
588
744
|
// If the block adjacent this paragraph is a paragraph, merge the paragraph into the adjacent paragraph.
|
|
589
745
|
if (adjacentBlock instanceof ParagraphNode) {
|
|
590
|
-
const currentCaret = next
|
|
746
|
+
const currentCaret = next
|
|
747
|
+
? parent.getLastCaret()
|
|
748
|
+
: adjacentBlock.getLastCaret();
|
|
591
749
|
if (currentCaret === undefined)
|
|
592
750
|
return;
|
|
593
|
-
const textIndex = next
|
|
751
|
+
const textIndex = next
|
|
752
|
+
? caretToIndex(parent.getFormat(), currentCaret)
|
|
753
|
+
: caretToIndex(adjacentBlock.getFormat(), currentCaret);
|
|
594
754
|
if (textIndex === undefined)
|
|
595
755
|
return;
|
|
596
|
-
const mergedParagraph = next
|
|
756
|
+
const mergedParagraph = next
|
|
757
|
+
? adjacentBlock.withParagraphPrepended(parent)
|
|
758
|
+
: adjacentBlock.withParagraphAppended(parent);
|
|
597
759
|
if (mergedParagraph === undefined)
|
|
598
760
|
return;
|
|
599
|
-
const newBlocks = this.withNodeReplaced(blocks, blocks
|
|
761
|
+
const newBlocks = this.withNodeReplaced(blocks, blocks
|
|
762
|
+
.withChildReplaced(adjacentBlock, mergedParagraph)
|
|
763
|
+
?.withoutBlock(parent));
|
|
600
764
|
if (newBlocks === undefined)
|
|
601
765
|
return;
|
|
602
766
|
const newCaret = indexToCaret(mergedParagraph.getFormat(), textIndex);
|
|
603
767
|
if (newCaret === undefined)
|
|
604
768
|
return;
|
|
605
|
-
return {
|
|
769
|
+
return {
|
|
770
|
+
root: newBlocks,
|
|
771
|
+
range: { start: newCaret, end: newCaret },
|
|
772
|
+
};
|
|
606
773
|
}
|
|
607
774
|
// If the block adjacent is a list node, merge the paragraph to the list's first/last item.
|
|
608
775
|
else if (adjacentBlock instanceof ListNode) {
|
|
@@ -610,11 +777,18 @@ export default class BlocksNode extends BlockNode {
|
|
|
610
777
|
if (next) {
|
|
611
778
|
const format = adjacentBlock.getFirstItem();
|
|
612
779
|
if (format !== undefined) {
|
|
613
|
-
const newParagraph = parent.withContent(parent
|
|
614
|
-
|
|
780
|
+
const newParagraph = parent.withContent(parent
|
|
781
|
+
.getFormat()
|
|
782
|
+
.withSegmentsAppended(format));
|
|
783
|
+
const newBlocks = blocks
|
|
784
|
+
.withNodeReplaced(parent, newParagraph)
|
|
785
|
+
?.withNodeReplaced(format, undefined);
|
|
615
786
|
if (newBlocks === undefined)
|
|
616
787
|
return;
|
|
617
|
-
return {
|
|
788
|
+
return {
|
|
789
|
+
root: newBlocks,
|
|
790
|
+
range: { start: caret, end: caret },
|
|
791
|
+
};
|
|
618
792
|
}
|
|
619
793
|
}
|
|
620
794
|
// If we're going backwards, get the last format of the list and insert the paragraph's content into it,
|
|
@@ -623,18 +797,31 @@ export default class BlocksNode extends BlockNode {
|
|
|
623
797
|
const format = adjacentBlock.getLastItem();
|
|
624
798
|
if (format !== undefined) {
|
|
625
799
|
const newFormat = format.withSegmentAppended(parent.getFormat());
|
|
626
|
-
const newBlocks = blocks
|
|
627
|
-
|
|
628
|
-
|
|
800
|
+
const newBlocks = blocks
|
|
801
|
+
.withNodeReplaced(format, newFormat)
|
|
802
|
+
?.withoutBlock(parent);
|
|
803
|
+
const newCaret = parent
|
|
804
|
+
.getFormat()
|
|
805
|
+
.getFirstCaret();
|
|
806
|
+
if (newBlocks === undefined ||
|
|
807
|
+
newCaret === undefined)
|
|
629
808
|
return;
|
|
630
|
-
return {
|
|
809
|
+
return {
|
|
810
|
+
root: newBlocks,
|
|
811
|
+
range: { start: newCaret, end: newCaret },
|
|
812
|
+
};
|
|
631
813
|
}
|
|
632
814
|
}
|
|
633
815
|
}
|
|
634
816
|
// Otherwise, return a root without the previous block, deleting it.
|
|
635
817
|
else {
|
|
636
818
|
const newBlocks = this.withNodeReplaced(blocks, blocks.withoutBlock(adjacentBlock));
|
|
637
|
-
return newBlocks === undefined
|
|
819
|
+
return newBlocks === undefined
|
|
820
|
+
? undefined
|
|
821
|
+
: {
|
|
822
|
+
root: newBlocks,
|
|
823
|
+
range: { start: caret, end: caret },
|
|
824
|
+
};
|
|
638
825
|
}
|
|
639
826
|
}
|
|
640
827
|
}
|
|
@@ -646,12 +833,16 @@ export default class BlocksNode extends BlockNode {
|
|
|
646
833
|
if (!this.contains(caret.node))
|
|
647
834
|
return;
|
|
648
835
|
// Get the blocks to insert.
|
|
649
|
-
const blocks = node instanceof BlocksNode
|
|
836
|
+
const blocks = node instanceof BlocksNode
|
|
837
|
+
? node.getBlocks()
|
|
838
|
+
: node instanceof BlockNode
|
|
839
|
+
? [node]
|
|
840
|
+
: [];
|
|
650
841
|
// If there are none, do nothing.
|
|
651
842
|
if (blocks.length === 0)
|
|
652
843
|
return;
|
|
653
844
|
// Find the block in this blocks node that contains the caret.
|
|
654
|
-
const anchor = this.#blocks.find(b => b.contains(caret.node));
|
|
845
|
+
const anchor = this.#blocks.find((b) => b.contains(caret.node));
|
|
655
846
|
if (anchor === undefined)
|
|
656
847
|
return;
|
|
657
848
|
let lastInsert = anchor;
|
|
@@ -662,14 +853,18 @@ export default class BlocksNode extends BlockNode {
|
|
|
662
853
|
if (newBlock === undefined)
|
|
663
854
|
return;
|
|
664
855
|
// If we're inserting after the anchor and the anchor is a paragraph and the block to insert is a paragraph, merge them.
|
|
665
|
-
if (lastInsert === anchor &&
|
|
856
|
+
if (lastInsert === anchor &&
|
|
857
|
+
anchor instanceof ParagraphNode &&
|
|
858
|
+
newBlock instanceof ParagraphNode) {
|
|
666
859
|
newBlock = anchor.withParagraphAppended(newBlock);
|
|
667
860
|
if (newBlock === undefined)
|
|
668
861
|
return;
|
|
669
862
|
newBlocks = newBlocks.withChildReplaced(anchor, newBlock);
|
|
670
863
|
}
|
|
671
864
|
// If we're inserting after the anchor and the anchor is a list and the block to insert is a list, merge them.
|
|
672
|
-
else if (lastInsert === anchor &&
|
|
865
|
+
else if (lastInsert === anchor &&
|
|
866
|
+
anchor instanceof ListNode &&
|
|
867
|
+
newBlock instanceof ListNode) {
|
|
673
868
|
const edit = anchor.withNodeInserted(caret, newBlock);
|
|
674
869
|
if (edit === undefined || !(edit.root instanceof BlockNode))
|
|
675
870
|
return;
|
|
@@ -690,7 +885,7 @@ export default class BlocksNode extends BlockNode {
|
|
|
690
885
|
const formats = lastInsert.getFormats();
|
|
691
886
|
let newCaret = undefined;
|
|
692
887
|
if (formats.length === 0) {
|
|
693
|
-
const newParagraph = new ParagraphNode(0, new FormatNode(
|
|
888
|
+
const newParagraph = new ParagraphNode(0, new FormatNode('', [new TextNode()]));
|
|
694
889
|
newCaret = newParagraph.getFirstCaret();
|
|
695
890
|
newBlocks = newBlocks.withBlockInsertedAfter(lastInsert, newParagraph);
|
|
696
891
|
if (newCaret === undefined || newBlocks === undefined)
|
|
@@ -704,6 +899,6 @@ export default class BlocksNode extends BlockNode {
|
|
|
704
899
|
return { root: newBlocks, range: { start: newCaret, end: newCaret } };
|
|
705
900
|
}
|
|
706
901
|
toHTML() {
|
|
707
|
-
return this.#blocks.map(b => b.toHTML()).join(
|
|
902
|
+
return this.#blocks.map((b) => b.toHTML()).join('');
|
|
708
903
|
}
|
|
709
904
|
}
|