bookish-press 0.4.1 → 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 -81
- 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
package/models/book/Edition.js
CHANGED
|
@@ -1,314 +1,417 @@
|
|
|
1
1
|
import Chapter from './Chapter';
|
|
2
|
-
import Parser from
|
|
3
|
-
import EmbedNode from
|
|
4
|
-
import
|
|
2
|
+
import Parser from '../chapter/Parser';
|
|
3
|
+
import EmbedNode from '../chapter/EmbedNode';
|
|
4
|
+
import Reference from './Reference';
|
|
5
5
|
import ChapterIDs from './ChapterID.js';
|
|
6
|
-
export var BookSaveStatus;
|
|
7
|
-
(function (BookSaveStatus) {
|
|
8
|
-
BookSaveStatus[BookSaveStatus["Changed"] = 0] = "Changed";
|
|
9
|
-
BookSaveStatus[BookSaveStatus["Saving"] = 1] = "Saving";
|
|
10
|
-
BookSaveStatus[BookSaveStatus["Saved"] = 2] = "Saved";
|
|
11
|
-
BookSaveStatus[BookSaveStatus["Error"] = 3] = "Error";
|
|
12
|
-
})(BookSaveStatus || (BookSaveStatus = {}));
|
|
13
6
|
export default class Edition {
|
|
14
|
-
|
|
15
|
-
book;
|
|
7
|
+
bookRef;
|
|
16
8
|
editionRef;
|
|
9
|
+
uids;
|
|
10
|
+
title;
|
|
11
|
+
authors;
|
|
12
|
+
number;
|
|
13
|
+
summary;
|
|
14
|
+
published;
|
|
15
|
+
images;
|
|
16
|
+
description;
|
|
17
17
|
chapters;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
license;
|
|
19
|
+
acknowledgements;
|
|
20
|
+
tags;
|
|
21
|
+
sources;
|
|
22
|
+
references;
|
|
23
|
+
symbols;
|
|
24
|
+
glossary;
|
|
25
|
+
theme;
|
|
26
|
+
active;
|
|
24
27
|
// Given an object with a valid specification and an object mapping chapter IDs to chapter text,
|
|
25
28
|
// construct an object representing a book.
|
|
26
|
-
constructor(
|
|
27
|
-
|
|
28
|
-
throw Error("Expected a book specification object, but received " + specification);
|
|
29
|
-
this.book = book;
|
|
29
|
+
constructor(bookRef, editionRef, uids, title, authors, number, summary, published, images, description, chapters, license, acknowledgements, tags, sources, references, symbols, glossary, theme, active) {
|
|
30
|
+
this.bookRef = bookRef;
|
|
30
31
|
this.editionRef = editionRef;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// No listeners yet
|
|
51
|
-
this.listeners = new Set();
|
|
52
|
-
// Create a list and dictionary of Chapter objects.
|
|
53
|
-
this.chapters = [];
|
|
54
|
-
this.chaptersByID = {};
|
|
55
|
-
// If there's a spec and it has chapters, process them.
|
|
56
|
-
if (this.specification.chapters.length > 0) {
|
|
57
|
-
// Initialize the chapters dictionary since parsing depends this index to detect whether a chapter exists.
|
|
58
|
-
this.specification.chapters.forEach(chapterSpec => this.chaptersByID[chapterSpec.id] = undefined);
|
|
59
|
-
this.specification.chapters.forEach(chapterSpec => {
|
|
60
|
-
const chap = new Chapter(this, chapterSpec);
|
|
61
|
-
this.chaptersByID[chapterSpec.id] = chap;
|
|
62
|
-
this.chapters.push(chap);
|
|
63
|
-
});
|
|
32
|
+
this.uids = uids;
|
|
33
|
+
this.title = title;
|
|
34
|
+
this.authors = authors;
|
|
35
|
+
this.number = number;
|
|
36
|
+
this.summary = summary;
|
|
37
|
+
this.published = published;
|
|
38
|
+
this.images = images;
|
|
39
|
+
this.description = description;
|
|
40
|
+
this.chapters = chapters.slice();
|
|
41
|
+
this.license = license;
|
|
42
|
+
this.acknowledgements = acknowledgements;
|
|
43
|
+
this.tags = tags.slice();
|
|
44
|
+
this.sources = Object.assign({}, sources);
|
|
45
|
+
this.references = {};
|
|
46
|
+
for (const [citationID, ref] of Object.entries(references)) {
|
|
47
|
+
this.references[citationID] =
|
|
48
|
+
ref instanceof Reference
|
|
49
|
+
? ref
|
|
50
|
+
: Edition.parseReference(citationID, ref, this);
|
|
64
51
|
}
|
|
52
|
+
this.symbols = Object.assign({}, symbols);
|
|
53
|
+
this.glossary = Object.assign({}, glossary);
|
|
54
|
+
this.theme = theme;
|
|
55
|
+
this.active = active;
|
|
65
56
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.notifyListeners(BookSaveStatus.Saved);
|
|
84
|
-
})
|
|
85
|
-
.catch(() => {
|
|
86
|
-
// Reject the edits.
|
|
87
|
-
this.edits.forEach(edit => edit.reject());
|
|
88
|
-
this.notifyListeners(BookSaveStatus.Error);
|
|
89
|
-
})
|
|
90
|
-
.finally(() => {
|
|
91
|
-
// Reset the edit queue.
|
|
92
|
-
this.edits = [];
|
|
93
|
-
});
|
|
57
|
+
static fromJSON(editionRef, spec) {
|
|
58
|
+
// Copy all of the specification metadata to fields.
|
|
59
|
+
// Choose suitable defaults if the spec is lacking a field.
|
|
60
|
+
return new Edition(spec.bookRef, editionRef, spec.uids, spec.title, spec.authors, spec.number, spec.summary, spec.published, spec.images, spec.description, spec.chapters.map((chap) => Chapter.fromJSON(chap, '')), spec.license, spec.acknowledgements, spec.tags, spec.sources, spec.references, spec.symbols, spec.glossary, spec.theme, spec.active);
|
|
61
|
+
}
|
|
62
|
+
static parseReference(citationID, ref, edition, short = false) {
|
|
63
|
+
if (typeof ref === 'string')
|
|
64
|
+
return Parser.parseFormat(edition, ref);
|
|
65
|
+
else {
|
|
66
|
+
// APA Format. Could eventually support multiple formats.
|
|
67
|
+
let [authors, year, title, source, url, summary] = ref;
|
|
68
|
+
if (source.charAt(0) === '#') {
|
|
69
|
+
let src = edition.getSource(source);
|
|
70
|
+
if (src !== null)
|
|
71
|
+
source = src;
|
|
72
|
+
}
|
|
73
|
+
return new Reference(citationID, authors ?? '', year ?? '', title ?? '', source ?? '', url ?? '', summary ?? '', short);
|
|
94
74
|
}
|
|
95
75
|
}
|
|
96
|
-
getBook() { return this.book; }
|
|
97
|
-
addListener(listener) { this.listeners.add(listener); }
|
|
98
|
-
removeListener(listener) { this.listeners.delete(listener); }
|
|
99
|
-
notifyListeners(status) { this.listeners.forEach(listener => listener.call(undefined, status)); }
|
|
100
|
-
// Adds a save request to the queue, to be resolved later after a period of
|
|
101
|
-
// inactivity. Returns a promise that will eventually be resolved.
|
|
102
|
-
requestSave() {
|
|
103
|
-
// Tell listeners that this book model changed.
|
|
104
|
-
this.notifyListeners(BookSaveStatus.Changed);
|
|
105
|
-
// Return a promise that will resolve or reject later after this model saves the edits to the database.
|
|
106
|
-
this.lastEdit = Date.now();
|
|
107
|
-
const promise = new Promise((resolve, reject) => {
|
|
108
|
-
this.edits.push({ resolve: resolve, reject: reject });
|
|
109
|
-
});
|
|
110
|
-
return promise;
|
|
111
|
-
}
|
|
112
76
|
// Convert the book to an object for storage.
|
|
113
77
|
toObject() {
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
78
|
+
const references = {};
|
|
79
|
+
for (const [citationID, ref] of Object.entries(this.references))
|
|
80
|
+
references[citationID] =
|
|
81
|
+
ref instanceof Reference ? ref.toList() : ref.toBookdown();
|
|
82
|
+
const editionJSON = {
|
|
83
|
+
bookRef: this.bookRef,
|
|
84
|
+
title: this.title,
|
|
85
|
+
authors: this.authors,
|
|
86
|
+
number: this.number,
|
|
87
|
+
summary: this.summary,
|
|
88
|
+
published: this.published,
|
|
89
|
+
images: Object.assign({}, this.images),
|
|
90
|
+
description: this.description,
|
|
91
|
+
chapters: this.chapters.map((chap) => chap.toJSON()),
|
|
92
|
+
license: this.license,
|
|
93
|
+
acknowledgements: this.acknowledgements,
|
|
94
|
+
tags: this.tags.slice(),
|
|
95
|
+
sources: Object.assign({}, this.sources),
|
|
96
|
+
references: references,
|
|
97
|
+
symbols: Object.assign({}, this.symbols),
|
|
98
|
+
glossary: Object.assign({}, this.glossary),
|
|
99
|
+
theme: this.theme,
|
|
100
|
+
uids: this.uids.slice(),
|
|
101
|
+
chapteruids: this.getChapterUIDS(),
|
|
102
|
+
active: this.active,
|
|
103
|
+
};
|
|
104
|
+
return editionJSON;
|
|
105
|
+
}
|
|
106
|
+
getBookRef() {
|
|
107
|
+
return this.bookRef;
|
|
108
|
+
}
|
|
109
|
+
getEditionRef() {
|
|
110
|
+
return this.editionRef;
|
|
111
|
+
}
|
|
112
|
+
getChapterUIDS() {
|
|
113
|
+
return Array.from(new Set(this.chapters.map((chapter) => chapter.uids).flat()));
|
|
114
|
+
}
|
|
115
|
+
withRef(editionRef) {
|
|
116
|
+
return new Edition(this.bookRef, editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
117
|
+
}
|
|
118
|
+
getTitle() {
|
|
119
|
+
return this.title;
|
|
120
|
+
}
|
|
121
|
+
withTitle(title) {
|
|
122
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, title, this.authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
123
|
+
}
|
|
124
|
+
getDescription() {
|
|
125
|
+
return this.description;
|
|
126
|
+
}
|
|
127
|
+
setDescription(description) {
|
|
128
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
129
|
+
}
|
|
130
|
+
getAcknowledgements() {
|
|
131
|
+
return this.acknowledgements;
|
|
132
|
+
}
|
|
133
|
+
withAcknowledgements(acks) {
|
|
134
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, this.license, acks, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
135
|
+
}
|
|
136
|
+
withSummary(summary) {
|
|
137
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
138
|
+
}
|
|
139
|
+
asPublished(published) {
|
|
140
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, published ? Date.now() : null, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
141
|
+
}
|
|
142
|
+
getLicense() {
|
|
143
|
+
return this.license;
|
|
144
|
+
}
|
|
145
|
+
setLicense(license) {
|
|
146
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
147
|
+
}
|
|
148
|
+
getChapters() {
|
|
149
|
+
return this.chapters.slice();
|
|
150
|
+
}
|
|
151
|
+
hasChapter(chapterID) {
|
|
152
|
+
return (this.getChapter(chapterID) !== undefined ||
|
|
153
|
+
['references', 'glossary', 'index', 'search', 'media'].includes(chapterID));
|
|
154
|
+
}
|
|
155
|
+
getChapter(chapterID) {
|
|
156
|
+
return this.chapters.find((chapter) => chapter.getID() === chapterID);
|
|
157
|
+
}
|
|
158
|
+
getChapterByRef(ref) {
|
|
159
|
+
return this.chapters.find((chap) => chap.ref !== undefined && chap.ref.id === ref.id);
|
|
160
|
+
}
|
|
150
161
|
getChapterPosition(chapterID) {
|
|
151
162
|
var position = 0;
|
|
152
163
|
for (; position < this.chapters.length; position++)
|
|
153
|
-
if (this.chapters[position].
|
|
164
|
+
if (this.chapters[position].getID() === chapterID)
|
|
154
165
|
return position;
|
|
155
166
|
return undefined;
|
|
156
167
|
}
|
|
157
|
-
getChapterCount() {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
168
|
+
getChapterCount() {
|
|
169
|
+
return this.chapters.length;
|
|
170
|
+
}
|
|
171
|
+
withChapters(chapters) {
|
|
172
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
173
|
+
}
|
|
174
|
+
withChapterText(text) {
|
|
175
|
+
return this.withChapters(this.chapters.map((chapter) => {
|
|
176
|
+
if (chapter.ref === undefined)
|
|
177
|
+
return chapter;
|
|
178
|
+
const match = text.find(([ref, text]) => chapter.ref !== undefined &&
|
|
179
|
+
chapter.ref.id === ref.id &&
|
|
180
|
+
chapter.text !== text &&
|
|
181
|
+
text !== undefined);
|
|
182
|
+
return match ? chapter.withText(match[1]) : chapter;
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
withRevisedChapter(previous, edited) {
|
|
186
|
+
const index = this.chapters.indexOf(previous);
|
|
187
|
+
if (index < 0)
|
|
188
|
+
return this;
|
|
189
|
+
return this.withChapters([
|
|
190
|
+
...this.chapters.slice(0, index),
|
|
191
|
+
edited,
|
|
192
|
+
...this.chapters.slice(index + 1),
|
|
193
|
+
]);
|
|
194
|
+
}
|
|
195
|
+
withoutRefs() {
|
|
196
|
+
return this.withRef(undefined).withChapters(this.chapters.map((chap) => chap.withoutRef()));
|
|
197
|
+
}
|
|
198
|
+
withIncrementedEditionNumber() {
|
|
199
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number + 1, this.summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
200
|
+
}
|
|
201
|
+
withNewChapter() {
|
|
162
202
|
// Synthesize a chapter ID placeholder that doesn't overlap with existing chapter names
|
|
163
203
|
let number = 1;
|
|
164
|
-
while (this.hasChapter(
|
|
204
|
+
while (this.hasChapter('chapter' + number))
|
|
165
205
|
number++;
|
|
166
|
-
const chapterRef = await addChapterInFirestore(editionID, { text: "" });
|
|
167
206
|
// Create a default chapter on this model. Remember the document reference so we can modify it later.
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
id: `chapter${number}`,
|
|
171
|
-
title: "Untitled Chapter",
|
|
172
|
-
authors: [],
|
|
173
|
-
numbered: true,
|
|
174
|
-
forthcoming: true,
|
|
175
|
-
image: null
|
|
176
|
-
};
|
|
177
|
-
const chap = new Chapter(this, emptyChapter);
|
|
178
|
-
this.chapters.push(chap);
|
|
179
|
-
this.chaptersByID[emptyChapter.id] = chap;
|
|
180
|
-
// Ask the database to create the chapter, returning the promise
|
|
181
|
-
this.requestSave();
|
|
207
|
+
const newChapter = new Chapter(undefined, `chapter${number}`, 'Untitled Chapter', [], null, true, false, undefined, '', []);
|
|
208
|
+
return this.withChapters([...this.chapters, newChapter]);
|
|
182
209
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
let index = this.chapters.findIndex(chapter => chapter.getChapterID() === chapterID);
|
|
186
|
-
if (index < 0)
|
|
187
|
-
throw Error(`Chapter with ID ${chapterID} doesn't exist, can't move it.`);
|
|
188
|
-
else if (index + increment < 0)
|
|
189
|
-
throw Error(`Can't move this chapter ${increment} chapters earlier.`);
|
|
190
|
-
else if (index + increment >= this.chapters.length)
|
|
191
|
-
throw Error(`Can't move this chapter ${increment} chapters later.`);
|
|
192
|
-
const temp = this.chapters[index + increment];
|
|
193
|
-
this.chapters[index + increment] = this.chapters[index];
|
|
194
|
-
this.chapters[index] = temp;
|
|
195
|
-
// Ask the database to update with this new order.
|
|
196
|
-
return this.requestSave();
|
|
197
|
-
}
|
|
198
|
-
async deleteChapter(chapterID) {
|
|
199
|
-
let index = this.chapters.findIndex(chapter => chapter.getChapterID() === chapterID);
|
|
210
|
+
withoutChapter(chapterID) {
|
|
211
|
+
let index = this.chapters.findIndex((chapter) => chapter.getID() === chapterID);
|
|
200
212
|
if (index < 0)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
getSymbols() { return this.specification.symbols; }
|
|
208
|
-
hasReferences() { return this.specification.references && Object.keys(this.specification.references).length > 0; }
|
|
209
|
-
getReferences() { return this.specification.references; }
|
|
210
|
-
getReference(citationID) { return citationID in this.specification.references ? this.specification.references[citationID] : undefined; }
|
|
211
|
-
addReferences(references) {
|
|
212
|
-
// Generate a unique ID for the reference.
|
|
213
|
-
references.forEach(ref => this.specification.references[ref.citationID] = ref.toList());
|
|
214
|
-
return this.requestSave();
|
|
213
|
+
return this;
|
|
214
|
+
return this.withChapters([
|
|
215
|
+
...this.chapters.slice(0, index),
|
|
216
|
+
...this.chapters.slice(index + 1),
|
|
217
|
+
]);
|
|
215
218
|
}
|
|
216
|
-
|
|
217
|
-
|
|
219
|
+
withMovedChapter(chapterID, increment) {
|
|
220
|
+
// Get the index of the chapter.
|
|
221
|
+
let index = this.chapters.findIndex((chapter) => chapter.getID() === chapterID);
|
|
222
|
+
if (index + increment < 0 || index + increment >= this.chapters.length)
|
|
223
|
+
return this;
|
|
224
|
+
const newChapters = this.chapters.slice();
|
|
225
|
+
const temp = newChapters[index + increment];
|
|
226
|
+
newChapters[index + increment] = newChapters[index];
|
|
227
|
+
newChapters[index] = temp;
|
|
228
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, newChapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
229
|
+
}
|
|
230
|
+
getSymbols() {
|
|
231
|
+
return this.symbols;
|
|
232
|
+
}
|
|
233
|
+
hasReferences() {
|
|
234
|
+
return Object.keys(this.references).length > 0;
|
|
235
|
+
}
|
|
236
|
+
getReferences() {
|
|
237
|
+
return Object.assign({}, this.references);
|
|
238
|
+
}
|
|
239
|
+
getReference(citationID) {
|
|
240
|
+
return citationID in this.references
|
|
241
|
+
? this.references[citationID]
|
|
242
|
+
: undefined;
|
|
243
|
+
}
|
|
244
|
+
withReferences(newReferences) {
|
|
245
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, newReferences, this.symbols, this.glossary, this.theme, this.active);
|
|
246
|
+
}
|
|
247
|
+
withNewReferences(references) {
|
|
248
|
+
const newReferences = Object.assign({}, this.references);
|
|
249
|
+
// Generate a unique ID for the reference.
|
|
250
|
+
for (const newRef of references)
|
|
251
|
+
newReferences[newRef.citationID] = newRef;
|
|
252
|
+
return this.withReferences(newReferences);
|
|
253
|
+
}
|
|
254
|
+
withEditedReference(ref) {
|
|
255
|
+
if (!(ref.citationID in this.references))
|
|
256
|
+
return this;
|
|
257
|
+
const newReferences = Object.assign({}, this.references);
|
|
258
|
+
newReferences[ref.citationID] = ref;
|
|
259
|
+
return this.withReferences(newReferences);
|
|
260
|
+
}
|
|
261
|
+
withEditedReferenceID(newCitationID, ref) {
|
|
262
|
+
if (!(ref.citationID in this.references))
|
|
218
263
|
return;
|
|
219
|
-
|
|
220
|
-
|
|
264
|
+
const newReferences = Object.assign({}, this.references);
|
|
265
|
+
delete newReferences[ref.citationID];
|
|
266
|
+
newReferences[newCitationID] = ref.withCitationID(newCitationID);
|
|
267
|
+
return this.withReferences(newReferences);
|
|
221
268
|
}
|
|
222
|
-
|
|
223
|
-
if (!(
|
|
224
|
-
return;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return this.
|
|
269
|
+
withoutReference(citationID) {
|
|
270
|
+
if (!(citationID in this.references))
|
|
271
|
+
return this;
|
|
272
|
+
const newReferences = Object.assign({}, this.references);
|
|
273
|
+
delete newReferences[citationID];
|
|
274
|
+
return this.withReferences(newReferences);
|
|
228
275
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return this.
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
this.
|
|
276
|
+
hasGlossary() {
|
|
277
|
+
return Object.keys(this.glossary).length > 0;
|
|
278
|
+
}
|
|
279
|
+
getGlossary() {
|
|
280
|
+
return Object.assign({}, this.glossary);
|
|
281
|
+
}
|
|
282
|
+
hasDefinition(id) {
|
|
283
|
+
return id in this.glossary;
|
|
284
|
+
}
|
|
285
|
+
withGlossary(glossary) {
|
|
286
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, glossary, this.theme, this.active);
|
|
287
|
+
}
|
|
288
|
+
withDefinition(id, phrase, definition, synonyms) {
|
|
289
|
+
const newGlossary = Object.assign({}, this.glossary);
|
|
290
|
+
newGlossary[id] = {
|
|
240
291
|
phrase: phrase,
|
|
241
292
|
definition: definition,
|
|
242
|
-
synonyms: synonyms
|
|
293
|
+
synonyms: synonyms,
|
|
243
294
|
};
|
|
244
|
-
return this.
|
|
295
|
+
return this.withGlossary(newGlossary);
|
|
245
296
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
297
|
+
withoutDefinition(id) {
|
|
298
|
+
const newGlossary = Object.assign({}, this.glossary);
|
|
299
|
+
delete newGlossary[id];
|
|
300
|
+
return this.withGlossary(newGlossary);
|
|
249
301
|
}
|
|
250
|
-
|
|
251
|
-
this.
|
|
252
|
-
|
|
302
|
+
withEditedDefinition(id, definition) {
|
|
303
|
+
const newGlossary = Object.assign({}, this.glossary);
|
|
304
|
+
newGlossary[id] = definition;
|
|
305
|
+
return this.withGlossary(newGlossary);
|
|
253
306
|
}
|
|
254
|
-
|
|
255
|
-
if (!(id in this.
|
|
256
|
-
return;
|
|
257
|
-
const definition = this.specification.glossary[id];
|
|
258
|
-
delete this.specification.glossary[id];
|
|
259
|
-
this.specification.glossary[newID] = definition;
|
|
260
|
-
return this.requestSave();
|
|
261
|
-
}
|
|
262
|
-
getTags() { return this.specification.tags; }
|
|
263
|
-
getTheme() { return this.specification.theme; }
|
|
264
|
-
setTheme(theme) {
|
|
265
|
-
this.specification.theme = theme;
|
|
266
|
-
return this.requestSave();
|
|
267
|
-
}
|
|
268
|
-
setThemeValue(group, name, value) {
|
|
269
|
-
if (this.specification.theme[group][name] === value)
|
|
307
|
+
withEditedDefinitionID(id, newID) {
|
|
308
|
+
if (!(id in this.glossary))
|
|
270
309
|
return;
|
|
271
|
-
|
|
272
|
-
|
|
310
|
+
const newGlossary = Object.assign({}, this.glossary);
|
|
311
|
+
const definition = newGlossary[id];
|
|
312
|
+
delete newGlossary[id];
|
|
313
|
+
newGlossary[newID] = definition;
|
|
314
|
+
return this.withGlossary(newGlossary);
|
|
315
|
+
}
|
|
316
|
+
getTags() {
|
|
317
|
+
return this.tags;
|
|
318
|
+
}
|
|
319
|
+
getTheme() {
|
|
320
|
+
return this.theme;
|
|
321
|
+
}
|
|
322
|
+
withTheme(theme) {
|
|
323
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, theme, this.active);
|
|
324
|
+
}
|
|
325
|
+
withThemeValue(group, name, value) {
|
|
326
|
+
if (this.theme === null)
|
|
327
|
+
return this;
|
|
328
|
+
if (group === 'imports')
|
|
329
|
+
return this;
|
|
330
|
+
const newTheme = Object.assign({}, this.theme);
|
|
331
|
+
const newGroup = Object.assign({}, this.theme[group]);
|
|
332
|
+
newGroup[name] = value;
|
|
333
|
+
newTheme[group] = newGroup;
|
|
334
|
+
return this.withTheme(newTheme);
|
|
273
335
|
}
|
|
274
336
|
// Don't let callers get their sneaky hands on this mutable array...
|
|
275
|
-
getAuthors() {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (this.
|
|
295
|
-
return;
|
|
296
|
-
this.
|
|
297
|
-
|
|
337
|
+
getAuthors() {
|
|
338
|
+
return [...this.authors];
|
|
339
|
+
}
|
|
340
|
+
withAuthors(authors) {
|
|
341
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
342
|
+
}
|
|
343
|
+
withAuthor(name) {
|
|
344
|
+
return this.withAuthors([...this.authors, name]);
|
|
345
|
+
}
|
|
346
|
+
withAuthorName(index, name) {
|
|
347
|
+
if (index < 0 || index >= this.authors.length)
|
|
348
|
+
return this;
|
|
349
|
+
return this.withAuthors([
|
|
350
|
+
...this.authors.slice(0, index),
|
|
351
|
+
name,
|
|
352
|
+
...this.authors.slice(index + 1),
|
|
353
|
+
]);
|
|
354
|
+
}
|
|
355
|
+
withoutAuthor(index) {
|
|
356
|
+
if (index < 0 || index >= this.authors.length)
|
|
357
|
+
return this;
|
|
358
|
+
return this.withAuthors([
|
|
359
|
+
...this.authors.slice(0, index),
|
|
360
|
+
...this.authors.slice(index + 1),
|
|
361
|
+
]);
|
|
362
|
+
}
|
|
363
|
+
withEditors(uids) {
|
|
364
|
+
return new Edition(this.bookRef, this.editionRef, uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
365
|
+
}
|
|
366
|
+
hasImage(id) {
|
|
367
|
+
return this.images[id] !== null;
|
|
368
|
+
}
|
|
369
|
+
getImage(id) {
|
|
370
|
+
return this.images[id] ?? null;
|
|
371
|
+
}
|
|
372
|
+
withImage(id, embed) {
|
|
373
|
+
const newImages = Object.assign({}, this.images);
|
|
374
|
+
newImages[id] = embed;
|
|
375
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, newImages, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, this.active);
|
|
376
|
+
}
|
|
377
|
+
isEditor(uid) {
|
|
378
|
+
return this.uids.includes(uid);
|
|
379
|
+
}
|
|
380
|
+
isChapterEditor(uid) {
|
|
381
|
+
return this.getChapterUIDS().includes(uid);
|
|
382
|
+
}
|
|
383
|
+
getLeasee(content) {
|
|
384
|
+
return this.active[content];
|
|
385
|
+
}
|
|
386
|
+
hasLease(uid, content) {
|
|
387
|
+
return this.active[content] === uid;
|
|
388
|
+
}
|
|
389
|
+
isLeased(contentID) {
|
|
390
|
+
return contentID in this.active;
|
|
391
|
+
}
|
|
392
|
+
withLock(uid, content, lock) {
|
|
393
|
+
const newActive = Object.assign({}, this.active);
|
|
394
|
+
if (lock)
|
|
395
|
+
newActive[content] = uid;
|
|
396
|
+
else
|
|
397
|
+
delete newActive[content];
|
|
398
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.number, this.summary, this.published, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme, newActive);
|
|
298
399
|
}
|
|
299
400
|
getBookReadingTime() {
|
|
300
401
|
return this.chapters
|
|
301
|
-
.map(chapter => chapter.getReadingTime())
|
|
302
|
-
.reduce((total, time) => total === undefined
|
|
303
|
-
|
|
304
|
-
|
|
402
|
+
.map((chapter) => chapter.getReadingTime(this))
|
|
403
|
+
.reduce((total, time) => total === undefined
|
|
404
|
+
? 0
|
|
405
|
+
: time === undefined
|
|
406
|
+
? total
|
|
407
|
+
: total + time, 0);
|
|
305
408
|
}
|
|
306
409
|
getChapterNumber(chapterID) {
|
|
307
410
|
let chapterNumber = 1;
|
|
308
411
|
let match = null;
|
|
309
|
-
this.chapters.forEach(chapter => {
|
|
412
|
+
this.chapters.forEach((chapter) => {
|
|
310
413
|
// If we found a match...
|
|
311
|
-
if (chapter.
|
|
414
|
+
if (chapter.getID() === chapterID) {
|
|
312
415
|
match = chapterNumber;
|
|
313
416
|
// And it's an unnumbered chapter, set to null.
|
|
314
417
|
if (!chapter.isNumbered())
|
|
@@ -325,37 +428,39 @@ export default class Edition {
|
|
|
325
428
|
return undefined;
|
|
326
429
|
}
|
|
327
430
|
getSource(sourceID) {
|
|
328
|
-
return sourceID.charAt(0) ===
|
|
329
|
-
|
|
330
|
-
|
|
431
|
+
return sourceID.charAt(0) === '#' &&
|
|
432
|
+
sourceID.substring(1) in this.sources
|
|
433
|
+
? this.sources[sourceID.substring(1)]
|
|
434
|
+
: null;
|
|
331
435
|
}
|
|
332
436
|
getChapterName(chapterID) {
|
|
333
437
|
const chapter = this.getChapter(chapterID);
|
|
334
438
|
return chapter?.getTitle();
|
|
335
439
|
}
|
|
336
440
|
getChapterSection(chapterID) {
|
|
337
|
-
const chapter = this.
|
|
441
|
+
const chapter = this.getChapter(chapterID);
|
|
338
442
|
return chapter?.getSection();
|
|
339
443
|
}
|
|
340
444
|
getFootnoteSymbol(number) {
|
|
341
|
-
let symbols =
|
|
445
|
+
let symbols = 'abcdefghijklmnopqrstuvwxyz';
|
|
342
446
|
// Let's hope there are never more than 26^2 footnotes in a single chapter...
|
|
343
|
-
return number < symbols.length
|
|
344
|
-
symbols.charAt(number)
|
|
345
|
-
symbols.charAt(Math.floor(number / symbols.length) - 1) +
|
|
447
|
+
return number < symbols.length
|
|
448
|
+
? symbols.charAt(number)
|
|
449
|
+
: symbols.charAt(Math.floor(number / symbols.length) - 1) +
|
|
450
|
+
symbols.charAt(number % symbols.length);
|
|
346
451
|
}
|
|
347
452
|
getBookIndex() {
|
|
348
453
|
// A map from word to a map of chapters containing the word
|
|
349
454
|
const bookIndex = {};
|
|
350
455
|
// Construct the index by building a dictionary of chapters in which each word appears.
|
|
351
|
-
this.chapters.forEach(chapter => {
|
|
352
|
-
let index = chapter.getIndex();
|
|
456
|
+
this.chapters.forEach((chapter) => {
|
|
457
|
+
let index = chapter.getIndex(this);
|
|
353
458
|
if (index)
|
|
354
|
-
Object.keys(index).forEach(word => {
|
|
355
|
-
if (word !==
|
|
459
|
+
Object.keys(index).forEach((word) => {
|
|
460
|
+
if (word !== '' && word.length > 2) {
|
|
356
461
|
if (!(word in bookIndex))
|
|
357
462
|
bookIndex[word] = new Set();
|
|
358
|
-
bookIndex[word].add(chapter.
|
|
463
|
+
bookIndex[word].add(chapter.getID());
|
|
359
464
|
}
|
|
360
465
|
});
|
|
361
466
|
});
|
|
@@ -365,25 +470,39 @@ export default class Edition {
|
|
|
365
470
|
getNextChapterID(chapterID) {
|
|
366
471
|
// Handle back matter chapters.
|
|
367
472
|
switch (chapterID) {
|
|
368
|
-
case ChapterIDs.ReferencesID:
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
case ChapterIDs.
|
|
373
|
-
|
|
473
|
+
case ChapterIDs.ReferencesID:
|
|
474
|
+
return this.hasGlossary()
|
|
475
|
+
? ChapterIDs.GlossaryID
|
|
476
|
+
: ChapterIDs.IndexID;
|
|
477
|
+
case ChapterIDs.GlossaryID:
|
|
478
|
+
return ChapterIDs.IndexID;
|
|
479
|
+
case ChapterIDs.IndexID:
|
|
480
|
+
return ChapterIDs.SearchID;
|
|
481
|
+
case ChapterIDs.SearchID:
|
|
482
|
+
return ChapterIDs.MediaID;
|
|
483
|
+
case ChapterIDs.MediaID:
|
|
484
|
+
return ChapterIDs.TableOfContentsID;
|
|
485
|
+
case ChapterIDs.TableOfContentsID:
|
|
486
|
+
return this.chapters.length > 0
|
|
487
|
+
? this.chapters[0].getID()
|
|
488
|
+
: null;
|
|
374
489
|
default:
|
|
375
490
|
let after = false;
|
|
376
491
|
for (let i = 0; i < this.chapters.length; i++) {
|
|
377
492
|
let chapter = this.chapters[i];
|
|
378
|
-
if (chapter.
|
|
493
|
+
if (chapter.getID() === chapterID)
|
|
379
494
|
after = true;
|
|
380
495
|
// If we're after the given chapter and it's not forthcoming.
|
|
381
496
|
else if (after && !chapter.isForthcoming())
|
|
382
|
-
return chapter.
|
|
497
|
+
return chapter.getID();
|
|
383
498
|
}
|
|
384
499
|
// If the given ID was the last chapter, go to the next back matter chapter.
|
|
385
500
|
if (after)
|
|
386
|
-
return this.hasReferences()
|
|
501
|
+
return this.hasReferences()
|
|
502
|
+
? ChapterIDs.ReferencesID
|
|
503
|
+
: this.hasGlossary()
|
|
504
|
+
? ChapterIDs.GlossaryID
|
|
505
|
+
: ChapterIDs.IndexID;
|
|
387
506
|
// Otherwise, it wasn't a valid ID
|
|
388
507
|
else
|
|
389
508
|
return null;
|
|
@@ -393,20 +512,37 @@ export default class Edition {
|
|
|
393
512
|
getPreviousChapterID(chapterID) {
|
|
394
513
|
switch (chapterID) {
|
|
395
514
|
// Handle back matter chapters.
|
|
396
|
-
case ChapterIDs.ReferencesID:
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
case ChapterIDs.
|
|
515
|
+
case ChapterIDs.ReferencesID:
|
|
516
|
+
return this.chapters.length > 0
|
|
517
|
+
? this.chapters[this.chapters.length - 1].getID()
|
|
518
|
+
: null; // Last chapter of the book
|
|
519
|
+
case ChapterIDs.GlossaryID:
|
|
520
|
+
return this.hasReferences()
|
|
521
|
+
? ChapterIDs.ReferencesID
|
|
522
|
+
: this.chapters.length > 0
|
|
523
|
+
? this.chapters[this.chapters.length - 1].getID()
|
|
524
|
+
: ChapterIDs.TableOfContentsID;
|
|
525
|
+
case ChapterIDs.IndexID:
|
|
526
|
+
return this.hasGlossary()
|
|
527
|
+
? ChapterIDs.GlossaryID
|
|
528
|
+
: this.hasReferences()
|
|
529
|
+
? ChapterIDs.ReferencesID
|
|
530
|
+
: this.chapters.length > 0
|
|
531
|
+
? this.chapters[this.chapters.length - 1].getID()
|
|
532
|
+
: ChapterIDs.TableOfContentsID;
|
|
533
|
+
case ChapterIDs.SearchID:
|
|
534
|
+
return ChapterIDs.IndexID;
|
|
535
|
+
case ChapterIDs.MediaID:
|
|
536
|
+
return ChapterIDs.SearchID;
|
|
401
537
|
default:
|
|
402
538
|
let before = false;
|
|
403
539
|
for (let i = this.chapters.length - 1; i >= 0; i--) {
|
|
404
540
|
let chapter = this.chapters[i];
|
|
405
|
-
if (chapter.
|
|
541
|
+
if (chapter.getID() === chapterID)
|
|
406
542
|
before = true;
|
|
407
543
|
// If we're before the given chapter and it's not forthcoming.
|
|
408
544
|
else if (before && !chapter.isForthcoming())
|
|
409
|
-
return chapter.
|
|
545
|
+
return chapter.getID();
|
|
410
546
|
}
|
|
411
547
|
// If the given ID was the last chapter, go to the next back matter chapter.
|
|
412
548
|
if (before)
|
|
@@ -420,26 +556,26 @@ export default class Edition {
|
|
|
420
556
|
getEmbeds() {
|
|
421
557
|
let embeds = [];
|
|
422
558
|
// Add the book cover
|
|
423
|
-
const cover = this.getImage(
|
|
559
|
+
const cover = this.getImage('cover');
|
|
424
560
|
if (cover) {
|
|
425
561
|
let coverNode = Parser.parseEmbed(this, cover);
|
|
426
562
|
if (coverNode instanceof EmbedNode)
|
|
427
563
|
embeds.push(coverNode);
|
|
428
564
|
}
|
|
429
565
|
// Add the cover and images from each chapter.
|
|
430
|
-
this.getChapters().forEach(c => {
|
|
566
|
+
this.getChapters().forEach((c) => {
|
|
431
567
|
const image = c.getImage();
|
|
432
568
|
let cover = image === null ? undefined : Parser.parseEmbed(this, image);
|
|
433
569
|
if (cover && cover instanceof EmbedNode)
|
|
434
570
|
embeds.push(cover);
|
|
435
571
|
// Get the chapter body's embeds
|
|
436
|
-
let bodyEmbeds = c?.getAST()?.getEmbeds();
|
|
572
|
+
let bodyEmbeds = c?.getAST(this)?.getEmbeds();
|
|
437
573
|
if (bodyEmbeds)
|
|
438
574
|
bodyEmbeds.forEach((embed) => embeds.push(embed));
|
|
439
575
|
});
|
|
440
576
|
// Add the back matter covers
|
|
441
|
-
let backmatter = [
|
|
442
|
-
backmatter.forEach(id => {
|
|
577
|
+
let backmatter = ['references', 'glossary', 'index', 'search', 'media'];
|
|
578
|
+
backmatter.forEach((id) => {
|
|
443
579
|
const img = this.getImage(id);
|
|
444
580
|
if (img) {
|
|
445
581
|
let image = Parser.parseEmbed(this, img);
|
|
@@ -449,18 +585,33 @@ export default class Edition {
|
|
|
449
585
|
});
|
|
450
586
|
return embeds;
|
|
451
587
|
}
|
|
452
|
-
|
|
453
|
-
const latestEditionID =
|
|
454
|
-
return latestEditionID !== undefined &&
|
|
588
|
+
isLatestEdition(book) {
|
|
589
|
+
const latestEditionID = book.getLatestEditionID();
|
|
590
|
+
return (latestEditionID !== undefined &&
|
|
591
|
+
latestEditionID === this.editionRef?.id);
|
|
592
|
+
}
|
|
593
|
+
isLatestPublishedEdition(book) {
|
|
594
|
+
const latestEditionID = book.getLatestPublishedEditionID();
|
|
595
|
+
return (latestEditionID !== undefined &&
|
|
596
|
+
latestEditionID === this.editionRef?.id);
|
|
455
597
|
}
|
|
456
|
-
/* Edition numbers are 1 to N */
|
|
457
598
|
getEditionNumber() {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
599
|
+
return this.number;
|
|
600
|
+
}
|
|
601
|
+
getEditionLabel() {
|
|
602
|
+
const num = this.number;
|
|
603
|
+
return `${num}${num === 1 ? 'st' : num === 2 ? 'nd' : num === 3 ? 'rd' : ''}`;
|
|
604
|
+
}
|
|
605
|
+
getInfo() {
|
|
606
|
+
return this.editionRef === undefined
|
|
607
|
+
? undefined
|
|
608
|
+
: {
|
|
609
|
+
ref: this.editionRef,
|
|
610
|
+
summary: this.summary,
|
|
611
|
+
number: this.number,
|
|
612
|
+
published: this.published,
|
|
613
|
+
editionuids: this.uids,
|
|
614
|
+
chapteruids: Array.from(new Set(this.chapters.map((chapter) => chapter.uids).flat())),
|
|
615
|
+
};
|
|
465
616
|
}
|
|
466
617
|
}
|