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,8 +1,8 @@
|
|
|
1
|
-
import Node from
|
|
2
|
-
import TextNode from
|
|
3
|
-
import { caretRangeToIndexRange, caretToIndex, indexToCaret } from
|
|
4
|
-
import MetadataNode from
|
|
5
|
-
import AtomNode from
|
|
1
|
+
import Node from './Node';
|
|
2
|
+
import TextNode from './TextNode';
|
|
3
|
+
import { caretRangeToIndexRange, caretToIndex, indexToCaret, } from './Caret';
|
|
4
|
+
import MetadataNode from './MetadataNode';
|
|
5
|
+
import AtomNode from './AtomNode';
|
|
6
6
|
export default class FormatNode extends Node {
|
|
7
7
|
#format;
|
|
8
8
|
#segments;
|
|
@@ -11,42 +11,66 @@ export default class FormatNode extends Node {
|
|
|
11
11
|
this.#format = format;
|
|
12
12
|
// Remove consecutive empty text nodes.
|
|
13
13
|
this.#segments = segments.filter((item, position, list) => {
|
|
14
|
-
if (position === 0 ||
|
|
14
|
+
if (position === 0 ||
|
|
15
|
+
!(item instanceof TextNode) ||
|
|
16
|
+
item.getLength() > 0)
|
|
15
17
|
return true;
|
|
16
18
|
const previous = list[position - 1];
|
|
17
19
|
return !(previous instanceof TextNode && previous.getLength() === 0);
|
|
18
20
|
});
|
|
19
21
|
}
|
|
20
|
-
getType() {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
getType() {
|
|
23
|
+
return 'formatted';
|
|
24
|
+
}
|
|
25
|
+
getFormat() {
|
|
26
|
+
return this.#format;
|
|
27
|
+
}
|
|
28
|
+
getSegments() {
|
|
29
|
+
return this.#segments;
|
|
30
|
+
}
|
|
31
|
+
isEmpty() {
|
|
32
|
+
return this.#segments.length === 0;
|
|
33
|
+
}
|
|
34
|
+
isEmptyText() {
|
|
35
|
+
return (this.#segments.length === 1 &&
|
|
36
|
+
this.#segments[0] instanceof TextNode &&
|
|
37
|
+
this.#segments[0].getText() === '');
|
|
38
|
+
}
|
|
39
|
+
getLength() {
|
|
40
|
+
return this.#segments.length;
|
|
41
|
+
}
|
|
26
42
|
getParentOf(node) {
|
|
27
|
-
return this.#segments
|
|
43
|
+
return this.#segments
|
|
44
|
+
.map((b) => (b === node ? this : b.getParentOf(node)))
|
|
45
|
+
.find((b) => b !== undefined);
|
|
28
46
|
}
|
|
29
47
|
toText() {
|
|
30
|
-
return this.#segments.map(segment => segment.toText()).join(
|
|
48
|
+
return this.#segments.map((segment) => segment.toText()).join(' ');
|
|
31
49
|
}
|
|
32
50
|
toHTML() {
|
|
33
51
|
const format = this.#format;
|
|
34
|
-
const segments = this.#segments.map(s => s.toHTML()).join(
|
|
35
|
-
if (format ===
|
|
52
|
+
const segments = this.#segments.map((s) => s.toHTML()).join('');
|
|
53
|
+
if (format === '*')
|
|
36
54
|
return `<strong>${segments}</strong>`;
|
|
37
|
-
else if (format ===
|
|
55
|
+
else if (format === '_')
|
|
38
56
|
return `<em>${segments}</em>`;
|
|
39
|
-
else if (format ===
|
|
57
|
+
else if (format === '^')
|
|
40
58
|
return `<sup>${segments}</sup>`;
|
|
41
|
-
else if (format ===
|
|
59
|
+
else if (format === 'v')
|
|
42
60
|
return `<sub>${segments}</sub>`;
|
|
43
61
|
else
|
|
44
62
|
return segments;
|
|
45
63
|
}
|
|
46
64
|
toBookdown() {
|
|
47
|
-
return (this.#format ===
|
|
65
|
+
return ((this.#format === 'v' ? '^v' : this.#format) +
|
|
66
|
+
this.#segments
|
|
67
|
+
.map((s) => s instanceof AtomNode ? s.toBookdown(this) : s.toBookdown())
|
|
68
|
+
.join('') +
|
|
69
|
+
(this.#format === 'v' ? '^' : this.#format));
|
|
70
|
+
}
|
|
71
|
+
getChildren() {
|
|
72
|
+
return this.#segments;
|
|
48
73
|
}
|
|
49
|
-
getChildren() { return this.#segments; }
|
|
50
74
|
getFirstTextNode() {
|
|
51
75
|
const text = this.getTextNodes();
|
|
52
76
|
return text[0];
|
|
@@ -56,27 +80,34 @@ export default class FormatNode extends Node {
|
|
|
56
80
|
return text[text.length - 1];
|
|
57
81
|
}
|
|
58
82
|
copy() {
|
|
59
|
-
return new FormatNode(this.#format, this.#segments.map(s => s.copy()));
|
|
83
|
+
return new FormatNode(this.#format, this.#segments.map((s) => s.copy()));
|
|
60
84
|
}
|
|
61
85
|
getTextNodes() {
|
|
62
|
-
return this.getNodes().filter(n => n instanceof TextNode);
|
|
86
|
+
return this.getNodes().filter((n) => n instanceof TextNode);
|
|
63
87
|
}
|
|
64
88
|
// Get all text or atom nodes in this format, except for any inside an atom node,
|
|
65
89
|
// as this is used for navigation and editing, and they should be isolated from that.
|
|
66
90
|
getTextAndAtomNodes() {
|
|
67
|
-
return this.getNodes().filter(n =>
|
|
91
|
+
return this.getNodes().filter((n) => n instanceof TextNode || n instanceof AtomNode);
|
|
68
92
|
}
|
|
69
93
|
getAdjacentTextOrAtom(node, next) {
|
|
70
94
|
// Find all of the text and atom nodes not in atom nodes in this node.
|
|
71
|
-
const text = this.getTextAndAtomNodes().filter(n => {
|
|
95
|
+
const text = this.getTextAndAtomNodes().filter((n) => {
|
|
72
96
|
const atomAncestor = n.getClosestParentOfType(this, AtomNode);
|
|
73
|
-
return atomAncestor === undefined ||
|
|
97
|
+
return (atomAncestor === undefined ||
|
|
98
|
+
(atomAncestor instanceof AtomNode &&
|
|
99
|
+
atomAncestor.getMeta() === this));
|
|
74
100
|
});
|
|
75
101
|
const index = text.indexOf(node);
|
|
76
|
-
return index === undefined
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
102
|
+
return index === undefined
|
|
103
|
+
? undefined
|
|
104
|
+
: next
|
|
105
|
+
? index >= 0 && index < text.length - 1
|
|
106
|
+
? text[index + 1]
|
|
107
|
+
: undefined
|
|
108
|
+
: index > 0 && index <= text.length
|
|
109
|
+
? text[index - 1]
|
|
110
|
+
: undefined;
|
|
80
111
|
}
|
|
81
112
|
getNextTextOrAtom(node) {
|
|
82
113
|
return this.getAdjacentTextOrAtom(node, true);
|
|
@@ -85,11 +116,14 @@ export default class FormatNode extends Node {
|
|
|
85
116
|
return this.getAdjacentTextOrAtom(node, false);
|
|
86
117
|
}
|
|
87
118
|
getAdjacentCaret(caret, next) {
|
|
88
|
-
if (!(caret.node instanceof TextNode) &&
|
|
119
|
+
if (!(caret.node instanceof TextNode) &&
|
|
120
|
+
!(caret.node instanceof AtomNode))
|
|
89
121
|
return;
|
|
90
122
|
// Is there an adjascent caret in the current text node? If so, return it.
|
|
91
123
|
if (caret.node instanceof TextNode) {
|
|
92
|
-
const adjacentText = next
|
|
124
|
+
const adjacentText = next
|
|
125
|
+
? caret.node.getNextCaret(caret.index)
|
|
126
|
+
: caret.node.getPreviousCaret(caret.index);
|
|
93
127
|
if (adjacentText !== undefined)
|
|
94
128
|
return adjacentText;
|
|
95
129
|
}
|
|
@@ -98,8 +132,19 @@ export default class FormatNode extends Node {
|
|
|
98
132
|
if (adjacentNode !== undefined) {
|
|
99
133
|
// Normally we skip over node boundaries because they look identical to each other.
|
|
100
134
|
// But some nodes are zero length, so we have to account for that.
|
|
101
|
-
return {
|
|
102
|
-
|
|
135
|
+
return {
|
|
136
|
+
node: adjacentNode,
|
|
137
|
+
index: next
|
|
138
|
+
? adjacentNode instanceof TextNode
|
|
139
|
+
? adjacentNode.isEmpty()
|
|
140
|
+
? 0
|
|
141
|
+
: 1
|
|
142
|
+
: 0
|
|
143
|
+
: adjacentNode instanceof TextNode
|
|
144
|
+
? adjacentNode.isEmpty()
|
|
145
|
+
? 0
|
|
146
|
+
: adjacentNode.getLength() - 1
|
|
147
|
+
: 0,
|
|
103
148
|
};
|
|
104
149
|
}
|
|
105
150
|
// Otherwise, there is no adjascent caret.
|
|
@@ -121,29 +166,42 @@ export default class FormatNode extends Node {
|
|
|
121
166
|
getSelection() {
|
|
122
167
|
const first = this.getFirstTextNode();
|
|
123
168
|
const last = this.getLastTextNode();
|
|
124
|
-
return {
|
|
169
|
+
return {
|
|
170
|
+
start: { node: first, index: 0 },
|
|
171
|
+
end: { node: last, index: last.getLength() },
|
|
172
|
+
};
|
|
125
173
|
}
|
|
126
174
|
getIndexOfTextNode(node) {
|
|
127
175
|
const text = this.getTextNodes();
|
|
128
176
|
return text.indexOf(node);
|
|
129
177
|
}
|
|
130
178
|
getSelectedText(range) {
|
|
131
|
-
if (!(range.start.node instanceof TextNode) ||
|
|
179
|
+
if (!(range.start.node instanceof TextNode) ||
|
|
180
|
+
!(range.end.node instanceof TextNode))
|
|
132
181
|
return undefined;
|
|
133
182
|
const start = this.getIndexOfTextNode(range.start.node);
|
|
134
183
|
const end = this.getIndexOfTextNode(range.end.node);
|
|
135
184
|
if (start === undefined || end === undefined)
|
|
136
185
|
return undefined;
|
|
137
|
-
return this.getTextNodes()
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
current
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
186
|
+
return this.getTextNodes()
|
|
187
|
+
.map((current, index) => {
|
|
188
|
+
return current === range.start.node
|
|
189
|
+
? current === range.end.node
|
|
190
|
+
? current
|
|
191
|
+
.getText()
|
|
192
|
+
.substring(range.start.index, range.end.index)
|
|
193
|
+
: current.getText().substring(range.start.index)
|
|
194
|
+
: index > start && index < end
|
|
195
|
+
? current.getText()
|
|
196
|
+
: current === range.end.node
|
|
197
|
+
? current.getText().substring(0, range.end.index)
|
|
198
|
+
: '';
|
|
199
|
+
})
|
|
200
|
+
.join('');
|
|
201
|
+
}
|
|
202
|
+
withTextIfEmpty() {
|
|
203
|
+
return this.isEmpty() ? this.withSegmentAppended(new TextNode()) : this;
|
|
204
|
+
}
|
|
147
205
|
withSegmentPrepended(segment) {
|
|
148
206
|
return new FormatNode(this.#format, [segment, ...this.#segments]);
|
|
149
207
|
}
|
|
@@ -167,16 +225,16 @@ export default class FormatNode extends Node {
|
|
|
167
225
|
return new FormatNode(this.#format, newSegments);
|
|
168
226
|
}
|
|
169
227
|
withChildReplaced(node, replacement) {
|
|
170
|
-
return replacement === undefined
|
|
171
|
-
this.withoutSegment(node)
|
|
172
|
-
this.withSegmentReplaced(node, replacement);
|
|
228
|
+
return replacement === undefined
|
|
229
|
+
? this.withoutSegment(node)
|
|
230
|
+
: this.withSegmentReplaced(node, replacement);
|
|
173
231
|
}
|
|
174
232
|
// Creates two formatted nodes that split this node at the given caret location.
|
|
175
233
|
split(caret) {
|
|
176
234
|
// We can only copy if
|
|
177
235
|
// ... this has a parent.
|
|
178
236
|
// ... the given caret is in this formatted node.
|
|
179
|
-
// ... the caret is on a text node.
|
|
237
|
+
// ... the caret is on a text node.
|
|
180
238
|
if (!(caret.node instanceof TextNode) || !this.contains(caret.node))
|
|
181
239
|
return undefined;
|
|
182
240
|
const firstCaret = this.getFirstCaret();
|
|
@@ -197,21 +255,24 @@ export default class FormatNode extends Node {
|
|
|
197
255
|
// It's approach is to scan through every text, meta, and atom node build a new format based on the requested format.
|
|
198
256
|
withFormat(range, format) {
|
|
199
257
|
// This only transforms ranges that start and end with text/atom nodes in this format node.
|
|
200
|
-
if (!(range.start.node instanceof TextNode ||
|
|
201
|
-
|
|
258
|
+
if (!(range.start.node instanceof TextNode ||
|
|
259
|
+
range.start.node instanceof AtomNode) ||
|
|
260
|
+
!(range.end.node instanceof TextNode ||
|
|
261
|
+
range.end.node instanceof AtomNode) ||
|
|
202
262
|
!(this.contains(range.start.node) && this.contains(range.end.node)))
|
|
203
263
|
return;
|
|
204
264
|
const sortedRange = this.sortRange(range);
|
|
205
265
|
// Remember the text positions so we can return a new range in the new tree.
|
|
206
266
|
const selectionStartIndex = caretToIndex(this, sortedRange.start);
|
|
207
267
|
const selectionEndIndex = caretToIndex(this, sortedRange.end);
|
|
208
|
-
if (selectionStartIndex === undefined ||
|
|
268
|
+
if (selectionStartIndex === undefined ||
|
|
269
|
+
selectionEndIndex === undefined)
|
|
209
270
|
return;
|
|
210
271
|
// Remember if the selection is zero width.
|
|
211
272
|
let zeroWidthSelection = selectionStartIndex === selectionEndIndex;
|
|
212
273
|
// Find all of the content in the node, except for format nodes and decendants of atom nodes that have format nodes,
|
|
213
274
|
// to construct a new format tree with the old content.
|
|
214
|
-
const everythingButFormats = this.getNodes().filter(n => !(n instanceof FormatNode));
|
|
275
|
+
const everythingButFormats = this.getNodes().filter((n) => !(n instanceof FormatNode));
|
|
215
276
|
// Check if all of the selected content has the requested format so we can toggle it if so.
|
|
216
277
|
let checkIndex = 0; // This tracks the current location in our scan.
|
|
217
278
|
let editingEmptyNode = false; // This remembers the special case of the caret being inside an empty text node.
|
|
@@ -224,25 +285,42 @@ export default class FormatNode extends Node {
|
|
|
224
285
|
// Otherwise, formatting is already applied if all of the non-format nodes already have this format.
|
|
225
286
|
// We need to know this so we can toggle the format off.
|
|
226
287
|
else {
|
|
227
|
-
everythingButFormats.forEach(node => {
|
|
288
|
+
everythingButFormats.forEach((node) => {
|
|
228
289
|
const parent = this.getParentOf(node);
|
|
229
290
|
// If it's text, and the current position is in range of the selection, does the position contain the requested format?
|
|
230
291
|
if (node instanceof TextNode && parent instanceof FormatNode) {
|
|
231
292
|
// If we're formatting an empty node we previously found, this node's formatting is irrelevant.
|
|
232
|
-
if (editingEmptyNode) {
|
|
293
|
+
if (editingEmptyNode) {
|
|
294
|
+
}
|
|
233
295
|
// If this node is empty but contains a zero-width selection, remember it, since this is the only node for which formats are relevant.
|
|
234
296
|
else if (node.getText().length === 0) {
|
|
235
|
-
if (checkIndex === selectionStartIndex &&
|
|
297
|
+
if (checkIndex === selectionStartIndex &&
|
|
298
|
+
zeroWidthSelection) {
|
|
236
299
|
editingEmptyNode = true;
|
|
237
|
-
alreadyApplied = parent
|
|
300
|
+
alreadyApplied = parent
|
|
301
|
+
.getFormats(this)
|
|
302
|
+
.includes(format);
|
|
238
303
|
}
|
|
239
304
|
}
|
|
240
305
|
// If this node has more than zero characters, the formatting is all applied if the selection contains the entirety of this node's text
|
|
241
306
|
// and this node's parent contains the formatting.
|
|
242
307
|
else {
|
|
243
|
-
const parentIsFormatted = parent
|
|
244
|
-
|
|
245
|
-
|
|
308
|
+
const parentIsFormatted = parent
|
|
309
|
+
.getFormats(this)
|
|
310
|
+
.includes(format);
|
|
311
|
+
const selectionContainsNode = (selectionStartIndex > checkIndex &&
|
|
312
|
+
selectionStartIndex <
|
|
313
|
+
checkIndex +
|
|
314
|
+
node.getCaretPositionCount() -
|
|
315
|
+
1) ||
|
|
316
|
+
(selectionEndIndex > checkIndex &&
|
|
317
|
+
selectionEndIndex <
|
|
318
|
+
checkIndex +
|
|
319
|
+
node.getCaretPositionCount() -
|
|
320
|
+
1);
|
|
321
|
+
const nodeContainsSelection = selectionStartIndex >= checkIndex &&
|
|
322
|
+
selectionEndIndex <=
|
|
323
|
+
checkIndex + node.getCaretPositionCount();
|
|
246
324
|
checkIndex += node.getCaretPositionCount();
|
|
247
325
|
if (nodeContainsSelection || selectionContainsNode) {
|
|
248
326
|
nodeCount++;
|
|
@@ -260,45 +338,52 @@ export default class FormatNode extends Node {
|
|
|
260
338
|
}
|
|
261
339
|
// Reformat everything. The strategy is to step through each character, atom node, and metadata node in this format node
|
|
262
340
|
// and create a new series of formats that preserve existing formatting while applying new formatting to the selection.
|
|
263
|
-
let newFormats = [{ format:
|
|
341
|
+
let newFormats = [{ format: '', segments: [] }]; // A stack of formats we're constructing.
|
|
264
342
|
let textIndex = 0;
|
|
265
|
-
let currentText =
|
|
343
|
+
let currentText = ''; // The current text we've accumulated, inserted before each format change and at the end.
|
|
266
344
|
let formattingEmptyNode = false;
|
|
267
345
|
let emptyNode = undefined;
|
|
268
346
|
function saveText() {
|
|
269
347
|
// If there's some text, update the current format with the current text, then reset it.
|
|
270
348
|
if (currentText.length > 0) {
|
|
271
349
|
newFormats[0].segments.push(new TextNode(currentText));
|
|
272
|
-
currentText =
|
|
350
|
+
currentText = '';
|
|
273
351
|
}
|
|
274
352
|
}
|
|
275
353
|
function inRange() {
|
|
276
|
-
return selectionStartIndex !== undefined &&
|
|
354
|
+
return (selectionStartIndex !== undefined &&
|
|
355
|
+
selectionEndIndex !== undefined &&
|
|
356
|
+
textIndex >= selectionStartIndex &&
|
|
357
|
+
textIndex < selectionEndIndex);
|
|
277
358
|
}
|
|
278
359
|
function getFormats() {
|
|
279
360
|
// We don't include non-formatted text in the list of formats applied.
|
|
280
|
-
return newFormats.map(f => f.format).filter(f => f !==
|
|
361
|
+
return newFormats.map((f) => f.format).filter((f) => f !== '');
|
|
281
362
|
}
|
|
282
363
|
function finishFormat() {
|
|
283
364
|
const formatSpec = newFormats[0];
|
|
284
365
|
newFormats.shift();
|
|
285
366
|
// Keep the new format clean by only adding the format node if it's not empty, or if it's a zero width selection.
|
|
286
|
-
if (formatSpec.segments.length > 0 ||
|
|
367
|
+
if (formatSpec.segments.length > 0 ||
|
|
368
|
+
(zeroWidthSelection && textIndex === selectionStartIndex))
|
|
287
369
|
newFormats[0].segments.push(new FormatNode(formatSpec.format, formatSpec.segments));
|
|
288
370
|
}
|
|
289
|
-
everythingButFormats.forEach(node => {
|
|
371
|
+
everythingButFormats.forEach((node) => {
|
|
290
372
|
const parent = this.getParentOf(node);
|
|
291
373
|
if (node instanceof TextNode) {
|
|
292
374
|
// If this is a text node in an atom node we're not formatting the atom node's format, then just
|
|
293
375
|
// account for it's length, but do nothing else.
|
|
294
376
|
const atomAncestor = node.getClosestParentOfType(this, AtomNode);
|
|
295
|
-
if (atomAncestor instanceof AtomNode &&
|
|
377
|
+
if (atomAncestor instanceof AtomNode &&
|
|
378
|
+
atomAncestor.getMeta() !== this &&
|
|
379
|
+
atomAncestor.getMeta() instanceof FormatNode) {
|
|
296
380
|
textIndex += node.getCaretPositionCount();
|
|
297
381
|
}
|
|
298
382
|
else if (parent instanceof FormatNode) {
|
|
299
383
|
// Remember we found an empty node so that we don't insert an extra one later.
|
|
300
384
|
if (node.getText().length === 0) {
|
|
301
|
-
if (textIndex === selectionStartIndex &&
|
|
385
|
+
if (textIndex === selectionStartIndex &&
|
|
386
|
+
zeroWidthSelection) {
|
|
302
387
|
formattingEmptyNode = true;
|
|
303
388
|
textIndex++;
|
|
304
389
|
}
|
|
@@ -307,24 +392,30 @@ export default class FormatNode extends Node {
|
|
|
307
392
|
// Process each character in the node, including the very last position.
|
|
308
393
|
for (let i = 0; i <= node.getText().length; i++) {
|
|
309
394
|
// Determine the desired format for this character. Start with the current formats
|
|
310
|
-
// and if we're in the selected range, adjust them accordingly based on the current formats
|
|
395
|
+
// and if we're in the selected range, adjust them accordingly based on the current formats
|
|
311
396
|
// and the requested format. (If this is a range deletion, then we just stick with the existing formats).
|
|
312
397
|
let formatter = node.getFormat(this);
|
|
313
|
-
let desiredFormats = formatter
|
|
398
|
+
let desiredFormats = formatter
|
|
399
|
+
? formatter.getFormats(this)
|
|
400
|
+
: [];
|
|
314
401
|
if (format !== undefined &&
|
|
315
|
-
((textIndex === selectionStartIndex &&
|
|
402
|
+
((textIndex === selectionStartIndex &&
|
|
403
|
+
zeroWidthSelection) ||
|
|
404
|
+
inRange())) {
|
|
316
405
|
// Remove all formatting if we were asked to.
|
|
317
|
-
if (format ===
|
|
406
|
+
if (format === '')
|
|
318
407
|
desiredFormats = [];
|
|
319
408
|
// Apply the formatting if it's not already applied.
|
|
320
|
-
else if (!alreadyApplied &&
|
|
409
|
+
else if (!alreadyApplied &&
|
|
410
|
+
!desiredFormats.includes(format))
|
|
321
411
|
desiredFormats.push(format);
|
|
322
412
|
// Remove the formatting if it's already applied in the selection.
|
|
323
|
-
else if (alreadyApplied &&
|
|
413
|
+
else if (alreadyApplied &&
|
|
414
|
+
desiredFormats.includes(format))
|
|
324
415
|
desiredFormats.splice(desiredFormats.indexOf(format), 1);
|
|
325
416
|
}
|
|
326
417
|
// Remove undesired formats.
|
|
327
|
-
getFormats().forEach(activeFormat => {
|
|
418
|
+
getFormats().forEach((activeFormat) => {
|
|
328
419
|
// If the current format is not in the desired list, close the text
|
|
329
420
|
// node and keep popping formats until we find the parent of the offending format.
|
|
330
421
|
if (!desiredFormats.includes(activeFormat)) {
|
|
@@ -337,28 +428,38 @@ export default class FormatNode extends Node {
|
|
|
337
428
|
finishFormat();
|
|
338
429
|
// If we have unformatted something at a zero-width range, create empty format node, add a text node in it and remember it so
|
|
339
430
|
// we can place the caret in it.
|
|
340
|
-
if (!formattingEmptyNode &&
|
|
431
|
+
if (!formattingEmptyNode &&
|
|
432
|
+
textIndex === selectionStartIndex &&
|
|
433
|
+
zeroWidthSelection) {
|
|
341
434
|
// Remember the node for later, so we can place the caret in it.
|
|
342
435
|
emptyNode = new TextNode();
|
|
343
436
|
// Append the empty node to the current format.
|
|
344
437
|
newFormats[0].segments.push(emptyNode);
|
|
345
438
|
// Push a new format onto the stack to start adding to.
|
|
346
|
-
newFormats.unshift({
|
|
439
|
+
newFormats.unshift({
|
|
440
|
+
format: activeFormat,
|
|
441
|
+
segments: [],
|
|
442
|
+
});
|
|
347
443
|
}
|
|
348
444
|
}
|
|
349
445
|
});
|
|
350
446
|
// Ensure the desired formats.
|
|
351
|
-
desiredFormats.forEach(desiredFormat => {
|
|
447
|
+
desiredFormats.forEach((desiredFormat) => {
|
|
352
448
|
// If the current format does not yet include the desired format,
|
|
353
449
|
// close the text node and start a new format.
|
|
354
450
|
if (!getFormats().includes(desiredFormat)) {
|
|
355
451
|
// Save any text that we've accumulated in the curent format.
|
|
356
452
|
saveText();
|
|
357
453
|
// Add a new format onto the stack to start adding to.
|
|
358
|
-
newFormats.unshift({
|
|
454
|
+
newFormats.unshift({
|
|
455
|
+
format: desiredFormat,
|
|
456
|
+
segments: [],
|
|
457
|
+
});
|
|
359
458
|
// If we inserted an empty format node, add a text node in it and remember it so
|
|
360
459
|
// we can place the caret in it.
|
|
361
|
-
if (!formattingEmptyNode &&
|
|
460
|
+
if (!formattingEmptyNode &&
|
|
461
|
+
textIndex === selectionStartIndex &&
|
|
462
|
+
zeroWidthSelection) {
|
|
362
463
|
emptyNode = new TextNode();
|
|
363
464
|
newFormats[0].segments.push(emptyNode);
|
|
364
465
|
finishFormat();
|
|
@@ -390,7 +491,7 @@ export default class FormatNode extends Node {
|
|
|
390
491
|
// by simply not adding one to this new format. Then, erase the text, since it was added in the metadata node.
|
|
391
492
|
if (currentText.length > 0) {
|
|
392
493
|
newFormats[0].segments.push(parent.withText(new TextNode(currentText)));
|
|
393
|
-
currentText =
|
|
494
|
+
currentText = '';
|
|
394
495
|
}
|
|
395
496
|
}
|
|
396
497
|
}
|
|
@@ -401,12 +502,15 @@ export default class FormatNode extends Node {
|
|
|
401
502
|
saveText();
|
|
402
503
|
// Add the atom immediately after, unless it's in the deletion range.
|
|
403
504
|
// We include the start index since AtomNode's text index is on the left.
|
|
404
|
-
if (format !== undefined ||
|
|
505
|
+
if (format !== undefined ||
|
|
506
|
+
textIndex < selectionStartIndex ||
|
|
507
|
+
textIndex > selectionEndIndex) {
|
|
405
508
|
// Does the atom node have a format? Format it!
|
|
406
509
|
let newAtom = node;
|
|
407
510
|
const atomMeta = node.getMeta();
|
|
408
511
|
if (atomMeta instanceof FormatNode) {
|
|
409
|
-
if (atomMeta.contains(range.start.node) &&
|
|
512
|
+
if (atomMeta.contains(range.start.node) &&
|
|
513
|
+
atomMeta.contains(range.end.node)) {
|
|
410
514
|
const newFormat = atomMeta.withFormat(range, format);
|
|
411
515
|
newAtom = node.withMeta(newFormat);
|
|
412
516
|
}
|
|
@@ -427,12 +531,13 @@ export default class FormatNode extends Node {
|
|
|
427
531
|
let newFormat = new FormatNode(newFormats[0].format, newFormats[0].segments);
|
|
428
532
|
// If after all that, it's empty, make sure there's one empty text node to type in.
|
|
429
533
|
if (newFormat.getTextAndAtomNodes().length === 0)
|
|
430
|
-
newFormat = new FormatNode(
|
|
534
|
+
newFormat = new FormatNode('', [new TextNode()]);
|
|
431
535
|
// If it starts or ends with an atom, insert an empty node so that text can be inserted before or after.
|
|
432
536
|
else {
|
|
433
537
|
if (newFormat.#segments[0] instanceof AtomNode)
|
|
434
538
|
newFormat = newFormat.withSegmentPrepended(new TextNode());
|
|
435
|
-
if (newFormat.#segments[newFormat.getLength() - 1] instanceof
|
|
539
|
+
if (newFormat.#segments[newFormat.getLength() - 1] instanceof
|
|
540
|
+
AtomNode)
|
|
436
541
|
newFormat = newFormat.withSegmentAppended(new TextNode());
|
|
437
542
|
}
|
|
438
543
|
return newFormat;
|
|
@@ -455,7 +560,7 @@ export default class FormatNode extends Node {
|
|
|
455
560
|
let format = this;
|
|
456
561
|
const formats = [];
|
|
457
562
|
while (format instanceof FormatNode) {
|
|
458
|
-
if (format.#format !==
|
|
563
|
+
if (format.#format !== '')
|
|
459
564
|
formats.push(format.#format);
|
|
460
565
|
format = format.getParent(root);
|
|
461
566
|
}
|
|
@@ -482,7 +587,8 @@ export default class FormatNode extends Node {
|
|
|
482
587
|
let newFormat = this;
|
|
483
588
|
const sortedRange = this.sortRange(range);
|
|
484
589
|
let caret = sortedRange.start;
|
|
485
|
-
if (sortedRange.start.node !== sortedRange.end.node ||
|
|
590
|
+
if (sortedRange.start.node !== sortedRange.end.node ||
|
|
591
|
+
sortedRange.start.index !== sortedRange.end.index) {
|
|
486
592
|
// Try to remove the selected text. Bail on fail.
|
|
487
593
|
const textIndex = caretToIndex(this, sortedRange.start);
|
|
488
594
|
if (textIndex === undefined)
|
|
@@ -496,18 +602,25 @@ export default class FormatNode extends Node {
|
|
|
496
602
|
caret = newCaret;
|
|
497
603
|
}
|
|
498
604
|
// Create and insert the into the formatted node.
|
|
499
|
-
const newNode = nodeCreator.call(undefined, selectedText ? selectedText :
|
|
605
|
+
const newNode = nodeCreator.call(undefined, selectedText ? selectedText : '');
|
|
500
606
|
const revisedFormat = newFormat.withSegmentAt(newNode, caret);
|
|
501
607
|
if (revisedFormat === undefined)
|
|
502
608
|
return;
|
|
503
|
-
const newCaret = newNode instanceof AtomNode
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
609
|
+
const newCaret = newNode instanceof AtomNode
|
|
610
|
+
? newNode.getDefaultCaret()
|
|
611
|
+
: newNode instanceof FormatNode
|
|
612
|
+
? newNode.getFirstCaret()
|
|
613
|
+
: newNode instanceof MetadataNode
|
|
614
|
+
? { node: newNode.getText(), index: 0 }
|
|
615
|
+
: newNode instanceof TextNode
|
|
616
|
+
? { node: newNode, index: 0 }
|
|
617
|
+
: undefined;
|
|
508
618
|
if (newCaret === undefined)
|
|
509
619
|
return;
|
|
510
|
-
return {
|
|
620
|
+
return {
|
|
621
|
+
root: revisedFormat,
|
|
622
|
+
range: { start: newCaret, end: newCaret },
|
|
623
|
+
};
|
|
511
624
|
}
|
|
512
625
|
withoutContentBefore(caret) {
|
|
513
626
|
return this.withContentAt(caret, false);
|
|
@@ -547,13 +660,16 @@ export default class FormatNode extends Node {
|
|
|
547
660
|
const withoutBefore = this.withoutContentBefore(startCaret);
|
|
548
661
|
if (withoutBefore === undefined)
|
|
549
662
|
return;
|
|
550
|
-
const revisedEndCaret = indexToCaret(withoutBefore,
|
|
663
|
+
const revisedEndCaret = indexToCaret(withoutBefore, endIndex - startIndex);
|
|
551
664
|
if (revisedEndCaret === undefined)
|
|
552
665
|
return;
|
|
553
666
|
return withoutBefore.withoutContentAfter(revisedEndCaret);
|
|
554
667
|
}
|
|
555
668
|
withSegmentsAppended(format) {
|
|
556
|
-
return new FormatNode(this.#format, [
|
|
669
|
+
return new FormatNode(this.#format, [
|
|
670
|
+
...this.#segments,
|
|
671
|
+
...format.getSegments(),
|
|
672
|
+
]);
|
|
557
673
|
}
|
|
558
674
|
withoutAdjacentContent(caret, next) {
|
|
559
675
|
return this.withoutCharacter(caret, next);
|
|
@@ -571,7 +687,10 @@ export default class FormatNode extends Node {
|
|
|
571
687
|
const newFormat = this.withNodeReplaced(caret.node, undefined);
|
|
572
688
|
if (newFormat === undefined)
|
|
573
689
|
return;
|
|
574
|
-
return {
|
|
690
|
+
return {
|
|
691
|
+
root: newFormat,
|
|
692
|
+
range: { start: adjacentCaret, end: adjacentCaret },
|
|
693
|
+
};
|
|
575
694
|
}
|
|
576
695
|
else if (adjacentCaret.node instanceof AtomNode) {
|
|
577
696
|
const newFormat = this.withNodeReplaced(adjacentCaret.node, undefined);
|
|
@@ -585,13 +704,19 @@ export default class FormatNode extends Node {
|
|
|
585
704
|
if (textIndex === undefined)
|
|
586
705
|
return;
|
|
587
706
|
// If there is one, try removing everything between this and the adjascent caret.
|
|
588
|
-
const newFormat = this.withoutRange({
|
|
707
|
+
const newFormat = this.withoutRange({
|
|
708
|
+
start: caret,
|
|
709
|
+
end: adjacentCaret,
|
|
710
|
+
});
|
|
589
711
|
if (newFormat === undefined)
|
|
590
712
|
return;
|
|
591
713
|
const newCaret = indexToCaret(newFormat, textIndex);
|
|
592
714
|
if (newCaret === undefined)
|
|
593
715
|
return;
|
|
594
|
-
return {
|
|
716
|
+
return {
|
|
717
|
+
root: newFormat,
|
|
718
|
+
range: { start: newCaret, end: newCaret },
|
|
719
|
+
};
|
|
595
720
|
}
|
|
596
721
|
}
|
|
597
722
|
withNodeInserted(caret, node) {
|
|
@@ -600,13 +725,19 @@ export default class FormatNode extends Node {
|
|
|
600
725
|
if (index < 0)
|
|
601
726
|
return;
|
|
602
727
|
// The inserted node has to be a segment type.
|
|
603
|
-
if (!(node instanceof FormatNode ||
|
|
728
|
+
if (!(node instanceof FormatNode ||
|
|
729
|
+
node instanceof TextNode ||
|
|
730
|
+
node instanceof MetadataNode ||
|
|
731
|
+
node instanceof AtomNode))
|
|
604
732
|
return;
|
|
605
733
|
const newFormat = this.withSegmentAt(node, caret);
|
|
606
|
-
const newCaret = node instanceof AtomNode
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
734
|
+
const newCaret = node instanceof AtomNode
|
|
735
|
+
? node.getDefaultCaret()
|
|
736
|
+
: node instanceof FormatNode
|
|
737
|
+
? node.getLastCaret()
|
|
738
|
+
: node instanceof MetadataNode
|
|
739
|
+
? { node: node.getText(), index: node.getText().getLength() }
|
|
740
|
+
: { node: node, index: node.getLength() };
|
|
610
741
|
if (newFormat === undefined || newCaret === undefined)
|
|
611
742
|
return;
|
|
612
743
|
return { root: newFormat, range: { start: newCaret, end: newCaret } };
|