bookish-press 0.4.0 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (403) hide show
  1. package/README.md +3 -1
  2. package/components/Auth.svelte +27 -24
  3. package/components/Auth.svelte.d.ts +4 -4
  4. package/components/Authentication.d.ts +2 -2
  5. package/components/BookPreview.svelte +75 -59
  6. package/components/BookPreview.svelte.d.ts +5 -5
  7. package/components/External.svelte +1 -1
  8. package/components/External.svelte.d.ts +3 -3
  9. package/components/Link.svelte +49 -3
  10. package/components/Link.svelte.d.ts +3 -4
  11. package/components/app/BookList.svelte +19 -0
  12. package/components/app/BookList.svelte.d.ts +18 -0
  13. package/components/app/Button.svelte +49 -0
  14. package/components/app/Button.svelte.d.ts +22 -0
  15. package/components/app/Feedback.svelte +47 -0
  16. package/components/app/Feedback.svelte.d.ts +18 -0
  17. package/components/app/Head.svelte +15 -0
  18. package/components/app/Head.svelte.d.ts +18 -0
  19. package/components/app/Large.svelte +8 -0
  20. package/components/app/Large.svelte.d.ts +27 -0
  21. package/components/app/Lead.svelte +12 -0
  22. package/components/app/Lead.svelte.d.ts +27 -0
  23. package/components/app/Link.svelte +24 -0
  24. package/components/app/Link.svelte.d.ts +20 -0
  25. package/components/app/Options.svelte +24 -0
  26. package/components/app/Options.svelte.d.ts +19 -0
  27. package/components/app/Paragraph.svelte +20 -0
  28. package/components/app/Paragraph.svelte.d.ts +18 -0
  29. package/components/app/Section.svelte +12 -0
  30. package/components/app/Section.svelte.d.ts +27 -0
  31. package/components/app/Table.svelte +32 -0
  32. package/components/app/Table.svelte.d.ts +27 -0
  33. package/components/app/TextInput.svelte +38 -0
  34. package/components/app/TextInput.svelte.d.ts +22 -0
  35. package/components/chapter/Atom.svelte +20 -6
  36. package/components/chapter/Atom.svelte.d.ts +3 -3
  37. package/components/chapter/Block.svelte +26 -21
  38. package/components/chapter/Block.svelte.d.ts +4 -4
  39. package/components/chapter/Callout.svelte +38 -7
  40. package/components/chapter/Callout.svelte.d.ts +4 -4
  41. package/components/chapter/CaptionedCode.svelte +67 -24
  42. package/components/chapter/CaptionedCode.svelte.d.ts +4 -4
  43. package/components/chapter/ChapterBody.svelte +62 -9
  44. package/components/chapter/ChapterBody.svelte.d.ts +5 -4
  45. package/components/chapter/Citations.svelte +86 -20
  46. package/components/chapter/Citations.svelte.d.ts +4 -4
  47. package/components/chapter/Code.svelte +152 -21
  48. package/components/chapter/Code.svelte.d.ts +3 -3
  49. package/components/chapter/Comment.svelte +39 -17
  50. package/components/chapter/Comment.svelte.d.ts +3 -3
  51. package/components/chapter/Definition.svelte +52 -18
  52. package/components/chapter/Definition.svelte.d.ts +5 -8
  53. package/components/chapter/Embed.svelte +155 -67
  54. package/components/chapter/Embed.svelte.d.ts +6 -4
  55. package/components/chapter/ErrorMessage.svelte +7 -2
  56. package/components/chapter/ErrorMessage.svelte.d.ts +4 -4
  57. package/components/chapter/ExtendedPrism.d.ts +2 -0
  58. package/components/chapter/ExtendedPrism.js +69 -0
  59. package/components/chapter/Figure.svelte +90 -0
  60. package/components/chapter/Figure.svelte.d.ts +24 -0
  61. package/components/chapter/Footnote.svelte +75 -12
  62. package/components/chapter/Footnote.svelte.d.ts +4 -4
  63. package/components/chapter/Format.svelte +63 -38
  64. package/components/chapter/Format.svelte.d.ts +5 -4
  65. package/components/chapter/InlineCode.svelte +16 -6
  66. package/components/chapter/InlineCode.svelte.d.ts +4 -4
  67. package/components/chapter/Label.svelte +38 -9
  68. package/components/chapter/Label.svelte.d.ts +4 -4
  69. package/components/chapter/Link.svelte +24 -19
  70. package/components/chapter/Link.svelte.d.ts +4 -4
  71. package/components/chapter/List.svelte +75 -8
  72. package/components/chapter/List.svelte.d.ts +4 -4
  73. package/components/chapter/Marginal.svelte +169 -27
  74. package/components/chapter/Marginal.svelte.d.ts +6 -3
  75. package/components/chapter/Paragraph.svelte +79 -6
  76. package/components/chapter/Paragraph.svelte.d.ts +4 -4
  77. package/components/chapter/Positioned.svelte +33 -0
  78. package/components/chapter/Positioned.svelte.d.ts +19 -0
  79. package/components/chapter/Problem.svelte +15 -0
  80. package/components/chapter/Problem.svelte.d.ts +27 -0
  81. package/components/chapter/Python.svelte +68 -21
  82. package/components/chapter/Python.svelte.d.ts +4 -4
  83. package/components/chapter/Quote.svelte +64 -11
  84. package/components/chapter/Quote.svelte.d.ts +4 -4
  85. package/components/chapter/Rule.svelte +12 -1
  86. package/components/chapter/Rule.svelte.d.ts +4 -4
  87. package/components/chapter/Table.svelte +36 -25
  88. package/components/chapter/Table.svelte.d.ts +4 -4
  89. package/components/chapter/Text.svelte +61 -36
  90. package/components/chapter/Text.svelte.d.ts +5 -4
  91. package/components/editor/BookishEditor.svelte +373 -244
  92. package/components/editor/BookishEditor.svelte.d.ts +9 -6
  93. package/components/editor/CalloutEditor.svelte +5 -5
  94. package/components/editor/CalloutEditor.svelte.d.ts +4 -4
  95. package/components/editor/CaptionedCodeEditor.svelte +16 -12
  96. package/components/editor/CaptionedCodeEditor.svelte.d.ts +4 -4
  97. package/components/editor/CaretContext.d.ts +48 -16
  98. package/components/editor/CaretState.d.ts +16 -44
  99. package/components/editor/CaretUtilities.d.ts +2 -2
  100. package/components/editor/CaretView.svelte +82 -0
  101. package/components/editor/CaretView.svelte.d.ts +25 -0
  102. package/components/editor/CitationsEditor.svelte +36 -25
  103. package/components/editor/CitationsEditor.svelte.d.ts +4 -4
  104. package/components/editor/Clipboard.d.ts +2 -2
  105. package/components/editor/Command.d.ts +13 -12
  106. package/components/editor/Commands.d.ts +1 -1
  107. package/components/editor/Commands.js +1114 -571
  108. package/components/editor/ConfirmButton.svelte +18 -12
  109. package/components/editor/ConfirmButton.svelte.d.ts +5 -4
  110. package/components/editor/DefinitionEditor.svelte +29 -21
  111. package/components/editor/DefinitionEditor.svelte.d.ts +4 -4
  112. package/components/editor/EmbedEditor.svelte +93 -43
  113. package/components/editor/EmbedEditor.svelte.d.ts +3 -3
  114. package/components/editor/Icon.svelte +17 -0
  115. package/components/editor/Icon.svelte.d.ts +16 -0
  116. package/components/editor/ImageChooser.svelte +53 -34
  117. package/components/editor/ImageChooser.svelte.d.ts +3 -3
  118. package/components/editor/InlineCodeEditor.svelte +7 -4
  119. package/components/editor/InlineCodeEditor.svelte.d.ts +4 -4
  120. package/components/editor/LabelEditor.svelte +20 -11
  121. package/components/editor/LabelEditor.svelte.d.ts +4 -4
  122. package/components/editor/LanguageEditor.svelte +10 -7
  123. package/components/editor/LanguageEditor.svelte.d.ts +3 -3
  124. package/components/editor/LinkEditor.svelte +64 -39
  125. package/components/editor/LinkEditor.svelte.d.ts +4 -4
  126. package/components/editor/Note.svelte +4 -3
  127. package/components/editor/Note.svelte.d.ts +6 -2
  128. package/components/editor/Permissions.svelte +95 -0
  129. package/components/editor/Permissions.svelte.d.ts +20 -0
  130. package/components/editor/PositionEditor.svelte +9 -6
  131. package/components/editor/PositionEditor.svelte.d.ts +4 -4
  132. package/components/editor/QuoteEditor.svelte +7 -2
  133. package/components/editor/QuoteEditor.svelte.d.ts +4 -4
  134. package/components/editor/Switch.svelte +55 -28
  135. package/components/editor/Switch.svelte.d.ts +4 -4
  136. package/components/editor/TableEditor.svelte +10 -0
  137. package/components/editor/TableEditor.svelte.d.ts +17 -0
  138. package/components/editor/TextEditor.svelte +83 -45
  139. package/components/editor/TextEditor.svelte.d.ts +5 -4
  140. package/components/editor/Toggle.svelte +11 -8
  141. package/components/editor/Toggle.svelte.d.ts +4 -4
  142. package/components/editor/Toolbar.svelte +191 -144
  143. package/components/editor/Toolbar.svelte.d.ts +5 -8
  144. package/components/editor/ToolbarGroup.svelte +17 -23
  145. package/components/editor/ToolbarGroup.svelte.d.ts +3 -4
  146. package/components/editor/ToolbarSpacer.svelte +8 -1
  147. package/components/editor/ToolbarSpacer.svelte.d.ts +6 -2
  148. package/components/editor/URLEditor.svelte +6 -8
  149. package/components/editor/URLEditor.svelte.d.ts +3 -3
  150. package/components/editor/UndoState.d.ts +3 -3
  151. package/components/editor/icons/annotate.svg +1 -0
  152. package/components/editor/icons/block.svg +1 -0
  153. package/components/editor/icons/bold.svg +1 -0
  154. package/components/editor/icons/bullets.svg +1 -0
  155. package/components/editor/icons/callout.svg +1 -0
  156. package/components/editor/icons/citation.svg +8 -0
  157. package/components/editor/icons/clear.svg +1 -0
  158. package/components/editor/icons/clipboard.svg +1 -0
  159. package/components/editor/icons/code.svg +1 -0
  160. package/components/editor/icons/columnafter.svg +1 -0
  161. package/components/editor/icons/columnbefore.svg +1 -0
  162. package/components/editor/icons/comment.svg +1 -0
  163. package/components/editor/icons/copy.svg +1 -0
  164. package/components/editor/icons/cut.svg +1 -0
  165. package/components/editor/icons/define.svg +7 -0
  166. package/components/editor/icons/deletecolumn.svg +1 -0
  167. package/components/editor/icons/deleterow.svg +1 -0
  168. package/components/editor/icons/footnote.svg +8 -0
  169. package/components/editor/icons/header1.svg +7 -0
  170. package/components/editor/icons/header2.svg +7 -0
  171. package/components/editor/icons/header3.svg +7 -0
  172. package/components/editor/icons/home.svg +1 -0
  173. package/components/editor/icons/indent.svg +1 -0
  174. package/components/editor/icons/italic.svg +1 -0
  175. package/components/editor/icons/label.svg +1 -0
  176. package/components/editor/icons/left.svg +1 -0
  177. package/components/editor/icons/level.svg +1 -0
  178. package/components/editor/icons/link.svg +1 -0
  179. package/components/editor/icons/list.svg +1 -0
  180. package/components/editor/icons/media.svg +1 -0
  181. package/components/editor/icons/middle.svg +1 -0
  182. package/components/editor/icons/numbers.svg +10 -0
  183. package/components/editor/icons/paragraph.svg +1 -0
  184. package/components/editor/icons/paste.svg +10 -0
  185. package/components/editor/icons/quote.svg +1 -0
  186. package/components/editor/icons/redo.svg +1 -0
  187. package/components/editor/icons/right.svg +1 -0
  188. package/components/editor/icons/rowabove.svg +1 -0
  189. package/components/editor/icons/rowbelow.svg +1 -0
  190. package/components/editor/icons/rule.svg +1 -0
  191. package/components/editor/icons/sub.svg +1 -0
  192. package/components/editor/icons/super.svg +1 -0
  193. package/components/editor/icons/table.svg +1 -0
  194. package/components/editor/icons/text.svg +1 -0
  195. package/components/editor/icons/time.svg +1 -0
  196. package/components/editor/icons/undo.svg +1 -0
  197. package/components/editor/icons/unindent.svg +1 -0
  198. package/components/editor/icons/unlink.svg +1 -0
  199. package/components/page/Acknowledgements.svelte +35 -24
  200. package/components/page/Acknowledgements.svelte.d.ts +4 -4
  201. package/components/page/Authors.svelte +34 -17
  202. package/components/page/Authors.svelte.d.ts +7 -6
  203. package/components/page/BookLoader.svelte +59 -0
  204. package/components/page/BookLoader.svelte.d.ts +16 -0
  205. package/components/page/BulkReferenceEditor.svelte +54 -23
  206. package/components/page/BulkReferenceEditor.svelte.d.ts +4 -4
  207. package/components/page/Chapter.svelte +234 -143
  208. package/components/page/Chapter.svelte.d.ts +3 -3
  209. package/components/page/ChapterContext.d.ts +4 -4
  210. package/components/page/ChapterNumber.svelte +9 -0
  211. package/components/page/ChapterNumber.svelte.d.ts +27 -0
  212. package/components/page/ChapterTitle.svelte +16 -0
  213. package/components/page/ChapterTitle.svelte.d.ts +18 -0
  214. package/components/page/Contexts.d.ts +42 -22
  215. package/components/page/Contexts.js +129 -17
  216. package/components/page/DefinitionView.svelte +129 -90
  217. package/components/page/DefinitionView.svelte.d.ts +3 -3
  218. package/components/page/Description.svelte +31 -19
  219. package/components/page/Description.svelte.d.ts +4 -4
  220. package/components/page/Edition.svelte +135 -80
  221. package/components/page/Edition.svelte.d.ts +5 -6
  222. package/components/page/EditionLoader.svelte +99 -0
  223. package/components/page/EditionLoader.svelte.d.ts +18 -0
  224. package/components/page/Editions.svelte +106 -0
  225. package/components/page/Editions.svelte.d.ts +14 -0
  226. package/components/page/Glossary.svelte +65 -49
  227. package/components/page/Glossary.svelte.d.ts +4 -4
  228. package/components/page/Header.svelte +143 -56
  229. package/components/page/Header.svelte.d.ts +8 -6
  230. package/components/page/Index.svelte +116 -80
  231. package/components/page/Index.svelte.d.ts +4 -4
  232. package/components/page/Instructions.svelte +18 -17
  233. package/components/page/Instructions.svelte.d.ts +6 -4
  234. package/components/page/License.svelte +39 -23
  235. package/components/page/License.svelte.d.ts +4 -4
  236. package/components/page/Loading.svelte +102 -12
  237. package/components/page/Loading.svelte.d.ts +6 -2
  238. package/components/page/Media.svelte +81 -53
  239. package/components/page/Media.svelte.d.ts +4 -4
  240. package/components/page/MediaPreview.svelte +26 -8
  241. package/components/page/MediaPreview.svelte.d.ts +3 -3
  242. package/components/page/Muted.svelte +10 -0
  243. package/components/page/Muted.svelte.d.ts +27 -0
  244. package/components/page/Outline.svelte +279 -59
  245. package/components/page/Outline.svelte.d.ts +3 -3
  246. package/components/page/Page.svelte +40 -9
  247. package/components/page/Page.svelte.d.ts +3 -3
  248. package/components/page/PageHeader.svelte +14 -0
  249. package/components/page/PageHeader.svelte.d.ts +18 -0
  250. package/components/page/PageParagraph.svelte +18 -0
  251. package/components/page/PageParagraph.svelte.d.ts +27 -0
  252. package/components/page/PossibleChapter.svelte +7 -7
  253. package/components/page/PossibleChapter.svelte.d.ts +4 -4
  254. package/components/page/PossibleReference.svelte +6 -11
  255. package/components/page/PossibleReference.svelte.d.ts +6 -7
  256. package/components/page/Print.svelte +27 -3
  257. package/components/page/Print.svelte.d.ts +4 -4
  258. package/components/page/Publish.svelte +134 -0
  259. package/components/page/Publish.svelte.d.ts +14 -0
  260. package/components/page/Reference.svelte +259 -117
  261. package/components/page/Reference.svelte.d.ts +5 -5
  262. package/components/page/References.svelte +45 -48
  263. package/components/page/References.svelte.d.ts +4 -4
  264. package/components/page/Rows.svelte +54 -0
  265. package/components/page/Rows.svelte.d.ts +27 -0
  266. package/components/page/Search.svelte +88 -63
  267. package/components/page/Search.svelte.d.ts +4 -4
  268. package/components/page/Status.svelte +46 -39
  269. package/components/page/Status.svelte.d.ts +4 -9
  270. package/components/page/SubdomainEditor.svelte +41 -27
  271. package/components/page/SubdomainEditor.svelte.d.ts +4 -4
  272. package/components/page/TableOfContents.svelte +264 -191
  273. package/components/page/TableOfContents.svelte.d.ts +4 -4
  274. package/components/page/TableOfContentsImage.svelte +8 -8
  275. package/components/page/TableOfContentsImage.svelte.d.ts +3 -3
  276. package/components/page/TableOfContentsRow.svelte +97 -34
  277. package/components/page/TableOfContentsRow.svelte.d.ts +4 -4
  278. package/components/page/ThemeEditor.svelte +177 -39
  279. package/components/page/ThemeEditor.svelte.d.ts +4 -4
  280. package/components/page/ThemeEditorPreview.svelte +35 -23
  281. package/components/page/ThemeEditorPreview.svelte.d.ts +5 -5
  282. package/components/page/ThemeSetEditor.svelte +15 -13
  283. package/components/page/ThemeSetEditor.svelte.d.ts +4 -4
  284. package/components/page/ThemeVariableEditor.svelte +24 -15
  285. package/components/page/ThemeVariableEditor.svelte.d.ts +3 -3
  286. package/components/page/Title.svelte +12 -0
  287. package/components/page/Title.svelte.d.ts +27 -0
  288. package/components/page/Unknown.svelte +28 -21
  289. package/components/page/Unknown.svelte.d.ts +4 -4
  290. package/components/page/margins.js +50 -33
  291. package/index.d.ts +13 -0
  292. package/index.js +14 -0
  293. package/models/CRUD.d.ts +27 -0
  294. package/models/CRUD.js +262 -0
  295. package/models/Firebase.d.ts +1 -0
  296. package/models/Firebase.js +26 -16
  297. package/models/book/Book.d.ts +40 -39
  298. package/models/book/Book.js +121 -121
  299. package/models/book/BookMedia.d.ts +3 -3
  300. package/models/book/BookMedia.js +22 -16
  301. package/models/book/BookSaveStatus.d.ts +7 -0
  302. package/models/book/BookSaveStatus.js +8 -0
  303. package/models/book/Chapter.d.ts +50 -39
  304. package/models/book/Chapter.js +189 -198
  305. package/models/book/ChapterID.js +7 -7
  306. package/models/book/Definition.d.ts +1 -1
  307. package/models/book/Edition.d.ts +87 -61
  308. package/models/book/Edition.js +460 -309
  309. package/models/book/Reference.d.ts +24 -0
  310. package/models/book/Reference.js +78 -0
  311. package/models/book/Schema.d.ts +168 -0
  312. package/models/book/Schema.js +115 -0
  313. package/models/book/Theme.d.ts +44 -37
  314. package/models/book/Theme.js +452 -52
  315. package/models/book/ThemeColors.d.ts +1 -1
  316. package/models/book/Words.d.ts +2 -0
  317. package/models/book/Words.js +110 -0
  318. package/models/chapter/AtomNode.d.ts +4 -4
  319. package/models/chapter/AtomNode.js +20 -13
  320. package/models/chapter/BlockNode.d.ts +9 -10
  321. package/models/chapter/BlockNode.js +32 -13
  322. package/models/chapter/BlocksNode.d.ts +10 -10
  323. package/models/chapter/BlocksNode.js +315 -120
  324. package/models/chapter/BlocksNode.test.js +494 -228
  325. package/models/chapter/Bookkeeping.d.ts +1 -1
  326. package/models/chapter/CalloutNode.d.ts +3 -3
  327. package/models/chapter/CalloutNode.js +34 -12
  328. package/models/chapter/Caret.d.ts +9 -7
  329. package/models/chapter/Caret.js +11 -6
  330. package/models/chapter/ChapterNode.d.ts +11 -11
  331. package/models/chapter/ChapterNode.js +70 -33
  332. package/models/chapter/CitationsNode.d.ts +3 -3
  333. package/models/chapter/CitationsNode.js +31 -12
  334. package/models/chapter/CodeNode.d.ts +11 -6
  335. package/models/chapter/CodeNode.js +143 -34
  336. package/models/chapter/CommentNode.d.ts +5 -5
  337. package/models/chapter/CommentNode.js +29 -13
  338. package/models/chapter/DefinitionNode.d.ts +2 -2
  339. package/models/chapter/DefinitionNode.js +15 -7
  340. package/models/chapter/Edit.d.ts +3 -3
  341. package/models/chapter/EmbedNode.d.ts +9 -5
  342. package/models/chapter/EmbedNode.js +108 -35
  343. package/models/chapter/ErrorNode.d.ts +2 -2
  344. package/models/chapter/ErrorNode.js +34 -12
  345. package/models/chapter/FootnoteNode.d.ts +5 -5
  346. package/models/chapter/FootnoteNode.js +34 -16
  347. package/models/chapter/FormatNode.d.ts +10 -10
  348. package/models/chapter/FormatNode.js +237 -106
  349. package/models/chapter/FormatNode.test.js +87 -45
  350. package/models/chapter/InlineCodeNode.d.ts +2 -2
  351. package/models/chapter/InlineCodeNode.js +22 -9
  352. package/models/chapter/LabelNode.d.ts +4 -4
  353. package/models/chapter/LabelNode.js +31 -13
  354. package/models/chapter/LinkNode.d.ts +2 -2
  355. package/models/chapter/LinkNode.js +21 -9
  356. package/models/chapter/ListNode.d.ts +8 -8
  357. package/models/chapter/ListNode.js +99 -38
  358. package/models/chapter/ListNode.test.js +29 -24
  359. package/models/chapter/MetadataNode.d.ts +3 -3
  360. package/models/chapter/MetadataNode.js +13 -5
  361. package/models/chapter/Node.d.ts +5 -3
  362. package/models/chapter/Node.js +76 -29
  363. package/models/chapter/Node.test.js +20 -18
  364. package/models/chapter/ParagraphNode.d.ts +6 -6
  365. package/models/chapter/ParagraphNode.js +84 -29
  366. package/models/chapter/ParagraphNode.test.js +22 -13
  367. package/models/chapter/Parser.d.ts +27 -27
  368. package/models/chapter/Parser.js +220 -206
  369. package/models/chapter/Parser.test.js +16 -16
  370. package/models/chapter/Position.d.ts +1 -1
  371. package/models/chapter/QuoteNode.d.ts +6 -6
  372. package/models/chapter/QuoteNode.js +61 -23
  373. package/models/chapter/RootNode.d.ts +4 -4
  374. package/models/chapter/RuleNode.d.ts +2 -2
  375. package/models/chapter/RuleNode.js +31 -11
  376. package/models/chapter/TableNode.d.ts +8 -6
  377. package/models/chapter/TableNode.js +89 -34
  378. package/models/chapter/TableNode.test.js +22 -24
  379. package/models/chapter/TextNode.d.ts +6 -6
  380. package/models/chapter/TextNode.js +72 -32
  381. package/models/chapter/TextNode.test.js +4 -4
  382. package/package.json +108 -26
  383. package/util/getSubdomain.js +8 -6
  384. package/util/isMobile.js +1 -1
  385. package/util/mineReference.d.ts +3 -2
  386. package/util/mineReference.js +67 -29
  387. package/util/scrollToEyeLevel.js +6 -1
  388. package/components/chapter/renderPosition.d.ts +0 -3
  389. package/components/chapter/renderPosition.js +0 -4
  390. package/components/editor/ToolbarIcon.svelte +0 -22
  391. package/components/editor/ToolbarIcon.svelte.d.ts +0 -16
  392. package/components/page/Alert.svelte +0 -11
  393. package/components/page/Alert.svelte.d.ts +0 -23
  394. package/components/page/Revisions.svelte +0 -124
  395. package/components/page/Revisions.svelte.d.ts +0 -14
  396. package/models/BookLoader.d.ts +0 -2
  397. package/models/BookLoader.js +0 -67
  398. package/models/Firestore.d.ts +0 -22
  399. package/models/Firestore.js +0 -194
  400. package/models/chapter/ReferenceNode.d.ts +0 -29
  401. package/models/chapter/ReferenceNode.js +0 -48
  402. package/models/loadEdition.d.ts +0 -5
  403. package/models/loadEdition.js +0 -16
@@ -1,314 +1,417 @@
1
1
  import Chapter from './Chapter';
2
- import Parser from "../chapter/Parser";
3
- import EmbedNode from "../chapter/EmbedNode";
4
- import { addChapterInFirestore, removeChapterFromEditionInFirestore, updateEditionInFirestore } from "../Firestore";
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
- specification;
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
- chaptersByID;
19
- listeners;
20
- // A list of requested edits, stored as promises, resolved
21
- // when the book is ready to save.
22
- edits = [];
23
- lastEdit = 0;
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(book, editionRef, specification) {
27
- if (typeof specification !== "object" && specification !== undefined)
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
- // Copy all of the specification metadata to fields.
32
- // Choose suitable defaults if the spec is lacking a field.
33
- this.specification = {
34
- title: specification ? specification.title : "Untitled",
35
- symbols: specification && specification.symbols ? specification.symbols : {},
36
- tags: specification && specification.tags ? specification.tags : [],
37
- license: specification ? specification.license : "All rights reserved.",
38
- references: specification && specification.references ? specification.references : {},
39
- glossary: specification && specification.glossary ? specification.glossary : {},
40
- authors: specification && specification.authors ? specification.authors : [],
41
- description: specification ? specification.description : "",
42
- acknowledgements: specification && specification.acknowledgements ? specification.acknowledgements : "",
43
- revisions: specification && specification.revisions ? specification.revisions : [],
44
- images: specification && specification.revisions ? specification.images : {},
45
- sources: specification && specification.revisions ? specification.sources : {},
46
- theme: specification && specification.theme ? specification.theme : null,
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
- });
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
- setRef(ref) {
67
- if (this.editionRef)
68
- throw Error("Can only set a ref of an edition when not yet set.");
69
- this.editionRef = ref;
70
- }
71
- async saveEdits() {
72
- // If it's been more than a second since our last edit and there
73
- // are edits that haven't been saved, try updating the book,
74
- // and if we succeed, resolve all of the edits, and if we fail,
75
- // then reject them.
76
- if (Date.now() - this.lastEdit > 1000 && this.edits.length > 0) {
77
- // Tell listeners that this book model changed.
78
- this.notifyListeners(BookSaveStatus.Saving);
79
- return updateEditionInFirestore(this)
80
- .then(() => {
81
- // Approve the edits.
82
- this.edits.forEach(edit => edit.resolve());
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
- // Deep copy, then let the chapter models handle the chapters.
115
- const spec = JSON.parse(JSON.stringify(this.specification));
116
- spec.chapters = this.chapters.map(chapter => chapter.toObject());
117
- return spec;
118
- }
119
- getRef() { return this.editionRef; }
120
- addUserID(uid) {
121
- this.specification.uids.push(uid);
122
- }
123
- getTitle() { return this.specification.title; }
124
- setTitle(title) {
125
- // Update locally, then update on the server.
126
- this.specification.title = title;
127
- return this.requestSave();
128
- }
129
- getDescription() { return this.specification.description; }
130
- setDescription(text) {
131
- // Update locally, then update on the server.
132
- this.specification.description = text;
133
- return this.requestSave();
134
- }
135
- getAcknowledgements() { return this.specification.acknowledgements; }
136
- setAcknowledgements(text) {
137
- // Update locally, then update on the server.
138
- this.specification.acknowledgements = text;
139
- return this.requestSave();
140
- }
141
- getLicense() { return this.specification.license; }
142
- setLicense(text) {
143
- // Update locally, then update on the server.
144
- this.specification.license = text;
145
- return this.requestSave();
146
- }
147
- getChapters() { return this.chapters; }
148
- hasChapter(chapterID) { return chapterID in this.chaptersByID || ["references", "glossary", "index", "search", "media"].includes(chapterID); }
149
- getChapter(chapterID) { return this.hasChapter(chapterID) ? this.chaptersByID[chapterID] : undefined; }
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].getChapterID() === chapterID)
164
+ if (this.chapters[position].getID() === chapterID)
154
165
  return position;
155
166
  return undefined;
156
167
  }
157
- getChapterCount() { return this.chapters.length; }
158
- async addChapter() {
159
- if (!this.editionRef)
160
- throw Error("No edition ID, can't add chapter");
161
- const editionID = this.editionRef;
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("chapter" + number))
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 emptyChapter = {
169
- ref: chapterRef,
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
- moveChapter(chapterID, increment) {
184
- // Get the index of the chapter.
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
- throw Error(`Chapter with ID ${chapterID} doesn't exist, can't delete it.`);
202
- const chapter = this.chapters[index];
203
- this.chapters.splice(index, 1);
204
- // Ask the database to update the new book metadata then delete the chapter.
205
- return this.requestSave().then(() => removeChapterFromEditionInFirestore(chapter));
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
- editReference(ref) {
217
- if (!(ref.citationID in this.specification.references))
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
- this.specification.references[ref.citationID] = ref.toList();
220
- return this.requestSave();
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
- editReferenceID(newCitationID, ref) {
223
- if (!(ref.citationID in this.specification.references))
224
- return;
225
- delete this.specification.references[ref.citationID];
226
- this.specification.references[newCitationID] = ref.withCitationID(newCitationID).toList();
227
- return this.requestSave();
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
- removeReference(citationID) {
230
- if (!(citationID in this.specification.references))
231
- return;
232
- delete this.specification.references[citationID];
233
- return this.requestSave();
234
- }
235
- hasGlossary() { return this.specification.glossary && Object.keys(this.specification.glossary).length > 0; }
236
- getGlossary() { return this.specification.glossary; }
237
- hasDefinition(id) { return id in this.specification.glossary; }
238
- addDefinition(id, phrase, definition, synonyms) {
239
- this.specification.glossary[id] = {
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.requestSave();
295
+ return this.withGlossary(newGlossary);
245
296
  }
246
- removeDefinition(id) {
247
- delete this.specification.glossary[id];
248
- return this.requestSave();
297
+ withoutDefinition(id) {
298
+ const newGlossary = Object.assign({}, this.glossary);
299
+ delete newGlossary[id];
300
+ return this.withGlossary(newGlossary);
249
301
  }
250
- editDefinition(id, definition) {
251
- this.specification.glossary[id] = definition;
252
- return this.requestSave();
302
+ withEditedDefinition(id, definition) {
303
+ const newGlossary = Object.assign({}, this.glossary);
304
+ newGlossary[id] = definition;
305
+ return this.withGlossary(newGlossary);
253
306
  }
254
- editDefinitionID(id, newID) {
255
- if (!(id in this.specification.glossary))
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
- this.specification.theme[group][name] = value;
272
- return this.requestSave();
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() { return [...this.specification.authors]; }
276
- addAuthor(name) {
277
- this.specification.authors.push(name);
278
- return this.requestSave();
279
- }
280
- setAuthor(index, name) {
281
- if (index >= 0 && index < this.specification.authors.length)
282
- this.specification.authors[index] = name;
283
- return this.requestSave();
284
- }
285
- removeAuthor(index) {
286
- if (index >= 0 && index < this.specification.authors.length)
287
- this.specification.authors.splice(index, 1);
288
- return this.requestSave();
289
- }
290
- getRevisions() { return [...this.specification.revisions]; }
291
- hasImage(id) { return id in this.specification.images && this.specification.images[id] !== null; }
292
- getImage(id) { return this.specification.images[id] ?? null; }
293
- setImage(id, embed) {
294
- if (this.specification.images[id] === embed)
295
- return;
296
- this.specification.images[id] = embed ?? null;
297
- return this.requestSave();
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 ? 0 :
303
- time === undefined ?
304
- total : total + time, 0);
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.getChapterID() === chapterID) {
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) === "#" && sourceID.substring(1) in this.specification.sources ?
329
- this.specification.sources[sourceID.substring(1)] :
330
- null;
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.chaptersByID[chapterID];
441
+ const chapter = this.getChapter(chapterID);
338
442
  return chapter?.getSection();
339
443
  }
340
444
  getFootnoteSymbol(number) {
341
- let symbols = "abcdefghijklmnopqrstuvwxyz";
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) + symbols.charAt(number % symbols.length);
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 !== "" && word.length > 2) {
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.getChapterID());
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: return this.hasGlossary() ? ChapterIDs.GlossaryID : ChapterIDs.IndexID;
369
- case ChapterIDs.GlossaryID: return ChapterIDs.IndexID;
370
- case ChapterIDs.IndexID: return ChapterIDs.SearchID;
371
- case ChapterIDs.SearchID: return ChapterIDs.MediaID;
372
- case ChapterIDs.MediaID: return ChapterIDs.TableOfContentsID;
373
- case ChapterIDs.TableOfContentsID: return this.chapters.length > 0 ? this.chapters[0].getChapterID() : null;
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.getChapterID() === chapterID)
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.getChapterID();
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() ? ChapterIDs.ReferencesID : this.hasGlossary() ? ChapterIDs.GlossaryID : ChapterIDs.IndexID;
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: return this.chapters.length > 0 ? this.chapters[this.chapters.length - 1].getChapterID() : null; // Last chapter of the book
397
- case ChapterIDs.GlossaryID: return this.hasReferences() ? ChapterIDs.ReferencesID : this.chapters.length > 0 ? this.chapters[this.chapters.length - 1].getChapterID() : ChapterIDs.TableOfContentsID;
398
- case ChapterIDs.IndexID: return this.hasGlossary() ? ChapterIDs.GlossaryID : this.hasReferences() ? ChapterIDs.ReferencesID : this.chapters.length > 0 ? this.chapters[this.chapters.length - 1].getChapterID() : ChapterIDs.TableOfContentsID;
399
- case ChapterIDs.SearchID: return ChapterIDs.IndexID;
400
- case ChapterIDs.MediaID: return ChapterIDs.SearchID;
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.getChapterID() === chapterID)
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.getChapterID();
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("cover");
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 = ["references", "glossary", "index", "search", "media"];
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
- isLatestPublishedEdition() {
453
- const latestEditionID = this.book?.getLatestPublishedEditionID();
454
- return latestEditionID !== undefined && latestEditionID === this.editionRef?.id;
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
- const revisions = this.book?.getRevisions();
459
- if (revisions === undefined)
460
- return undefined;
461
- for (let i = 0; i < revisions.length; i++)
462
- if (revisions[i].ref.id === this.editionRef?.id)
463
- return revisions.length - i;
464
- return undefined;
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
  }