notations 1.0.2 → 1.0.4
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/dist/notations.umd.js +3933 -12155
- package/dist/notations.umd.min.js +2 -3
- package/dist/notations.umd.min.js.map +1 -1
- package/lib/cjs/parser.js +1 -1
- package/lib/cjs/parser.js.map +1 -1
- package/lib/cjs/web/components/DockViewPlayground.d.ts +51 -0
- package/lib/cjs/web/components/DockViewPlayground.js +364 -0
- package/lib/cjs/web/components/DockViewPlayground.js.map +1 -0
- package/lib/cjs/web/components/NotationBlock.d.ts +35 -0
- package/lib/cjs/web/components/NotationBlock.js +219 -0
- package/lib/cjs/web/components/NotationBlock.js.map +1 -0
- package/lib/cjs/web/components/NotebookCell.d.ts +41 -0
- package/lib/cjs/web/components/NotebookCell.js +269 -0
- package/lib/cjs/web/components/NotebookCell.js.map +1 -0
- package/lib/cjs/web/components/NotebookView.d.ts +37 -0
- package/lib/cjs/web/components/NotebookView.js +379 -0
- package/lib/cjs/web/components/NotebookView.js.map +1 -0
- package/lib/cjs/web/components/SideBySideEditor.d.ts +47 -0
- package/lib/cjs/web/components/SideBySideEditor.js +171 -0
- package/lib/cjs/web/components/SideBySideEditor.js.map +1 -0
- package/lib/cjs/web/dockview.d.ts +2 -0
- package/lib/cjs/web/dockview.js +11 -0
- package/lib/cjs/web/dockview.js.map +1 -0
- package/lib/cjs/web/index.d.ts +8 -0
- package/lib/cjs/web/index.js +34 -0
- package/lib/cjs/web/index.js.map +1 -0
- package/lib/cjs/web/types/notebook.d.ts +64 -0
- package/lib/cjs/web/types/notebook.js +56 -0
- package/lib/cjs/web/types/notebook.js.map +1 -0
- package/lib/cjs/web/utils/cellFactory.d.ts +16 -0
- package/lib/cjs/web/utils/cellFactory.js +137 -0
- package/lib/cjs/web/utils/cellFactory.js.map +1 -0
- package/lib/cjs/web/utils/sourceSerializer.d.ts +19 -0
- package/lib/cjs/web/utils/sourceSerializer.js +162 -0
- package/lib/cjs/web/utils/sourceSerializer.js.map +1 -0
- package/lib/esm/parser.js +1 -1
- package/lib/esm/parser.js.map +1 -1
- package/lib/esm/web/components/DockViewPlayground.d.ts +51 -0
- package/lib/esm/web/components/DockViewPlayground.js +358 -0
- package/lib/esm/web/components/DockViewPlayground.js.map +1 -0
- package/lib/esm/web/components/NotationBlock.d.ts +35 -0
- package/lib/esm/web/components/NotationBlock.js +216 -0
- package/lib/esm/web/components/NotationBlock.js.map +1 -0
- package/lib/esm/web/components/NotebookCell.d.ts +41 -0
- package/lib/esm/web/components/NotebookCell.js +266 -0
- package/lib/esm/web/components/NotebookCell.js.map +1 -0
- package/lib/esm/web/components/NotebookView.d.ts +37 -0
- package/lib/esm/web/components/NotebookView.js +376 -0
- package/lib/esm/web/components/NotebookView.js.map +1 -0
- package/lib/esm/web/components/SideBySideEditor.d.ts +47 -0
- package/lib/esm/web/components/SideBySideEditor.js +168 -0
- package/lib/esm/web/components/SideBySideEditor.js.map +1 -0
- package/lib/esm/web/dockview.d.ts +2 -0
- package/lib/esm/web/dockview.js +3 -0
- package/lib/esm/web/dockview.js.map +1 -0
- package/lib/esm/web/index.d.ts +8 -0
- package/lib/esm/web/index.js +9 -0
- package/lib/esm/web/index.js.map +1 -0
- package/lib/esm/web/types/notebook.d.ts +64 -0
- package/lib/esm/web/types/notebook.js +50 -0
- package/lib/esm/web/types/notebook.js.map +1 -0
- package/lib/esm/web/utils/cellFactory.d.ts +16 -0
- package/lib/esm/web/utils/cellFactory.js +127 -0
- package/lib/esm/web/utils/cellFactory.js.map +1 -0
- package/lib/esm/web/utils/sourceSerializer.d.ts +19 -0
- package/lib/esm/web/utils/sourceSerializer.js +154 -0
- package/lib/esm/web/utils/sourceSerializer.js.map +1 -0
- package/package.json +41 -1
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const loader_1 = require("../../loader");
|
|
4
|
+
const carnatic_1 = require("../../carnatic");
|
|
5
|
+
const grids_1 = require("../../grids");
|
|
6
|
+
const block_1 = require("../../block");
|
|
7
|
+
const cellFactory_1 = require("../utils/cellFactory");
|
|
8
|
+
const DEFAULT_CONFIG = {
|
|
9
|
+
maxDepth: 1,
|
|
10
|
+
enableReordering: false,
|
|
11
|
+
enableAddCell: true,
|
|
12
|
+
enableDeleteCell: true,
|
|
13
|
+
};
|
|
14
|
+
class NotebookView {
|
|
15
|
+
constructor(container, config = {}) {
|
|
16
|
+
var _a, _b;
|
|
17
|
+
this.notation = null;
|
|
18
|
+
this.notationSource = "";
|
|
19
|
+
this.cells = [];
|
|
20
|
+
this.cellElements = new Map();
|
|
21
|
+
this.cellNotationViews = new Map();
|
|
22
|
+
this.layoutChangeUnsubscribe = null;
|
|
23
|
+
this.config = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
|
|
24
|
+
this.rootElement = document.createElement("div");
|
|
25
|
+
this.rootElement.className = "notebook-view";
|
|
26
|
+
if ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.root) {
|
|
27
|
+
this.rootElement.className += " " + this.config.cssClasses.root;
|
|
28
|
+
}
|
|
29
|
+
container.appendChild(this.rootElement);
|
|
30
|
+
this.gridLayoutGroup = (_b = this.config.sharedGridLayoutGroup) !== null && _b !== void 0 ? _b : new grids_1.GridLayoutGroup();
|
|
31
|
+
this.layoutChangeUnsubscribe = this.gridLayoutGroup.onLayoutChange((event) => {
|
|
32
|
+
this.handleLayoutChange(event);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
loadNotation(source) {
|
|
36
|
+
this.notationSource = source;
|
|
37
|
+
const [notation, beatLayout, errors] = (0, loader_1.load)(source, { log: false });
|
|
38
|
+
if (errors.length > 0) {
|
|
39
|
+
console.error("Notation parse errors:", errors);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.notation = notation;
|
|
43
|
+
this.cells = (0, cellFactory_1.createCellModels)(notation, {
|
|
44
|
+
maxDepth: this.config.maxDepth,
|
|
45
|
+
notationSource: source,
|
|
46
|
+
includeLines: true,
|
|
47
|
+
includeRawBlocks: true,
|
|
48
|
+
});
|
|
49
|
+
this.render();
|
|
50
|
+
}
|
|
51
|
+
getNotation() {
|
|
52
|
+
return this.notation;
|
|
53
|
+
}
|
|
54
|
+
getCells() {
|
|
55
|
+
return this.cells;
|
|
56
|
+
}
|
|
57
|
+
getVisibleCells() {
|
|
58
|
+
return (0, cellFactory_1.getVisibleCells)(this.cells);
|
|
59
|
+
}
|
|
60
|
+
getCell(cellId) {
|
|
61
|
+
return (0, cellFactory_1.findCellById)(this.cells, cellId);
|
|
62
|
+
}
|
|
63
|
+
render() {
|
|
64
|
+
this.rootElement.innerHTML = "";
|
|
65
|
+
this.cellElements.clear();
|
|
66
|
+
this.cellNotationViews.clear();
|
|
67
|
+
for (let i = 0; i < this.cells.length; i++) {
|
|
68
|
+
const cell = this.cells[i];
|
|
69
|
+
this.renderCell(cell, this.rootElement);
|
|
70
|
+
if (this.config.enableAddCell && i < this.cells.length - 1) {
|
|
71
|
+
this.renderAddCellButton(this.rootElement, i + 1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (this.config.enableAddCell) {
|
|
75
|
+
this.renderAddCellButton(this.rootElement, this.cells.length);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
renderCell(cell, parent) {
|
|
79
|
+
var _a, _b;
|
|
80
|
+
const cellClass = ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.cell) || "";
|
|
81
|
+
const container = document.createElement("div");
|
|
82
|
+
container.className = `notebook-cell notebook-cell-${cell.state.type} ${cellClass}`;
|
|
83
|
+
container.dataset.cellId = cell.state.id;
|
|
84
|
+
container.dataset.depth = String(cell.state.depth);
|
|
85
|
+
this.renderCellHeader(cell, container);
|
|
86
|
+
const contentContainer = document.createElement("div");
|
|
87
|
+
contentContainer.className = "notebook-cell-content";
|
|
88
|
+
if ((_b = this.config.cssClasses) === null || _b === void 0 ? void 0 : _b.cellContent) {
|
|
89
|
+
contentContainer.className += " " + this.config.cssClasses.cellContent;
|
|
90
|
+
}
|
|
91
|
+
container.appendChild(contentContainer);
|
|
92
|
+
if (cell.state.isEditing) {
|
|
93
|
+
this.renderCellEditMode(cell, contentContainer);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this.renderCellPreviewMode(cell, contentContainer);
|
|
97
|
+
}
|
|
98
|
+
this.cellElements.set(cell.state.id, container);
|
|
99
|
+
parent.appendChild(container);
|
|
100
|
+
if (cell.state.isExpanded && cell.children.length > 0) {
|
|
101
|
+
const childrenContainer = document.createElement("div");
|
|
102
|
+
childrenContainer.className = "notebook-cell-children";
|
|
103
|
+
container.appendChild(childrenContainer);
|
|
104
|
+
for (const child of cell.children) {
|
|
105
|
+
this.renderCell(child, childrenContainer);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
renderCellHeader(cell, container) {
|
|
110
|
+
var _a, _b, _c;
|
|
111
|
+
const headerClass = ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.cellHeader) || "";
|
|
112
|
+
const header = document.createElement("div");
|
|
113
|
+
header.className = `notebook-cell-header ${headerClass}`;
|
|
114
|
+
const badge = document.createElement("span");
|
|
115
|
+
badge.className = `notebook-cell-badge badge-${cell.state.type}`;
|
|
116
|
+
badge.textContent = cell.state.type;
|
|
117
|
+
header.appendChild(badge);
|
|
118
|
+
if ((0, block_1.isBlock)(cell.blockItem)) {
|
|
119
|
+
const block = cell.blockItem;
|
|
120
|
+
if (block.name) {
|
|
121
|
+
const name = document.createElement("span");
|
|
122
|
+
name.className = "notebook-cell-name";
|
|
123
|
+
name.textContent = block.name;
|
|
124
|
+
header.appendChild(name);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (cell.children.length > 0) {
|
|
128
|
+
const expandBtn = document.createElement("button");
|
|
129
|
+
expandBtn.className = "notebook-btn notebook-expand-btn";
|
|
130
|
+
expandBtn.textContent = cell.state.isExpanded ? "▼" : "▶";
|
|
131
|
+
expandBtn.title = cell.state.isExpanded ? "Collapse" : "Expand";
|
|
132
|
+
expandBtn.addEventListener("click", () => this.toggleExpanded(cell.state.id));
|
|
133
|
+
header.appendChild(expandBtn);
|
|
134
|
+
}
|
|
135
|
+
const controlsClass = ((_b = this.config.cssClasses) === null || _b === void 0 ? void 0 : _b.cellControls) || "";
|
|
136
|
+
const controls = document.createElement("div");
|
|
137
|
+
controls.className = `notebook-cell-controls ${controlsClass}`;
|
|
138
|
+
const editBtn = document.createElement("button");
|
|
139
|
+
editBtn.className = "notebook-btn notebook-edit-btn";
|
|
140
|
+
editBtn.textContent = cell.state.isEditing ? "Cancel" : "Edit";
|
|
141
|
+
editBtn.addEventListener("click", () => {
|
|
142
|
+
if (cell.state.isEditing) {
|
|
143
|
+
this.cancelEdit(cell.state.id);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
this.startEdit(cell.state.id);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
controls.appendChild(editBtn);
|
|
150
|
+
if (this.config.enableDeleteCell) {
|
|
151
|
+
const deleteBtn = document.createElement("button");
|
|
152
|
+
deleteBtn.className = "notebook-btn notebook-delete-btn";
|
|
153
|
+
deleteBtn.textContent = "Delete";
|
|
154
|
+
deleteBtn.addEventListener("click", () => this.deleteCell(cell.state.id));
|
|
155
|
+
controls.appendChild(deleteBtn);
|
|
156
|
+
}
|
|
157
|
+
header.appendChild(controls);
|
|
158
|
+
container.appendChild(header);
|
|
159
|
+
if (cell.state.hasError && cell.state.errorMessage) {
|
|
160
|
+
const errorClass = ((_c = this.config.cssClasses) === null || _c === void 0 ? void 0 : _c.errorMessage) || "";
|
|
161
|
+
const errorDiv = document.createElement("div");
|
|
162
|
+
errorDiv.className = `notebook-cell-error ${errorClass}`;
|
|
163
|
+
errorDiv.textContent = cell.state.errorMessage;
|
|
164
|
+
container.appendChild(errorDiv);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
renderCellPreviewMode(cell, container) {
|
|
168
|
+
if ((0, block_1.isRawBlock)(cell.blockItem)) {
|
|
169
|
+
const rawBlock = cell.blockItem;
|
|
170
|
+
const content = document.createElement("div");
|
|
171
|
+
content.className = "notebook-rawblock-content";
|
|
172
|
+
if (this.config.markdownParser && rawBlock.contentType === "md") {
|
|
173
|
+
content.innerHTML = this.config.markdownParser(rawBlock.content);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
content.textContent = rawBlock.content;
|
|
177
|
+
}
|
|
178
|
+
container.appendChild(content);
|
|
179
|
+
}
|
|
180
|
+
else if ((0, block_1.isLine)(cell.blockItem) || (0, block_1.isBlock)(cell.blockItem)) {
|
|
181
|
+
const viewContainer = document.createElement("div");
|
|
182
|
+
viewContainer.className = "notebook-notation-view";
|
|
183
|
+
container.appendChild(viewContainer);
|
|
184
|
+
const notationView = new carnatic_1.NotationView(viewContainer, {
|
|
185
|
+
sharedGridLayoutGroup: this.gridLayoutGroup,
|
|
186
|
+
markdownParser: this.config.markdownParser,
|
|
187
|
+
});
|
|
188
|
+
this.cellNotationViews.set(cell.state.id, notationView);
|
|
189
|
+
const placeholder = document.createElement("div");
|
|
190
|
+
placeholder.className = "notebook-notation-placeholder";
|
|
191
|
+
placeholder.textContent = `[${cell.state.type} notation content]`;
|
|
192
|
+
viewContainer.appendChild(placeholder);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
renderCellEditMode(cell, container) {
|
|
196
|
+
var _a;
|
|
197
|
+
const textareaClass = ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.editTextarea) || "";
|
|
198
|
+
const textarea = document.createElement("textarea");
|
|
199
|
+
textarea.className = `notebook-edit-textarea ${textareaClass}`;
|
|
200
|
+
textarea.value = cell.source;
|
|
201
|
+
textarea.rows = Math.max(3, cell.source.split("\n").length);
|
|
202
|
+
container.appendChild(textarea);
|
|
203
|
+
const actions = document.createElement("div");
|
|
204
|
+
actions.className = "notebook-edit-actions";
|
|
205
|
+
const applyBtn = document.createElement("button");
|
|
206
|
+
applyBtn.className = "notebook-btn notebook-apply-btn";
|
|
207
|
+
applyBtn.textContent = "Apply";
|
|
208
|
+
applyBtn.addEventListener("click", () => {
|
|
209
|
+
this.applyEdit(cell.state.id, textarea.value);
|
|
210
|
+
});
|
|
211
|
+
actions.appendChild(applyBtn);
|
|
212
|
+
const cancelBtn = document.createElement("button");
|
|
213
|
+
cancelBtn.className = "notebook-btn notebook-cancel-btn";
|
|
214
|
+
cancelBtn.textContent = "Cancel";
|
|
215
|
+
cancelBtn.addEventListener("click", () => this.cancelEdit(cell.state.id));
|
|
216
|
+
actions.appendChild(cancelBtn);
|
|
217
|
+
container.appendChild(actions);
|
|
218
|
+
}
|
|
219
|
+
renderAddCellButton(parent, insertIndex) {
|
|
220
|
+
var _a;
|
|
221
|
+
const btnClass = ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.addCellButton) || "";
|
|
222
|
+
const btn = document.createElement("button");
|
|
223
|
+
btn.className = `notebook-add-cell-btn ${btnClass}`;
|
|
224
|
+
btn.textContent = "+ Add Cell";
|
|
225
|
+
btn.addEventListener("click", () => {
|
|
226
|
+
const newCell = this.insertCell(insertIndex, "");
|
|
227
|
+
this.startEdit(newCell.state.id);
|
|
228
|
+
});
|
|
229
|
+
parent.appendChild(btn);
|
|
230
|
+
}
|
|
231
|
+
handleLayoutChange(event) {
|
|
232
|
+
if (this.config.onLayoutChange) {
|
|
233
|
+
this.config.onLayoutChange(event);
|
|
234
|
+
}
|
|
235
|
+
if (!event.columnWidthsChanged && !event.rowHeightsChanged) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
startEdit(cellId) {
|
|
240
|
+
const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
|
|
241
|
+
if (!cell)
|
|
242
|
+
return;
|
|
243
|
+
const updatedCell = (0, cellFactory_1.updateCellState)(cell, { isEditing: true });
|
|
244
|
+
this.replaceCellInTree(cell, updatedCell);
|
|
245
|
+
this.rerenderCell(updatedCell);
|
|
246
|
+
}
|
|
247
|
+
applyEdit(cellId, newSource) {
|
|
248
|
+
const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
|
|
249
|
+
if (!cell)
|
|
250
|
+
return;
|
|
251
|
+
const updatedCell = Object.assign(Object.assign({}, cell), { source: newSource, state: Object.assign(Object.assign({}, cell.state), { isEditing: false, hasError: false, errorMessage: undefined }) });
|
|
252
|
+
this.replaceCellInTree(cell, updatedCell);
|
|
253
|
+
this.rerenderCell(updatedCell);
|
|
254
|
+
if (this.config.onNotationChange) {
|
|
255
|
+
this.config.onNotationChange(this.notationSource, this.notation);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
cancelEdit(cellId) {
|
|
259
|
+
const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
|
|
260
|
+
if (!cell)
|
|
261
|
+
return;
|
|
262
|
+
const updatedCell = (0, cellFactory_1.updateCellState)(cell, { isEditing: false });
|
|
263
|
+
this.replaceCellInTree(cell, updatedCell);
|
|
264
|
+
this.rerenderCell(updatedCell);
|
|
265
|
+
}
|
|
266
|
+
deleteCell(cellId) {
|
|
267
|
+
const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
|
|
268
|
+
if (!cell)
|
|
269
|
+
return;
|
|
270
|
+
if (cell.parent) {
|
|
271
|
+
const index = cell.parent.children.indexOf(cell);
|
|
272
|
+
if (index >= 0) {
|
|
273
|
+
cell.parent.children.splice(index, 1);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const index = this.cells.indexOf(cell);
|
|
278
|
+
if (index >= 0) {
|
|
279
|
+
this.cells.splice(index, 1);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const element = this.cellElements.get(cellId);
|
|
283
|
+
if (element) {
|
|
284
|
+
element.remove();
|
|
285
|
+
this.cellElements.delete(cellId);
|
|
286
|
+
}
|
|
287
|
+
this.cellNotationViews.delete(cellId);
|
|
288
|
+
}
|
|
289
|
+
moveCell(cellId, targetIndex) {
|
|
290
|
+
const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
|
|
291
|
+
if (!cell)
|
|
292
|
+
return;
|
|
293
|
+
if (cell.parent) {
|
|
294
|
+
console.warn("Moving nested cells not yet supported");
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const currentIndex = this.cells.indexOf(cell);
|
|
298
|
+
if (currentIndex < 0 || currentIndex === targetIndex)
|
|
299
|
+
return;
|
|
300
|
+
this.cells.splice(currentIndex, 1);
|
|
301
|
+
this.cells.splice(targetIndex, 0, cell);
|
|
302
|
+
this.render();
|
|
303
|
+
}
|
|
304
|
+
insertCell(index, source) {
|
|
305
|
+
const rawBlock = new block_1.RawBlock(source, "notation");
|
|
306
|
+
const cell = {
|
|
307
|
+
blockItem: rawBlock,
|
|
308
|
+
state: {
|
|
309
|
+
id: `cell-${Date.now()}`,
|
|
310
|
+
type: "rawblock",
|
|
311
|
+
depth: 0,
|
|
312
|
+
isExpanded: true,
|
|
313
|
+
isEditing: false,
|
|
314
|
+
hasError: false,
|
|
315
|
+
},
|
|
316
|
+
source,
|
|
317
|
+
children: [],
|
|
318
|
+
parent: null,
|
|
319
|
+
};
|
|
320
|
+
this.cells.splice(index, 0, cell);
|
|
321
|
+
this.render();
|
|
322
|
+
return cell;
|
|
323
|
+
}
|
|
324
|
+
toggleExpanded(cellId) {
|
|
325
|
+
const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
|
|
326
|
+
if (!cell)
|
|
327
|
+
return;
|
|
328
|
+
const updatedCell = (0, cellFactory_1.updateCellState)(cell, {
|
|
329
|
+
isExpanded: !cell.state.isExpanded,
|
|
330
|
+
});
|
|
331
|
+
this.replaceCellInTree(cell, updatedCell);
|
|
332
|
+
this.rerenderCell(updatedCell);
|
|
333
|
+
}
|
|
334
|
+
replaceCellInTree(oldCell, newCell) {
|
|
335
|
+
if (oldCell.parent) {
|
|
336
|
+
const index = oldCell.parent.children.indexOf(oldCell);
|
|
337
|
+
if (index >= 0) {
|
|
338
|
+
oldCell.parent.children[index] = newCell;
|
|
339
|
+
newCell.parent = oldCell.parent;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
const index = this.cells.indexOf(oldCell);
|
|
344
|
+
if (index >= 0) {
|
|
345
|
+
this.cells[index] = newCell;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
rerenderCell(cell) {
|
|
350
|
+
const element = this.cellElements.get(cell.state.id);
|
|
351
|
+
if (!element || !element.parentElement)
|
|
352
|
+
return;
|
|
353
|
+
const parent = element.parentElement;
|
|
354
|
+
const nextSibling = element.nextSibling;
|
|
355
|
+
element.remove();
|
|
356
|
+
this.cellElements.delete(cell.state.id);
|
|
357
|
+
this.cellNotationViews.delete(cell.state.id);
|
|
358
|
+
const tempContainer = document.createElement("div");
|
|
359
|
+
this.renderCell(cell, tempContainer);
|
|
360
|
+
const newElement = tempContainer.firstChild;
|
|
361
|
+
if (nextSibling) {
|
|
362
|
+
parent.insertBefore(newElement, nextSibling);
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
parent.appendChild(newElement);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
destroy() {
|
|
369
|
+
if (this.layoutChangeUnsubscribe) {
|
|
370
|
+
this.layoutChangeUnsubscribe();
|
|
371
|
+
this.layoutChangeUnsubscribe = null;
|
|
372
|
+
}
|
|
373
|
+
this.rootElement.innerHTML = "";
|
|
374
|
+
this.cellElements.clear();
|
|
375
|
+
this.cellNotationViews.clear();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
exports.default = NotebookView;
|
|
379
|
+
//# sourceMappingURL=NotebookView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotebookView.js","sourceRoot":"","sources":["../../../../src/web/components/NotebookView.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * NotebookView - Main container for notebook-style notation editing.\n *\n * The NotebookView owns a shared GridLayoutGroup and manages a collection\n * of cells, each representing a Block from the notation.\n */\n\nimport { load } from \"../../loader\";\nimport { NotationView } from \"../../carnatic\";\nimport { GridLayoutGroup } from \"../../grids\";\nimport { Notation } from \"../../notation\";\nimport { isBlock, isLine, isRawBlock, Block, RawBlock } from \"../../block\";\nimport { NotebookConfig, CellModel, CellOperations, LayoutChangeEvent } from \"../types/notebook\";\nimport {\n createCellModels,\n findCellById,\n findCellIndex,\n flattenCells,\n getVisibleCells,\n updateCellState,\n} from \"../utils/cellFactory\";\n\n/**\n * Default configuration for NotebookView.\n */\nconst DEFAULT_CONFIG: NotebookConfig = {\n maxDepth: 1,\n enableReordering: false,\n enableAddCell: true,\n enableDeleteCell: true,\n};\n\n/**\n * NotebookView manages a notebook-style view of notation with editable cells.\n *\n * Features:\n * - Shared GridLayoutGroup for column alignment across all cells\n * - Cell-based editing with preview/edit modes\n * - Support for nested blocks up to configurable depth\n * - Optional cell reordering, adding, and deleting\n */\nexport default class NotebookView implements CellOperations {\n /** The root HTML element */\n readonly rootElement: HTMLDivElement;\n\n /** Configuration options */\n readonly config: NotebookConfig;\n\n /** Shared grid layout group for column alignment */\n readonly gridLayoutGroup: GridLayoutGroup;\n\n /** The current notation */\n private notation: Notation | null = null;\n\n /** The full notation source */\n private notationSource: string = \"\";\n\n /** Cell models representing the notebook structure */\n private cells: CellModel[] = [];\n\n /** Map of cell ID to its rendered container element */\n private cellElements = new Map<string, HTMLElement>();\n\n /** Map of cell ID to its NotationView (for notation cells) */\n private cellNotationViews = new Map<string, NotationView>();\n\n /** Unsubscribe function for layout change listener */\n private layoutChangeUnsubscribe: (() => void) | null = null;\n\n /**\n * Creates a new NotebookView.\n *\n * @param container The container element to render into\n * @param config Configuration options\n */\n constructor(container: HTMLElement, config: Partial<NotebookConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n\n // Create root element\n this.rootElement = document.createElement(\"div\");\n this.rootElement.className = \"notebook-view\";\n if (this.config.cssClasses?.root) {\n this.rootElement.className += \" \" + this.config.cssClasses.root;\n }\n container.appendChild(this.rootElement);\n\n // Create or use shared grid layout group\n this.gridLayoutGroup = this.config.sharedGridLayoutGroup ?? new GridLayoutGroup();\n\n // Subscribe to layout changes\n this.layoutChangeUnsubscribe = this.gridLayoutGroup.onLayoutChange((event) => {\n this.handleLayoutChange(event);\n });\n }\n\n /**\n * Loads notation from source text.\n *\n * @param source The notation source text\n */\n loadNotation(source: string): void {\n this.notationSource = source;\n\n // Parse the notation\n const [notation, beatLayout, errors] = load(source, { log: false });\n\n if (errors.length > 0) {\n console.error(\"Notation parse errors:\", errors);\n // TODO: Show errors in UI\n return;\n }\n\n this.notation = notation;\n\n // Create cell models from the notation\n this.cells = createCellModels(notation, {\n maxDepth: this.config.maxDepth,\n notationSource: source,\n includeLines: true,\n includeRawBlocks: true,\n });\n\n // Render all cells\n this.render();\n }\n\n /**\n * Gets the current notation.\n */\n getNotation(): Notation | null {\n return this.notation;\n }\n\n /**\n * Gets all cell models.\n */\n getCells(): CellModel[] {\n return this.cells;\n }\n\n /**\n * Gets visible cells (respecting expanded state).\n */\n getVisibleCells(): CellModel[] {\n return getVisibleCells(this.cells);\n }\n\n /**\n * Gets a cell by ID.\n */\n getCell(cellId: string): CellModel | null {\n return findCellById(this.cells, cellId);\n }\n\n /**\n * Renders the notebook.\n */\n private render(): void {\n // Clear existing content\n this.rootElement.innerHTML = \"\";\n this.cellElements.clear();\n this.cellNotationViews.clear();\n\n // Render each top-level cell\n for (let i = 0; i < this.cells.length; i++) {\n const cell = this.cells[i];\n this.renderCell(cell, this.rootElement);\n\n // Add \"add cell\" button between cells if enabled\n if (this.config.enableAddCell && i < this.cells.length - 1) {\n this.renderAddCellButton(this.rootElement, i + 1);\n }\n }\n\n // Add final \"add cell\" button if enabled\n if (this.config.enableAddCell) {\n this.renderAddCellButton(this.rootElement, this.cells.length);\n }\n }\n\n /**\n * Renders a single cell.\n */\n private renderCell(cell: CellModel, parent: HTMLElement): void {\n const cellClass = this.config.cssClasses?.cell || \"\";\n const container = document.createElement(\"div\");\n container.className = `notebook-cell notebook-cell-${cell.state.type} ${cellClass}`;\n container.dataset.cellId = cell.state.id;\n container.dataset.depth = String(cell.state.depth);\n\n // Render cell header\n this.renderCellHeader(cell, container);\n\n // Render cell content\n const contentContainer = document.createElement(\"div\");\n contentContainer.className = \"notebook-cell-content\";\n if (this.config.cssClasses?.cellContent) {\n contentContainer.className += \" \" + this.config.cssClasses.cellContent;\n }\n container.appendChild(contentContainer);\n\n if (cell.state.isEditing) {\n this.renderCellEditMode(cell, contentContainer);\n } else {\n this.renderCellPreviewMode(cell, contentContainer);\n }\n\n // Store reference\n this.cellElements.set(cell.state.id, container);\n parent.appendChild(container);\n\n // Render children if expanded\n if (cell.state.isExpanded && cell.children.length > 0) {\n const childrenContainer = document.createElement(\"div\");\n childrenContainer.className = \"notebook-cell-children\";\n container.appendChild(childrenContainer);\n\n for (const child of cell.children) {\n this.renderCell(child, childrenContainer);\n }\n }\n }\n\n /**\n * Renders the cell header with type badge, name, and controls.\n */\n private renderCellHeader(cell: CellModel, container: HTMLElement): void {\n const headerClass = this.config.cssClasses?.cellHeader || \"\";\n const header = document.createElement(\"div\");\n header.className = `notebook-cell-header ${headerClass}`;\n\n // Type badge\n const badge = document.createElement(\"span\");\n badge.className = `notebook-cell-badge badge-${cell.state.type}`;\n badge.textContent = cell.state.type;\n header.appendChild(badge);\n\n // Name (if block has a name)\n if (isBlock(cell.blockItem)) {\n const block = cell.blockItem as Block;\n if (block.name) {\n const name = document.createElement(\"span\");\n name.className = \"notebook-cell-name\";\n name.textContent = block.name;\n header.appendChild(name);\n }\n }\n\n // Expand/collapse button for cells with children\n if (cell.children.length > 0) {\n const expandBtn = document.createElement(\"button\");\n expandBtn.className = \"notebook-btn notebook-expand-btn\";\n expandBtn.textContent = cell.state.isExpanded ? \"▼\" : \"▶\";\n expandBtn.title = cell.state.isExpanded ? \"Collapse\" : \"Expand\";\n expandBtn.addEventListener(\"click\", () => this.toggleExpanded(cell.state.id));\n header.appendChild(expandBtn);\n }\n\n // Controls container\n const controlsClass = this.config.cssClasses?.cellControls || \"\";\n const controls = document.createElement(\"div\");\n controls.className = `notebook-cell-controls ${controlsClass}`;\n\n // Edit button\n const editBtn = document.createElement(\"button\");\n editBtn.className = \"notebook-btn notebook-edit-btn\";\n editBtn.textContent = cell.state.isEditing ? \"Cancel\" : \"Edit\";\n editBtn.addEventListener(\"click\", () => {\n if (cell.state.isEditing) {\n this.cancelEdit(cell.state.id);\n } else {\n this.startEdit(cell.state.id);\n }\n });\n controls.appendChild(editBtn);\n\n // Delete button (if enabled)\n if (this.config.enableDeleteCell) {\n const deleteBtn = document.createElement(\"button\");\n deleteBtn.className = \"notebook-btn notebook-delete-btn\";\n deleteBtn.textContent = \"Delete\";\n deleteBtn.addEventListener(\"click\", () => this.deleteCell(cell.state.id));\n controls.appendChild(deleteBtn);\n }\n\n header.appendChild(controls);\n container.appendChild(header);\n\n // Error message (if any)\n if (cell.state.hasError && cell.state.errorMessage) {\n const errorClass = this.config.cssClasses?.errorMessage || \"\";\n const errorDiv = document.createElement(\"div\");\n errorDiv.className = `notebook-cell-error ${errorClass}`;\n errorDiv.textContent = cell.state.errorMessage;\n container.appendChild(errorDiv);\n }\n }\n\n /**\n * Renders cell content in preview mode.\n */\n private renderCellPreviewMode(cell: CellModel, container: HTMLElement): void {\n if (isRawBlock(cell.blockItem)) {\n // Render RawBlock content (markdown or plain text)\n const rawBlock = cell.blockItem as RawBlock;\n const content = document.createElement(\"div\");\n content.className = \"notebook-rawblock-content\";\n\n if (this.config.markdownParser && rawBlock.contentType === \"md\") {\n content.innerHTML = this.config.markdownParser(rawBlock.content);\n } else {\n content.textContent = rawBlock.content;\n }\n container.appendChild(content);\n } else if (isLine(cell.blockItem) || isBlock(cell.blockItem)) {\n // Render notation content using NotationView\n const viewContainer = document.createElement(\"div\");\n viewContainer.className = \"notebook-notation-view\";\n container.appendChild(viewContainer);\n\n // Create NotationView sharing the grid layout group\n const notationView = new NotationView(viewContainer, {\n sharedGridLayoutGroup: this.gridLayoutGroup,\n markdownParser: this.config.markdownParser,\n });\n\n this.cellNotationViews.set(cell.state.id, notationView);\n\n // For now, render placeholder - full implementation would need\n // to create a mini-notation from just this cell's content\n // This is a simplified version that shows the cell exists\n const placeholder = document.createElement(\"div\");\n placeholder.className = \"notebook-notation-placeholder\";\n placeholder.textContent = `[${cell.state.type} notation content]`;\n viewContainer.appendChild(placeholder);\n }\n }\n\n /**\n * Renders cell content in edit mode.\n */\n private renderCellEditMode(cell: CellModel, container: HTMLElement): void {\n const textareaClass = this.config.cssClasses?.editTextarea || \"\";\n const textarea = document.createElement(\"textarea\");\n textarea.className = `notebook-edit-textarea ${textareaClass}`;\n textarea.value = cell.source;\n textarea.rows = Math.max(3, cell.source.split(\"\\n\").length);\n container.appendChild(textarea);\n\n // Apply/Cancel buttons\n const actions = document.createElement(\"div\");\n actions.className = \"notebook-edit-actions\";\n\n const applyBtn = document.createElement(\"button\");\n applyBtn.className = \"notebook-btn notebook-apply-btn\";\n applyBtn.textContent = \"Apply\";\n applyBtn.addEventListener(\"click\", () => {\n this.applyEdit(cell.state.id, textarea.value);\n });\n actions.appendChild(applyBtn);\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.className = \"notebook-btn notebook-cancel-btn\";\n cancelBtn.textContent = \"Cancel\";\n cancelBtn.addEventListener(\"click\", () => this.cancelEdit(cell.state.id));\n actions.appendChild(cancelBtn);\n\n container.appendChild(actions);\n }\n\n /**\n * Renders an \"add cell\" button.\n */\n private renderAddCellButton(parent: HTMLElement, insertIndex: number): void {\n const btnClass = this.config.cssClasses?.addCellButton || \"\";\n const btn = document.createElement(\"button\");\n btn.className = `notebook-add-cell-btn ${btnClass}`;\n btn.textContent = \"+ Add Cell\";\n btn.addEventListener(\"click\", () => {\n const newCell = this.insertCell(insertIndex, \"\");\n this.startEdit(newCell.state.id);\n });\n parent.appendChild(btn);\n }\n\n /**\n * Handles layout change events from the shared GridLayoutGroup.\n */\n private handleLayoutChange(event: LayoutChangeEvent): void {\n // Notify external listener if configured\n if (this.config.onLayoutChange) {\n this.config.onLayoutChange(event);\n }\n\n // If dimensions didn't change, no need to update views\n if (!event.columnWidthsChanged && !event.rowHeightsChanged) {\n return;\n }\n\n // TODO: Implement incremental re-render based on affected range\n // For now, this is a placeholder for future optimization\n }\n\n // ============================================\n // CellOperations implementation\n // ============================================\n\n /**\n * Enters edit mode for a cell.\n */\n startEdit(cellId: string): void {\n const cell = findCellById(this.cells, cellId);\n if (!cell) return;\n\n // Update cell state\n const updatedCell = updateCellState(cell, { isEditing: true });\n this.replaceCellInTree(cell, updatedCell);\n\n // Re-render the cell\n this.rerenderCell(updatedCell);\n }\n\n /**\n * Applies edit and exits edit mode.\n */\n applyEdit(cellId: string, newSource: string): void {\n const cell = findCellById(this.cells, cellId);\n if (!cell) return;\n\n // TODO: Parse newSource and update the block\n // For now, just update the source and exit edit mode\n const updatedCell: CellModel = {\n ...cell,\n source: newSource,\n state: {\n ...cell.state,\n isEditing: false,\n hasError: false,\n errorMessage: undefined,\n },\n };\n\n this.replaceCellInTree(cell, updatedCell);\n this.rerenderCell(updatedCell);\n\n // Notify change listener\n if (this.config.onNotationChange) {\n // TODO: Serialize cells back to source\n this.config.onNotationChange(this.notationSource, this.notation);\n }\n }\n\n /**\n * Cancels edit mode without applying changes.\n */\n cancelEdit(cellId: string): void {\n const cell = findCellById(this.cells, cellId);\n if (!cell) return;\n\n const updatedCell = updateCellState(cell, { isEditing: false });\n this.replaceCellInTree(cell, updatedCell);\n this.rerenderCell(updatedCell);\n }\n\n /**\n * Deletes a cell.\n */\n deleteCell(cellId: string): void {\n const cell = findCellById(this.cells, cellId);\n if (!cell) return;\n\n // Remove from parent's children or top-level cells\n if (cell.parent) {\n const index = cell.parent.children.indexOf(cell);\n if (index >= 0) {\n cell.parent.children.splice(index, 1);\n }\n } else {\n const index = this.cells.indexOf(cell);\n if (index >= 0) {\n this.cells.splice(index, 1);\n }\n }\n\n // Remove DOM element\n const element = this.cellElements.get(cellId);\n if (element) {\n element.remove();\n this.cellElements.delete(cellId);\n }\n\n // Clean up NotationView\n this.cellNotationViews.delete(cellId);\n }\n\n /**\n * Moves a cell to a new position.\n */\n moveCell(cellId: string, targetIndex: number): void {\n const cell = findCellById(this.cells, cellId);\n if (!cell) return;\n\n // For now, only support moving top-level cells\n if (cell.parent) {\n console.warn(\"Moving nested cells not yet supported\");\n return;\n }\n\n const currentIndex = this.cells.indexOf(cell);\n if (currentIndex < 0 || currentIndex === targetIndex) return;\n\n // Remove and reinsert\n this.cells.splice(currentIndex, 1);\n this.cells.splice(targetIndex, 0, cell);\n\n // Re-render\n this.render();\n }\n\n /**\n * Inserts a new cell at the given index.\n */\n insertCell(index: number, source: string): CellModel {\n // Create a new RawBlock for the cell\n const rawBlock = new RawBlock(source, \"notation\");\n\n // Create cell model\n const cell: CellModel = {\n blockItem: rawBlock,\n state: {\n id: `cell-${Date.now()}`,\n type: \"rawblock\",\n depth: 0,\n isExpanded: true,\n isEditing: false,\n hasError: false,\n },\n source,\n children: [],\n parent: null,\n };\n\n // Insert at index\n this.cells.splice(index, 0, cell);\n\n // Re-render\n this.render();\n\n return cell;\n }\n\n /**\n * Toggles expanded state for a cell with children.\n */\n toggleExpanded(cellId: string): void {\n const cell = findCellById(this.cells, cellId);\n if (!cell) return;\n\n const updatedCell = updateCellState(cell, {\n isExpanded: !cell.state.isExpanded,\n });\n this.replaceCellInTree(cell, updatedCell);\n this.rerenderCell(updatedCell);\n }\n\n // ============================================\n // Helper methods\n // ============================================\n\n /**\n * Replaces a cell in the tree with an updated version.\n */\n private replaceCellInTree(oldCell: CellModel, newCell: CellModel): void {\n if (oldCell.parent) {\n const index = oldCell.parent.children.indexOf(oldCell);\n if (index >= 0) {\n oldCell.parent.children[index] = newCell;\n newCell.parent = oldCell.parent;\n }\n } else {\n const index = this.cells.indexOf(oldCell);\n if (index >= 0) {\n this.cells[index] = newCell;\n }\n }\n }\n\n /**\n * Re-renders a single cell (and its children).\n */\n private rerenderCell(cell: CellModel): void {\n const element = this.cellElements.get(cell.state.id);\n if (!element || !element.parentElement) return;\n\n const parent = element.parentElement;\n const nextSibling = element.nextSibling;\n\n // Remove old element\n element.remove();\n this.cellElements.delete(cell.state.id);\n this.cellNotationViews.delete(cell.state.id);\n\n // Create new element\n const tempContainer = document.createElement(\"div\");\n this.renderCell(cell, tempContainer);\n\n // Insert at same position\n const newElement = tempContainer.firstChild as HTMLElement;\n if (nextSibling) {\n parent.insertBefore(newElement, nextSibling);\n } else {\n parent.appendChild(newElement);\n }\n }\n\n /**\n * Cleans up resources when the view is destroyed.\n */\n destroy(): void {\n // Unsubscribe from layout changes\n if (this.layoutChangeUnsubscribe) {\n this.layoutChangeUnsubscribe();\n this.layoutChangeUnsubscribe = null;\n }\n\n // Clear DOM\n this.rootElement.innerHTML = \"\";\n this.cellElements.clear();\n this.cellNotationViews.clear();\n }\n}\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { NotationView } from "../../carnatic";
|
|
2
|
+
import { GridLayoutGroup } from "../../grids";
|
|
3
|
+
import { Notation } from "../../notation";
|
|
4
|
+
import { GlobalBeatLayout } from "../../beats";
|
|
5
|
+
export interface SideBySideEditorConfig {
|
|
6
|
+
initialSource?: string;
|
|
7
|
+
debounceDelay?: number;
|
|
8
|
+
syncScroll?: boolean;
|
|
9
|
+
onSourceChange?: (source: string) => void;
|
|
10
|
+
onNotationParsed?: (notation: Notation, beatLayout: GlobalBeatLayout) => void;
|
|
11
|
+
onParseError?: (errors: any[]) => void;
|
|
12
|
+
sharedGridLayoutGroup?: GridLayoutGroup;
|
|
13
|
+
markdownParser?: (content: string) => string;
|
|
14
|
+
editorClass?: string;
|
|
15
|
+
outputClass?: string;
|
|
16
|
+
}
|
|
17
|
+
export default class SideBySideEditor {
|
|
18
|
+
readonly editorElement: HTMLTextAreaElement;
|
|
19
|
+
readonly outputElement: HTMLDivElement;
|
|
20
|
+
readonly notationView: NotationView;
|
|
21
|
+
readonly config: SideBySideEditorConfig;
|
|
22
|
+
private notation;
|
|
23
|
+
private beatLayout;
|
|
24
|
+
private debounceTimer;
|
|
25
|
+
private isScrollSyncing;
|
|
26
|
+
constructor(config?: SideBySideEditorConfig);
|
|
27
|
+
get source(): string;
|
|
28
|
+
set source(value: string);
|
|
29
|
+
getNotation(): Notation | null;
|
|
30
|
+
getBeatLayout(): GlobalBeatLayout | null;
|
|
31
|
+
render(): boolean;
|
|
32
|
+
private setupEventListeners;
|
|
33
|
+
private syncScrollToOutput;
|
|
34
|
+
private syncScrollToEditor;
|
|
35
|
+
scrollToTop(): void;
|
|
36
|
+
scrollToBottom(): void;
|
|
37
|
+
scrollToLine(lineNumber: number): void;
|
|
38
|
+
focus(): void;
|
|
39
|
+
insertAtCursor(text: string): void;
|
|
40
|
+
getSelection(): {
|
|
41
|
+
start: number;
|
|
42
|
+
end: number;
|
|
43
|
+
text: string;
|
|
44
|
+
};
|
|
45
|
+
setSelection(start: number, end: number): void;
|
|
46
|
+
destroy(): void;
|
|
47
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const loader_1 = require("../../loader");
|
|
4
|
+
const carnatic_1 = require("../../carnatic");
|
|
5
|
+
const DEFAULT_CONFIG = {
|
|
6
|
+
debounceDelay: 300,
|
|
7
|
+
syncScroll: true,
|
|
8
|
+
};
|
|
9
|
+
class SideBySideEditor {
|
|
10
|
+
constructor(config = {}) {
|
|
11
|
+
this.notation = null;
|
|
12
|
+
this.beatLayout = null;
|
|
13
|
+
this.debounceTimer = null;
|
|
14
|
+
this.isScrollSyncing = false;
|
|
15
|
+
this.config = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
|
|
16
|
+
this.editorElement = document.createElement("textarea");
|
|
17
|
+
this.editorElement.className = "side-by-side-editor";
|
|
18
|
+
if (this.config.editorClass) {
|
|
19
|
+
this.editorElement.className += " " + this.config.editorClass;
|
|
20
|
+
}
|
|
21
|
+
this.editorElement.spellcheck = false;
|
|
22
|
+
this.editorElement.placeholder = "Enter notation source...";
|
|
23
|
+
if (this.config.initialSource) {
|
|
24
|
+
this.editorElement.value = this.config.initialSource;
|
|
25
|
+
}
|
|
26
|
+
this.outputElement = document.createElement("div");
|
|
27
|
+
this.outputElement.className = "side-by-side-output";
|
|
28
|
+
if (this.config.outputClass) {
|
|
29
|
+
this.outputElement.className += " " + this.config.outputClass;
|
|
30
|
+
}
|
|
31
|
+
this.notationView = new carnatic_1.NotationView(this.outputElement, {
|
|
32
|
+
sharedGridLayoutGroup: this.config.sharedGridLayoutGroup,
|
|
33
|
+
markdownParser: this.config.markdownParser,
|
|
34
|
+
});
|
|
35
|
+
this.setupEventListeners();
|
|
36
|
+
if (this.config.initialSource) {
|
|
37
|
+
this.render();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
get source() {
|
|
41
|
+
return this.editorElement.value;
|
|
42
|
+
}
|
|
43
|
+
set source(value) {
|
|
44
|
+
this.editorElement.value = value;
|
|
45
|
+
this.render();
|
|
46
|
+
}
|
|
47
|
+
getNotation() {
|
|
48
|
+
return this.notation;
|
|
49
|
+
}
|
|
50
|
+
getBeatLayout() {
|
|
51
|
+
return this.beatLayout;
|
|
52
|
+
}
|
|
53
|
+
render() {
|
|
54
|
+
var _a, _b, _c, _d;
|
|
55
|
+
const source = this.editorElement.value;
|
|
56
|
+
this.notationView.clear();
|
|
57
|
+
const [notation, beatLayout, errors] = (0, loader_1.load)(source, { log: false });
|
|
58
|
+
if (errors.length > 0) {
|
|
59
|
+
this.notation = null;
|
|
60
|
+
this.beatLayout = null;
|
|
61
|
+
(_b = (_a = this.config).onParseError) === null || _b === void 0 ? void 0 : _b.call(_a, errors);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
this.notation = notation;
|
|
65
|
+
this.beatLayout = beatLayout;
|
|
66
|
+
this.notationView.renderNotation(notation, beatLayout);
|
|
67
|
+
(_d = (_c = this.config).onNotationParsed) === null || _d === void 0 ? void 0 : _d.call(_c, notation, beatLayout);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
setupEventListeners() {
|
|
71
|
+
this.editorElement.addEventListener("input", () => {
|
|
72
|
+
var _a, _b;
|
|
73
|
+
(_b = (_a = this.config).onSourceChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.editorElement.value);
|
|
74
|
+
if (this.config.debounceDelay && this.config.debounceDelay > 0) {
|
|
75
|
+
if (this.debounceTimer) {
|
|
76
|
+
clearTimeout(this.debounceTimer);
|
|
77
|
+
}
|
|
78
|
+
this.debounceTimer = setTimeout(() => {
|
|
79
|
+
this.render();
|
|
80
|
+
}, this.config.debounceDelay);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
if (this.config.syncScroll) {
|
|
84
|
+
this.editorElement.addEventListener("scroll", () => {
|
|
85
|
+
this.syncScrollToOutput();
|
|
86
|
+
});
|
|
87
|
+
this.outputElement.addEventListener("scroll", () => {
|
|
88
|
+
this.syncScrollToEditor();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
syncScrollToOutput() {
|
|
93
|
+
if (this.isScrollSyncing)
|
|
94
|
+
return;
|
|
95
|
+
this.isScrollSyncing = true;
|
|
96
|
+
const editor = this.editorElement;
|
|
97
|
+
const output = this.outputElement;
|
|
98
|
+
const maxScrollTop = editor.scrollHeight - editor.clientHeight;
|
|
99
|
+
if (maxScrollTop <= 0) {
|
|
100
|
+
this.isScrollSyncing = false;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const scrollPercent = editor.scrollTop / maxScrollTop;
|
|
104
|
+
const outputMaxScroll = output.scrollHeight - output.clientHeight;
|
|
105
|
+
output.scrollTop = scrollPercent * outputMaxScroll;
|
|
106
|
+
this.isScrollSyncing = false;
|
|
107
|
+
}
|
|
108
|
+
syncScrollToEditor() {
|
|
109
|
+
if (this.isScrollSyncing)
|
|
110
|
+
return;
|
|
111
|
+
this.isScrollSyncing = true;
|
|
112
|
+
const editor = this.editorElement;
|
|
113
|
+
const output = this.outputElement;
|
|
114
|
+
const maxScrollTop = output.scrollHeight - output.clientHeight;
|
|
115
|
+
if (maxScrollTop <= 0) {
|
|
116
|
+
this.isScrollSyncing = false;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const scrollPercent = output.scrollTop / maxScrollTop;
|
|
120
|
+
const editorMaxScroll = editor.scrollHeight - editor.clientHeight;
|
|
121
|
+
editor.scrollTop = scrollPercent * editorMaxScroll;
|
|
122
|
+
this.isScrollSyncing = false;
|
|
123
|
+
}
|
|
124
|
+
scrollToTop() {
|
|
125
|
+
this.editorElement.scrollTop = 0;
|
|
126
|
+
this.outputElement.scrollTop = 0;
|
|
127
|
+
}
|
|
128
|
+
scrollToBottom() {
|
|
129
|
+
this.editorElement.scrollTop = this.editorElement.scrollHeight;
|
|
130
|
+
this.outputElement.scrollTop = this.outputElement.scrollHeight;
|
|
131
|
+
}
|
|
132
|
+
scrollToLine(lineNumber) {
|
|
133
|
+
const lines = this.editorElement.value.split("\n");
|
|
134
|
+
const lineHeight = this.editorElement.scrollHeight / lines.length;
|
|
135
|
+
this.editorElement.scrollTop = (lineNumber - 1) * lineHeight;
|
|
136
|
+
this.syncScrollToOutput();
|
|
137
|
+
}
|
|
138
|
+
focus() {
|
|
139
|
+
this.editorElement.focus();
|
|
140
|
+
}
|
|
141
|
+
insertAtCursor(text) {
|
|
142
|
+
var _a, _b;
|
|
143
|
+
const start = this.editorElement.selectionStart;
|
|
144
|
+
const end = this.editorElement.selectionEnd;
|
|
145
|
+
const value = this.editorElement.value;
|
|
146
|
+
this.editorElement.value = value.substring(0, start) + text + value.substring(end);
|
|
147
|
+
this.editorElement.selectionStart = start + text.length;
|
|
148
|
+
this.editorElement.selectionEnd = start + text.length;
|
|
149
|
+
(_b = (_a = this.config).onSourceChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.editorElement.value);
|
|
150
|
+
}
|
|
151
|
+
getSelection() {
|
|
152
|
+
return {
|
|
153
|
+
start: this.editorElement.selectionStart,
|
|
154
|
+
end: this.editorElement.selectionEnd,
|
|
155
|
+
text: this.editorElement.value.substring(this.editorElement.selectionStart, this.editorElement.selectionEnd),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
setSelection(start, end) {
|
|
159
|
+
this.editorElement.selectionStart = start;
|
|
160
|
+
this.editorElement.selectionEnd = end;
|
|
161
|
+
}
|
|
162
|
+
destroy() {
|
|
163
|
+
if (this.debounceTimer) {
|
|
164
|
+
clearTimeout(this.debounceTimer);
|
|
165
|
+
}
|
|
166
|
+
this.editorElement.remove();
|
|
167
|
+
this.outputElement.remove();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
exports.default = SideBySideEditor;
|
|
171
|
+
//# sourceMappingURL=SideBySideEditor.js.map
|