quasar-ui-danx 0.4.99 → 0.5.1

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 (90) hide show
  1. package/dist/danx.es.js +17884 -12732
  2. package/dist/danx.es.js.map +1 -1
  3. package/dist/danx.umd.js +192 -118
  4. package/dist/danx.umd.js.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +11 -2
  7. package/scripts/publish.sh +76 -0
  8. package/src/components/Utility/Code/CodeViewer.vue +31 -14
  9. package/src/components/Utility/Code/CodeViewerCollapsed.vue +2 -0
  10. package/src/components/Utility/Code/CodeViewerFooter.vue +1 -1
  11. package/src/components/Utility/Code/LanguageBadge.vue +278 -5
  12. package/src/components/Utility/Code/MarkdownContent.vue +160 -6
  13. package/src/components/Utility/Code/index.ts +3 -0
  14. package/src/components/Utility/Markdown/ContextMenu.vue +314 -0
  15. package/src/components/Utility/Markdown/HotkeyHelpPopover.vue +259 -0
  16. package/src/components/Utility/Markdown/LineTypeMenu.vue +226 -0
  17. package/src/components/Utility/Markdown/LinkPopover.vue +331 -0
  18. package/src/components/Utility/Markdown/MarkdownEditor.vue +228 -0
  19. package/src/components/Utility/Markdown/MarkdownEditorContent.vue +235 -0
  20. package/src/components/Utility/Markdown/MarkdownEditorFooter.vue +50 -0
  21. package/src/components/Utility/Markdown/TablePopover.vue +420 -0
  22. package/src/components/Utility/Markdown/index.ts +11 -0
  23. package/src/components/Utility/Markdown/types.ts +27 -0
  24. package/src/components/Utility/index.ts +1 -0
  25. package/src/composables/index.ts +1 -0
  26. package/src/composables/markdown/features/useBlockquotes.spec.ts +428 -0
  27. package/src/composables/markdown/features/useBlockquotes.ts +248 -0
  28. package/src/composables/markdown/features/useCodeBlockManager.ts +369 -0
  29. package/src/composables/markdown/features/useCodeBlocks.spec.ts +779 -0
  30. package/src/composables/markdown/features/useCodeBlocks.ts +774 -0
  31. package/src/composables/markdown/features/useContextMenu.ts +444 -0
  32. package/src/composables/markdown/features/useFocusTracking.ts +116 -0
  33. package/src/composables/markdown/features/useHeadings.spec.ts +834 -0
  34. package/src/composables/markdown/features/useHeadings.ts +290 -0
  35. package/src/composables/markdown/features/useInlineFormatting.spec.ts +705 -0
  36. package/src/composables/markdown/features/useInlineFormatting.ts +402 -0
  37. package/src/composables/markdown/features/useLineTypeMenu.ts +285 -0
  38. package/src/composables/markdown/features/useLinks.spec.ts +369 -0
  39. package/src/composables/markdown/features/useLinks.ts +374 -0
  40. package/src/composables/markdown/features/useLists.spec.ts +834 -0
  41. package/src/composables/markdown/features/useLists.ts +747 -0
  42. package/src/composables/markdown/features/usePopoverManager.ts +181 -0
  43. package/src/composables/markdown/features/useTables.spec.ts +1601 -0
  44. package/src/composables/markdown/features/useTables.ts +1107 -0
  45. package/src/composables/markdown/index.ts +16 -0
  46. package/src/composables/markdown/useMarkdownEditor.spec.ts +332 -0
  47. package/src/composables/markdown/useMarkdownEditor.ts +1068 -0
  48. package/src/composables/markdown/useMarkdownHotkeys.spec.ts +791 -0
  49. package/src/composables/markdown/useMarkdownHotkeys.ts +266 -0
  50. package/src/composables/markdown/useMarkdownSelection.ts +219 -0
  51. package/src/composables/markdown/useMarkdownSync.ts +549 -0
  52. package/src/composables/useCodeViewerEditor.spec.ts +655 -0
  53. package/src/composables/useCodeViewerEditor.ts +174 -20
  54. package/src/helpers/formats/index.ts +1 -1
  55. package/src/helpers/formats/markdown/escapeHtml.ts +15 -0
  56. package/src/helpers/formats/markdown/escapeSequences.ts +60 -0
  57. package/src/helpers/formats/markdown/htmlToMarkdown/convertHeadings.ts +41 -0
  58. package/src/helpers/formats/markdown/htmlToMarkdown/index.spec.ts +489 -0
  59. package/src/helpers/formats/markdown/htmlToMarkdown/index.ts +412 -0
  60. package/src/helpers/formats/markdown/index.ts +92 -0
  61. package/src/helpers/formats/markdown/linePatterns.spec.ts +495 -0
  62. package/src/helpers/formats/markdown/linePatterns.ts +172 -0
  63. package/src/helpers/formats/markdown/parseInline.ts +124 -0
  64. package/src/helpers/formats/markdown/render/index.ts +92 -0
  65. package/src/helpers/formats/markdown/render/renderFootnotes.ts +30 -0
  66. package/src/helpers/formats/markdown/render/renderList.ts +69 -0
  67. package/src/helpers/formats/markdown/render/renderTable.ts +38 -0
  68. package/src/helpers/formats/markdown/state.ts +58 -0
  69. package/src/helpers/formats/markdown/tokenize/extractDefinitions.ts +39 -0
  70. package/src/helpers/formats/markdown/tokenize/index.ts +139 -0
  71. package/src/helpers/formats/markdown/tokenize/parseBlockquote.ts +34 -0
  72. package/src/helpers/formats/markdown/tokenize/parseCodeBlock.ts +85 -0
  73. package/src/helpers/formats/markdown/tokenize/parseDefinitionList.ts +88 -0
  74. package/src/helpers/formats/markdown/tokenize/parseHeading.ts +65 -0
  75. package/src/helpers/formats/markdown/tokenize/parseHorizontalRule.ts +22 -0
  76. package/src/helpers/formats/markdown/tokenize/parseList.ts +119 -0
  77. package/src/helpers/formats/markdown/tokenize/parseParagraph.ts +59 -0
  78. package/src/helpers/formats/markdown/tokenize/parseTable.ts +70 -0
  79. package/src/helpers/formats/markdown/tokenize/parseTaskList.ts +47 -0
  80. package/src/helpers/formats/markdown/tokenize/utils.ts +25 -0
  81. package/src/helpers/formats/markdown/types.ts +63 -0
  82. package/src/styles/danx.scss +1 -0
  83. package/src/styles/themes/danx/markdown.scss +96 -0
  84. package/src/test/helpers/editorTestUtils.spec.ts +296 -0
  85. package/src/test/helpers/editorTestUtils.ts +253 -0
  86. package/src/test/helpers/index.ts +1 -0
  87. package/src/test/setup.test.ts +12 -0
  88. package/src/test/setup.ts +12 -0
  89. package/vitest.config.ts +19 -0
  90. package/src/helpers/formats/renderMarkdown.ts +0 -338
@@ -0,0 +1,266 @@
1
+ import { Ref, ref } from "vue";
2
+
3
+ /**
4
+ * Hotkey group categories for organization
5
+ */
6
+ export type HotkeyGroup = "headings" | "formatting" | "lists" | "blocks" | "tables" | "other";
7
+
8
+ /**
9
+ * Definition for a registered hotkey
10
+ */
11
+ export interface HotkeyDefinition {
12
+ /** Key combination string, e.g., 'ctrl+1', 'ctrl+shift+b' */
13
+ key: string;
14
+ /** Action to execute when hotkey is triggered */
15
+ action: () => void;
16
+ /** Human-readable description for help display */
17
+ description: string;
18
+ /** Category group for help organization */
19
+ group: HotkeyGroup;
20
+ }
21
+
22
+ /**
23
+ * Options for useMarkdownHotkeys composable
24
+ */
25
+ export interface UseMarkdownHotkeysOptions {
26
+ contentRef: Ref<HTMLElement | null>;
27
+ onShowHotkeyHelp: () => void;
28
+ }
29
+
30
+ /**
31
+ * Return type for useMarkdownHotkeys composable
32
+ */
33
+ export interface UseMarkdownHotkeysReturn {
34
+ registerHotkey: (def: HotkeyDefinition) => void;
35
+ unregisterHotkey: (key: string) => void;
36
+ handleKeyDown: (event: KeyboardEvent) => boolean;
37
+ getHotkeyDefinitions: () => HotkeyDefinition[];
38
+ }
39
+
40
+ /**
41
+ * Parsed key combination for matching
42
+ */
43
+ export interface ParsedKey {
44
+ key: string;
45
+ ctrl: boolean;
46
+ shift: boolean;
47
+ alt: boolean;
48
+ meta: boolean;
49
+ }
50
+
51
+ /**
52
+ * Parse a key combination string into its components
53
+ * Supports: ctrl, shift, alt, meta/cmd
54
+ *
55
+ * Examples:
56
+ * - 'ctrl+1' -> { key: '1', ctrl: true, ... }
57
+ * - 'ctrl+shift+b' -> { key: 'b', ctrl: true, shift: true, ... }
58
+ * - 'cmd+s' -> { key: 's', meta: true, ... } (Mac)
59
+ */
60
+ export function parseKeyCombo(combo: string): ParsedKey {
61
+ const parts = combo.toLowerCase().split("+");
62
+ const result: ParsedKey = {
63
+ key: "",
64
+ ctrl: false,
65
+ shift: false,
66
+ alt: false,
67
+ meta: false
68
+ };
69
+
70
+ for (const part of parts) {
71
+ switch (part) {
72
+ case "ctrl":
73
+ case "control":
74
+ result.ctrl = true;
75
+ break;
76
+ case "shift":
77
+ result.shift = true;
78
+ break;
79
+ case "alt":
80
+ case "option":
81
+ result.alt = true;
82
+ break;
83
+ case "meta":
84
+ case "cmd":
85
+ case "command":
86
+ case "win":
87
+ case "windows":
88
+ result.meta = true;
89
+ break;
90
+ default:
91
+ // This is the actual key
92
+ result.key = part;
93
+ }
94
+ }
95
+
96
+ return result;
97
+ }
98
+
99
+ /**
100
+ * Check if a keyboard event matches a parsed key combination
101
+ * Handles cross-platform modifier differences (Ctrl on Windows/Linux, Cmd on Mac)
102
+ */
103
+ export function matchesKeyCombo(event: KeyboardEvent, parsed: ParsedKey): boolean {
104
+ // Normalize the event key
105
+ let eventKey = event.key.toLowerCase();
106
+
107
+ // Normalize arrow keys: ArrowUp -> up, ArrowDown -> down, etc.
108
+ if (eventKey.startsWith("arrow")) {
109
+ eventKey = eventKey.replace("arrow", "");
110
+ }
111
+
112
+ // Special handling for shifted keys
113
+ // When shift is held, some keys produce different characters
114
+ const shiftedKeys: Record<string, string> = {
115
+ ">": ".",
116
+ "<": ",",
117
+ "?": "/",
118
+ "!": "1",
119
+ "@": "2",
120
+ "#": "3",
121
+ "$": "4",
122
+ "%": "5",
123
+ "^": "6",
124
+ "&": "7",
125
+ "*": "8",
126
+ "(": "9",
127
+ ")": "0",
128
+ "{": "[",
129
+ "}": "]"
130
+ };
131
+
132
+ // If the parsed key expects a shifted character, check if we have the right combination
133
+ if (shiftedKeys[parsed.key]) {
134
+ // User wants to match '>' which is shift+.
135
+ if (eventKey === parsed.key) {
136
+ // Browser reports the shifted character directly
137
+ return matchesModifiers(event, { ...parsed, shift: true });
138
+ }
139
+ // Or check if shift+base key matches
140
+ if (event.shiftKey && eventKey === shiftedKeys[parsed.key]) {
141
+ return matchesModifiers(event, { ...parsed, shift: true });
142
+ }
143
+ }
144
+
145
+ // Handle case where browser reports shifted character but hotkey expects base key with shift
146
+ // e.g., hotkey "ctrl+shift+[" but browser reports "{" when Ctrl+Shift+[ is pressed
147
+ if (shiftedKeys[eventKey] && shiftedKeys[eventKey] === parsed.key) {
148
+ // The event key is a shifted character (e.g., "{") that maps to the parsed key (e.g., "[")
149
+ return matchesModifiers(event, parsed);
150
+ }
151
+
152
+ // Handle number keys (both main keyboard and numpad)
153
+ if (/^[0-6]$/.test(parsed.key)) {
154
+ if (eventKey !== parsed.key && event.code !== `Digit${parsed.key}` && event.code !== `Numpad${parsed.key}`) {
155
+ return false;
156
+ }
157
+ } else if (eventKey !== parsed.key) {
158
+ return false;
159
+ }
160
+
161
+ return matchesModifiers(event, parsed);
162
+ }
163
+
164
+ /**
165
+ * Check if modifier keys match
166
+ * On Mac, treat Cmd (metaKey) as equivalent to Ctrl for cross-platform support
167
+ */
168
+ function matchesModifiers(event: KeyboardEvent, parsed: ParsedKey): boolean {
169
+ const isMac = navigator.platform.toLowerCase().includes("mac");
170
+
171
+ // For cross-platform support:
172
+ // - If hotkey specifies 'ctrl', match either ctrlKey or metaKey (on Mac)
173
+ // - If hotkey specifies 'meta', match metaKey only
174
+ let ctrlMatch: boolean;
175
+ if (parsed.ctrl) {
176
+ if (isMac) {
177
+ // On Mac, ctrl+key can be either Ctrl+key or Cmd+key
178
+ ctrlMatch = event.ctrlKey || event.metaKey;
179
+ } else {
180
+ ctrlMatch = event.ctrlKey;
181
+ }
182
+ } else if (parsed.meta) {
183
+ ctrlMatch = event.metaKey;
184
+ } else {
185
+ // No modifier required, ensure neither is pressed
186
+ ctrlMatch = !event.ctrlKey && !event.metaKey;
187
+ }
188
+
189
+ // Check other modifiers exactly
190
+ const shiftMatch = parsed.shift === event.shiftKey;
191
+ const altMatch = parsed.alt === event.altKey;
192
+
193
+ return ctrlMatch && shiftMatch && altMatch;
194
+ }
195
+
196
+ /**
197
+ * Composable for hotkey registration and dispatch in markdown editor
198
+ */
199
+ export function useMarkdownHotkeys(options: UseMarkdownHotkeysOptions): UseMarkdownHotkeysReturn {
200
+ const { onShowHotkeyHelp } = options;
201
+
202
+ // Registry of all hotkeys
203
+ const hotkeys = ref<Map<string, HotkeyDefinition>>(new Map());
204
+
205
+ // Pre-parsed key combinations for performance
206
+ const parsedKeys = new Map<string, ParsedKey>();
207
+
208
+ /**
209
+ * Register a new hotkey
210
+ */
211
+ function registerHotkey(def: HotkeyDefinition): void {
212
+ const normalizedKey = def.key.toLowerCase();
213
+ hotkeys.value.set(normalizedKey, def);
214
+ parsedKeys.set(normalizedKey, parseKeyCombo(normalizedKey));
215
+ }
216
+
217
+ /**
218
+ * Unregister a hotkey
219
+ */
220
+ function unregisterHotkey(key: string): void {
221
+ const normalizedKey = key.toLowerCase();
222
+ hotkeys.value.delete(normalizedKey);
223
+ parsedKeys.delete(normalizedKey);
224
+ }
225
+
226
+ /**
227
+ * Get all registered hotkey definitions for help display
228
+ */
229
+ function getHotkeyDefinitions(): HotkeyDefinition[] {
230
+ return Array.from(hotkeys.value.values());
231
+ }
232
+
233
+ /**
234
+ * Handle a keydown event and dispatch to registered hotkey
235
+ * Returns true if a hotkey was matched and handled
236
+ */
237
+ function handleKeyDown(event: KeyboardEvent): boolean {
238
+ // Check for help shortcut first (Ctrl/Cmd + / or Ctrl/Cmd + ?)
239
+ // Supports both Ctrl+/ (without shift) and Ctrl+? (which is Ctrl+Shift+/)
240
+ if ((event.ctrlKey || event.metaKey) && (event.key === "?" || event.key === "/")) {
241
+ event.preventDefault();
242
+ onShowHotkeyHelp();
243
+ return true;
244
+ }
245
+
246
+ // Check all registered hotkeys
247
+ for (const [key, def] of hotkeys.value) {
248
+ const parsed = parsedKeys.get(key);
249
+
250
+ if (parsed && matchesKeyCombo(event, parsed)) {
251
+ event.preventDefault();
252
+ def.action();
253
+ return true;
254
+ }
255
+ }
256
+
257
+ return false;
258
+ }
259
+
260
+ return {
261
+ registerHotkey,
262
+ unregisterHotkey,
263
+ handleKeyDown,
264
+ getHotkeyDefinitions
265
+ };
266
+ }
@@ -0,0 +1,219 @@
1
+ import { Ref } from "vue";
2
+
3
+ /**
4
+ * Cursor position tracking for markdown editor
5
+ */
6
+ export interface CursorPosition {
7
+ /** Index of the block element containing the cursor */
8
+ blockIndex: number;
9
+ /** Character offset within the block */
10
+ charOffset: number;
11
+ }
12
+
13
+ /**
14
+ * Return type for useMarkdownSelection composable
15
+ */
16
+ export interface UseMarkdownSelectionReturn {
17
+ saveCursorPosition: () => CursorPosition | null;
18
+ restoreCursorPosition: (position: CursorPosition) => void;
19
+ getCurrentBlock: () => Element | null;
20
+ getBlockIndex: () => number;
21
+ }
22
+
23
+ /**
24
+ * Get cursor offset in plain text within a contenteditable element
25
+ * Adapted from useCodeViewerEditor.ts
26
+ */
27
+ function getCursorOffset(element: HTMLElement | null): number {
28
+ const selection = window.getSelection();
29
+ if (!selection || !selection.rangeCount || !element) return 0;
30
+
31
+ const range = selection.getRangeAt(0);
32
+ const preCaretRange = document.createRange();
33
+ preCaretRange.selectNodeContents(element);
34
+ preCaretRange.setEnd(range.startContainer, range.startOffset);
35
+
36
+ // Count characters by walking text nodes
37
+ let offset = 0;
38
+ const walker = document.createTreeWalker(preCaretRange.commonAncestorContainer, NodeFilter.SHOW_TEXT);
39
+ let node = walker.nextNode();
40
+ while (node) {
41
+ if (preCaretRange.intersectsNode(node)) {
42
+ const nodeRange = document.createRange();
43
+ nodeRange.selectNodeContents(node);
44
+ if (preCaretRange.compareBoundaryPoints(Range.END_TO_END, nodeRange) >= 0) {
45
+ offset += node.textContent?.length || 0;
46
+ } else {
47
+ // Partial node - cursor is in this node
48
+ offset += range.startOffset;
49
+ break;
50
+ }
51
+ }
52
+ node = walker.nextNode();
53
+ }
54
+ return offset;
55
+ }
56
+
57
+ /**
58
+ * Set cursor to offset in plain text within a contenteditable element
59
+ * Adapted from useCodeViewerEditor.ts
60
+ */
61
+ function setCursorOffset(element: HTMLElement | null, targetOffset: number): void {
62
+ if (!element) return;
63
+
64
+ const selection = window.getSelection();
65
+ if (!selection) return;
66
+
67
+ let currentOffset = 0;
68
+ const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
69
+ let node = walker.nextNode();
70
+
71
+ while (node) {
72
+ const nodeLength = node.textContent?.length || 0;
73
+ if (currentOffset + nodeLength >= targetOffset) {
74
+ const range = document.createRange();
75
+ range.setStart(node, targetOffset - currentOffset);
76
+ range.collapse(true);
77
+ selection.removeAllRanges();
78
+ selection.addRange(range);
79
+ return;
80
+ }
81
+ currentOffset += nodeLength;
82
+ node = walker.nextNode();
83
+ }
84
+
85
+ // If offset not found, place at end
86
+ const range = document.createRange();
87
+ range.selectNodeContents(element);
88
+ range.collapse(false);
89
+ selection.removeAllRanges();
90
+ selection.addRange(range);
91
+ }
92
+
93
+ /**
94
+ * Get the block-level parent element (p, h1-h6, li, blockquote, etc.) containing the cursor
95
+ */
96
+ function findBlockParent(node: Node | null, contentRef: HTMLElement): Element | null {
97
+ if (!node) return null;
98
+
99
+ const blockTags = ["P", "H1", "H2", "H3", "H4", "H5", "H6", "LI", "BLOCKQUOTE", "PRE", "DIV"];
100
+
101
+ let current: Node | null = node;
102
+ while (current && current !== contentRef) {
103
+ if (current.nodeType === Node.ELEMENT_NODE) {
104
+ const element = current as Element;
105
+ if (blockTags.includes(element.tagName)) {
106
+ return element;
107
+ }
108
+ }
109
+ current = current.parentNode;
110
+ }
111
+
112
+ return null;
113
+ }
114
+
115
+ /**
116
+ * Get all direct block children of the content element
117
+ */
118
+ function getBlockElements(contentRef: HTMLElement): Element[] {
119
+ const blocks: Element[] = [];
120
+ const blockTags = ["P", "H1", "H2", "H3", "H4", "H5", "H6", "UL", "OL", "BLOCKQUOTE", "PRE", "DIV", "TABLE", "HR"];
121
+
122
+ for (const child of Array.from(contentRef.children)) {
123
+ if (blockTags.includes(child.tagName)) {
124
+ blocks.push(child);
125
+ }
126
+ }
127
+
128
+ return blocks;
129
+ }
130
+
131
+ /**
132
+ * Composable for cursor and selection management in markdown editor
133
+ */
134
+ export function useMarkdownSelection(contentRef: Ref<HTMLElement | null>): UseMarkdownSelectionReturn {
135
+ /**
136
+ * Get the current block element containing the cursor
137
+ */
138
+ function getCurrentBlock(): Element | null {
139
+ if (!contentRef.value) return null;
140
+
141
+ const selection = window.getSelection();
142
+ if (!selection || !selection.rangeCount) return null;
143
+
144
+ const range = selection.getRangeAt(0);
145
+ return findBlockParent(range.startContainer, contentRef.value);
146
+ }
147
+
148
+ /**
149
+ * Get the index of the current block within the content element
150
+ */
151
+ function getBlockIndex(): number {
152
+ if (!contentRef.value) return -1;
153
+
154
+ const currentBlock = getCurrentBlock();
155
+ if (!currentBlock) return -1;
156
+
157
+ const blocks = getBlockElements(contentRef.value);
158
+ return blocks.indexOf(currentBlock);
159
+ }
160
+
161
+ /**
162
+ * Save current cursor position as block index + character offset
163
+ */
164
+ function saveCursorPosition(): CursorPosition | null {
165
+ if (!contentRef.value) return null;
166
+
167
+ const selection = window.getSelection();
168
+ if (!selection || !selection.rangeCount) return null;
169
+
170
+ const currentBlock = getCurrentBlock();
171
+ if (!currentBlock) {
172
+ // Cursor is not in a block, save position relative to content root
173
+ return {
174
+ blockIndex: -1,
175
+ charOffset: getCursorOffset(contentRef.value)
176
+ };
177
+ }
178
+
179
+ const blocks = getBlockElements(contentRef.value);
180
+ const blockIndex = blocks.indexOf(currentBlock);
181
+ const charOffset = getCursorOffset(currentBlock as HTMLElement);
182
+
183
+ return { blockIndex, charOffset };
184
+ }
185
+
186
+ /**
187
+ * Restore cursor position from saved state
188
+ */
189
+ function restoreCursorPosition(position: CursorPosition): void {
190
+ if (!contentRef.value) return;
191
+
192
+ if (position.blockIndex === -1) {
193
+ // Restore to content root level
194
+ setCursorOffset(contentRef.value, position.charOffset);
195
+ return;
196
+ }
197
+
198
+ const blocks = getBlockElements(contentRef.value);
199
+ if (position.blockIndex >= 0 && position.blockIndex < blocks.length) {
200
+ const block = blocks[position.blockIndex] as HTMLElement;
201
+ setCursorOffset(block, position.charOffset);
202
+ } else {
203
+ // Block no longer exists, place cursor at end
204
+ const range = document.createRange();
205
+ range.selectNodeContents(contentRef.value);
206
+ range.collapse(false);
207
+ const selection = window.getSelection();
208
+ selection?.removeAllRanges();
209
+ selection?.addRange(range);
210
+ }
211
+ }
212
+
213
+ return {
214
+ saveCursorPosition,
215
+ restoreCursorPosition,
216
+ getCurrentBlock,
217
+ getBlockIndex
218
+ };
219
+ }