bookish-press 0.4.0 → 0.4.16
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 +19 -14
- package/components/Auth.svelte.d.ts +4 -4
- package/components/Authentication.d.ts +2 -2
- package/components/BookPreview.svelte +77 -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 +45 -0
- package/components/app/Feedback.svelte.d.ts +18 -0
- package/components/app/Head.svelte +12 -0
- package/components/app/Head.svelte.d.ts +27 -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 +19 -0
- package/components/app/Paragraph.svelte.d.ts +18 -0
- package/components/app/Table.svelte +32 -0
- package/components/app/Table.svelte.d.ts +27 -0
- package/components/app/TextInput.svelte +37 -0
- package/components/app/TextInput.svelte.d.ts +22 -0
- package/components/app/Writing.svelte +13 -0
- package/components/app/Writing.svelte.d.ts +27 -0
- package/components/chapter/Atom.svelte +20 -6
- package/components/chapter/Atom.svelte.d.ts +3 -3
- package/components/chapter/Block.svelte +23 -20
- 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 +66 -23
- package/components/chapter/CaptionedCode.svelte.d.ts +4 -4
- package/components/chapter/ChapterBody.svelte +61 -9
- package/components/chapter/ChapterBody.svelte.d.ts +4 -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 +38 -16
- 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 +154 -66
- package/components/chapter/Embed.svelte.d.ts +5 -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 +60 -37
- package/components/chapter/Format.svelte.d.ts +4 -4
- package/components/chapter/InlineCode.svelte +15 -5
- package/components/chapter/InlineCode.svelte.d.ts +4 -4
- package/components/chapter/Label.svelte +37 -8
- package/components/chapter/Label.svelte.d.ts +4 -4
- package/components/chapter/Link.svelte +23 -18
- 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 +74 -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 +343 -237
- package/components/editor/BookishEditor.svelte.d.ts +5 -5
- 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 +80 -0
- package/components/editor/CaretView.svelte.d.ts +24 -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 +3 -3
- package/components/editor/Note.svelte.d.ts +6 -2
- 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 +192 -144
- package/components/editor/Toolbar.svelte.d.ts +5 -8
- package/components/editor/ToolbarGroup.svelte +18 -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 +31 -22
- package/components/page/Acknowledgements.svelte.d.ts +4 -4
- package/components/page/Authors.svelte +34 -14
- package/components/page/Authors.svelte.d.ts +6 -6
- package/components/page/BulkReferenceEditor.svelte +53 -22
- package/components/page/BulkReferenceEditor.svelte.d.ts +4 -4
- package/components/page/Chapter.svelte +196 -141
- 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 +31 -20
- package/components/page/Contexts.js +47 -17
- package/components/page/DefinitionView.svelte +115 -86
- package/components/page/DefinitionView.svelte.d.ts +3 -3
- package/components/page/Description.svelte +27 -18
- package/components/page/Description.svelte.d.ts +4 -4
- package/components/page/Edition.svelte +127 -74
- package/components/page/Edition.svelte.d.ts +4 -4
- package/components/page/Editions.svelte +144 -0
- package/components/page/Editions.svelte.d.ts +14 -0
- package/components/page/Glossary.svelte +57 -48
- package/components/page/Glossary.svelte.d.ts +4 -4
- package/components/page/Header.svelte +129 -44
- package/components/page/Header.svelte.d.ts +6 -6
- package/components/page/Index.svelte +114 -80
- package/components/page/Index.svelte.d.ts +4 -4
- package/components/page/Instructions.svelte +18 -16
- package/components/page/Instructions.svelte.d.ts +4 -4
- package/components/page/License.svelte +29 -21
- 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 +77 -51
- 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/Reference.svelte +256 -113
- package/components/page/Reference.svelte.d.ts +5 -5
- package/components/page/References.svelte +39 -47
- 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 +86 -63
- package/components/page/Search.svelte.d.ts +4 -4
- package/components/page/Status.svelte +43 -35
- package/components/page/Status.svelte.d.ts +4 -9
- package/components/page/SubdomainEditor.svelte +40 -27
- package/components/page/SubdomainEditor.svelte.d.ts +4 -4
- package/components/page/TableOfContents.svelte +225 -190
- 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 +96 -33
- package/components/page/TableOfContentsRow.svelte.d.ts +4 -4
- package/components/page/ThemeEditor.svelte +174 -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 +25 -21
- package/components/page/Unknown.svelte.d.ts +4 -4
- package/components/page/margins.js +50 -33
- package/index.d.ts +14 -0
- package/index.js +14 -0
- package/models/CRUD.d.ts +17 -0
- package/models/CRUD.js +194 -0
- package/models/Firebase.js +17 -15
- package/models/book/Book.d.ts +24 -28
- package/models/book/Book.js +120 -113
- 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 +46 -39
- package/models/book/Chapter.js +180 -198
- package/models/book/ChapterID.js +7 -7
- package/models/book/Definition.d.ts +1 -1
- package/models/book/Edition.d.ts +62 -60
- package/models/book/Edition.js +385 -303
- package/models/book/Reference.d.ts +24 -0
- package/models/book/Reference.js +78 -0
- package/models/book/Schema.d.ts +169 -0
- package/models/book/Schema.js +114 -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 +25 -25
- package/models/chapter/Parser.js +201 -189
- 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/models/loadEdition.d.ts +1 -1
- package/models/loadEdition.js +10 -6
- package/package.json +104 -25
- 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/book/Edition.js
CHANGED
|
@@ -1,314 +1,353 @@
|
|
|
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
|
+
images;
|
|
13
|
+
description;
|
|
17
14
|
chapters;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
license;
|
|
16
|
+
acknowledgements;
|
|
17
|
+
tags;
|
|
18
|
+
sources;
|
|
19
|
+
references;
|
|
20
|
+
symbols;
|
|
21
|
+
glossary;
|
|
22
|
+
theme;
|
|
24
23
|
// Given an object with a valid specification and an object mapping chapter IDs to chapter text,
|
|
25
24
|
// construct an object representing a book.
|
|
26
|
-
constructor(
|
|
27
|
-
|
|
28
|
-
throw Error("Expected a book specification object, but received " + specification);
|
|
29
|
-
this.book = book;
|
|
25
|
+
constructor(bookRef, editionRef, uids, title, authors, images, description, chapters, license, acknowledgements, tags, sources, references, symbols, glossary, theme) {
|
|
26
|
+
this.bookRef = bookRef;
|
|
30
27
|
this.editionRef = editionRef;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
uids: specification && specification.uids ? specification.uids : [],
|
|
48
|
-
chapters: specification && specification.chapters ? specification.chapters : []
|
|
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
|
-
});
|
|
28
|
+
this.uids = uids;
|
|
29
|
+
this.title = title;
|
|
30
|
+
this.authors = authors;
|
|
31
|
+
this.images = images;
|
|
32
|
+
this.description = description;
|
|
33
|
+
this.chapters = chapters.slice();
|
|
34
|
+
this.license = license;
|
|
35
|
+
this.acknowledgements = acknowledgements;
|
|
36
|
+
this.tags = tags.slice();
|
|
37
|
+
this.sources = Object.assign({}, sources);
|
|
38
|
+
this.references = {};
|
|
39
|
+
for (const [citationID, ref] of Object.entries(references)) {
|
|
40
|
+
this.references[citationID] =
|
|
41
|
+
ref instanceof Reference
|
|
42
|
+
? ref
|
|
43
|
+
: Edition.parseReference(citationID, ref, this);
|
|
64
44
|
}
|
|
45
|
+
this.symbols = Object.assign({}, symbols);
|
|
46
|
+
this.glossary = Object.assign({}, glossary);
|
|
47
|
+
this.theme = theme;
|
|
65
48
|
}
|
|
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
|
-
});
|
|
49
|
+
static async fromJSON(editionRef, spec) {
|
|
50
|
+
// Copy all of the specification metadata to fields.
|
|
51
|
+
// Choose suitable defaults if the spec is lacking a field.
|
|
52
|
+
return new Edition(spec.bookRef, editionRef, spec.uids, spec.title, spec.authors, 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);
|
|
53
|
+
}
|
|
54
|
+
static parseReference(citationID, ref, edition, short = false) {
|
|
55
|
+
if (typeof ref === 'string')
|
|
56
|
+
return Parser.parseFormat(edition, ref);
|
|
57
|
+
else {
|
|
58
|
+
// APA Format. Could eventually support multiple formats.
|
|
59
|
+
let [authors, year, title, source, url, summary] = ref;
|
|
60
|
+
if (source.charAt(0) === '#') {
|
|
61
|
+
let src = edition.getSource(source);
|
|
62
|
+
if (src !== null)
|
|
63
|
+
source = src;
|
|
64
|
+
}
|
|
65
|
+
return new Reference(citationID, authors ?? '', year ?? '', title ?? '', source ?? '', url ?? '', summary ?? '', short);
|
|
94
66
|
}
|
|
95
67
|
}
|
|
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
68
|
// Convert the book to an object for storage.
|
|
113
69
|
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
|
-
return this.
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return this.
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
70
|
+
const references = {};
|
|
71
|
+
for (const [citationID, ref] of Object.entries(this.references))
|
|
72
|
+
references[citationID] =
|
|
73
|
+
ref instanceof Reference ? ref.toList() : ref.toBookdown();
|
|
74
|
+
const editionJSON = {
|
|
75
|
+
title: this.title,
|
|
76
|
+
authors: this.authors,
|
|
77
|
+
images: Object.assign({}, this.images),
|
|
78
|
+
description: this.description,
|
|
79
|
+
chapters: this.chapters.map((chap) => chap.toJSON()),
|
|
80
|
+
license: this.license,
|
|
81
|
+
acknowledgements: this.acknowledgements,
|
|
82
|
+
tags: this.tags.slice(),
|
|
83
|
+
sources: Object.assign({}, this.sources),
|
|
84
|
+
references: references,
|
|
85
|
+
symbols: Object.assign({}, this.symbols),
|
|
86
|
+
glossary: Object.assign({}, this.glossary),
|
|
87
|
+
theme: this.theme,
|
|
88
|
+
uids: this.uids.slice(),
|
|
89
|
+
};
|
|
90
|
+
if (this.bookRef)
|
|
91
|
+
editionJSON.bookRef = this.bookRef;
|
|
92
|
+
return editionJSON;
|
|
93
|
+
}
|
|
94
|
+
getRef() {
|
|
95
|
+
return this.editionRef;
|
|
96
|
+
}
|
|
97
|
+
withRef(editionRef) {
|
|
98
|
+
return new Edition(this.bookRef, editionRef, this.uids, this.title, this.authors, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme);
|
|
99
|
+
}
|
|
100
|
+
getTitle() {
|
|
101
|
+
return this.title;
|
|
102
|
+
}
|
|
103
|
+
withTitle(title) {
|
|
104
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, title, this.authors, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme);
|
|
105
|
+
}
|
|
106
|
+
getDescription() {
|
|
107
|
+
return this.description;
|
|
108
|
+
}
|
|
109
|
+
setDescription(description) {
|
|
110
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.images, description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme);
|
|
111
|
+
}
|
|
112
|
+
getAcknowledgements() {
|
|
113
|
+
return this.acknowledgements;
|
|
114
|
+
}
|
|
115
|
+
setAcknowledgements(acks) {
|
|
116
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.images, this.description, this.chapters, this.license, acks, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme);
|
|
117
|
+
}
|
|
118
|
+
getLicense() {
|
|
119
|
+
return this.license;
|
|
120
|
+
}
|
|
121
|
+
setLicense(license) {
|
|
122
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.images, this.description, this.chapters, license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme);
|
|
123
|
+
}
|
|
124
|
+
getChapters() {
|
|
125
|
+
return this.chapters.slice();
|
|
126
|
+
}
|
|
127
|
+
hasChapter(chapterID) {
|
|
128
|
+
return (this.getChapter(chapterID) !== undefined ||
|
|
129
|
+
['references', 'glossary', 'index', 'search', 'media'].includes(chapterID));
|
|
130
|
+
}
|
|
131
|
+
getChapter(chapterID) {
|
|
132
|
+
return this.chapters.find((chapter) => chapter.getID() === chapterID);
|
|
133
|
+
}
|
|
134
|
+
getChapterByRef(ref) {
|
|
135
|
+
return this.chapters.find((chap) => chap.ref !== undefined && chap.ref.id === ref.id);
|
|
136
|
+
}
|
|
150
137
|
getChapterPosition(chapterID) {
|
|
151
138
|
var position = 0;
|
|
152
139
|
for (; position < this.chapters.length; position++)
|
|
153
|
-
if (this.chapters[position].
|
|
140
|
+
if (this.chapters[position].getID() === chapterID)
|
|
154
141
|
return position;
|
|
155
142
|
return undefined;
|
|
156
143
|
}
|
|
157
|
-
getChapterCount() {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
144
|
+
getChapterCount() {
|
|
145
|
+
return this.chapters.length;
|
|
146
|
+
}
|
|
147
|
+
withChapters(chapters) {
|
|
148
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.images, this.description, chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme);
|
|
149
|
+
}
|
|
150
|
+
withRevisedChapter(previous, edited) {
|
|
151
|
+
const index = this.chapters.indexOf(previous);
|
|
152
|
+
if (index < 0)
|
|
153
|
+
return this;
|
|
154
|
+
return this.withChapters([
|
|
155
|
+
...this.chapters.slice(0, index),
|
|
156
|
+
edited,
|
|
157
|
+
...this.chapters.slice(index + 1),
|
|
158
|
+
]);
|
|
159
|
+
}
|
|
160
|
+
withoutRefs() {
|
|
161
|
+
return this.withRef(undefined).withChapters(this.chapters.map((chap) => chap.withoutRef()));
|
|
162
|
+
}
|
|
163
|
+
withNewChapter() {
|
|
162
164
|
// Synthesize a chapter ID placeholder that doesn't overlap with existing chapter names
|
|
163
165
|
let number = 1;
|
|
164
|
-
while (this.hasChapter(
|
|
166
|
+
while (this.hasChapter('chapter' + number))
|
|
165
167
|
number++;
|
|
166
|
-
const chapterRef = await addChapterInFirestore(editionID, { text: "" });
|
|
167
168
|
// 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();
|
|
169
|
+
const newChapter = new Chapter(undefined, `chapter${number}`, 'Untitled Chapter', [], null, true, false, undefined, '');
|
|
170
|
+
return this.withChapters([...this.chapters, newChapter]);
|
|
182
171
|
}
|
|
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);
|
|
172
|
+
withoutChapter(chapterID) {
|
|
173
|
+
let index = this.chapters.findIndex((chapter) => chapter.getID() === chapterID);
|
|
200
174
|
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();
|
|
175
|
+
return this;
|
|
176
|
+
return this.withChapters([
|
|
177
|
+
...this.chapters.slice(0, index),
|
|
178
|
+
...this.chapters.slice(index + 1),
|
|
179
|
+
]);
|
|
215
180
|
}
|
|
216
|
-
|
|
217
|
-
|
|
181
|
+
withMovedChapter(chapterID, increment) {
|
|
182
|
+
// Get the index of the chapter.
|
|
183
|
+
let index = this.chapters.findIndex((chapter) => chapter.getID() === chapterID);
|
|
184
|
+
if (index + increment < 0 || index + increment >= this.chapters.length)
|
|
185
|
+
return this;
|
|
186
|
+
const newChapters = this.chapters.slice();
|
|
187
|
+
const temp = newChapters[index + increment];
|
|
188
|
+
newChapters[index + increment] = newChapters[index];
|
|
189
|
+
newChapters[index] = temp;
|
|
190
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.images, this.description, newChapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme);
|
|
191
|
+
}
|
|
192
|
+
getSymbols() {
|
|
193
|
+
return this.symbols;
|
|
194
|
+
}
|
|
195
|
+
hasReferences() {
|
|
196
|
+
return Object.keys(this.references).length > 0;
|
|
197
|
+
}
|
|
198
|
+
getReferences() {
|
|
199
|
+
return Object.assign({}, this.references);
|
|
200
|
+
}
|
|
201
|
+
getReference(citationID) {
|
|
202
|
+
return citationID in this.references
|
|
203
|
+
? this.references[citationID]
|
|
204
|
+
: undefined;
|
|
205
|
+
}
|
|
206
|
+
withReferences(newReferences) {
|
|
207
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, newReferences, this.symbols, this.glossary, this.theme);
|
|
208
|
+
}
|
|
209
|
+
withNewReferences(references) {
|
|
210
|
+
const newReferences = Object.assign({}, this.references);
|
|
211
|
+
// Generate a unique ID for the reference.
|
|
212
|
+
for (const newRef of references)
|
|
213
|
+
newReferences[newRef.citationID] = newRef;
|
|
214
|
+
return this.withReferences(newReferences);
|
|
215
|
+
}
|
|
216
|
+
withEditedReference(ref) {
|
|
217
|
+
if (!(ref.citationID in this.references))
|
|
218
|
+
return this;
|
|
219
|
+
const newReferences = Object.assign({}, this.references);
|
|
220
|
+
newReferences[ref.citationID] = ref;
|
|
221
|
+
return this.withReferences(newReferences);
|
|
222
|
+
}
|
|
223
|
+
withEditedReferenceID(newCitationID, ref) {
|
|
224
|
+
if (!(ref.citationID in this.references))
|
|
218
225
|
return;
|
|
219
|
-
|
|
220
|
-
|
|
226
|
+
const newReferences = Object.assign({}, this.references);
|
|
227
|
+
delete newReferences[ref.citationID];
|
|
228
|
+
newReferences[newCitationID] = ref.withCitationID(newCitationID);
|
|
229
|
+
return this.withReferences(newReferences);
|
|
221
230
|
}
|
|
222
|
-
|
|
223
|
-
if (!(
|
|
224
|
-
return;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return this.
|
|
231
|
+
withoutReference(citationID) {
|
|
232
|
+
if (!(citationID in this.references))
|
|
233
|
+
return this;
|
|
234
|
+
const newReferences = Object.assign({}, this.references);
|
|
235
|
+
delete newReferences[citationID];
|
|
236
|
+
return this.withReferences(newReferences);
|
|
228
237
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return this.
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
this.
|
|
238
|
+
hasGlossary() {
|
|
239
|
+
return Object.keys(this.glossary).length > 0;
|
|
240
|
+
}
|
|
241
|
+
getGlossary() {
|
|
242
|
+
return Object.assign({}, this.glossary);
|
|
243
|
+
}
|
|
244
|
+
hasDefinition(id) {
|
|
245
|
+
return id in this.glossary;
|
|
246
|
+
}
|
|
247
|
+
withGlossary(glossary) {
|
|
248
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, glossary, this.theme);
|
|
249
|
+
}
|
|
250
|
+
withDefinition(id, phrase, definition, synonyms) {
|
|
251
|
+
const newGlossary = Object.assign({}, this.glossary);
|
|
252
|
+
newGlossary[id] = {
|
|
240
253
|
phrase: phrase,
|
|
241
254
|
definition: definition,
|
|
242
|
-
synonyms: synonyms
|
|
255
|
+
synonyms: synonyms,
|
|
243
256
|
};
|
|
244
|
-
return this.
|
|
257
|
+
return this.withGlossary(newGlossary);
|
|
245
258
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
259
|
+
withoutDefinition(id) {
|
|
260
|
+
const newGlossary = Object.assign({}, this.glossary);
|
|
261
|
+
delete newGlossary[id];
|
|
262
|
+
return this.withGlossary(newGlossary);
|
|
249
263
|
}
|
|
250
|
-
|
|
251
|
-
this.
|
|
252
|
-
|
|
264
|
+
withEditedDefinition(id, definition) {
|
|
265
|
+
const newGlossary = Object.assign({}, this.glossary);
|
|
266
|
+
newGlossary[id] = definition;
|
|
267
|
+
return this.withGlossary(newGlossary);
|
|
253
268
|
}
|
|
254
|
-
|
|
255
|
-
if (!(id in this.
|
|
269
|
+
withEditedDefinitionID(id, newID) {
|
|
270
|
+
if (!(id in this.glossary))
|
|
256
271
|
return;
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
272
|
+
const newGlossary = Object.assign({}, this.glossary);
|
|
273
|
+
const definition = newGlossary[id];
|
|
274
|
+
delete newGlossary[id];
|
|
275
|
+
newGlossary[newID] = definition;
|
|
276
|
+
return this.withGlossary(newGlossary);
|
|
277
|
+
}
|
|
278
|
+
getTags() {
|
|
279
|
+
return this.tags;
|
|
280
|
+
}
|
|
281
|
+
getTheme() {
|
|
282
|
+
return this.theme;
|
|
283
|
+
}
|
|
284
|
+
withTheme(theme) {
|
|
285
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, theme);
|
|
286
|
+
}
|
|
287
|
+
withThemeValue(group, name, value) {
|
|
288
|
+
if (this.theme === null)
|
|
289
|
+
return this;
|
|
290
|
+
if (group === 'imports')
|
|
291
|
+
return this;
|
|
292
|
+
const newTheme = Object.assign({}, this.theme);
|
|
293
|
+
const newGroup = Object.assign({}, this.theme[group]);
|
|
294
|
+
newGroup[name] = value;
|
|
295
|
+
newTheme[group] = newGroup;
|
|
296
|
+
return this.withTheme(newTheme);
|
|
273
297
|
}
|
|
274
298
|
// 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
|
-
|
|
299
|
+
getAuthors() {
|
|
300
|
+
return [...this.authors];
|
|
301
|
+
}
|
|
302
|
+
withAuthors(authors) {
|
|
303
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, authors, this.images, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme);
|
|
304
|
+
}
|
|
305
|
+
withAuthor(name) {
|
|
306
|
+
return this.withAuthors([...this.authors, name]);
|
|
307
|
+
}
|
|
308
|
+
withAuthorName(index, name) {
|
|
309
|
+
if (index < 0 || index >= this.authors.length)
|
|
310
|
+
return this;
|
|
311
|
+
return this.withAuthors([
|
|
312
|
+
...this.authors.slice(0, index),
|
|
313
|
+
name,
|
|
314
|
+
...this.authors.slice(index + 1),
|
|
315
|
+
]);
|
|
316
|
+
}
|
|
317
|
+
withoutAuthor(index) {
|
|
318
|
+
if (index < 0 || index >= this.authors.length)
|
|
319
|
+
return this;
|
|
320
|
+
return this.withAuthors([
|
|
321
|
+
...this.authors.slice(0, index),
|
|
322
|
+
...this.authors.slice(index + 1),
|
|
323
|
+
]);
|
|
324
|
+
}
|
|
325
|
+
hasImage(id) {
|
|
326
|
+
return this.images[id] !== null;
|
|
327
|
+
}
|
|
328
|
+
getImage(id) {
|
|
329
|
+
return this.images[id] ?? null;
|
|
330
|
+
}
|
|
331
|
+
withImage(id, embed) {
|
|
332
|
+
const newImages = Object.assign({}, this.images);
|
|
333
|
+
newImages[id] = embed;
|
|
334
|
+
return new Edition(this.bookRef, this.editionRef, this.uids, this.title, this.authors, newImages, this.description, this.chapters, this.license, this.acknowledgements, this.tags, this.sources, this.references, this.symbols, this.glossary, this.theme);
|
|
298
335
|
}
|
|
299
336
|
getBookReadingTime() {
|
|
300
337
|
return this.chapters
|
|
301
|
-
.map(chapter => chapter.getReadingTime())
|
|
302
|
-
.reduce((total, time) => total === undefined
|
|
303
|
-
|
|
304
|
-
|
|
338
|
+
.map((chapter) => chapter.getReadingTime(this))
|
|
339
|
+
.reduce((total, time) => total === undefined
|
|
340
|
+
? 0
|
|
341
|
+
: time === undefined
|
|
342
|
+
? total
|
|
343
|
+
: total + time, 0);
|
|
305
344
|
}
|
|
306
345
|
getChapterNumber(chapterID) {
|
|
307
346
|
let chapterNumber = 1;
|
|
308
347
|
let match = null;
|
|
309
|
-
this.chapters.forEach(chapter => {
|
|
348
|
+
this.chapters.forEach((chapter) => {
|
|
310
349
|
// If we found a match...
|
|
311
|
-
if (chapter.
|
|
350
|
+
if (chapter.getID() === chapterID) {
|
|
312
351
|
match = chapterNumber;
|
|
313
352
|
// And it's an unnumbered chapter, set to null.
|
|
314
353
|
if (!chapter.isNumbered())
|
|
@@ -325,37 +364,39 @@ export default class Edition {
|
|
|
325
364
|
return undefined;
|
|
326
365
|
}
|
|
327
366
|
getSource(sourceID) {
|
|
328
|
-
return sourceID.charAt(0) ===
|
|
329
|
-
|
|
330
|
-
|
|
367
|
+
return sourceID.charAt(0) === '#' &&
|
|
368
|
+
sourceID.substring(1) in this.sources
|
|
369
|
+
? this.sources[sourceID.substring(1)]
|
|
370
|
+
: null;
|
|
331
371
|
}
|
|
332
372
|
getChapterName(chapterID) {
|
|
333
373
|
const chapter = this.getChapter(chapterID);
|
|
334
374
|
return chapter?.getTitle();
|
|
335
375
|
}
|
|
336
376
|
getChapterSection(chapterID) {
|
|
337
|
-
const chapter = this.
|
|
377
|
+
const chapter = this.getChapter(chapterID);
|
|
338
378
|
return chapter?.getSection();
|
|
339
379
|
}
|
|
340
380
|
getFootnoteSymbol(number) {
|
|
341
|
-
let symbols =
|
|
381
|
+
let symbols = 'abcdefghijklmnopqrstuvwxyz';
|
|
342
382
|
// 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) +
|
|
383
|
+
return number < symbols.length
|
|
384
|
+
? symbols.charAt(number)
|
|
385
|
+
: symbols.charAt(Math.floor(number / symbols.length) - 1) +
|
|
386
|
+
symbols.charAt(number % symbols.length);
|
|
346
387
|
}
|
|
347
388
|
getBookIndex() {
|
|
348
389
|
// A map from word to a map of chapters containing the word
|
|
349
390
|
const bookIndex = {};
|
|
350
391
|
// Construct the index by building a dictionary of chapters in which each word appears.
|
|
351
|
-
this.chapters.forEach(chapter => {
|
|
352
|
-
let index = chapter.getIndex();
|
|
392
|
+
this.chapters.forEach((chapter) => {
|
|
393
|
+
let index = chapter.getIndex(this);
|
|
353
394
|
if (index)
|
|
354
|
-
Object.keys(index).forEach(word => {
|
|
355
|
-
if (word !==
|
|
395
|
+
Object.keys(index).forEach((word) => {
|
|
396
|
+
if (word !== '' && word.length > 2) {
|
|
356
397
|
if (!(word in bookIndex))
|
|
357
398
|
bookIndex[word] = new Set();
|
|
358
|
-
bookIndex[word].add(chapter.
|
|
399
|
+
bookIndex[word].add(chapter.getID());
|
|
359
400
|
}
|
|
360
401
|
});
|
|
361
402
|
});
|
|
@@ -365,25 +406,39 @@ export default class Edition {
|
|
|
365
406
|
getNextChapterID(chapterID) {
|
|
366
407
|
// Handle back matter chapters.
|
|
367
408
|
switch (chapterID) {
|
|
368
|
-
case ChapterIDs.ReferencesID:
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
case ChapterIDs.
|
|
373
|
-
|
|
409
|
+
case ChapterIDs.ReferencesID:
|
|
410
|
+
return this.hasGlossary()
|
|
411
|
+
? ChapterIDs.GlossaryID
|
|
412
|
+
: ChapterIDs.IndexID;
|
|
413
|
+
case ChapterIDs.GlossaryID:
|
|
414
|
+
return ChapterIDs.IndexID;
|
|
415
|
+
case ChapterIDs.IndexID:
|
|
416
|
+
return ChapterIDs.SearchID;
|
|
417
|
+
case ChapterIDs.SearchID:
|
|
418
|
+
return ChapterIDs.MediaID;
|
|
419
|
+
case ChapterIDs.MediaID:
|
|
420
|
+
return ChapterIDs.TableOfContentsID;
|
|
421
|
+
case ChapterIDs.TableOfContentsID:
|
|
422
|
+
return this.chapters.length > 0
|
|
423
|
+
? this.chapters[0].getID()
|
|
424
|
+
: null;
|
|
374
425
|
default:
|
|
375
426
|
let after = false;
|
|
376
427
|
for (let i = 0; i < this.chapters.length; i++) {
|
|
377
428
|
let chapter = this.chapters[i];
|
|
378
|
-
if (chapter.
|
|
429
|
+
if (chapter.getID() === chapterID)
|
|
379
430
|
after = true;
|
|
380
431
|
// If we're after the given chapter and it's not forthcoming.
|
|
381
432
|
else if (after && !chapter.isForthcoming())
|
|
382
|
-
return chapter.
|
|
433
|
+
return chapter.getID();
|
|
383
434
|
}
|
|
384
435
|
// If the given ID was the last chapter, go to the next back matter chapter.
|
|
385
436
|
if (after)
|
|
386
|
-
return this.hasReferences()
|
|
437
|
+
return this.hasReferences()
|
|
438
|
+
? ChapterIDs.ReferencesID
|
|
439
|
+
: this.hasGlossary()
|
|
440
|
+
? ChapterIDs.GlossaryID
|
|
441
|
+
: ChapterIDs.IndexID;
|
|
387
442
|
// Otherwise, it wasn't a valid ID
|
|
388
443
|
else
|
|
389
444
|
return null;
|
|
@@ -393,20 +448,37 @@ export default class Edition {
|
|
|
393
448
|
getPreviousChapterID(chapterID) {
|
|
394
449
|
switch (chapterID) {
|
|
395
450
|
// Handle back matter chapters.
|
|
396
|
-
case ChapterIDs.ReferencesID:
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
case ChapterIDs.
|
|
451
|
+
case ChapterIDs.ReferencesID:
|
|
452
|
+
return this.chapters.length > 0
|
|
453
|
+
? this.chapters[this.chapters.length - 1].getID()
|
|
454
|
+
: null; // Last chapter of the book
|
|
455
|
+
case ChapterIDs.GlossaryID:
|
|
456
|
+
return this.hasReferences()
|
|
457
|
+
? ChapterIDs.ReferencesID
|
|
458
|
+
: this.chapters.length > 0
|
|
459
|
+
? this.chapters[this.chapters.length - 1].getID()
|
|
460
|
+
: ChapterIDs.TableOfContentsID;
|
|
461
|
+
case ChapterIDs.IndexID:
|
|
462
|
+
return this.hasGlossary()
|
|
463
|
+
? ChapterIDs.GlossaryID
|
|
464
|
+
: this.hasReferences()
|
|
465
|
+
? ChapterIDs.ReferencesID
|
|
466
|
+
: this.chapters.length > 0
|
|
467
|
+
? this.chapters[this.chapters.length - 1].getID()
|
|
468
|
+
: ChapterIDs.TableOfContentsID;
|
|
469
|
+
case ChapterIDs.SearchID:
|
|
470
|
+
return ChapterIDs.IndexID;
|
|
471
|
+
case ChapterIDs.MediaID:
|
|
472
|
+
return ChapterIDs.SearchID;
|
|
401
473
|
default:
|
|
402
474
|
let before = false;
|
|
403
475
|
for (let i = this.chapters.length - 1; i >= 0; i--) {
|
|
404
476
|
let chapter = this.chapters[i];
|
|
405
|
-
if (chapter.
|
|
477
|
+
if (chapter.getID() === chapterID)
|
|
406
478
|
before = true;
|
|
407
479
|
// If we're before the given chapter and it's not forthcoming.
|
|
408
480
|
else if (before && !chapter.isForthcoming())
|
|
409
|
-
return chapter.
|
|
481
|
+
return chapter.getID();
|
|
410
482
|
}
|
|
411
483
|
// If the given ID was the last chapter, go to the next back matter chapter.
|
|
412
484
|
if (before)
|
|
@@ -420,26 +492,26 @@ export default class Edition {
|
|
|
420
492
|
getEmbeds() {
|
|
421
493
|
let embeds = [];
|
|
422
494
|
// Add the book cover
|
|
423
|
-
const cover = this.getImage(
|
|
495
|
+
const cover = this.getImage('cover');
|
|
424
496
|
if (cover) {
|
|
425
497
|
let coverNode = Parser.parseEmbed(this, cover);
|
|
426
498
|
if (coverNode instanceof EmbedNode)
|
|
427
499
|
embeds.push(coverNode);
|
|
428
500
|
}
|
|
429
501
|
// Add the cover and images from each chapter.
|
|
430
|
-
this.getChapters().forEach(c => {
|
|
502
|
+
this.getChapters().forEach((c) => {
|
|
431
503
|
const image = c.getImage();
|
|
432
504
|
let cover = image === null ? undefined : Parser.parseEmbed(this, image);
|
|
433
505
|
if (cover && cover instanceof EmbedNode)
|
|
434
506
|
embeds.push(cover);
|
|
435
507
|
// Get the chapter body's embeds
|
|
436
|
-
let bodyEmbeds = c?.getAST()?.getEmbeds();
|
|
508
|
+
let bodyEmbeds = c?.getAST(this)?.getEmbeds();
|
|
437
509
|
if (bodyEmbeds)
|
|
438
510
|
bodyEmbeds.forEach((embed) => embeds.push(embed));
|
|
439
511
|
});
|
|
440
512
|
// Add the back matter covers
|
|
441
|
-
let backmatter = [
|
|
442
|
-
backmatter.forEach(id => {
|
|
513
|
+
let backmatter = ['references', 'glossary', 'index', 'search', 'media'];
|
|
514
|
+
backmatter.forEach((id) => {
|
|
443
515
|
const img = this.getImage(id);
|
|
444
516
|
if (img) {
|
|
445
517
|
let image = Parser.parseEmbed(this, img);
|
|
@@ -449,13 +521,19 @@ export default class Edition {
|
|
|
449
521
|
});
|
|
450
522
|
return embeds;
|
|
451
523
|
}
|
|
452
|
-
|
|
453
|
-
const latestEditionID =
|
|
454
|
-
return latestEditionID !== undefined &&
|
|
524
|
+
isLatestEdition(book) {
|
|
525
|
+
const latestEditionID = book.getLatestEditionID();
|
|
526
|
+
return (latestEditionID !== undefined &&
|
|
527
|
+
latestEditionID === this.editionRef?.id);
|
|
528
|
+
}
|
|
529
|
+
isLatestPublishedEdition(book) {
|
|
530
|
+
const latestEditionID = book.getLatestPublishedEditionID();
|
|
531
|
+
return (latestEditionID !== undefined &&
|
|
532
|
+
latestEditionID === this.editionRef?.id);
|
|
455
533
|
}
|
|
456
534
|
/* Edition numbers are 1 to N */
|
|
457
|
-
getEditionNumber() {
|
|
458
|
-
const revisions =
|
|
535
|
+
getEditionNumber(book) {
|
|
536
|
+
const revisions = book.getRevisions();
|
|
459
537
|
if (revisions === undefined)
|
|
460
538
|
return undefined;
|
|
461
539
|
for (let i = 0; i < revisions.length; i++)
|
|
@@ -463,4 +541,8 @@ export default class Edition {
|
|
|
463
541
|
return revisions.length - i;
|
|
464
542
|
return undefined;
|
|
465
543
|
}
|
|
544
|
+
getEditionLabel(book) {
|
|
545
|
+
const num = this.getEditionNumber(book);
|
|
546
|
+
return `${num}${num === 1 ? 'st' : num === 2 ? 'nd' : num === 3 ? 'rd' : 'th'}`;
|
|
547
|
+
}
|
|
466
548
|
}
|