bookish-press 0.7.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/components/Auth.svelte +29 -39
- package/dist/components/Auth.svelte.d.ts +5 -17
- package/dist/components/BookPreview.svelte +14 -20
- package/dist/components/BookPreview.svelte.d.ts +6 -18
- package/dist/components/Link.svelte +19 -30
- package/dist/components/Link.svelte.d.ts +7 -20
- package/dist/components/app/BookList.svelte +2 -3
- package/dist/components/app/BookList.svelte.d.ts +6 -18
- package/dist/components/app/Button.svelte +12 -8
- package/dist/components/app/Button.svelte.d.ts +10 -23
- package/dist/components/app/Feedback.svelte +4 -4
- package/dist/components/app/Feedback.svelte.d.ts +6 -19
- package/dist/components/app/Head.svelte +2 -2
- package/dist/components/app/Head.svelte.d.ts +6 -19
- package/dist/components/app/Large.svelte +4 -1
- package/dist/components/app/Large.svelte.d.ts +5 -28
- package/dist/components/app/Lead.svelte +4 -1
- package/dist/components/app/Lead.svelte.d.ts +5 -28
- package/dist/components/app/Link.svelte +12 -9
- package/dist/components/app/Link.svelte.d.ts +9 -22
- package/dist/components/app/Options.svelte +8 -6
- package/dist/components/app/Options.svelte.d.ts +8 -20
- package/dist/components/app/Paragraph.svelte +2 -2
- package/dist/components/app/Paragraph.svelte.d.ts +6 -19
- package/dist/components/app/Section.svelte +4 -1
- package/dist/components/app/Section.svelte.d.ts +5 -28
- package/dist/components/app/Table.svelte +4 -1
- package/dist/components/app/Table.svelte.d.ts +5 -28
- package/dist/components/app/TextInput.svelte +10 -8
- package/dist/components/app/TextInput.svelte.d.ts +12 -23
- package/dist/components/chapter/Atom.svelte +4 -7
- package/dist/components/chapter/Atom.svelte.d.ts +6 -19
- package/dist/components/chapter/Block.svelte +21 -23
- package/dist/components/chapter/Block.svelte.d.ts +5 -17
- package/dist/components/chapter/Callout.svelte +3 -5
- package/dist/components/chapter/Callout.svelte.d.ts +5 -17
- package/dist/components/chapter/CaptionedCode.svelte +12 -14
- package/dist/components/chapter/CaptionedCode.svelte.d.ts +5 -17
- package/dist/components/chapter/ChapterBody.svelte +14 -17
- package/dist/components/chapter/ChapterBody.svelte.d.ts +7 -19
- package/dist/components/chapter/ChapterBody.test.d.ts +1 -0
- package/dist/components/chapter/ChapterBody.test.js +85 -0
- package/dist/components/chapter/Citations.svelte +39 -45
- package/dist/components/chapter/Citations.svelte.d.ts +5 -17
- package/dist/components/chapter/Code.svelte +158 -155
- package/dist/components/chapter/Code.svelte.d.ts +10 -23
- package/dist/components/chapter/Comment.svelte +30 -23
- package/dist/components/chapter/Comment.svelte.d.ts +5 -17
- package/dist/components/chapter/Definition.svelte +36 -34
- package/dist/components/chapter/Definition.svelte.d.ts +5 -17
- package/dist/components/chapter/Embed.svelte +78 -72
- package/dist/components/chapter/Embed.svelte.d.ts +8 -20
- package/dist/components/chapter/ErrorMessage.svelte +2 -4
- package/dist/components/chapter/ErrorMessage.svelte.d.ts +5 -17
- package/dist/components/chapter/Figure.svelte +22 -29
- package/dist/components/chapter/Figure.svelte.d.ts +9 -22
- package/dist/components/chapter/Footnote.svelte +40 -32
- package/dist/components/chapter/Footnote.svelte.d.ts +5 -17
- package/dist/components/chapter/Format.svelte +26 -41
- package/dist/components/chapter/Format.svelte.d.ts +7 -18
- package/dist/components/chapter/InlineCode.svelte +7 -8
- package/dist/components/chapter/InlineCode.svelte.d.ts +5 -17
- package/dist/components/chapter/Label.svelte +5 -11
- package/dist/components/chapter/Label.svelte.d.ts +5 -17
- package/dist/components/chapter/LineBreak.svelte +1 -3
- package/dist/components/chapter/LineBreak.svelte.d.ts +5 -17
- package/dist/components/chapter/Link.svelte +17 -23
- package/dist/components/chapter/Link.svelte.d.ts +5 -17
- package/dist/components/chapter/List.svelte +9 -9
- package/dist/components/chapter/List.svelte.d.ts +6 -17
- package/dist/components/chapter/Marginal.svelte +59 -60
- package/dist/components/chapter/Marginal.svelte.d.ts +10 -22
- package/dist/components/chapter/Paragraph.svelte +8 -23
- package/dist/components/chapter/Paragraph.svelte.d.ts +6 -18
- package/dist/components/chapter/Positioned.svelte +2 -4
- package/dist/components/chapter/Positioned.svelte.d.ts +6 -19
- package/dist/components/chapter/Problem.svelte +3 -2
- package/dist/components/chapter/Problem.svelte.d.ts +5 -28
- package/dist/components/chapter/Python.svelte +45 -58
- package/dist/components/chapter/Python.svelte.d.ts +6 -18
- package/dist/components/chapter/Quote.svelte +5 -7
- package/dist/components/chapter/Quote.svelte.d.ts +5 -17
- package/dist/components/chapter/Rule.svelte +1 -3
- package/dist/components/chapter/Rule.svelte.d.ts +5 -17
- package/dist/components/chapter/Table.svelte +6 -8
- package/dist/components/chapter/Table.svelte.d.ts +5 -17
- package/dist/components/chapter/Text.svelte +54 -69
- package/dist/components/chapter/Text.svelte.d.ts +6 -18
- package/dist/components/controls/DarkToggle.svelte +7 -8
- package/dist/components/controls/DarkToggle.svelte.d.ts +6 -18
- package/dist/components/editor/BookishEditor.svelte +583 -761
- package/dist/components/editor/BookishEditor.svelte.d.ts +14 -26
- package/dist/components/editor/CalloutEditor.svelte +3 -3
- package/dist/components/editor/CalloutEditor.svelte.d.ts +5 -17
- package/dist/components/editor/CaptionedCodeEditor.svelte +5 -5
- package/dist/components/editor/CaptionedCodeEditor.svelte.d.ts +5 -17
- package/dist/components/editor/CaretView.svelte +23 -25
- package/dist/components/editor/CaretView.svelte.d.ts +15 -27
- package/dist/components/editor/CitationsEditor.svelte +25 -28
- package/dist/components/editor/CitationsEditor.svelte.d.ts +5 -17
- package/dist/components/editor/ConfirmButton.svelte +9 -6
- package/dist/components/editor/ConfirmButton.svelte.d.ts +8 -21
- package/dist/components/editor/DefinitionEditor.svelte +11 -15
- package/dist/components/editor/DefinitionEditor.svelte.d.ts +5 -17
- package/dist/components/editor/EmbedEditor.svelte +43 -44
- package/dist/components/editor/EmbedEditor.svelte.d.ts +5 -17
- package/dist/components/editor/Icon.svelte +1 -1
- package/dist/components/editor/Icon.svelte.d.ts +5 -17
- package/dist/components/editor/ImageChooser.svelte +15 -18
- package/dist/components/editor/ImageChooser.svelte.d.ts +6 -18
- package/dist/components/editor/ImageThumbnail.svelte +29 -24
- package/dist/components/editor/ImageThumbnail.svelte.d.ts +7 -19
- package/dist/components/editor/InlineCodeEditor.svelte +3 -3
- package/dist/components/editor/InlineCodeEditor.svelte.d.ts +5 -17
- package/dist/components/editor/LabelEditor.svelte +5 -6
- package/dist/components/editor/LabelEditor.svelte.d.ts +5 -17
- package/dist/components/editor/LanguageEditor.svelte +4 -5
- package/dist/components/editor/LanguageEditor.svelte.d.ts +6 -18
- package/dist/components/editor/LinkEditor.svelte +52 -68
- package/dist/components/editor/LinkEditor.svelte.d.ts +5 -17
- package/dist/components/editor/Note.svelte +4 -1
- package/dist/components/editor/Note.svelte.d.ts +5 -28
- package/dist/components/editor/Permissions.svelte +55 -51
- package/dist/components/editor/Permissions.svelte.d.ts +9 -21
- package/dist/components/editor/PositionEditor.svelte +6 -7
- package/dist/components/editor/PositionEditor.svelte.d.ts +6 -18
- package/dist/components/editor/QuoteEditor.svelte +3 -3
- package/dist/components/editor/QuoteEditor.svelte.d.ts +5 -17
- package/dist/components/editor/Switch.svelte +16 -11
- package/dist/components/editor/Switch.svelte.d.ts +9 -21
- package/dist/components/editor/TableEditor.svelte +3 -3
- package/dist/components/editor/TableEditor.svelte.d.ts +5 -17
- package/dist/components/editor/TextEditor.svelte +74 -87
- package/dist/components/editor/TextEditor.svelte.d.ts +13 -25
- package/dist/components/editor/Toggle.svelte +18 -21
- package/dist/components/editor/Toggle.svelte.d.ts +7 -20
- package/dist/components/editor/Toolbar.svelte +140 -145
- package/dist/components/editor/Toolbar.svelte.d.ts +5 -17
- package/dist/components/editor/ToolbarGroup.svelte +4 -4
- package/dist/components/editor/ToolbarGroup.svelte.d.ts +6 -19
- package/dist/components/editor/ToolbarSpacer.svelte +1 -1
- package/dist/components/editor/ToolbarSpacer.svelte.d.ts +22 -21
- package/dist/components/editor/URLEditor.svelte +3 -5
- package/dist/components/editor/URLEditor.svelte.d.ts +7 -19
- package/dist/components/page/Acknowledgements.svelte +14 -8
- package/dist/components/page/Acknowledgements.svelte.d.ts +3 -16
- package/dist/components/page/Analytics.svelte +2 -3
- package/dist/components/page/Analytics.svelte.d.ts +6 -17
- package/dist/components/page/Authors.svelte +29 -29
- package/dist/components/page/Authors.svelte.d.ts +11 -23
- package/dist/components/page/BookLoader.svelte +47 -43
- package/dist/components/page/BookLoader.svelte.d.ts +5 -17
- package/dist/components/page/BulkReferenceEditor.svelte +43 -26
- package/dist/components/page/BulkReferenceEditor.svelte.d.ts +3 -16
- package/dist/components/page/Chapter.svelte +226 -250
- package/dist/components/page/Chapter.svelte.d.ts +6 -18
- package/dist/components/page/ChapterContext.d.ts +3 -1
- package/dist/components/page/ChapterNumber.svelte +4 -1
- package/dist/components/page/ChapterNumber.svelte.d.ts +5 -28
- package/dist/components/page/ChapterTitle.svelte +4 -4
- package/dist/components/page/ChapterTitle.svelte.d.ts +6 -19
- package/dist/components/page/Contexts.js +2 -2
- package/dist/components/page/DefinitionView.svelte +51 -44
- package/dist/components/page/DefinitionView.svelte.d.ts +6 -18
- package/dist/components/page/Description.svelte +10 -4
- package/dist/components/page/Description.svelte.d.ts +16 -14
- package/dist/components/page/EditableHeader.svelte +4 -6
- package/dist/components/page/EditableHeader.svelte.d.ts +7 -18
- package/dist/components/page/Edition.svelte +57 -71
- package/dist/components/page/Edition.svelte.d.ts +7 -20
- package/dist/components/page/EditionLoader.svelte +119 -82
- package/dist/components/page/EditionLoader.svelte.d.ts +6 -19
- package/dist/components/page/Editions.svelte +61 -41
- package/dist/components/page/Editions.svelte.d.ts +5 -17
- package/dist/components/page/Glossary.svelte +31 -35
- package/dist/components/page/Glossary.svelte.d.ts +3 -16
- package/dist/components/page/Header.svelte +43 -49
- package/dist/components/page/Header.svelte.d.ts +19 -30
- package/dist/components/page/Index.svelte +46 -46
- package/dist/components/page/Index.svelte.d.ts +3 -16
- package/dist/components/page/Instructions.svelte +2 -2
- package/dist/components/page/Instructions.svelte.d.ts +6 -19
- package/dist/components/page/License.svelte +13 -7
- package/dist/components/page/License.svelte.d.ts +16 -14
- package/dist/components/page/Loading.svelte +9 -9
- package/dist/components/page/Loading.svelte.d.ts +22 -21
- package/dist/components/page/Media.svelte +36 -27
- package/dist/components/page/Media.svelte.d.ts +3 -16
- package/dist/components/page/MediaPreview.svelte +22 -19
- package/dist/components/page/MediaPreview.svelte.d.ts +8 -21
- package/dist/components/page/Muted.svelte +4 -1
- package/dist/components/page/Muted.svelte.d.ts +5 -28
- package/dist/components/page/Outline.svelte +76 -97
- package/dist/components/page/Outline.svelte.d.ts +8 -20
- package/dist/components/page/Page.svelte +27 -35
- package/dist/components/page/Page.svelte.d.ts +7 -20
- package/dist/components/page/PageHeader.svelte +2 -2
- package/dist/components/page/PageHeader.svelte.d.ts +6 -19
- package/dist/components/page/PageParagraph.svelte +4 -1
- package/dist/components/page/PageParagraph.svelte.d.ts +5 -28
- package/dist/components/page/PossibleChapter.svelte +7 -7
- package/dist/components/page/PossibleChapter.svelte.d.ts +3 -16
- package/dist/components/page/PossibleReference.svelte +4 -5
- package/dist/components/page/PossibleReference.svelte.d.ts +6 -18
- package/dist/components/page/Print.svelte +18 -2
- package/dist/components/page/Print.svelte.d.ts +3 -16
- package/dist/components/page/Publish.svelte +47 -47
- package/dist/components/page/Publish.svelte.d.ts +3 -16
- package/dist/components/page/Reference.svelte +24 -35
- package/dist/components/page/Reference.svelte.d.ts +6 -18
- package/dist/components/page/References.svelte +21 -22
- package/dist/components/page/References.svelte.d.ts +3 -16
- package/dist/components/page/Rows.svelte +4 -1
- package/dist/components/page/Rows.svelte.d.ts +5 -28
- package/dist/components/page/Search.svelte +58 -60
- package/dist/components/page/Search.svelte.d.ts +3 -16
- package/dist/components/page/Status.svelte +2 -2
- package/dist/components/page/Status.svelte.d.ts +16 -14
- package/dist/components/page/SubdomainEditor.svelte +11 -11
- package/dist/components/page/SubdomainEditor.svelte.d.ts +16 -14
- package/dist/components/page/TableOfContents.svelte +143 -125
- package/dist/components/page/TableOfContents.svelte.d.ts +3 -16
- package/dist/components/page/TableOfContentsImage.svelte +6 -7
- package/dist/components/page/TableOfContentsImage.svelte.d.ts +6 -18
- package/dist/components/page/TableOfContentsRow.svelte +32 -32
- package/dist/components/page/TableOfContentsRow.svelte.d.ts +10 -22
- package/dist/components/page/ThemeEditor.svelte +35 -28
- package/dist/components/page/ThemeEditor.svelte.d.ts +3 -16
- package/dist/components/page/ThemeEditorPreview.svelte +11 -13
- package/dist/components/page/ThemeEditorPreview.svelte.d.ts +5 -17
- package/dist/components/page/ThemeSetEditor.svelte +4 -6
- package/dist/components/page/ThemeSetEditor.svelte.d.ts +7 -19
- package/dist/components/page/ThemeVariableEditor.svelte +9 -11
- package/dist/components/page/ThemeVariableEditor.svelte.d.ts +7 -19
- package/dist/components/page/Title.svelte +4 -1
- package/dist/components/page/Title.svelte.d.ts +5 -28
- package/dist/components/page/Unknown.svelte +11 -8
- package/dist/components/page/Unknown.svelte.d.ts +5 -17
- package/dist/models/CRUD.js +23 -4
- package/dist/models/Firebase.js +18 -4
- package/dist/models/book/Book.d.ts +1 -1
- package/dist/models/book/Book.js +4 -3
- package/dist/models/book/BookMedia.js +1 -2
- package/dist/models/book/Chapter.js +3 -2
- package/dist/models/book/Edition.d.ts +1 -1
- package/dist/models/book/Edition.js +5 -1
- package/dist/models/chapter/BlocksNode.js +3 -1
- package/dist/models/chapter/BlocksNode.test.js +5 -1
- package/dist/models/chapter/Node.test.js +2 -2
- package/package.json +36 -25
|
@@ -1,830 +1,649 @@
|
|
|
1
|
-
<script>import BookishNode from
|
|
2
|
-
import ChapterNode from
|
|
3
|
-
import LinkNode from
|
|
4
|
-
import ParagraphNode from
|
|
5
|
-
import TextNode from
|
|
6
|
-
import AtomNode from
|
|
7
|
-
import FormatNode from
|
|
8
|
-
import BlocksNode from
|
|
9
|
-
import ListNode from
|
|
10
|
-
import TableNode from
|
|
11
|
-
import MetadataNode from
|
|
12
|
-
import CodeNode from
|
|
13
|
-
import BlockNode from
|
|
14
|
-
import EmbedNode from
|
|
15
|
-
import ErrorNode from
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
import
|
|
21
|
-
import
|
|
1
|
+
<script lang="ts">import BookishNode from "../../models/chapter/Node";
|
|
2
|
+
import ChapterNode from "../../models/chapter/ChapterNode";
|
|
3
|
+
import LinkNode from "../../models/chapter/LinkNode";
|
|
4
|
+
import ParagraphNode from "../../models/chapter/ParagraphNode";
|
|
5
|
+
import TextNode from "../../models/chapter/TextNode";
|
|
6
|
+
import AtomNode from "../../models/chapter/AtomNode";
|
|
7
|
+
import FormatNode from "../../models/chapter/FormatNode";
|
|
8
|
+
import BlocksNode from "../../models/chapter/BlocksNode";
|
|
9
|
+
import ListNode from "../../models/chapter/ListNode";
|
|
10
|
+
import TableNode from "../../models/chapter/TableNode";
|
|
11
|
+
import MetadataNode from "../../models/chapter/MetadataNode";
|
|
12
|
+
import CodeNode from "../../models/chapter/CodeNode";
|
|
13
|
+
import BlockNode from "../../models/chapter/BlockNode";
|
|
14
|
+
import EmbedNode from "../../models/chapter/EmbedNode";
|
|
15
|
+
import ErrorNode from "../../models/chapter/ErrorNode";
|
|
16
|
+
import {
|
|
17
|
+
caretRangeToIndexRange,
|
|
18
|
+
indexRangeToCaretRange
|
|
19
|
+
} from "../../models/chapter/Caret";
|
|
20
|
+
import commands from "./Commands";
|
|
21
|
+
import { onMount, setContext, untrack } from "svelte";
|
|
22
|
+
import { getCaret } from "../page/Contexts";
|
|
23
|
+
import CaretView from "./CaretView.svelte";
|
|
24
|
+
import Parser, { Reserved } from "../../models/chapter/Parser";
|
|
22
25
|
const IDLE_TIME = 500;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
let
|
|
26
|
+
let {
|
|
27
|
+
text,
|
|
28
|
+
parser,
|
|
29
|
+
save,
|
|
30
|
+
chapter,
|
|
31
|
+
autofocus = false,
|
|
32
|
+
component,
|
|
33
|
+
placeholder,
|
|
34
|
+
leasee,
|
|
35
|
+
lease,
|
|
36
|
+
inline = false
|
|
37
|
+
} = $props();
|
|
38
|
+
let element = $state(null);
|
|
39
|
+
let caretRange = $state(void 0);
|
|
40
|
+
let caretCoordinate = $state(void 0);
|
|
36
41
|
let lastInputTime = 0;
|
|
37
|
-
let keyboardIdle = true;
|
|
38
|
-
let editorFocused = false;
|
|
39
|
-
let undoStack = [];
|
|
40
|
-
let undoPosition = -1;
|
|
41
|
-
let clipboard =
|
|
42
|
-
let ignoredInput = false;
|
|
42
|
+
let keyboardIdle = $state(true);
|
|
43
|
+
let editorFocused = $state(false);
|
|
44
|
+
let undoStack = $state([]);
|
|
45
|
+
let undoPosition = $state(-1);
|
|
46
|
+
let clipboard = $state(void 0);
|
|
47
|
+
let ignoredInput = $state(false);
|
|
43
48
|
let activeEditor = getCaret();
|
|
44
|
-
let accent =
|
|
45
|
-
let editedNode;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
$: locked = typeof leasee === 'string';
|
|
49
|
+
let accent = $state(void 0);
|
|
50
|
+
let editedNode = $state(untrack(() => parser(text)));
|
|
51
|
+
$effect.pre(() => {
|
|
52
|
+
if (untrack(() => editedNode).toBookdown() !== text) {
|
|
53
|
+
editedNode = parser(text);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
let locked = $derived(typeof leasee === "string");
|
|
57
|
+
let RootView = $derived(component);
|
|
56
58
|
onMount(() => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
59
|
+
const caret = editedNode.getFirstCaret();
|
|
60
|
+
if (caret) caretRange = { start: caret, end: caret };
|
|
61
|
+
if (element && autofocus === true) {
|
|
62
|
+
element.focus();
|
|
63
|
+
}
|
|
64
|
+
document.addEventListener("selectionchange", handleSelectionChange);
|
|
65
|
+
return () => {
|
|
66
|
+
document.removeEventListener(
|
|
67
|
+
"selectionchange",
|
|
68
|
+
handleSelectionChange
|
|
69
|
+
);
|
|
70
|
+
};
|
|
70
71
|
});
|
|
71
72
|
onMount(() => {
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
// Clear the timer if we're unmounting or re-rendering.
|
|
83
|
-
clearTimeout(keystrokeTimer);
|
|
84
|
-
};
|
|
73
|
+
const keystrokeTimer = setInterval(() => {
|
|
74
|
+
const isIdle = Date.now() - lastInputTime > IDLE_TIME;
|
|
75
|
+
if (isIdle) {
|
|
76
|
+
keyboardIdle = true;
|
|
77
|
+
ignoredInput = false;
|
|
78
|
+
}
|
|
79
|
+
}, IDLE_TIME);
|
|
80
|
+
return () => {
|
|
81
|
+
clearTimeout(keystrokeTimer);
|
|
82
|
+
};
|
|
85
83
|
});
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
// Measure and remember caret position
|
|
155
|
-
if (currentRange) {
|
|
156
|
-
const rangeRect = currentRange.getBoundingClientRect();
|
|
157
|
-
const textRect = startNode.getBoundingClientRect();
|
|
158
|
-
const lineHeightString = window
|
|
159
|
-
.getComputedStyle(startNode)
|
|
160
|
-
.getPropertyValue('line-height');
|
|
161
|
-
const lineHeight = lineHeightString.endsWith('px')
|
|
162
|
-
? parseInt(lineHeightString.substring(0, lineHeightString.length - 2))
|
|
163
|
-
: undefined;
|
|
164
|
-
// Figure out the relative position of this editor.
|
|
165
|
-
let editorAncestor = element;
|
|
166
|
-
let relativeX = 0;
|
|
167
|
-
let relativeY = 0;
|
|
168
|
-
while (editorAncestor != null) {
|
|
169
|
-
const style = window.getComputedStyle(editorAncestor);
|
|
170
|
-
if (style.position === 'relative') {
|
|
171
|
-
relativeX += editorAncestor.offsetLeft;
|
|
172
|
-
relativeY += editorAncestor.offsetTop;
|
|
173
|
-
}
|
|
174
|
-
editorAncestor = editorAncestor.parentElement;
|
|
175
|
-
}
|
|
176
|
-
// If we're after a new line, calculate the correct position, since selections don't actually render to the next line.
|
|
177
|
-
const left = afterNewLine
|
|
178
|
-
? textRect.left
|
|
179
|
-
: rangeRect.left;
|
|
180
|
-
const top = afterNewLine && lineHeight
|
|
181
|
-
? rangeRect.top + lineHeight
|
|
182
|
-
: rangeRect.top;
|
|
183
|
-
// Compute the final position of the caret.
|
|
184
|
-
const position = {
|
|
185
|
-
x: left + window.scrollX - relativeX,
|
|
186
|
-
y: top + window.scrollY - relativeY,
|
|
187
|
-
height: rangeRect.height,
|
|
188
|
-
};
|
|
189
|
-
newCaretPosition = position;
|
|
190
|
-
}
|
|
84
|
+
$effect(() => {
|
|
85
|
+
void caretRange;
|
|
86
|
+
void editedNode;
|
|
87
|
+
if (!editorFocused) return;
|
|
88
|
+
let docSelection = document.getSelection();
|
|
89
|
+
let newCaretPosition = void 0;
|
|
90
|
+
if (docSelection) {
|
|
91
|
+
if (caretRange) {
|
|
92
|
+
const sortedRange = caretRange;
|
|
93
|
+
let startNode = document.querySelector(
|
|
94
|
+
`[data-nodeid='${sortedRange.start.node.nodeID}`
|
|
95
|
+
);
|
|
96
|
+
let endNode = document.querySelector(
|
|
97
|
+
`[data-nodeid='${sortedRange.end.node.nodeID}`
|
|
98
|
+
);
|
|
99
|
+
if (startNode && endNode && element) {
|
|
100
|
+
let rangeChanged = true;
|
|
101
|
+
let currentRange = void 0;
|
|
102
|
+
if (docSelection.rangeCount > 0) {
|
|
103
|
+
currentRange = docSelection.getRangeAt(0);
|
|
104
|
+
const startIsEqual = startNode.childNodes.length > 0 && currentRange.startContainer === startNode.childNodes[0] && currentRange.startOffset === sortedRange.start.index;
|
|
105
|
+
const endIsEqual = endNode.childNodes.length > 0 && currentRange.endContainer === endNode.childNodes[0] && currentRange.endOffset === sortedRange.end.index;
|
|
106
|
+
if (startIsEqual && endIsEqual) rangeChanged = false;
|
|
107
|
+
}
|
|
108
|
+
const emptyStart = startNode.childNodes.length === 0;
|
|
109
|
+
const emptyEnd = startNode !== endNode && endNode.childNodes.length === 0;
|
|
110
|
+
if (emptyStart)
|
|
111
|
+
startNode.appendChild(
|
|
112
|
+
document.createTextNode("\uFEFF")
|
|
113
|
+
);
|
|
114
|
+
if (emptyEnd)
|
|
115
|
+
endNode.appendChild(document.createTextNode("\uFEFF"));
|
|
116
|
+
const afterNewLine = sortedRange.start.node instanceof TextNode && sortedRange.start.index > 0 && sortedRange.start.node.getText().charAt(sortedRange.start.index - 1) === "\n";
|
|
117
|
+
if (rangeChanged) {
|
|
118
|
+
try {
|
|
119
|
+
docSelection.setBaseAndExtent(
|
|
120
|
+
startNode.childNodes[0],
|
|
121
|
+
sortedRange.start.index,
|
|
122
|
+
endNode.childNodes[0],
|
|
123
|
+
sortedRange.end.index
|
|
124
|
+
);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
console.error(e);
|
|
127
|
+
console.error(
|
|
128
|
+
`Error setting caret range, trying to set to ${startNode.childNodes[0]}:${sortedRange.start.index} - ${endNode.childNodes[0]}:${sortedRange.end.index}`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
currentRange = docSelection.getRangeAt(0);
|
|
132
|
+
}
|
|
133
|
+
if (currentRange) {
|
|
134
|
+
const rangeRect = currentRange.getBoundingClientRect();
|
|
135
|
+
const textRect = startNode.getBoundingClientRect();
|
|
136
|
+
const lineHeightString = window.getComputedStyle(startNode).getPropertyValue("line-height");
|
|
137
|
+
const lineHeight = lineHeightString.endsWith("px") ? parseInt(
|
|
138
|
+
lineHeightString.substring(
|
|
139
|
+
0,
|
|
140
|
+
lineHeightString.length - 2
|
|
141
|
+
)
|
|
142
|
+
) : void 0;
|
|
143
|
+
let editorAncestor = element;
|
|
144
|
+
let relativeX = 0;
|
|
145
|
+
let relativeY = 0;
|
|
146
|
+
while (editorAncestor != null) {
|
|
147
|
+
const style = window.getComputedStyle(editorAncestor);
|
|
148
|
+
if (style.position === "relative") {
|
|
149
|
+
relativeX += editorAncestor.offsetLeft;
|
|
150
|
+
relativeY += editorAncestor.offsetTop;
|
|
191
151
|
}
|
|
152
|
+
editorAncestor = editorAncestor.parentElement;
|
|
153
|
+
}
|
|
154
|
+
const left = afterNewLine ? textRect.left : rangeRect.left;
|
|
155
|
+
const top = afterNewLine && lineHeight ? rangeRect.top + lineHeight : rangeRect.top;
|
|
156
|
+
const position = {
|
|
157
|
+
x: left + window.scrollX - relativeX,
|
|
158
|
+
y: top + window.scrollY - relativeY,
|
|
159
|
+
height: rangeRect.height
|
|
160
|
+
};
|
|
161
|
+
newCaretPosition = position;
|
|
192
162
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
// Save the new caret position so we render it.
|
|
198
|
-
caretCoordinate = newCaretPosition;
|
|
163
|
+
}
|
|
164
|
+
} else if (editorFocused) document.getSelection()?.empty();
|
|
165
|
+
}
|
|
166
|
+
caretCoordinate = newCaretPosition;
|
|
199
167
|
});
|
|
200
168
|
function rangeToCaret(domNode, rangeIndex) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
node: node,
|
|
215
|
-
index: Math.min(rangeIndex, node.getLength()),
|
|
216
|
-
};
|
|
217
|
-
}
|
|
169
|
+
if (domNode.nodeType === Node.TEXT_NODE) {
|
|
170
|
+
let parent = domNode.parentNode;
|
|
171
|
+
while (parent && !(parent instanceof HTMLElement && parent.classList.contains("bookish-text")))
|
|
172
|
+
parent = parent.parentNode;
|
|
173
|
+
if (parent && parent.dataset.nodeid) {
|
|
174
|
+
const node = editedNode.getNode(
|
|
175
|
+
parseInt(parent.dataset.nodeid)
|
|
176
|
+
);
|
|
177
|
+
if (node instanceof TextNode)
|
|
178
|
+
return {
|
|
179
|
+
node,
|
|
180
|
+
index: Math.min(rangeIndex, node.getLength())
|
|
181
|
+
};
|
|
218
182
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (node instanceof ParagraphNode) {
|
|
227
|
-
const first = node.getFirstTextNode();
|
|
228
|
-
return { node: first, index: 0 };
|
|
229
|
-
}
|
|
230
|
-
else if (node instanceof TextNode) {
|
|
231
|
-
return { node: node, index: 0 };
|
|
232
|
-
}
|
|
183
|
+
} else if (domNode.nodeType === Node.ELEMENT_NODE && domNode instanceof HTMLElement && domNode.dataset.nodeid) {
|
|
184
|
+
const node = editedNode.getNode(parseInt(domNode.dataset.nodeid));
|
|
185
|
+
if (node instanceof ParagraphNode) {
|
|
186
|
+
const first = node.getFirstTextNode();
|
|
187
|
+
return { node: first, index: 0 };
|
|
188
|
+
} else if (node instanceof TextNode) {
|
|
189
|
+
return { node, index: 0 };
|
|
233
190
|
}
|
|
234
|
-
|
|
235
|
-
|
|
191
|
+
}
|
|
192
|
+
return void 0;
|
|
236
193
|
}
|
|
237
194
|
function handleSelectionChange() {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
195
|
+
lastInputTime = Date.now();
|
|
196
|
+
keyboardIdle = false;
|
|
197
|
+
const selection = document.getSelection();
|
|
198
|
+
if (selection && selection.anchorNode && selection.focusNode) {
|
|
199
|
+
const start = rangeToCaret(
|
|
200
|
+
selection.anchorNode,
|
|
201
|
+
selection.anchorOffset
|
|
202
|
+
);
|
|
203
|
+
const end = rangeToCaret(
|
|
204
|
+
selection.focusNode,
|
|
205
|
+
selection.focusOffset
|
|
206
|
+
);
|
|
207
|
+
if (start && end) {
|
|
208
|
+
caretRange = { start, end };
|
|
250
209
|
}
|
|
210
|
+
}
|
|
251
211
|
}
|
|
252
212
|
function getCaretCoordinate(caret) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
height: characterRect.height,
|
|
268
|
-
};
|
|
269
|
-
const elementRect = domNode.getBoundingClientRect();
|
|
213
|
+
if (!(caret.node instanceof TextNode || caret.node instanceof AtomNode))
|
|
214
|
+
return void 0;
|
|
215
|
+
const domNode = document.querySelector(
|
|
216
|
+
`[data-nodeid='${caret.node.nodeID}`
|
|
217
|
+
);
|
|
218
|
+
if (domNode === null || domNode.childNodes.length === 0)
|
|
219
|
+
return void 0;
|
|
220
|
+
const range = document.createRange();
|
|
221
|
+
range.setStart(
|
|
222
|
+
domNode.childNodes.length === 0 ? domNode : domNode.childNodes[0],
|
|
223
|
+
domNode.childNodes.length === 0 ? 0 : caret.index
|
|
224
|
+
);
|
|
225
|
+
const characterRect = range.getBoundingClientRect();
|
|
226
|
+
if (characterRect.left > 0)
|
|
270
227
|
return {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
228
|
+
top: characterRect.top,
|
|
229
|
+
left: characterRect.left,
|
|
230
|
+
height: characterRect.height
|
|
274
231
|
};
|
|
232
|
+
const elementRect = domNode.getBoundingClientRect();
|
|
233
|
+
return {
|
|
234
|
+
top: elementRect.top,
|
|
235
|
+
left: elementRect.left,
|
|
236
|
+
height: elementRect.height
|
|
237
|
+
};
|
|
275
238
|
}
|
|
276
239
|
function getCaretOnLine(caret, below) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
previousCoordinate.height)
|
|
311
|
-
return previousCandidate;
|
|
312
|
-
// If this is just below the start position, stop and return the closer of the current and previous candidates.
|
|
313
|
-
else if (candidateTop >
|
|
314
|
-
startTop + startCoordinate.height &&
|
|
315
|
-
candidateCoordinate.left >= startCoordinate.left)
|
|
316
|
-
return closerCandidate;
|
|
317
|
-
}
|
|
318
|
-
else {
|
|
319
|
-
// If this candidate is on the live above the line above the start line, then return the last candidate on the line above the start line.
|
|
320
|
-
if (previousCandidate &&
|
|
321
|
-
previousCoordinate &&
|
|
322
|
-
previousCoordinate.top +
|
|
323
|
-
previousCoordinate.height <
|
|
324
|
-
startTop &&
|
|
325
|
-
candidateTop + candidateCoordinate.height <
|
|
326
|
-
previousCoordinate.top)
|
|
327
|
-
return previousCandidate;
|
|
328
|
-
// If this is just above the start position, stop and return the closer of the current and previous candidates.
|
|
329
|
-
if (candidateTop + candidateCoordinate.height <
|
|
330
|
-
startTop &&
|
|
331
|
-
candidateCoordinate.left <= startCoordinate.left)
|
|
332
|
-
return closerCandidate;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
// Get the next candidate to consider.
|
|
336
|
-
const nextCandidate = editedNode.getAdjacentCaret(candidate, below);
|
|
337
|
-
if (nextCandidate === undefined)
|
|
338
|
-
break;
|
|
339
|
-
// If the caret didn't move, we stop searching, something is wrong.
|
|
340
|
-
if (nextCandidate.node === candidate.node &&
|
|
341
|
-
nextCandidate.index === candidate.index) {
|
|
342
|
-
break;
|
|
343
|
-
}
|
|
344
|
-
// Otherwise, we advance to the next candidate.
|
|
345
|
-
previousCandidate = candidate;
|
|
346
|
-
previousCoordinate = candidateCoordinate;
|
|
347
|
-
candidate = nextCandidate;
|
|
348
|
-
if (candidate === undefined)
|
|
349
|
-
return caret;
|
|
350
|
-
}
|
|
351
|
-
return candidate;
|
|
240
|
+
if (caret.node instanceof TextNode || caret.node instanceof AtomNode) {
|
|
241
|
+
const startCoordinate = getCaretCoordinate(caret);
|
|
242
|
+
let candidate = editedNode.getAdjacentCaret(caret, below);
|
|
243
|
+
if (candidate === void 0) return caret;
|
|
244
|
+
let previousCandidate = void 0;
|
|
245
|
+
let previousCoordinate = void 0;
|
|
246
|
+
if (startCoordinate) {
|
|
247
|
+
while (candidate.node instanceof TextNode || candidate.node instanceof AtomNode) {
|
|
248
|
+
const candidateCoordinate = getCaretCoordinate(candidate);
|
|
249
|
+
if (candidateCoordinate) {
|
|
250
|
+
const startTop = startCoordinate.top;
|
|
251
|
+
const candidateTop = candidateCoordinate.top;
|
|
252
|
+
const closerCandidate = previousCoordinate && previousCandidate && Math.abs(
|
|
253
|
+
startCoordinate.left - previousCoordinate.left
|
|
254
|
+
) < Math.abs(
|
|
255
|
+
startCoordinate.left - candidateCoordinate.left
|
|
256
|
+
) ? previousCandidate : candidate;
|
|
257
|
+
if (below) {
|
|
258
|
+
if (previousCandidate && previousCoordinate && previousCoordinate.top > startTop + startCoordinate.height && candidateTop > previousCoordinate.top + previousCoordinate.height)
|
|
259
|
+
return previousCandidate;
|
|
260
|
+
else if (candidateTop > startTop + startCoordinate.height && candidateCoordinate.left >= startCoordinate.left)
|
|
261
|
+
return closerCandidate;
|
|
262
|
+
} else {
|
|
263
|
+
if (previousCandidate && previousCoordinate && previousCoordinate.top + previousCoordinate.height < startTop && candidateTop + candidateCoordinate.height < previousCoordinate.top)
|
|
264
|
+
return previousCandidate;
|
|
265
|
+
if (candidateTop + candidateCoordinate.height < startTop && candidateCoordinate.left <= startCoordinate.left)
|
|
266
|
+
return closerCandidate;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const nextCandidate = editedNode.getAdjacentCaret(candidate, below);
|
|
270
|
+
if (nextCandidate === void 0) break;
|
|
271
|
+
if (nextCandidate.node === candidate.node && nextCandidate.index === candidate.index) {
|
|
272
|
+
break;
|
|
352
273
|
}
|
|
274
|
+
previousCandidate = candidate;
|
|
275
|
+
previousCoordinate = candidateCoordinate;
|
|
276
|
+
candidate = nextCandidate;
|
|
277
|
+
if (candidate === void 0) return caret;
|
|
278
|
+
}
|
|
279
|
+
return candidate;
|
|
353
280
|
}
|
|
354
|
-
|
|
355
|
-
|
|
281
|
+
}
|
|
282
|
+
return caret;
|
|
356
283
|
}
|
|
357
284
|
function atParagraphStart() {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
return false;
|
|
363
|
-
const firstCaret = caretRange.start.node
|
|
364
|
-
.getFormatRoot(editedNode)
|
|
365
|
-
?.getFirstCaret();
|
|
366
|
-
return (firstCaret !== undefined &&
|
|
367
|
-
firstCaret.node === caretRange.start.node &&
|
|
368
|
-
firstCaret.index === caretRange.start.index);
|
|
285
|
+
if (caretRange === void 0 || caretRange.start.node !== caretRange.end.node || caretRange.start.index !== caretRange.end.index || !(caretRange.start.node instanceof TextNode))
|
|
286
|
+
return false;
|
|
287
|
+
const firstCaret = caretRange.start.node.getFormatRoot(editedNode)?.getFirstCaret();
|
|
288
|
+
return firstCaret !== void 0 && firstCaret.node === caretRange.start.node && firstCaret.index === caretRange.start.index;
|
|
369
289
|
}
|
|
370
290
|
function undo() {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
save(node);
|
|
381
|
-
// Move the undo state down a position.
|
|
382
|
-
if (undoPosition < undoStack.length)
|
|
383
|
-
undoPosition = undoPosition + 1;
|
|
384
|
-
// Return the original caret.
|
|
385
|
-
const range = indexRangeToCaretRange(node, undoState.range);
|
|
386
|
-
if (range === undefined)
|
|
387
|
-
return;
|
|
388
|
-
return { root: node, range: range };
|
|
291
|
+
let undoState = undoStack[undoPosition + 1];
|
|
292
|
+
let node = parser(undoState.bookdown);
|
|
293
|
+
if (node === void 0 || node instanceof ErrorNode) return;
|
|
294
|
+
updateRoot(node);
|
|
295
|
+
save(node);
|
|
296
|
+
if (undoPosition < undoStack.length) undoPosition = undoPosition + 1;
|
|
297
|
+
const range = indexRangeToCaretRange(node, undoState.range);
|
|
298
|
+
if (range === void 0) return;
|
|
299
|
+
return { root: node, range };
|
|
389
300
|
}
|
|
390
301
|
function redo() {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if (undoPosition > 0)
|
|
400
|
-
undoPosition = undoPosition - 1;
|
|
401
|
-
// Return the original caret.
|
|
402
|
-
const range = indexRangeToCaretRange(node, undoState.range);
|
|
403
|
-
if (range === undefined)
|
|
404
|
-
return;
|
|
405
|
-
return { root: node, range: range };
|
|
302
|
+
let undoState = undoStack[undoPosition - 1];
|
|
303
|
+
let node = parser(undoState.bookdown);
|
|
304
|
+
if (node === void 0) return;
|
|
305
|
+
updateRoot(node);
|
|
306
|
+
if (undoPosition > 0) undoPosition = undoPosition - 1;
|
|
307
|
+
const range = indexRangeToCaretRange(node, undoState.range);
|
|
308
|
+
if (range === void 0) return;
|
|
309
|
+
return { root: node, range };
|
|
406
310
|
}
|
|
407
311
|
function getCaretContext() {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
undoPosition: undoPosition,
|
|
461
|
-
undo: undo,
|
|
462
|
-
redo: redo,
|
|
463
|
-
clipboard: clipboard,
|
|
464
|
-
handleCopy: handleCopy,
|
|
465
|
-
handlePaste: handlePaste,
|
|
466
|
-
setAccent,
|
|
467
|
-
getAccent,
|
|
468
|
-
};
|
|
312
|
+
if (caretRange === void 0) return void 0;
|
|
313
|
+
const nodes = editedNode.getNodes();
|
|
314
|
+
let inside = false;
|
|
315
|
+
let includesList = false;
|
|
316
|
+
nodes.forEach((n) => {
|
|
317
|
+
if (caretRange === void 0) return;
|
|
318
|
+
if (n === caretRange.start.node) inside = true;
|
|
319
|
+
if (inside && n.getClosestParentMatching(
|
|
320
|
+
editedNode,
|
|
321
|
+
(p) => p instanceof ListNode
|
|
322
|
+
) !== void 0)
|
|
323
|
+
includesList = true;
|
|
324
|
+
if (n === caretRange.end.node) inside = false;
|
|
325
|
+
});
|
|
326
|
+
const parents = editedNode.getParentsOf(caretRange.start.node)?.reverse();
|
|
327
|
+
return {
|
|
328
|
+
// We make a new range so that setCaretRange always causes a re-render
|
|
329
|
+
chapter,
|
|
330
|
+
range: { start: caretRange.start, end: caretRange.end },
|
|
331
|
+
start: caretRange.start,
|
|
332
|
+
end: caretRange.end,
|
|
333
|
+
isSelection: caretRange.start.node !== caretRange.end.node || caretRange.start.index !== caretRange.end.index,
|
|
334
|
+
root: editedNode,
|
|
335
|
+
blocks: parents?.find((n) => n instanceof BlocksNode),
|
|
336
|
+
paragraph: parents?.find(
|
|
337
|
+
(n) => n instanceof ParagraphNode
|
|
338
|
+
),
|
|
339
|
+
block: parents?.find((n) => n instanceof BlockNode),
|
|
340
|
+
code: parents?.find((n) => n instanceof CodeNode),
|
|
341
|
+
list: parents?.find((n) => n instanceof ListNode),
|
|
342
|
+
atom: parents?.find((n) => n instanceof AtomNode),
|
|
343
|
+
meta: parents?.find(
|
|
344
|
+
(n) => n instanceof MetadataNode
|
|
345
|
+
),
|
|
346
|
+
includesList,
|
|
347
|
+
table: parents?.find((n) => n instanceof TableNode),
|
|
348
|
+
formatRoot: caretRange.end.node instanceof TextNode || caretRange.end.node instanceof AtomNode ? caretRange.end.node.getFormatRoot(editedNode) : void 0,
|
|
349
|
+
startIsText: caretRange.start.node instanceof TextNode,
|
|
350
|
+
endIsText: caretRange.end.node instanceof TextNode,
|
|
351
|
+
startIsTextOrAtom: caretRange.start.node instanceof TextNode || caretRange.start.node instanceof AtomNode || caretRange.start.node instanceof EmbedNode,
|
|
352
|
+
endIsTextOrAtom: caretRange.end.node instanceof TextNode || caretRange.end.node instanceof AtomNode || caretRange.start.node instanceof EmbedNode,
|
|
353
|
+
atParagraphStart: atParagraphStart(),
|
|
354
|
+
undoStack,
|
|
355
|
+
undoPosition,
|
|
356
|
+
undo,
|
|
357
|
+
redo,
|
|
358
|
+
clipboard,
|
|
359
|
+
handleCopy,
|
|
360
|
+
handlePaste,
|
|
361
|
+
setAccent,
|
|
362
|
+
getAccent
|
|
363
|
+
};
|
|
469
364
|
}
|
|
470
365
|
function setAccent(newAccent) {
|
|
471
|
-
|
|
366
|
+
accent = newAccent;
|
|
472
367
|
}
|
|
473
368
|
function getAccent() {
|
|
474
|
-
|
|
369
|
+
return accent;
|
|
475
370
|
}
|
|
476
371
|
function getUtilities() {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
372
|
+
return {
|
|
373
|
+
getCaretOnLine
|
|
374
|
+
};
|
|
480
375
|
}
|
|
481
376
|
function handlePress(event) {
|
|
482
|
-
|
|
377
|
+
handleKey(event, true);
|
|
483
378
|
}
|
|
484
379
|
function handleKey(event, press = false) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if (
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
// See if the command is handled
|
|
518
|
-
if (executeCommand(command, event.key, event.code)) {
|
|
519
|
-
event.preventDefault();
|
|
520
|
-
event.stopPropagation();
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
|
-
// If not, this is not it.
|
|
524
|
-
else
|
|
525
|
-
return false;
|
|
526
|
-
}
|
|
527
|
-
// Continue searching for a matching command.
|
|
528
|
-
return false;
|
|
529
|
-
});
|
|
530
|
-
if (command === undefined) {
|
|
531
|
-
// Toolbar navigation
|
|
532
|
-
if (event.key === 'Escape') {
|
|
533
|
-
// If we've selected a FootnoteNode or Comment, navigate to the footnote or comment text to edit it.
|
|
534
|
-
if (caretRange.start.node instanceof AtomNode &&
|
|
535
|
-
caretRange.start.node.getMeta() instanceof FormatNode) {
|
|
536
|
-
const firstCaret = caretRange.start.node
|
|
537
|
-
.getMeta()
|
|
538
|
-
.getFirstCaret();
|
|
539
|
-
caretRange = { start: firstCaret, end: firstCaret };
|
|
540
|
-
event.preventDefault();
|
|
541
|
-
event.stopPropagation();
|
|
542
|
-
return true;
|
|
543
|
-
}
|
|
544
|
-
// If we're inside an atom node, select the atom itself.
|
|
545
|
-
else if (caretRange.start.node.isInside(editedNode, AtomNode)) {
|
|
546
|
-
const atom = caretRange.start.node.getClosestParentOfType(editedNode, AtomNode);
|
|
547
|
-
if (atom) {
|
|
548
|
-
const atomCaret = { node: atom, index: 0 };
|
|
549
|
-
caretRange = { start: atomCaret, end: atomCaret };
|
|
550
|
-
event.preventDefault();
|
|
551
|
-
event.stopPropagation();
|
|
552
|
-
return true;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
// Otherwise, if we have a reference to this editor's DOM element, find the nearest focusable element in it's toolbar and focus on that.
|
|
556
|
-
const controls = [
|
|
557
|
-
document.querySelector('.bookish-editor-toolbar [tabindex="0"]'),
|
|
558
|
-
document.querySelector('.bookish-editor-toolbar input'),
|
|
559
|
-
document.querySelector('.bookish-editor-toolbar select'),
|
|
560
|
-
document.querySelector('.bookish-editor-toolbar button'),
|
|
561
|
-
];
|
|
562
|
-
const match = controls.find((control) => control && control instanceof HTMLElement);
|
|
563
|
-
if (match && match instanceof HTMLElement) {
|
|
564
|
-
match.focus();
|
|
565
|
-
event.preventDefault();
|
|
566
|
-
event.stopPropagation();
|
|
567
|
-
return true;
|
|
568
|
-
}
|
|
380
|
+
if (!editorFocused) return;
|
|
381
|
+
lastInputTime = Date.now();
|
|
382
|
+
keyboardIdle = false;
|
|
383
|
+
if (caretRange === void 0) return;
|
|
384
|
+
const context = getCaretContext();
|
|
385
|
+
if (context === void 0) return;
|
|
386
|
+
const command = commands.find((command2) => {
|
|
387
|
+
if ((command2.press === void 0 || command2.press === press) && (command2.shift === void 0 || command2.shift === event.shiftKey) && (command2.alt === void 0 || command2.alt === event.altKey) && (command2.control === void 0 || command2.control === (event.ctrlKey || event.metaKey)) && (command2.key === void 0 || Array.isArray(command2.key) && command2.key.includes(event.key) || command2.key instanceof Function && command2.key(event.key) || command2.key === event.key) && (command2.code === void 0 || command2.code === event.code) && (command2.active === true || command2.active instanceof Function && command2.active.call(void 0, context, event.key))) {
|
|
388
|
+
if (executeCommand(command2, event.key, event.code)) {
|
|
389
|
+
event.preventDefault();
|
|
390
|
+
event.stopPropagation();
|
|
391
|
+
return true;
|
|
392
|
+
} else return false;
|
|
393
|
+
}
|
|
394
|
+
return false;
|
|
395
|
+
});
|
|
396
|
+
if (command === void 0) {
|
|
397
|
+
if (event.key === "Escape") {
|
|
398
|
+
if (caretRange.start.node instanceof AtomNode && caretRange.start.node.getMeta() instanceof FormatNode) {
|
|
399
|
+
const firstCaret = caretRange.start.node.getMeta().getFirstCaret();
|
|
400
|
+
caretRange = { start: firstCaret, end: firstCaret };
|
|
401
|
+
event.preventDefault();
|
|
402
|
+
event.stopPropagation();
|
|
403
|
+
return true;
|
|
404
|
+
} else if (caretRange.start.node.isInside(editedNode, AtomNode)) {
|
|
405
|
+
const atom = caretRange.start.node.getClosestParentOfType(editedNode, AtomNode);
|
|
406
|
+
if (atom) {
|
|
407
|
+
const atomCaret = { node: atom, index: 0 };
|
|
408
|
+
caretRange = { start: atomCaret, end: atomCaret };
|
|
409
|
+
event.preventDefault();
|
|
410
|
+
event.stopPropagation();
|
|
411
|
+
return true;
|
|
569
412
|
}
|
|
413
|
+
}
|
|
414
|
+
const controls = [
|
|
415
|
+
document.querySelector(
|
|
416
|
+
'.bookish-editor-toolbar [tabindex="0"]'
|
|
417
|
+
),
|
|
418
|
+
document.querySelector(".bookish-editor-toolbar input"),
|
|
419
|
+
document.querySelector(".bookish-editor-toolbar select"),
|
|
420
|
+
document.querySelector(".bookish-editor-toolbar button")
|
|
421
|
+
];
|
|
422
|
+
const match = controls.find(
|
|
423
|
+
(control) => control && control instanceof HTMLElement
|
|
424
|
+
);
|
|
425
|
+
if (match && match instanceof HTMLElement) {
|
|
426
|
+
match.focus();
|
|
427
|
+
event.preventDefault();
|
|
428
|
+
event.stopPropagation();
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
570
431
|
}
|
|
432
|
+
}
|
|
571
433
|
}
|
|
572
434
|
function executeCommand(command, key, code) {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}
|
|
435
|
+
ignoredInput = false;
|
|
436
|
+
const context = getCaretContext();
|
|
437
|
+
if (context && caretRange) {
|
|
438
|
+
const results = command.handler.call(
|
|
439
|
+
void 0,
|
|
440
|
+
context,
|
|
441
|
+
getUtilities(),
|
|
442
|
+
key,
|
|
443
|
+
code
|
|
444
|
+
);
|
|
445
|
+
if (results === true) {
|
|
446
|
+
return true;
|
|
447
|
+
} else if (results !== void 0) {
|
|
448
|
+
const { root, range } = results;
|
|
449
|
+
const newRange = { start: range.start, end: range.end };
|
|
450
|
+
if (root === editedNode && command.mutates)
|
|
451
|
+
console.error(
|
|
452
|
+
`Warning: immutability violation on ${command.description}`
|
|
453
|
+
);
|
|
454
|
+
caretRange = newRange;
|
|
455
|
+
if (command.category !== "navigation" && command.category !== "selection" && command.category !== "history") {
|
|
456
|
+
saveEdit(root, newRange, command);
|
|
457
|
+
}
|
|
458
|
+
return true;
|
|
459
|
+
} else {
|
|
460
|
+
ignoredInput = true;
|
|
461
|
+
return false;
|
|
601
462
|
}
|
|
602
|
-
|
|
463
|
+
}
|
|
464
|
+
return false;
|
|
603
465
|
}
|
|
604
466
|
async function saveEdit(newRoot, newRange, command) {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
// If the undo position is beyond the front, clear everything before it, because we're changing history.
|
|
635
|
-
},
|
|
636
|
-
...(undoPosition > 0 ? newStack.slice(undoPosition) : newStack),
|
|
637
|
-
];
|
|
638
|
-
// Set the undo position to the last index.
|
|
639
|
-
undoPosition = 0;
|
|
640
|
-
// Focus the editor on the new caret location, unless the toolbar is focused.
|
|
641
|
-
if (!toolbarIsFocused())
|
|
642
|
-
element?.focus();
|
|
643
|
-
// Update the caret
|
|
644
|
-
claimActiveEditor();
|
|
467
|
+
if (locked) return;
|
|
468
|
+
save(newRoot);
|
|
469
|
+
let newStack = undoStack.length > 0 ? undoStack : [];
|
|
470
|
+
if (undoStack.length === 0 && caretRange !== void 0) {
|
|
471
|
+
const currentRange = caretRangeToIndexRange(editedNode, caretRange);
|
|
472
|
+
if (currentRange !== void 0)
|
|
473
|
+
newStack = [
|
|
474
|
+
{
|
|
475
|
+
bookdown: editedNode.toBookdown(),
|
|
476
|
+
command: void 0,
|
|
477
|
+
range: currentRange
|
|
478
|
+
}
|
|
479
|
+
];
|
|
480
|
+
}
|
|
481
|
+
updateRoot(newRoot);
|
|
482
|
+
const newTextRange = caretRangeToIndexRange(newRoot, newRange);
|
|
483
|
+
if (newTextRange !== void 0)
|
|
484
|
+
undoStack = [
|
|
485
|
+
{
|
|
486
|
+
bookdown: newRoot.toBookdown(),
|
|
487
|
+
command,
|
|
488
|
+
range: newTextRange
|
|
489
|
+
// If the undo position is beyond the front, clear everything before it, because we're changing history.
|
|
490
|
+
},
|
|
491
|
+
...undoPosition > 0 ? newStack.slice(undoPosition) : newStack
|
|
492
|
+
];
|
|
493
|
+
undoPosition = 0;
|
|
494
|
+
if (!toolbarIsFocused()) element?.focus();
|
|
495
|
+
claimActiveEditor();
|
|
645
496
|
}
|
|
646
497
|
function updateRoot(newRoot) {
|
|
647
|
-
|
|
648
|
-
|
|
498
|
+
editedNode = newRoot;
|
|
499
|
+
text = editedNode.toBookdown();
|
|
649
500
|
}
|
|
650
501
|
function editNode(previous, edited) {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
caretRange = {
|
|
663
|
-
start: { node: edited, index: 0 },
|
|
664
|
-
end: { node: edited, index: 0 },
|
|
665
|
-
};
|
|
666
|
-
}
|
|
502
|
+
if (previous === edited) return;
|
|
503
|
+
if (caretRange) {
|
|
504
|
+
const newRoot = editedNode.withNodeReplaced(previous, edited);
|
|
505
|
+
if (newRoot === void 0) return;
|
|
506
|
+
saveEdit(newRoot, { start: caretRange.start, end: caretRange.end });
|
|
507
|
+
if (caretRange.start.node === previous && (edited instanceof AtomNode || edited instanceof TextNode))
|
|
508
|
+
caretRange = {
|
|
509
|
+
start: { node: edited, index: 0 },
|
|
510
|
+
end: { node: edited, index: 0 }
|
|
511
|
+
};
|
|
512
|
+
}
|
|
667
513
|
}
|
|
668
514
|
function handlePointerDown() {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
// If we've selected a non-TextNode, release it, so the browser is free to select a text node.
|
|
677
|
-
if (caretRange &&
|
|
678
|
-
!(caretRange.start.node instanceof TextNode ||
|
|
679
|
-
caretRange.start.node instanceof AtomNode ||
|
|
680
|
-
caretRange.start.node instanceof EmbedNode)) {
|
|
681
|
-
caretRange = undefined;
|
|
682
|
-
}
|
|
515
|
+
if (!element) return;
|
|
516
|
+
element.focus();
|
|
517
|
+
if (caretRange)
|
|
518
|
+
caretRange = { start: caretRange.start, end: caretRange.end };
|
|
519
|
+
if (caretRange && !(caretRange.start.node instanceof TextNode || caretRange.start.node instanceof AtomNode || caretRange.start.node instanceof EmbedNode)) {
|
|
520
|
+
caretRange = void 0;
|
|
521
|
+
}
|
|
683
522
|
}
|
|
684
523
|
function isFocused() {
|
|
685
|
-
|
|
686
|
-
(element !== null && element?.contains(document.activeElement)) ||
|
|
687
|
-
toolbarIsFocused());
|
|
524
|
+
return document.activeElement === element || element !== null && element?.contains(document.activeElement) || toolbarIsFocused();
|
|
688
525
|
}
|
|
689
526
|
function handleFocus() {
|
|
690
|
-
|
|
691
|
-
|
|
527
|
+
editorFocused = isFocused();
|
|
528
|
+
lease(true);
|
|
692
529
|
}
|
|
693
530
|
function handleBlur() {
|
|
694
|
-
|
|
695
|
-
|
|
531
|
+
editorFocused = isFocused();
|
|
532
|
+
lease(false);
|
|
696
533
|
}
|
|
697
534
|
function handleCopy(node) {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
window.alert("Your browser doesn't support copying to the clipboard :(");
|
|
535
|
+
clipboard = node;
|
|
536
|
+
if (navigator.clipboard) {
|
|
537
|
+
navigator.clipboard.write([
|
|
538
|
+
new ClipboardItem({
|
|
539
|
+
"text/plain": new Blob([node.toText()], {
|
|
540
|
+
type: "text/plain"
|
|
541
|
+
}),
|
|
542
|
+
"text/html": new Blob([node.toHTML()], {
|
|
543
|
+
type: "text/html"
|
|
544
|
+
})
|
|
545
|
+
})
|
|
546
|
+
]);
|
|
547
|
+
} else
|
|
548
|
+
window.alert(
|
|
549
|
+
"Your browser doesn't support copying to the clipboard :("
|
|
550
|
+
);
|
|
715
551
|
}
|
|
716
|
-
function handlePaste(context,
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
// Escape all reserved Bookdown characters.
|
|
723
|
-
const escaped = text.plain.replaceAll(Reserved, '\\$1');
|
|
724
|
-
const chapter =
|
|
552
|
+
function handlePaste(context, text2, save2) {
|
|
553
|
+
if (text2 instanceof BookishNode)
|
|
554
|
+
return handlePasteNode(context, text2, save2);
|
|
555
|
+
if (text2.plain === void 0) return void 0;
|
|
556
|
+
const escaped = text2.plain.replaceAll(Reserved, "\\$1");
|
|
557
|
+
const chapter2 = (
|
|
725
558
|
// If we're pasting text into a paragraph node, then we parse it as a series of paragraphs.
|
|
726
|
-
context.block instanceof ParagraphNode && context.atom ===
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
559
|
+
context.block instanceof ParagraphNode && context.atom === void 0 ? Parser.parseChapter(void 0, escaped) : (
|
|
560
|
+
// Otherwise parse as just a format node, replacing all text newlines with a space.
|
|
561
|
+
Parser.parseFormat(void 0, escaped.replaceAll("\n", " "))
|
|
562
|
+
)
|
|
563
|
+
);
|
|
564
|
+
const edit = handlePasteNode(context, chapter2, save2);
|
|
565
|
+
if (edit) return edit;
|
|
566
|
+
return void 0;
|
|
734
567
|
}
|
|
735
|
-
function handlePasteNode(context, node,
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
if (
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
// Insert the node at the caret.
|
|
764
|
-
if (parent !== undefined && edit !== undefined) {
|
|
765
|
-
const newChapter = context.root.withNodeReplaced(parent, edit.root);
|
|
766
|
-
if (newChapter === undefined)
|
|
767
|
-
return;
|
|
768
|
-
if (save) {
|
|
769
|
-
// Set the range to force a rerender, assuming something in the document changed.
|
|
770
|
-
caretRange = edit.range;
|
|
771
|
-
// Save the copy in the undo stack if this isn't a navigation or selection state.
|
|
772
|
-
saveEdit(newChapter, edit.range);
|
|
773
|
-
}
|
|
774
|
-
else
|
|
775
|
-
return { root: newChapter, range: edit.range };
|
|
776
|
-
}
|
|
568
|
+
function handlePasteNode(context, node, save2) {
|
|
569
|
+
let newRoot = context.root;
|
|
570
|
+
let newCaret = context.start;
|
|
571
|
+
if (context.isSelection) {
|
|
572
|
+
const edit2 = newRoot.withRangeFormatted(context.range, void 0);
|
|
573
|
+
if (edit2 === void 0 || !(edit2.root instanceof ChapterNode))
|
|
574
|
+
return;
|
|
575
|
+
newRoot = edit2.root;
|
|
576
|
+
newCaret = edit2.range.start;
|
|
577
|
+
}
|
|
578
|
+
const parents = context.root.getParentsOf(newCaret.node);
|
|
579
|
+
if (parents === void 0) return;
|
|
580
|
+
let edit = void 0;
|
|
581
|
+
let parent = void 0;
|
|
582
|
+
while (parents.length > 0) {
|
|
583
|
+
parent = parents.pop();
|
|
584
|
+
if (parent === void 0) break;
|
|
585
|
+
edit = parent.withNodeInserted(newCaret, node.copy());
|
|
586
|
+
if (edit !== void 0) break;
|
|
587
|
+
}
|
|
588
|
+
if (parent !== void 0 && edit !== void 0) {
|
|
589
|
+
const newChapter = context.root.withNodeReplaced(parent, edit.root);
|
|
590
|
+
if (newChapter === void 0) return;
|
|
591
|
+
if (save2) {
|
|
592
|
+
caretRange = edit.range;
|
|
593
|
+
saveEdit(newChapter, edit.range);
|
|
594
|
+
} else return { root: newChapter, range: edit.range };
|
|
595
|
+
}
|
|
777
596
|
}
|
|
778
597
|
function toolbarIsFocused() {
|
|
779
|
-
|
|
780
|
-
|
|
598
|
+
const toolbar = document.querySelector(".bookish-editor-toolbar");
|
|
599
|
+
return toolbar !== null && toolbar.contains(document.activeElement);
|
|
781
600
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
601
|
+
let isAtom = $derived.by(
|
|
602
|
+
() => caretRange !== void 0 && caretRange.start.node instanceof AtomNode
|
|
603
|
+
);
|
|
604
|
+
let inAtom = $derived.by(
|
|
605
|
+
() => caretRange !== void 0 && caretRange.start.node.isInside(editedNode, AtomNode)
|
|
606
|
+
);
|
|
607
|
+
let isSelection = $derived.by(
|
|
608
|
+
() => caretRange !== void 0 && (caretRange.start.node !== caretRange.end.node || caretRange.start.index !== caretRange.end.index)
|
|
609
|
+
);
|
|
610
|
+
let isItalic = $derived.by(
|
|
611
|
+
() => caretRange !== void 0 && isSelection === false && caretRange.start.node instanceof TextNode && caretRange.start.node.isItalic(editedNode)
|
|
612
|
+
);
|
|
613
|
+
let isBold = $derived.by(
|
|
614
|
+
() => caretRange !== void 0 && isSelection === false && caretRange.start.node instanceof TextNode && caretRange.start.node.isBold(editedNode)
|
|
615
|
+
);
|
|
616
|
+
let isLink = $derived.by(
|
|
617
|
+
() => caretRange !== void 0 && isSelection === false && caretRange.start.node.getClosestParentMatching(
|
|
618
|
+
editedNode,
|
|
619
|
+
(p) => p instanceof LinkNode
|
|
620
|
+
) !== void 0
|
|
621
|
+
);
|
|
622
|
+
$effect.pre(() => {
|
|
623
|
+
void caretRange;
|
|
624
|
+
void editorFocused;
|
|
625
|
+
untrack(() => {
|
|
805
626
|
if ((caretRange || editorFocused) && isFocused())
|
|
806
|
-
|
|
807
|
-
else
|
|
808
|
-
|
|
809
|
-
}
|
|
627
|
+
claimActiveEditor();
|
|
628
|
+
else activeEditor.set(void 0);
|
|
629
|
+
});
|
|
630
|
+
});
|
|
810
631
|
function claimActiveEditor() {
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
632
|
+
activeEditor.set({
|
|
633
|
+
range: caretRange,
|
|
634
|
+
coordinate: caretCoordinate,
|
|
635
|
+
setCaret: (range) => {
|
|
636
|
+
caretRange = range;
|
|
637
|
+
element?.focus();
|
|
638
|
+
},
|
|
639
|
+
edit: editNode,
|
|
640
|
+
executor: executeCommand,
|
|
641
|
+
context: getCaretContext(),
|
|
642
|
+
root: editedNode,
|
|
643
|
+
focused: editorFocused
|
|
644
|
+
});
|
|
824
645
|
}
|
|
825
|
-
|
|
826
|
-
// (Drag and drop, for example.)
|
|
827
|
-
setContext('claimeditor', claimActiveEditor);
|
|
646
|
+
setContext("claimeditor", claimActiveEditor);
|
|
828
647
|
</script>
|
|
829
648
|
|
|
830
649
|
<div
|
|
@@ -834,15 +653,18 @@ setContext('claimeditor', claimActiveEditor);
|
|
|
834
653
|
aria-disabled={locked}
|
|
835
654
|
role="textbox"
|
|
836
655
|
bind:this={element}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
656
|
+
onkeydown={handleKey}
|
|
657
|
+
onkeypress={handlePress}
|
|
658
|
+
onpointerdown={(event) => {
|
|
659
|
+
event.stopPropagation();
|
|
660
|
+
handlePointerDown();
|
|
661
|
+
}}
|
|
662
|
+
onfocus={handleFocus}
|
|
663
|
+
onblur={handleBlur}
|
|
842
664
|
tabindex="0"
|
|
843
665
|
>
|
|
844
666
|
<!-- A view of the root -->
|
|
845
|
-
<
|
|
667
|
+
<RootView node={editedNode} {placeholder} />
|
|
846
668
|
<!-- The caret. We render our own since this view isn't contentEditable and we can't show a caret.
|
|
847
669
|
Customize the rendering based on the formatting applied to the text node. -->
|
|
848
670
|
{#if caretCoordinate && caretRange && !isAtom && isSelection === false && editorFocused}
|