bookish-press 0.5.32 → 0.5.71

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 (168) hide show
  1. package/README.md +30 -1
  2. package/dist/components/Auth.svelte.d.ts +2 -2
  3. package/dist/components/BookPreview.svelte.d.ts +2 -2
  4. package/dist/components/Link.svelte.d.ts +2 -2
  5. package/dist/components/app/BookList.svelte.d.ts +2 -2
  6. package/dist/components/app/Button.svelte.d.ts +2 -2
  7. package/dist/components/app/Feedback.svelte.d.ts +2 -2
  8. package/dist/components/app/Head.svelte.d.ts +2 -2
  9. package/dist/components/app/Large.svelte.d.ts +2 -2
  10. package/dist/components/app/Lead.svelte.d.ts +2 -2
  11. package/dist/components/app/Link.svelte.d.ts +2 -2
  12. package/dist/components/app/Options.svelte +1 -0
  13. package/dist/components/app/Options.svelte.d.ts +2 -2
  14. package/dist/components/app/Paragraph.svelte.d.ts +2 -2
  15. package/dist/components/app/Section.svelte.d.ts +2 -2
  16. package/dist/components/app/Table.svelte +0 -1
  17. package/dist/components/app/Table.svelte.d.ts +2 -2
  18. package/dist/components/app/TextInput.svelte.d.ts +2 -2
  19. package/dist/components/chapter/Atom.svelte.d.ts +2 -2
  20. package/dist/components/chapter/Block.svelte.d.ts +2 -2
  21. package/dist/components/chapter/Callout.svelte.d.ts +2 -2
  22. package/dist/components/chapter/CaptionedCode.svelte +21 -19
  23. package/dist/components/chapter/CaptionedCode.svelte.d.ts +2 -2
  24. package/dist/components/chapter/ChapterBody.svelte +2 -0
  25. package/dist/components/chapter/ChapterBody.svelte.d.ts +2 -2
  26. package/dist/components/chapter/Citations.svelte.d.ts +2 -2
  27. package/dist/components/chapter/Code.svelte.d.ts +2 -2
  28. package/dist/components/chapter/Comment.svelte.d.ts +2 -2
  29. package/dist/components/chapter/Definition.svelte +6 -7
  30. package/dist/components/chapter/Definition.svelte.d.ts +2 -2
  31. package/dist/components/chapter/Embed.svelte +4 -3
  32. package/dist/components/chapter/Embed.svelte.d.ts +2 -2
  33. package/dist/components/chapter/ErrorMessage.svelte.d.ts +2 -2
  34. package/dist/components/chapter/Figure.svelte +9 -1
  35. package/dist/components/chapter/Figure.svelte.d.ts +3 -2
  36. package/dist/components/chapter/Footnote.svelte.d.ts +2 -2
  37. package/dist/components/chapter/Format.svelte +21 -16
  38. package/dist/components/chapter/Format.svelte.d.ts +2 -2
  39. package/dist/components/chapter/InlineCode.svelte.d.ts +2 -2
  40. package/dist/components/chapter/Label.svelte.d.ts +2 -2
  41. package/dist/components/chapter/LineBreak.svelte +6 -0
  42. package/dist/components/chapter/LineBreak.svelte.d.ts +17 -0
  43. package/dist/components/chapter/Link.svelte.d.ts +2 -2
  44. package/dist/components/chapter/List.svelte.d.ts +2 -2
  45. package/dist/components/chapter/Marginal.svelte +5 -4
  46. package/dist/components/chapter/Marginal.svelte.d.ts +2 -2
  47. package/dist/components/chapter/Paragraph.svelte.d.ts +2 -2
  48. package/dist/components/chapter/Positioned.svelte.d.ts +2 -2
  49. package/dist/components/chapter/Problem.svelte.d.ts +2 -2
  50. package/dist/components/chapter/Python.svelte.d.ts +2 -2
  51. package/dist/components/chapter/Quote.svelte.d.ts +2 -2
  52. package/dist/components/chapter/Rule.svelte +2 -2
  53. package/dist/components/chapter/Rule.svelte.d.ts +2 -2
  54. package/dist/components/chapter/Table.svelte.d.ts +2 -2
  55. package/dist/components/chapter/Text.svelte.d.ts +2 -2
  56. package/dist/components/controls/DarkToggle.svelte.d.ts +2 -2
  57. package/dist/components/editor/BookishEditor.svelte +22 -22
  58. package/dist/components/editor/BookishEditor.svelte.d.ts +2 -2
  59. package/dist/components/editor/CalloutEditor.svelte.d.ts +2 -2
  60. package/dist/components/editor/CaptionedCodeEditor.svelte.d.ts +2 -2
  61. package/dist/components/editor/CaretContext.d.ts +1 -1
  62. package/dist/components/editor/CaretView.svelte +8 -3
  63. package/dist/components/editor/CaretView.svelte.d.ts +2 -2
  64. package/dist/components/editor/CitationsEditor.svelte.d.ts +2 -2
  65. package/dist/components/editor/Commands.js +109 -43
  66. package/dist/components/editor/ConfirmButton.svelte +7 -1
  67. package/dist/components/editor/ConfirmButton.svelte.d.ts +2 -2
  68. package/dist/components/editor/DefinitionEditor.svelte.d.ts +2 -2
  69. package/dist/components/editor/EmbedEditor.svelte.d.ts +2 -2
  70. package/dist/components/editor/Icon.svelte.d.ts +2 -2
  71. package/dist/components/editor/ImageChooser.svelte +2 -1
  72. package/dist/components/editor/ImageChooser.svelte.d.ts +2 -2
  73. package/dist/components/editor/ImageThumbnail.svelte +11 -7
  74. package/dist/components/editor/ImageThumbnail.svelte.d.ts +2 -2
  75. package/dist/components/editor/InlineCodeEditor.svelte.d.ts +2 -2
  76. package/dist/components/editor/LabelEditor.svelte.d.ts +2 -2
  77. package/dist/components/editor/LanguageEditor.svelte.d.ts +2 -2
  78. package/dist/components/editor/LinkEditor.svelte +4 -3
  79. package/dist/components/editor/LinkEditor.svelte.d.ts +2 -2
  80. package/dist/components/editor/Note.svelte.d.ts +2 -2
  81. package/dist/components/editor/Permissions.svelte.d.ts +2 -2
  82. package/dist/components/editor/PositionEditor.svelte.d.ts +2 -2
  83. package/dist/components/editor/QuoteEditor.svelte.d.ts +2 -2
  84. package/dist/components/editor/Switch.svelte.d.ts +2 -2
  85. package/dist/components/editor/TableEditor.svelte.d.ts +2 -2
  86. package/dist/components/editor/TextEditor.svelte.d.ts +2 -2
  87. package/dist/components/editor/Toggle.svelte.d.ts +2 -2
  88. package/dist/components/editor/Toolbar.svelte +2 -1
  89. package/dist/components/editor/Toolbar.svelte.d.ts +2 -2
  90. package/dist/components/editor/ToolbarGroup.svelte.d.ts +2 -2
  91. package/dist/components/editor/ToolbarSpacer.svelte.d.ts +2 -2
  92. package/dist/components/editor/URLEditor.svelte.d.ts +2 -2
  93. package/dist/components/page/Acknowledgements.svelte.d.ts +2 -2
  94. package/dist/components/page/Authors.svelte.d.ts +2 -2
  95. package/dist/components/page/BookLoader.svelte.d.ts +2 -2
  96. package/dist/components/page/BulkReferenceEditor.svelte +1 -1
  97. package/dist/components/page/BulkReferenceEditor.svelte.d.ts +2 -2
  98. package/dist/components/page/Chapter.svelte +4 -5
  99. package/dist/components/page/Chapter.svelte.d.ts +2 -2
  100. package/dist/components/page/ChapterNumber.svelte.d.ts +2 -2
  101. package/dist/components/page/ChapterTitle.svelte.d.ts +2 -2
  102. package/dist/components/page/DefinitionView.svelte.d.ts +2 -2
  103. package/dist/components/page/Description.svelte.d.ts +2 -2
  104. package/dist/components/page/Edition.svelte.d.ts +2 -2
  105. package/dist/components/page/EditionLoader.svelte +9 -18
  106. package/dist/components/page/EditionLoader.svelte.d.ts +2 -2
  107. package/dist/components/page/Editions.svelte +4 -3
  108. package/dist/components/page/Editions.svelte.d.ts +2 -2
  109. package/dist/components/page/Glossary.svelte +8 -2
  110. package/dist/components/page/Glossary.svelte.d.ts +2 -2
  111. package/dist/components/page/Header.svelte.d.ts +2 -2
  112. package/dist/components/page/Index.svelte +5 -2
  113. package/dist/components/page/Index.svelte.d.ts +2 -2
  114. package/dist/components/page/Instructions.svelte.d.ts +2 -2
  115. package/dist/components/page/License.svelte.d.ts +2 -2
  116. package/dist/components/page/Loading.svelte.d.ts +2 -2
  117. package/dist/components/page/Media.svelte +5 -2
  118. package/dist/components/page/Media.svelte.d.ts +2 -2
  119. package/dist/components/page/MediaPreview.svelte.d.ts +2 -2
  120. package/dist/components/page/Muted.svelte.d.ts +2 -2
  121. package/dist/components/page/Outline.svelte.d.ts +2 -2
  122. package/dist/components/page/Page.svelte.d.ts +2 -2
  123. package/dist/components/page/PageHeader.svelte.d.ts +2 -2
  124. package/dist/components/page/PageParagraph.svelte.d.ts +2 -2
  125. package/dist/components/page/PossibleChapter.svelte.d.ts +2 -2
  126. package/dist/components/page/PossibleReference.svelte.d.ts +2 -2
  127. package/dist/components/page/Print.svelte.d.ts +2 -2
  128. package/dist/components/page/Publish.svelte.d.ts +2 -2
  129. package/dist/components/page/Reference.svelte +24 -15
  130. package/dist/components/page/Reference.svelte.d.ts +2 -2
  131. package/dist/components/page/References.svelte +6 -2
  132. package/dist/components/page/References.svelte.d.ts +2 -2
  133. package/dist/components/page/Rows.svelte.d.ts +2 -2
  134. package/dist/components/page/Search.svelte +5 -3
  135. package/dist/components/page/Search.svelte.d.ts +2 -2
  136. package/dist/components/page/Status.svelte.d.ts +2 -2
  137. package/dist/components/page/SubdomainEditor.svelte +4 -3
  138. package/dist/components/page/SubdomainEditor.svelte.d.ts +2 -2
  139. package/dist/components/page/TableOfContents.svelte +9 -3
  140. package/dist/components/page/TableOfContents.svelte.d.ts +2 -2
  141. package/dist/components/page/TableOfContentsImage.svelte.d.ts +2 -2
  142. package/dist/components/page/TableOfContentsRow.svelte +4 -2
  143. package/dist/components/page/TableOfContentsRow.svelte.d.ts +2 -2
  144. package/dist/components/page/ThemeEditor.svelte.d.ts +2 -2
  145. package/dist/components/page/ThemeEditorPreview.svelte.d.ts +2 -2
  146. package/dist/components/page/ThemeSetEditor.svelte.d.ts +2 -2
  147. package/dist/components/page/ThemeVariableEditor.svelte.d.ts +2 -2
  148. package/dist/components/page/Title.svelte.d.ts +2 -2
  149. package/dist/components/page/Unknown.svelte.d.ts +2 -2
  150. package/dist/models/CRUD.d.ts +1 -2
  151. package/dist/models/CRUD.js +3 -5
  152. package/dist/models/book/BookMedia.js +8 -3
  153. package/dist/models/book/Chapter.d.ts +1 -1
  154. package/dist/models/book/Chapter.js +2 -3
  155. package/dist/models/book/Edition.d.ts +7 -5
  156. package/dist/models/book/Edition.js +10 -15
  157. package/dist/models/chapter/Caret.d.ts +2 -1
  158. package/dist/models/chapter/Caret.js +20 -6
  159. package/dist/models/chapter/FormatNode.d.ts +4 -1
  160. package/dist/models/chapter/FormatNode.js +53 -9
  161. package/dist/models/chapter/LineBreakNode.d.ts +15 -0
  162. package/dist/models/chapter/LineBreakNode.js +37 -0
  163. package/dist/models/chapter/Parser.d.ts +2 -0
  164. package/dist/models/chapter/Parser.js +12 -2
  165. package/dist/models/chapter/Symbols.d.ts +1 -0
  166. package/dist/models/chapter/Symbols.js +1 -0
  167. package/dist/util/mineReference.js +8 -6
  168. package/package.json +22 -19
@@ -174,20 +174,15 @@ export default class Edition {
174
174
  withChapters(chapters) {
175
175
  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.base, this.active);
176
176
  }
177
- withChapterText(text) {
178
- // No need to make a new edition if no chapter was changed.
179
- let modified = false;
177
+ withChapterText(textByID) {
180
178
  const newChapters = this.chapters.map((chapter) => {
181
- if (chapter.ref === undefined)
179
+ if (chapter.ref === undefined) {
182
180
  return chapter;
183
- const match = text.find(([ref, text]) => chapter.ref !== undefined &&
184
- chapter.ref.id === ref.id &&
185
- chapter.text !== text);
186
- if (match)
187
- modified = true;
188
- return match ? chapter.withText(match[1]) : chapter;
181
+ }
182
+ const text = textByID.get(chapter.ref.id);
183
+ return text === undefined ? chapter : chapter.withText(text);
189
184
  });
190
- return modified ? this.withChapters(newChapters) : this;
185
+ return this.withChapters(newChapters);
191
186
  }
192
187
  withRevisedChapter(previous, edited) {
193
188
  const index = this.chapters.indexOf(previous);
@@ -482,7 +477,7 @@ export default class Edition {
482
477
  return bookIndex;
483
478
  }
484
479
  // Given the current chapter, find the available chapter after it.
485
- getNextChapterID(chapterID) {
480
+ getNextChapterID(chapterID, editable) {
486
481
  // Handle back matter chapters.
487
482
  switch (chapterID) {
488
483
  case ChapterIDs.ReferencesID:
@@ -508,7 +503,7 @@ export default class Edition {
508
503
  if (chapter.getID() === chapterID)
509
504
  after = true;
510
505
  // If we're after the given chapter and it's not forthcoming.
511
- else if (after && !chapter.isForthcoming())
506
+ else if (after && (!chapter.isForthcoming() || editable))
512
507
  return chapter.getID();
513
508
  }
514
509
  // If the given ID was the last chapter, go to the next back matter chapter.
@@ -524,7 +519,7 @@ export default class Edition {
524
519
  }
525
520
  }
526
521
  // Given a chapter id, find the available chapter before it.
527
- getPreviousChapterID(chapterID) {
522
+ getPreviousChapterID(chapterID, editable) {
528
523
  switch (chapterID) {
529
524
  // Handle back matter chapters.
530
525
  case ChapterIDs.ReferencesID:
@@ -556,7 +551,7 @@ export default class Edition {
556
551
  if (chapter.getID() === chapterID)
557
552
  before = true;
558
553
  // If we're before the given chapter and it's not forthcoming.
559
- else if (before && !chapter.isForthcoming())
554
+ else if (before && (!chapter.isForthcoming() || editable))
560
555
  return chapter.getID();
561
556
  }
562
557
  // If the given ID was the last chapter, go to the next back matter chapter.
@@ -2,6 +2,7 @@ import type Node from './Node';
2
2
  import AtomNode from './AtomNode';
3
3
  import TextNode from './TextNode';
4
4
  import type EmbedNode from './EmbedNode';
5
+ import LineBreakNode from './LineBreakNode';
5
6
  export type SelectableNode = TextNode | AtomNode<any> | EmbedNode;
6
7
  type Caret = {
7
8
  node: SelectableNode;
@@ -16,7 +17,7 @@ export type IndexRange = {
16
17
  start: number;
17
18
  end: number;
18
19
  };
19
- export declare function getTextAndAtomNodes(node: Node): (AtomNode<any> | TextNode)[];
20
+ export declare function getNavigableNodes(node: Node): (AtomNode<any> | TextNode | LineBreakNode)[];
20
21
  export declare function caretToIndex(node: Node, caret: Caret): number | undefined;
21
22
  export declare function indexToCaret(node: Node, index: number): Caret | undefined;
22
23
  export declare function caretRangeToIndexRange(node: Node, range: CaretRange): IndexRange | undefined;
@@ -1,10 +1,13 @@
1
1
  import AtomNode from './AtomNode';
2
2
  import TextNode from './TextNode';
3
3
  import FormatNode from './FormatNode';
4
- export function getTextAndAtomNodes(node) {
4
+ import LineBreakNode from './LineBreakNode';
5
+ export function getNavigableNodes(node) {
5
6
  return node
6
7
  .getNodes()
7
- .filter((n) => n instanceof TextNode || n instanceof AtomNode);
8
+ .filter((n) => n instanceof TextNode ||
9
+ n instanceof AtomNode ||
10
+ n instanceof LineBreakNode);
8
11
  }
9
12
  function getFormatRoots(node) {
10
13
  const roots = [];
@@ -22,7 +25,7 @@ export function caretToIndex(node, caret) {
22
25
  roots = [node];
23
26
  let currentIndex = 0;
24
27
  for (let n = 0; n < roots.length; n++) {
25
- const nodes = getTextAndAtomNodes(roots[n]);
28
+ const nodes = getNavigableNodes(roots[n]);
26
29
  for (let i = 0; i < nodes.length; i++) {
27
30
  const t = nodes[i];
28
31
  if (t !== caret.node)
@@ -40,9 +43,9 @@ export function indexToCaret(node, index) {
40
43
  roots = [node];
41
44
  let currentIndex = 0;
42
45
  for (let n = 0; n < roots.length; n++) {
43
- const nodes = getTextAndAtomNodes(roots[n]);
46
+ const nodes = getNavigableNodes(roots[n]);
44
47
  for (let i = 0; i < nodes.length; i++) {
45
- const t = nodes[i];
48
+ let t = nodes[i];
46
49
  if (index >= currentIndex &&
47
50
  index <= currentIndex + t.getCaretPositionCount()) {
48
51
  // Prefer empty nodes to enable zero width formats.
@@ -51,7 +54,18 @@ export function indexToCaret(node, index) {
51
54
  if (next instanceof TextNode && next.getLength() === 0)
52
55
  return { node: next, index: 0 };
53
56
  }
54
- return { node: t, index: index - currentIndex };
57
+ // If it's a line break node, find the next non-line break node.
58
+ if (t instanceof LineBreakNode) {
59
+ while (i < nodes.length &&
60
+ nodes[i] instanceof LineBreakNode)
61
+ i++;
62
+ t = nodes[i];
63
+ if (i === nodes.length || t instanceof LineBreakNode)
64
+ return undefined;
65
+ return { node: t, index: 0 };
66
+ }
67
+ else
68
+ return { node: t, index: index - currentIndex };
55
69
  }
56
70
  currentIndex += t.getCaretPositionCount();
57
71
  }
@@ -6,8 +6,9 @@ import { type CaretRange } from './Caret';
6
6
  import MetadataNode from './MetadataNode';
7
7
  import AtomNode from './AtomNode';
8
8
  import type Edit from './Edit';
9
+ import LineBreakNode from './LineBreakNode';
9
10
  export type Format = '' | '*' | '_' | '^' | 'v';
10
- export type FormatNodeSegmentType = FormatNode | TextNode | ErrorNode | MetadataNode<any> | AtomNode<any>;
11
+ export type FormatNodeSegmentType = FormatNode | TextNode | LineBreakNode | ErrorNode | MetadataNode<any> | AtomNode<any>;
11
12
  export default class FormatNode extends Node {
12
13
  #private;
13
14
  constructor(format: Format, segments: FormatNodeSegmentType[]);
@@ -57,4 +58,6 @@ export default class FormatNode extends Node {
57
58
  withoutAdjacentContent(caret: Caret, next: boolean): Edit | undefined;
58
59
  withoutCharacter(caret: Caret, next: boolean): Edit | undefined;
59
60
  withNodeInserted(caret: Caret, node: Node): Edit;
61
+ getSegmentAfter(segment: FormatNodeSegmentType): FormatNodeSegmentType | undefined;
62
+ getSegmentBefore(segment: FormatNodeSegmentType): FormatNodeSegmentType | undefined;
60
63
  }
@@ -3,6 +3,7 @@ import TextNode from './TextNode';
3
3
  import { caretRangeToIndexRange, caretToIndex, indexToCaret, } from './Caret';
4
4
  import MetadataNode from './MetadataNode';
5
5
  import AtomNode from './AtomNode';
6
+ import LineBreakNode from './LineBreakNode';
6
7
  export default class FormatNode extends Node {
7
8
  #format;
8
9
  #segments;
@@ -10,14 +11,22 @@ export default class FormatNode extends Node {
10
11
  super();
11
12
  this.#format = format;
12
13
  // Remove consecutive empty text nodes.
13
- this.#segments = segments.filter((item, position, list) => {
14
+ this.#segments = segments
15
+ .filter((item, position, list) => {
14
16
  if (position === 0 ||
15
17
  !(item instanceof TextNode) ||
16
18
  item.getLength() > 0)
17
19
  return true;
18
20
  const previous = list[position - 1];
19
21
  return !(previous instanceof TextNode && previous.getLength() === 0);
20
- });
22
+ })
23
+ // Insert text nodes between consecutive line breaks without them.
24
+ .map((item, position, list) => item instanceof LineBreakNode &&
25
+ list[position + 1] instanceof LineBreakNode
26
+ ? [item, new TextNode()]
27
+ : [item])
28
+ // Flatten the mapped list we made.
29
+ .flat();
21
30
  // Always ensure an empty text node.
22
31
  if (this.#segments.length === 0)
23
32
  this.#segments.push(new TextNode());
@@ -127,6 +136,11 @@ export default class FormatNode extends Node {
127
136
  }
128
137
  // If there's not, is there an adjacent caret in the sequence of text and atom nodes?
129
138
  const adjacentNode = this.getAdjacentTextOrAtom(caret.node, next);
139
+ // If there's a line break adjacent to the next node, account for it.
140
+ const linebreak = adjacentNode &&
141
+ (next
142
+ ? this.getSegmentBefore(adjacentNode) instanceof LineBreakNode
143
+ : this.getSegmentAfter(adjacentNode) instanceof LineBreakNode);
130
144
  if (adjacentNode !== undefined) {
131
145
  // Normally we skip over node boundaries because they look identical to each other.
132
146
  // But some nodes are zero length, so we have to account for that.
@@ -134,18 +148,20 @@ export default class FormatNode extends Node {
134
148
  node: adjacentNode,
135
149
  index: next
136
150
  ? adjacentNode instanceof TextNode
137
- ? adjacentNode.isEmpty()
151
+ ? adjacentNode.isEmpty() || linebreak
138
152
  ? 0
139
153
  : 1
140
154
  : 0
141
155
  : adjacentNode instanceof TextNode
142
156
  ? adjacentNode.isEmpty()
143
157
  ? 0
144
- : adjacentNode.getLength() - 1
158
+ : linebreak
159
+ ? adjacentNode.getLength()
160
+ : adjacentNode.getLength() - 1
145
161
  : 0,
146
162
  };
147
163
  }
148
- // Otherwise, there is no adjascent caret.
164
+ // Otherwise, there is no adjacent caret.
149
165
  return undefined;
150
166
  }
151
167
  getFirstCaret() {
@@ -519,6 +535,19 @@ export default class FormatNode extends Node {
519
535
  // Increment the text index; atoms count for one character.
520
536
  textIndex++;
521
537
  }
538
+ // Line break? Preserve the node, unless it's being deleted.
539
+ else if (node instanceof LineBreakNode) {
540
+ // Save any text prior to the line break as a text node in the current format.
541
+ saveText();
542
+ // Insert the line break unless we're deleting
543
+ if (format !== undefined ||
544
+ textIndex < selectionStartIndex ||
545
+ textIndex > selectionEndIndex) {
546
+ newFormats[0].segments.push(node);
547
+ }
548
+ // Increment the text index; atoms count for one character.
549
+ textIndex++;
550
+ }
522
551
  });
523
552
  // Save any remaining text that we've accumulated.
524
553
  saveText();
@@ -726,18 +755,33 @@ export default class FormatNode extends Node {
726
755
  if (!(node instanceof FormatNode ||
727
756
  node instanceof TextNode ||
728
757
  node instanceof MetadataNode ||
758
+ node instanceof LineBreakNode ||
729
759
  node instanceof AtomNode))
730
760
  return;
731
761
  const newFormat = this.withSegmentAt(node, caret);
762
+ if (newFormat === undefined)
763
+ return;
764
+ const segmentAfter = newFormat.getSegmentAfter(node);
732
765
  const newCaret = node instanceof AtomNode
733
766
  ? node.getDefaultCaret()
734
767
  : node instanceof FormatNode
735
768
  ? node.getLastCaret()
736
- : node instanceof MetadataNode
737
- ? { node: node.getText(), index: node.getText().getLength() }
738
- : { node: node, index: node.getLength() };
739
- if (newFormat === undefined || newCaret === undefined)
769
+ : // Line break? Place the caret just after the line break, whether a text node or something else
770
+ node instanceof LineBreakNode
771
+ ? segmentAfter !== undefined && segmentAfter instanceof TextNode
772
+ ? { node: segmentAfter, index: 0 }
773
+ : undefined
774
+ : node instanceof MetadataNode
775
+ ? { node: node.getText(), index: node.getText().getLength() }
776
+ : { node: node, index: node.getLength() };
777
+ if (newCaret === undefined)
740
778
  return;
741
779
  return { root: newFormat, range: { start: newCaret, end: newCaret } };
742
780
  }
781
+ getSegmentAfter(segment) {
782
+ return this.#segments[this.#segments.indexOf(segment) + 1];
783
+ }
784
+ getSegmentBefore(segment) {
785
+ return this.#segments[this.#segments.indexOf(segment) - 1];
786
+ }
743
787
  }
@@ -0,0 +1,15 @@
1
+ import type { CaretRange } from './Caret';
2
+ import Node from './Node';
3
+ export default class LineBreakNode extends Node {
4
+ constructor();
5
+ getType(): string;
6
+ getParentOf(): Node | undefined;
7
+ toText(): string;
8
+ toBookdown(): string;
9
+ getCaretPositionCount(): number;
10
+ toHTML(): string;
11
+ getChildren(): never[];
12
+ copy(): this;
13
+ withChildReplaced(): this | undefined;
14
+ withContentInRange(range: CaretRange): this | undefined;
15
+ }
@@ -0,0 +1,37 @@
1
+ import Node from './Node';
2
+ import { LINE_BREAK } from './Symbols';
3
+ export default class LineBreakNode extends Node {
4
+ constructor() {
5
+ super();
6
+ }
7
+ getType() {
8
+ return 'linebreak';
9
+ }
10
+ getParentOf() {
11
+ return undefined;
12
+ }
13
+ toText() {
14
+ return LINE_BREAK;
15
+ }
16
+ toBookdown() {
17
+ return LINE_BREAK;
18
+ }
19
+ getCaretPositionCount() {
20
+ return 1;
21
+ }
22
+ toHTML() {
23
+ return '<br/>';
24
+ }
25
+ getChildren() {
26
+ return [];
27
+ }
28
+ copy() {
29
+ return new LineBreakNode();
30
+ }
31
+ withChildReplaced() {
32
+ return this;
33
+ }
34
+ withContentInRange(range) {
35
+ return this;
36
+ }
37
+ }
@@ -21,6 +21,7 @@ import TextNode from './TextNode';
21
21
  import type Position from './Position';
22
22
  import type BlockNode from './BlockNode';
23
23
  import type Bookkeeping from './Bookkeeping';
24
+ import LineBreakNode from './LineBreakNode';
24
25
  export default class Parser {
25
26
  book: Edition | undefined;
26
27
  text: string;
@@ -62,6 +63,7 @@ export default class Parser {
62
63
  parseCallout(): CalloutNode;
63
64
  parseTable(): TableNode;
64
65
  parseFormat(awaiting?: string): FormatNode;
66
+ parseLineBreak(): LineBreakNode;
65
67
  parseEmbed(): EmbedNode;
66
68
  parseComment(): CommentNode;
67
69
  parseLabel(): LabelNode | ErrorNode;
@@ -14,10 +14,11 @@ import LinkNode from './LinkNode';
14
14
  import ListNode from './ListNode';
15
15
  import ParagraphNode from './ParagraphNode';
16
16
  import QuoteNode from './QuoteNode';
17
- import Reference from '../book/Reference';
18
17
  import RuleNode from './RuleNode';
19
18
  import TableNode from './TableNode';
20
19
  import TextNode from './TextNode';
20
+ import LineBreakNode from './LineBreakNode';
21
+ import { LINE_BREAK } from './Symbols';
21
22
  const numberedRE = /^[0-9]+\.+/;
22
23
  const bulletRE = /^\*+\s+/;
23
24
  // TODO This grammar is slightly out of date.
@@ -181,6 +182,7 @@ export default class Parser {
181
182
  next === '*' ||
182
183
  next === '`' ||
183
184
  next === '@' ||
185
+ next === LINE_BREAK ||
184
186
  next === '~' ||
185
187
  (next === ':' &&
186
188
  charAfterNext !== null &&
@@ -578,7 +580,10 @@ export default class Parser {
578
580
  // Parse some bold, italic, subscript, superscript
579
581
  if (next === '_' || next === '*' || next === '^')
580
582
  segments.push(this.parseStyle(next));
581
- // Parse unformatted text
583
+ // Parse a line break
584
+ else if (this.nextIs(LINE_BREAK))
585
+ segments.push(this.parseLineBreak());
586
+ // Parse inline code text
582
587
  else if (this.nextIs('`'))
583
588
  segments.push(this.parseInlineCode());
584
589
  // Parse a citation list
@@ -634,6 +639,11 @@ export default class Parser {
634
639
  }
635
640
  return new FormatNode('', segments);
636
641
  }
642
+ parseLineBreak() {
643
+ // Read the line break
644
+ this.read();
645
+ return new LineBreakNode();
646
+ }
637
647
  parseEmbed() {
638
648
  // Read |
639
649
  this.read();
@@ -0,0 +1 @@
1
+ export declare const LINE_BREAK = "\u21A9";
@@ -0,0 +1 @@
1
+ export const LINE_BREAK = '↩';
@@ -1,12 +1,16 @@
1
1
  import Reference from '../models/book/Reference';
2
2
  export function mineReference(ids, text) {
3
3
  // First find the year, since it's the most easily detected. Optional parens.
4
- let yearMatches = text.match(/(\(?[0-9]{4}\)?)/);
4
+ let yearMatches = text.match(/(\(?[0-9]{4}(,[a-zA-Z ]+)?\)?)/);
5
5
  let year = yearMatches !== null && yearMatches.length > 0
6
6
  ? yearMatches[1].replace('(', '').replace(')', '')
7
7
  : undefined;
8
- if (year && yearMatches)
8
+ if (year && yearMatches) {
9
+ const digits = year.match(/([0-9]{4})/);
10
+ if (digits !== null)
11
+ year = digits[1];
9
12
  text = text.replace(yearMatches[1], '');
13
+ }
10
14
  // Next, find the URL
11
15
  let url = null;
12
16
  let urlMatches = text.match(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/);
@@ -38,9 +42,7 @@ export function mineReference(ids, text) {
38
42
  source = source.trim();
39
43
  }
40
44
  // If there's anything left, fall back to just a string.
41
- return chunks.length > 0
42
- ? new Reference(getUniqueReferenceID(ids), text)
43
- : new Reference(getUniqueReferenceID(ids, authors, year), authors || '', year || '', title || '', source || '', url || '', '', false);
45
+ return new Reference(getUniqueReferenceID(ids, authors, year), authors || '', year || '', title || '', source || '', url || '', '', false);
44
46
  }
45
47
  export function splitIntoSentences(text) {
46
48
  // Split the remaining text by period-space sequences, assuming chunks of information are segmented by sentences
@@ -92,7 +94,7 @@ export function getUniqueReferenceID(ids, authors, year) {
92
94
  return revisedID;
93
95
  }
94
96
  else {
95
- let id = 'ref';
97
+ let id = '00';
96
98
  for (let i = 0; i < 4; i++)
97
99
  id = id + Math.round(Math.random() * 9);
98
100
  return id;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bookish-press",
3
3
  "private": false,
4
- "version": "0.5.32",
4
+ "version": "0.5.71",
5
5
  "type": "module",
6
6
  "description": "A platform for reading and writing readable, accessible, beautiful online books.",
7
7
  "license": "MIT",
@@ -28,37 +28,40 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@sveltejs/adapter-static": "^2.0",
31
- "@sveltejs/kit": "^1.2",
32
- "@sveltejs/package": "^2.0",
31
+ "@sveltejs/adapter-auto": "^2.1.1",
32
+ "@sveltejs/kit": "^1.27",
33
+ "@sveltejs/package": "^2.2",
33
34
  "@types/prismjs": "^1.26",
34
- "@types/smoothscroll-polyfill": "^0.3.1",
35
+ "@types/smoothscroll-polyfill": "^0",
35
36
  "@types/uuid": "^9.0",
36
- "prettier": "^2.8",
37
- "prettier-plugin-svelte": "^2.10",
37
+ "prettier": "^3",
38
+ "prettier-plugin-svelte": "^3",
38
39
  "svelte-adapter-firebase": "^0.15.0",
39
- "svelte-check": "^3.4",
40
- "svelte-preprocess": "^5.0",
41
- "tslib": "^2.5",
42
- "typescript": "^5.1",
43
- "vite": "^4.1.2",
44
- "vitest": "^0.29.2"
40
+ "svelte-check": "^3.6",
41
+ "svelte-preprocess": "^5.1",
42
+ "tslib": "^2",
43
+ "typescript": "^5",
44
+ "vite": "^4",
45
+ "vitest": "^0"
45
46
  },
46
47
  "dependencies": {
47
- "ajv": "^8.12.0",
48
- "ajv-formats": "^2.1.1",
48
+ "@sveltejs/kit": "^1.27",
49
+ "ajv": "^8",
50
+ "ajv-formats": "^2",
49
51
  "firebase": "latest",
50
- "firebase-functions": "^4.4.0",
51
- "prismjs": "^1.29.0",
52
- "smoothscroll-polyfill": "^0.4.4",
53
- "svelte": "^3.59",
54
- "@sveltejs/kit": "^1.2",
52
+ "firebase-functions": "latest",
53
+ "prismjs": "^1.29",
54
+ "smoothscroll-polyfill": "^0.4",
55
+ "svelte": "^4.2",
55
56
  "uuid": "^9.0"
56
57
  },
57
58
  "types": "./dist/index.d.ts",
59
+ "main": "./dist/index.js",
58
60
  "exports": {
59
61
  "./package.json": "./package.json",
60
62
  ".": {
61
63
  "types": "./dist/index.d.ts",
64
+ "main": "./dist/index.js",
62
65
  "svelte": "./dist/index.js",
63
66
  "default": "./dist/index.js"
64
67
  },