ep_data_tables 0.0.5 → 0.0.7

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.
@@ -120,16 +120,16 @@ function getTableLineMetadata(lineNum, editorInfo, docManager) {
120
120
  try {
121
121
  const metadata = JSON.parse(attribs);
122
122
  if (metadata && metadata.tblId) {
123
- // log(`${funcName}: Found metadata via attribute for line ${lineNum}`);
123
+ // log(`${funcName}: Found metadata via attribute for line ${lineNum}`);
124
124
  return metadata;
125
125
  }
126
126
  } catch (e) {
127
- // log(`${funcName}: Invalid JSON in tbljson attribute on line ${lineNum}:`, e.message);
127
+ // log(`${funcName}: Invalid JSON in tbljson attribute on line ${lineNum}:`, e.message);
128
128
  }
129
129
  }
130
130
 
131
131
  // Fallback for block-styled lines.
132
- // log(`${funcName}: No valid attribute on line ${lineNum}, checking DOM.`);
132
+ // log(`${funcName}: No valid attribute on line ${lineNum}, checking DOM.`);
133
133
  const rep = editorInfo.ace_getRep();
134
134
 
135
135
  // This is the fix: Get the lineNode directly from the rep. It's more reliable
@@ -138,7 +138,7 @@ function getTableLineMetadata(lineNum, editorInfo, docManager) {
138
138
  const lineNode = lineEntry?.lineNode;
139
139
 
140
140
  if (!lineNode) {
141
- // log(`${funcName}: Could not find line node in rep for line ${lineNum}`);
141
+ // log(`${funcName}: Could not find line node in rep for line ${lineNum}`);
142
142
  return null;
143
143
  }
144
144
 
@@ -150,7 +150,7 @@ function getTableLineMetadata(lineNum, editorInfo, docManager) {
150
150
  try {
151
151
  const decodedString = atob(encodedData);
152
152
  const metadata = JSON.parse(decodedString);
153
- // log(`${funcName}: Reconstructed metadata from DOM for line ${lineNum}:`, metadata);
153
+ // log(`${funcName}: Reconstructed metadata from DOM for line ${lineNum}:`, metadata);
154
154
  return metadata;
155
155
  } catch (e) {
156
156
  console.error(`${funcName}: Failed to decode/parse tbljson class on line ${lineNum}:`, e);
@@ -160,7 +160,7 @@ function getTableLineMetadata(lineNum, editorInfo, docManager) {
160
160
  }
161
161
  }
162
162
 
163
- // log(`${funcName}: Could not find table metadata for line ${lineNum} in DOM.`);
163
+ // log(`${funcName}: Could not find table metadata for line ${lineNum} in DOM.`);
164
164
  return null;
165
165
  } catch (e) {
166
166
  console.error(`[ep_data_tables] ${funcName}: Error getting metadata for line ${lineNum}:`, e);
@@ -181,7 +181,7 @@ function getTableLineMetadata(lineNum, editorInfo, docManager) {
181
181
  */
182
182
  function navigateToNextCell(currentLineNum, currentCellIndex, tableMetadata, shiftKey, editorInfo, docManager) {
183
183
  const funcName = 'navigateToNextCell';
184
- // log(`${funcName}: START - Current: Line=${currentLineNum}, Cell=${currentCellIndex}, Shift=${shiftKey}`);
184
+ // log(`${funcName}: START - Current: Line=${currentLineNum}, Cell=${currentCellIndex}, Shift=${shiftKey}`);
185
185
 
186
186
  try {
187
187
  let targetRow = tableMetadata.row;
@@ -205,12 +205,12 @@ function navigateToNextCell(currentLineNum, currentCellIndex, tableMetadata, shi
205
205
  }
206
206
  }
207
207
 
208
- // log(`${funcName}: Target coordinates - Row=${targetRow}, Col=${targetCol}`);
208
+ // log(`${funcName}: Target coordinates - Row=${targetRow}, Col=${targetCol}`);
209
209
 
210
210
  // Find the line number for the target row
211
211
  const targetLineNum = findLineForTableRow(tableMetadata.tblId, targetRow, editorInfo, docManager);
212
212
  if (targetLineNum === -1) {
213
- // log(`${funcName}: Could not find line for target row ${targetRow}`);
213
+ // log(`${funcName}: Could not find line for target row ${targetRow}`);
214
214
  return false;
215
215
  }
216
216
 
@@ -234,25 +234,25 @@ function navigateToNextCell(currentLineNum, currentCellIndex, tableMetadata, shi
234
234
  */
235
235
  function navigateToCellBelow(currentLineNum, currentCellIndex, tableMetadata, editorInfo, docManager) {
236
236
  const funcName = 'navigateToCellBelow';
237
- // log(`${funcName}: START - Current: Line=${currentLineNum}, Cell=${currentCellIndex}`);
237
+ // log(`${funcName}: START - Current: Line=${currentLineNum}, Cell=${currentCellIndex}`);
238
238
 
239
239
  try {
240
240
  const targetRow = tableMetadata.row + 1;
241
241
  const targetCol = currentCellIndex;
242
242
 
243
- // log(`${funcName}: Target coordinates - Row=${targetRow}, Col=${targetCol}`);
243
+ // log(`${funcName}: Target coordinates - Row=${targetRow}, Col=${targetCol}`);
244
244
 
245
245
  // Find the line number for the target row
246
246
  const targetLineNum = findLineForTableRow(tableMetadata.tblId, targetRow, editorInfo, docManager);
247
247
 
248
248
  if (targetLineNum !== -1) {
249
249
  // Found the row below, navigate to it.
250
- // log(`${funcName}: Found line for target row ${targetRow}, navigating.`);
250
+ // log(`${funcName}: Found line for target row ${targetRow}, navigating.`);
251
251
  return navigateToCell(targetLineNum, targetCol, editorInfo, docManager);
252
252
  } else {
253
253
  // Could not find the row below, we must be on the last line.
254
254
  // Create a new, empty line after the table.
255
- // log(`${funcName}: Could not find next row. Creating new line after table.`);
255
+ // log(`${funcName}: Could not find next row. Creating new line after table.`);
256
256
  const rep = editorInfo.ace_getRep();
257
257
  const lineTextLength = rep.lines.atIndex(currentLineNum).text.length;
258
258
  const endOfLinePos = [currentLineNum, lineTextLength];
@@ -270,7 +270,7 @@ function navigateToCellBelow(currentLineNum, currentCellIndex, tableMetadata, ed
270
270
  // We've now exited the table, so clear the last-clicked state.
271
271
  const editor = editorInfo.editor;
272
272
  if (editor) editor.ep_data_tables_last_clicked = null;
273
- // log(`${funcName}: Cleared last click info as we have exited the table.`);
273
+ // log(`${funcName}: Cleared last click info as we have exited the table.`);
274
274
 
275
275
  return true; // We handled it.
276
276
  }
@@ -290,12 +290,12 @@ function navigateToCellBelow(currentLineNum, currentCellIndex, tableMetadata, ed
290
290
  */
291
291
  function findLineForTableRow(tblId, targetRow, editorInfo, docManager) {
292
292
  const funcName = 'findLineForTableRow';
293
- // log(`${funcName}: Searching for tblId=${tblId}, row=${targetRow}`);
293
+ // log(`${funcName}: Searching for tblId=${tblId}, row=${targetRow}`);
294
294
 
295
295
  try {
296
296
  const rep = editorInfo.ace_getRep();
297
297
  if (!rep || !rep.lines) {
298
- // log(`${funcName}: Could not get rep or rep.lines`);
298
+ // log(`${funcName}: Could not get rep or rep.lines`);
299
299
  return -1;
300
300
  }
301
301
 
@@ -313,7 +313,7 @@ function findLineForTableRow(tblId, targetRow, editorInfo, docManager) {
313
313
  const domTblId = tableInDOM.getAttribute('data-tblId');
314
314
  const domRow = tableInDOM.getAttribute('data-row');
315
315
  if (domTblId === tblId && domRow !== null && parseInt(domRow, 10) === targetRow) {
316
- // log(`${funcName}: Found target via DOM: line ${lineIndex}`);
316
+ // log(`${funcName}: Found target via DOM: line ${lineIndex}`);
317
317
  return lineIndex;
318
318
  }
319
319
  }
@@ -323,7 +323,7 @@ function findLineForTableRow(tblId, targetRow, editorInfo, docManager) {
323
323
  if (lineAttrString) {
324
324
  const lineMetadata = JSON.parse(lineAttrString);
325
325
  if (lineMetadata.tblId === tblId && lineMetadata.row === targetRow) {
326
- // log(`${funcName}: Found target via attribute: line ${lineIndex}`);
326
+ // log(`${funcName}: Found target via attribute: line ${lineIndex}`);
327
327
  return lineIndex;
328
328
  }
329
329
  }
@@ -332,7 +332,7 @@ function findLineForTableRow(tblId, targetRow, editorInfo, docManager) {
332
332
  }
333
333
  }
334
334
 
335
- // log(`${funcName}: Target row not found`);
335
+ // log(`${funcName}: Target row not found`);
336
336
  return -1;
337
337
  } catch (e) {
338
338
  console.error(`[ep_data_tables] ${funcName}: Error searching for line:`, e);
@@ -350,19 +350,19 @@ function findLineForTableRow(tblId, targetRow, editorInfo, docManager) {
350
350
  */
351
351
  function navigateToCell(targetLineNum, targetCellIndex, editorInfo, docManager) {
352
352
  const funcName = 'navigateToCell';
353
- // log(`${funcName}: START - Target: Line=${targetLineNum}, Cell=${targetCellIndex}`);
353
+ // log(`${funcName}: START - Target: Line=${targetLineNum}, Cell=${targetCellIndex}`);
354
354
  let targetPos;
355
355
 
356
356
  try {
357
357
  const rep = editorInfo.ace_getRep();
358
358
  if (!rep || !rep.lines) {
359
- // log(`${funcName}: Could not get rep or rep.lines`);
359
+ // log(`${funcName}: Could not get rep or rep.lines`);
360
360
  return false;
361
361
  }
362
362
 
363
363
  const lineEntry = rep.lines.atIndex(targetLineNum);
364
364
  if (!lineEntry) {
365
- // log(`${funcName}: Could not get line entry for line ${targetLineNum}`);
365
+ // log(`${funcName}: Could not get line entry for line ${targetLineNum}`);
366
366
  return false;
367
367
  }
368
368
 
@@ -370,7 +370,7 @@ function navigateToCell(targetLineNum, targetCellIndex, editorInfo, docManager)
370
370
  const cells = lineText.split(DELIMITER);
371
371
 
372
372
  if (targetCellIndex >= cells.length) {
373
- // log(`${funcName}: Target cell ${targetCellIndex} doesn't exist (only ${cells.length} cells)`);
373
+ // log(`${funcName}: Target cell ${targetCellIndex} doesn't exist (only ${cells.length} cells)`);
374
374
  return false;
375
375
  }
376
376
 
@@ -397,12 +397,12 @@ function navigateToCell(targetLineNum, targetCellIndex, editorInfo, docManager)
397
397
  cellIndex: targetCellIndex,
398
398
  relativePos: targetCellContent.length,
399
399
  };
400
- // log(`${funcName}: Pre-emptively updated stored click info:`, editor.ep_data_tables_last_clicked);
400
+ // log(`${funcName}: Pre-emptively updated stored click info:`, editor.ep_data_tables_last_clicked);
401
401
  } else {
402
- // log(`${funcName}: Could not get table metadata for target line ${targetLineNum}, cannot update click info.`);
402
+ // log(`${funcName}: Could not get table metadata for target line ${targetLineNum}, cannot update click info.`);
403
403
  }
404
404
  } catch (e) {
405
- // log(`${funcName}: Could not update stored click info before navigation:`, e.message);
405
+ // log(`${funcName}: Could not update stored click info before navigation:`, e.message);
406
406
  }
407
407
 
408
408
  // The previous attempts involving wrappers and poking the renderer have all
@@ -412,17 +412,17 @@ function navigateToCell(targetLineNum, targetCellIndex, editorInfo, docManager)
412
412
  try {
413
413
  // 1. Update the internal representation of the selection.
414
414
  editorInfo.ace_performSelectionChange(targetPos, targetPos, false);
415
- // log(`${funcName}: Updated internal selection to [${targetPos}]`);
415
+ // log(`${funcName}: Updated internal selection to [${targetPos}]`);
416
416
 
417
417
  // 2. Explicitly tell the editor to update the browser's visual selection
418
418
  // to match the new internal representation. This is the correct way to
419
419
  // make the caret appear in the new location without causing a race condition.
420
420
  editorInfo.ace_updateBrowserSelectionFromRep();
421
- // log(`${funcName}: Called updateBrowserSelectionFromRep to sync visual caret.`);
421
+ // log(`${funcName}: Called updateBrowserSelectionFromRep to sync visual caret.`);
422
422
 
423
423
  // 3. Ensure the editor has focus.
424
424
  editorInfo.ace_focus();
425
- // log(`${funcName}: Editor focused.`);
425
+ // log(`${funcName}: Editor focused.`);
426
426
 
427
427
  } catch(e) {
428
428
  console.error(`[ep_data_tables] ${funcName}: Error during direct navigation update:`, e);
@@ -435,7 +435,7 @@ function navigateToCell(targetLineNum, targetCellIndex, editorInfo, docManager)
435
435
  return false;
436
436
  }
437
437
 
438
- // log(`${funcName}: Navigation considered successful.`);
438
+ // log(`${funcName}: Navigation considered successful.`);
439
439
  return true;
440
440
  }
441
441
 
@@ -446,36 +446,36 @@ exports.collectContentPre = (hook, ctx) => {
446
446
  const state = ctx.state;
447
447
  const cc = ctx.cc; // ContentCollector instance
448
448
 
449
- // log(`${funcName}: *** ENTRY POINT *** Hook: ${hook}, Node: ${node?.tagName}.${node?.className}`);
449
+ // log(`${funcName}: *** ENTRY POINT *** Hook: ${hook}, Node: ${node?.tagName}.${node?.className}`);
450
450
 
451
451
  // ***** START Primary Path: Reconstruct from rendered table *****
452
452
  if (node?.classList?.contains('ace-line')) {
453
453
  const tableNode = node.querySelector('table.dataTable[data-tblId]');
454
454
  if (tableNode) {
455
- // log(`${funcName}: Found ace-line with rendered table. Attempting reconstruction from DOM.`);
455
+ // log(`${funcName}: Found ace-line with rendered table. Attempting reconstruction from DOM.`);
456
456
 
457
457
  const docManager = cc.documentAttributeManager;
458
458
  const rep = cc.rep;
459
459
  const lineNum = rep?.lines?.indexOfKey(node.id);
460
460
 
461
461
  if (typeof lineNum === 'number' && lineNum >= 0 && docManager) {
462
- // log(`${funcName}: Processing line ${lineNum} (NodeID: ${node.id}) for DOM reconstruction.`);
462
+ // log(`${funcName}: Processing line ${lineNum} (NodeID: ${node.id}) for DOM reconstruction.`);
463
463
  try {
464
464
  const existingAttrString = docManager.getAttributeOnLine(lineNum, ATTR_TABLE_JSON);
465
- // log(`${funcName}: Line ${lineNum} existing ${ATTR_TABLE_JSON} attribute: '${existingAttrString}'`);
465
+ // log(`${funcName}: Line ${lineNum} existing ${ATTR_TABLE_JSON} attribute: '${existingAttrString}'`);
466
466
 
467
467
  if (existingAttrString) {
468
468
  const existingMetadata = JSON.parse(existingAttrString);
469
469
  if (existingMetadata && typeof existingMetadata.tblId !== 'undefined' &&
470
470
  typeof existingMetadata.row !== 'undefined' && typeof existingMetadata.cols === 'number') {
471
- // log(`${funcName}: Line ${lineNum} existing metadata is valid:`, existingMetadata);
471
+ // log(`${funcName}: Line ${lineNum} existing metadata is valid:`, existingMetadata);
472
472
 
473
473
  const trNode = tableNode.querySelector('tbody > tr');
474
474
  if (trNode) {
475
- // log(`${funcName}: Line ${lineNum} found <tr> node for cell content extraction.`);
475
+ // log(`${funcName}: Line ${lineNum} found <tr> node for cell content extraction.`);
476
476
  let cellHTMLSegments = Array.from(trNode.children).map((td, index) => {
477
477
  let segmentHTML = td.innerHTML || '';
478
- // log(`${funcName}: Line ${lineNum} TD[${index}] raw innerHTML (first 100): "${segmentHTML.substring(0,100)}"`);
478
+ // log(`${funcName}: Line ${lineNum} TD[${index}] raw innerHTML (first 100): "${segmentHTML.substring(0,100)}"`);
479
479
 
480
480
  const resizeHandleRegex = /<div class="ep-data_tables-resize-handle"[^>]*><\/div>/ig;
481
481
  segmentHTML = segmentHTML.replace(resizeHandleRegex, '');
@@ -496,44 +496,44 @@ exports.collectContentPre = (hook, ctx) => {
496
496
  const hidden = index === 0 ? '' :
497
497
  /* keep the char in the DOM but make it visually disappear and non-editable */
498
498
  `<span class="ep-data_tables-delim" contenteditable="false">${HIDDEN_DELIM}</span>`;
499
- // log(`${funcName}: Line ${lineNum} TD[${index}] cleaned innerHTML (first 100): "${segmentHTML.substring(0,100)}"`);
499
+ // log(`${funcName}: Line ${lineNum} TD[${index}] cleaned innerHTML (first 100): "${segmentHTML.substring(0,100)}"`);
500
500
  return segmentHTML;
501
501
  });
502
502
 
503
503
  if (cellHTMLSegments.length !== existingMetadata.cols) {
504
- // log(`${funcName}: WARNING Line ${lineNum}: Reconstructed cell count (${cellHTMLSegments.length}) does not match metadata cols (${existingMetadata.cols}). Padding/truncating.`);
504
+ // log(`${funcName}: WARNING Line ${lineNum}: Reconstructed cell count (${cellHTMLSegments.length}) does not match metadata cols (${existingMetadata.cols}). Padding/truncating.`);
505
505
  while (cellHTMLSegments.length < existingMetadata.cols) cellHTMLSegments.push('');
506
506
  if (cellHTMLSegments.length > existingMetadata.cols) cellHTMLSegments.length = existingMetadata.cols;
507
507
  }
508
508
 
509
509
  const canonicalLineText = cellHTMLSegments.join(DELIMITER);
510
510
  state.line = canonicalLineText;
511
- // log(`${funcName}: Line ${lineNum} successfully reconstructed ctx.state.line: "${canonicalLineText.substring(0, 200)}..."`);
511
+ // log(`${funcName}: Line ${lineNum} successfully reconstructed ctx.state.line: "${canonicalLineText.substring(0, 200)}..."`);
512
512
 
513
513
  state.lineAttributes = state.lineAttributes || [];
514
514
  state.lineAttributes = state.lineAttributes.filter(attr => attr[0] !== ATTR_TABLE_JSON);
515
515
  state.lineAttributes.push([ATTR_TABLE_JSON, existingAttrString]);
516
- // log(`${funcName}: Line ${lineNum} ensured ${ATTR_TABLE_JSON} attribute is in state.lineAttributes.`);
516
+ // log(`${funcName}: Line ${lineNum} ensured ${ATTR_TABLE_JSON} attribute is in state.lineAttributes.`);
517
517
 
518
- // log(`${funcName}: Line ${lineNum} reconstruction complete. Returning undefined to prevent default DOM collection.`);
518
+ // log(`${funcName}: Line ${lineNum} reconstruction complete. Returning undefined to prevent default DOM collection.`);
519
519
  return undefined;
520
520
  } else {
521
- // log(`${funcName}: ERROR Line ${lineNum}: Could not find tbody > tr in rendered table for reconstruction.`);
521
+ // log(`${funcName}: ERROR Line ${lineNum}: Could not find tbody > tr in rendered table for reconstruction.`);
522
522
  }
523
523
  } else {
524
- // log(`${funcName}: ERROR Line ${lineNum}: Invalid or incomplete existing metadata from line attribute:`, existingMetadata);
524
+ // log(`${funcName}: ERROR Line ${lineNum}: Invalid or incomplete existing metadata from line attribute:`, existingMetadata);
525
525
  }
526
526
  } else {
527
- // log(`${funcName}: WARNING Line ${lineNum}: No existing ${ATTR_TABLE_JSON} attribute found for reconstruction, despite table DOM presence. Table may be malformed or attribute lost.`);
527
+ // log(`${funcName}: WARNING Line ${lineNum}: No existing ${ATTR_TABLE_JSON} attribute found for reconstruction, despite table DOM presence. Table may be malformed or attribute lost.`);
528
528
  const domTblId = tableNode.getAttribute('data-tblId');
529
529
  const domRow = tableNode.getAttribute('data-row');
530
530
  const trNode = tableNode.querySelector('tbody > tr');
531
531
  if (domTblId && domRow !== null && trNode && trNode.children.length > 0) {
532
- // log(`${funcName}: Line ${lineNum} FALLBACK: Attempting reconstruction using table DOM attributes as ${ATTR_TABLE_JSON} was missing.`);
532
+ // log(`${funcName}: Line ${lineNum} FALLBACK: Attempting reconstruction using table DOM attributes as ${ATTR_TABLE_JSON} was missing.`);
533
533
  const domCols = trNode.children.length;
534
534
  const tempMetadata = {tblId: domTblId, row: parseInt(domRow, 10), cols: domCols};
535
535
  const tempAttrString = JSON.stringify(tempMetadata);
536
- // log(`${funcName}: Line ${lineNum} FALLBACK: Constructed temporary metadata: ${tempAttrString}`);
536
+ // log(`${funcName}: Line ${lineNum} FALLBACK: Constructed temporary metadata: ${tempAttrString}`);
537
537
 
538
538
  let cellHTMLSegments = Array.from(trNode.children).map((td, index) => {
539
539
  let segmentHTML = td.innerHTML || '';
@@ -553,7 +553,7 @@ exports.collectContentPre = (hook, ctx) => {
553
553
  });
554
554
 
555
555
  if (cellHTMLSegments.length !== domCols) {
556
- // log(`${funcName}: WARNING Line ${lineNum} (Fallback): Reconstructed cell count (${cellHTMLSegments.length}) does not match DOM cols (${domCols}).`);
556
+ // log(`${funcName}: WARNING Line ${lineNum} (Fallback): Reconstructed cell count (${cellHTMLSegments.length}) does not match DOM cols (${domCols}).`);
557
557
  while(cellHTMLSegments.length < domCols) cellHTMLSegments.push('');
558
558
  if(cellHTMLSegments.length > domCols) cellHTMLSegments.length = domCols;
559
559
  }
@@ -563,24 +563,24 @@ exports.collectContentPre = (hook, ctx) => {
563
563
  state.lineAttributes = state.lineAttributes || [];
564
564
  state.lineAttributes = state.lineAttributes.filter(attr => attr[0] !== ATTR_TABLE_JSON);
565
565
  state.lineAttributes.push([ATTR_TABLE_JSON, tempAttrString]);
566
- // log(`${funcName}: Line ${lineNum} FALLBACK: Successfully reconstructed line using DOM attributes. Returning undefined.`);
566
+ // log(`${funcName}: Line ${lineNum} FALLBACK: Successfully reconstructed line using DOM attributes. Returning undefined.`);
567
567
  return undefined;
568
568
  } else {
569
- // log(`${funcName}: Line ${lineNum} FALLBACK: Could not reconstruct from DOM attributes due to missing info.`);
569
+ // log(`${funcName}: Line ${lineNum} FALLBACK: Could not reconstruct from DOM attributes due to missing info.`);
570
570
  }
571
571
  }
572
572
  } catch (e) {
573
573
  console.error(`[ep_data_tables] ${funcName}: Line ${lineNum} error during DOM reconstruction:`, e);
574
- // log(`${funcName}: Line ${lineNum} Exception details:`, { message: e.message, stack: e.stack });
574
+ // log(`${funcName}: Line ${lineNum} Exception details:`, { message: e.message, stack: e.stack });
575
575
  }
576
576
  } else {
577
- // log(`${funcName}: Could not get valid line number (${lineNum}), rep, or docManager for DOM reconstruction of ace-line.`);
577
+ // log(`${funcName}: Could not get valid line number (${lineNum}), rep, or docManager for DOM reconstruction of ace-line.`);
578
578
  }
579
579
  } else {
580
- // log(`${funcName}: Node is ace-line but no rendered table.dataTable[data-tblId] found. Allowing normal processing for: ${node?.className}`);
580
+ // log(`${funcName}: Node is ace-line but no rendered table.dataTable[data-tblId] found. Allowing normal processing for: ${node?.className}`);
581
581
  }
582
582
  } else {
583
- // log(`${funcName}: Node is not an ace-line (or node is null). Node: ${node?.tagName}.${node?.className}. Allowing normal processing.`);
583
+ // log(`${funcName}: Node is not an ace-line (or node is null). Node: ${node?.tagName}.${node?.className}. Allowing normal processing.`);
584
584
  }
585
585
  // ***** END Primary Path *****
586
586
 
@@ -589,19 +589,19 @@ exports.collectContentPre = (hook, ctx) => {
589
589
  const classes = ctx.cls ? ctx.cls.split(' ') : [];
590
590
  let appliedAttribFromClass = false;
591
591
  if (classes.length > 0) {
592
- // log(`${funcName}: Secondary path - Checking classes on node ${node?.tagName}.${node?.className}: [${classes.join(', ')}]`);
592
+ // log(`${funcName}: Secondary path - Checking classes on node ${node?.tagName}.${node?.className}: [${classes.join(', ')}]`);
593
593
  for (const cls of classes) {
594
594
  if (cls.startsWith('tbljson-')) {
595
- // log(`${funcName}: Secondary path - Found tbljson class: ${cls} on node ${node?.tagName}.${node?.className}`);
595
+ // log(`${funcName}: Secondary path - Found tbljson class: ${cls} on node ${node?.tagName}.${node?.className}`);
596
596
  const encodedMetadata = cls.substring(8);
597
597
  try {
598
598
  const decodedMetadata = dec(encodedMetadata);
599
599
  if (decodedMetadata) {
600
600
  cc.doAttrib(state, `${ATTR_TABLE_JSON}::${decodedMetadata}`);
601
601
  appliedAttribFromClass = true;
602
- // log(`${funcName}: Secondary path - Applied attribute to OP via cc.doAttrib for class ${cls.substring(0, 20)}... on ${node?.tagName}`);
602
+ // log(`${funcName}: Secondary path - Applied attribute to OP via cc.doAttrib for class ${cls.substring(0, 20)}... on ${node?.tagName}`);
603
603
  } else {
604
- // log(`${funcName}: Secondary path - ERROR - Decoded metadata is null or empty for class ${cls}`);
604
+ // log(`${funcName}: Secondary path - ERROR - Decoded metadata is null or empty for class ${cls}`);
605
605
  }
606
606
  } catch (e) {
607
607
  console.error(`[ep_data_tables] ${funcName}: Secondary path - Error processing tbljson class ${cls} on ${node?.tagName}:`, e);
@@ -610,49 +610,49 @@ exports.collectContentPre = (hook, ctx) => {
610
610
  }
611
611
  }
612
612
  if (!appliedAttribFromClass && classes.some(c => c.startsWith('tbljson-'))) {
613
- // log(`${funcName}: Secondary path - Found tbljson- class but failed to apply attribute.`);
613
+ // log(`${funcName}: Secondary path - Found tbljson- class but failed to apply attribute.`);
614
614
  } else if (!classes.some(c => c.startsWith('tbljson-'))) {
615
- // log(`${funcName}: Secondary path - No tbljson- class found on this node.`);
615
+ // log(`${funcName}: Secondary path - No tbljson- class found on this node.`);
616
616
  }
617
617
  } else {
618
- // log(`${funcName}: Secondary path - Node ${node?.tagName}.${node?.className} has no ctx.cls or classes array is empty.`);
618
+ // log(`${funcName}: Secondary path - Node ${node?.tagName}.${node?.className} has no ctx.cls or classes array is empty.`);
619
619
  }
620
620
 
621
- // log(`${funcName}: *** EXIT POINT *** For Node: ${node?.tagName}.${node?.className}. Applied from class: ${appliedAttribFromClass}`);
621
+ // log(`${funcName}: *** EXIT POINT *** For Node: ${node?.tagName}.${node?.className}. Applied from class: ${appliedAttribFromClass}`);
622
622
  };
623
623
 
624
624
  // ───────────── attribute → span‑class mapping (linestylefilter hook) ─────────
625
625
  exports.aceAttribsToClasses = (hook, ctx) => {
626
626
  const funcName = 'aceAttribsToClasses';
627
- // log(`>>>> ${funcName}: Called with key: ${ctx.key}`); // log entry
627
+ // log(`>>>> ${funcName}: Called with key: ${ctx.key}`); // log entry
628
628
  if (ctx.key === ATTR_TABLE_JSON) {
629
- // log(`${funcName}: Processing ATTR_TABLE_JSON.`);
629
+ // log(`${funcName}: Processing ATTR_TABLE_JSON.`);
630
630
  // ctx.value is the raw JSON string from Etherpad's attribute pool
631
631
  const rawJsonValue = ctx.value;
632
- // log(`${funcName}: Received raw attribute value (ctx.value):`, rawJsonValue);
632
+ // log(`${funcName}: Received raw attribute value (ctx.value):`, rawJsonValue);
633
633
 
634
634
  // Attempt to parse for logging purposes
635
635
  let parsedMetadataForLog = '[JSON Parse Error]';
636
636
  try {
637
637
  parsedMetadataForLog = JSON.parse(rawJsonValue);
638
- // log(`${funcName}: Value parsed for logging:`, parsedMetadataForLog);
638
+ // log(`${funcName}: Value parsed for logging:`, parsedMetadataForLog);
639
639
  } catch(e) {
640
- // log(`${funcName}: Error parsing raw JSON value for logging:`, e);
640
+ // log(`${funcName}: Error parsing raw JSON value for logging:`, e);
641
641
  // Continue anyway, enc() might still work if it's just a string
642
642
  }
643
643
 
644
644
  // Generate the class name by base64 encoding the raw JSON string.
645
645
  // This ensures acePostWriteDomLineHTML receives the expected encoded format.
646
646
  const className = `tbljson-${enc(rawJsonValue)}`;
647
- // log(`${funcName}: Generated class name by encoding raw JSON: ${className}`);
647
+ // log(`${funcName}: Generated class name by encoding raw JSON: ${className}`);
648
648
  return [className];
649
649
  }
650
650
  if (ctx.key === ATTR_CELL) {
651
651
  // Keep this in case we want cell-specific styling later
652
- // // log(`${funcName}: Processing ATTR_CELL: ${ctx.value}`); // Optional: Uncomment if needed
652
+ //// log(`${funcName}: Processing ATTR_CELL: ${ctx.value}`); // Optional: Uncomment if needed
653
653
  return [`tblCell-${ctx.value}`];
654
654
  }
655
- // // log(`${funcName}: Processing other key: ${ctx.key}`); // Optional: Uncomment if needed
655
+ //// log(`${funcName}: Processing other key: ${ctx.key}`); // Optional: Uncomment if needed
656
656
  return [];
657
657
  };
658
658
 
@@ -675,11 +675,11 @@ function escapeHtml(text = '') {
675
675
  // NEW Helper function to build table HTML from pre-rendered delimited content with resize handles
676
676
  function buildTableFromDelimitedHTML(metadata, innerHTMLSegments) {
677
677
  const funcName = 'buildTableFromDelimitedHTML';
678
- // log(`${funcName}: START`, { metadata, innerHTMLSegments });
678
+ // log(`${funcName}: START`, { metadata, innerHTMLSegments });
679
679
 
680
680
  if (!metadata || typeof metadata.tblId === 'undefined' || typeof metadata.row === 'undefined') {
681
681
  console.error(`[ep_data_tables] ${funcName}: Invalid or missing metadata. Aborting.`);
682
- // log(`${funcName}: END - Error`);
682
+ // log(`${funcName}: END - Error`);
683
683
  return '<table class="dataTable dataTable-error"><tbody><tr><td>Error: Missing table metadata</td></tr></tbody></table>'; // Return error table
684
684
  }
685
685
 
@@ -745,17 +745,17 @@ function buildTableFromDelimitedHTML(metadata, innerHTMLSegments) {
745
745
  const tdContent = `<td style="${cellStyle}" data-column="${index}" draggable="false">${modifiedSegment}${resizeHandle}</td>`;
746
746
  return tdContent;
747
747
  }).join('');
748
- // log(`${funcName}: Joined all cellsHtml:`, cellsHtml);
748
+ // log(`${funcName}: Joined all cellsHtml:`, cellsHtml);
749
749
 
750
750
  // Add 'dataTable-first-row' class if it's the logical first row (row index 0)
751
751
  const firstRowClass = metadata.row === 0 ? ' dataTable-first-row' : '';
752
- // log(`${funcName}: First row class applied: '${firstRowClass}'`);
752
+ // log(`${funcName}: First row class applied: '${firstRowClass}'`);
753
753
 
754
754
  // Construct the final table HTML
755
755
  // Rely on CSS for border-collapse, width etc. Add data attributes from metadata.
756
- const tableHtml = `<table class="dataTable${firstRowClass}" data-tblId="${metadata.tblId}" data-row="${metadata.row}" style="width:100%; border-collapse: collapse; table-layout: fixed;" draggable="false"><tbody><tr>${cellsHtml}</tr></tbody></table>`;
757
- // log(`${funcName}: Generated final table HTML:`, tableHtml);
758
- // log(`${funcName}: END - Success`);
756
+ const tableHtml = `<table class="dataTable${firstRowClass}" writingsuggestions="false" data-tblId="${metadata.tblId}" data-row="${metadata.row}" style="width:100%; border-collapse: collapse; table-layout: fixed;" draggable="false"><tbody><tr>${cellsHtml}</tr></tbody></table>`;
757
+ // log(`${funcName}: Generated final table HTML:`, tableHtml);
758
+ // log(`${funcName}: END - Success`);
759
759
  return tableHtml;
760
760
  }
761
761
 
@@ -768,28 +768,28 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
768
768
  const logPrefix = '[ep_data_tables:acePostWriteDomLineHTML]'; // Consistent prefix
769
769
 
770
770
  // *** STARTUP LOGGING ***
771
- // log(`${logPrefix} ----- START ----- NodeID: ${nodeId} LineNum: ${lineNum}`);
771
+ // log(`${logPrefix} ----- START ----- NodeID: ${nodeId} LineNum: ${lineNum}`);
772
772
  if (!node || !nodeId) {
773
- // log(`${logPrefix} ERROR - Received invalid node or node without ID. Aborting.`);
773
+ // log(`${logPrefix} ERROR - Received invalid node or node without ID. Aborting.`);
774
774
  console.error(`[ep_data_tables] ${funcName}: Received invalid node or node without ID.`);
775
775
  return cb();
776
776
  }
777
777
 
778
778
  // *** ENHANCED DEBUG: Log complete DOM state ***
779
- // log(`${logPrefix} NodeID#${nodeId}: COMPLETE DOM STRUCTURE DEBUG:`);
780
- // log(`${logPrefix} NodeID#${nodeId}: Node tagName: ${node.tagName}`);
781
- // log(`${logPrefix} NodeID#${nodeId}: Node className: ${node.className}`);
782
- // log(`${logPrefix} NodeID#${nodeId}: Node innerHTML length: ${node.innerHTML?.length || 0}`);
783
- // log(`${logPrefix} NodeID#${nodeId}: Node innerHTML (first 500 chars): "${(node.innerHTML || '').substring(0, 500)}"`);
784
- // log(`${logPrefix} NodeID#${nodeId}: Node children count: ${node.children?.length || 0}`);
779
+ // log(`${logPrefix} NodeID#${nodeId}: COMPLETE DOM STRUCTURE DEBUG:`);
780
+ // log(`${logPrefix} NodeID#${nodeId}: Node tagName: ${node.tagName}`);
781
+ // log(`${logPrefix} NodeID#${nodeId}: Node className: ${node.className}`);
782
+ // log(`${logPrefix} NodeID#${nodeId}: Node innerHTML length: ${node.innerHTML?.length || 0}`);
783
+ // log(`${logPrefix} NodeID#${nodeId}: Node innerHTML (first 500 chars): "${(node.innerHTML || '').substring(0, 500)}"`);
784
+ // log(`${logPrefix} NodeID#${nodeId}: Node children count: ${node.children?.length || 0}`);
785
785
 
786
786
  // log all child elements and their classes
787
787
  if (node.children) {
788
788
  for (let i = 0; i < Math.min(node.children.length, 10); i++) {
789
789
  const child = node.children[i];
790
- // log(`${logPrefix} NodeID#${nodeId}: Child[${i}] tagName: ${child.tagName}, className: "${child.className}", innerHTML length: ${child.innerHTML?.length || 0}`);
790
+ // log(`${logPrefix} NodeID#${nodeId}: Child[${i}] tagName: ${child.tagName}, className: "${child.className}", innerHTML length: ${child.innerHTML?.length || 0}`);
791
791
  if (child.className && child.className.includes('tbljson-')) {
792
- // log(`${logPrefix} NodeID#${nodeId}: *** FOUND TBLJSON CLASS ON CHILD[${i}] ***`);
792
+ // log(`${logPrefix} NodeID#${nodeId}: *** FOUND TBLJSON CLASS ON CHILD[${i}] ***`);
793
793
  }
794
794
  }
795
795
  }
@@ -798,69 +798,69 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
798
798
  let encodedJsonString = null;
799
799
 
800
800
  // --- 1. Find and Parse Metadata Attribute ---
801
- // log(`${logPrefix} NodeID#${nodeId}: Searching for tbljson-* class...`);
801
+ // log(`${logPrefix} NodeID#${nodeId}: Searching for tbljson-* class...`);
802
802
 
803
803
  // ENHANCED Helper function to recursively search for tbljson class in all descendants
804
804
  function findTbljsonClass(element, depth = 0, path = '') {
805
805
  const indent = ' '.repeat(depth);
806
- // log(`${logPrefix} NodeID#${nodeId}: ${indent}Searching element: ${element.tagName || 'unknown'}, path: ${path}`);
806
+ // log(`${logPrefix} NodeID#${nodeId}: ${indent}Searching element: ${element.tagName || 'unknown'}, path: ${path}`);
807
807
 
808
808
  // Check the element itself
809
809
  if (element.classList) {
810
- // log(`${logPrefix} NodeID#${nodeId}: ${indent}Element has ${element.classList.length} classes: [${Array.from(element.classList).join(', ')}]`);
810
+ // log(`${logPrefix} NodeID#${nodeId}: ${indent}Element has ${element.classList.length} classes: [${Array.from(element.classList).join(', ')}]`);
811
811
  for (const cls of element.classList) {
812
812
  if (cls.startsWith('tbljson-')) {
813
- // log(`${logPrefix} NodeID#${nodeId}: ${indent}*** FOUND TBLJSON CLASS: ${cls.substring(8)} at depth ${depth}, path: ${path} ***`);
813
+ // log(`${logPrefix} NodeID#${nodeId}: ${indent}*** FOUND TBLJSON CLASS: ${cls.substring(8)} at depth ${depth}, path: ${path} ***`);
814
814
  return cls.substring(8);
815
815
  }
816
816
  }
817
817
  } else {
818
- // log(`${logPrefix} NodeID#${nodeId}: ${indent}Element has no classList`);
818
+ // log(`${logPrefix} NodeID#${nodeId}: ${indent}Element has no classList`);
819
819
  }
820
820
 
821
821
  // Recursively check all descendants
822
822
  if (element.children) {
823
- // log(`${logPrefix} NodeID#${nodeId}: ${indent}Element has ${element.children.length} children`);
823
+ // log(`${logPrefix} NodeID#${nodeId}: ${indent}Element has ${element.children.length} children`);
824
824
  for (let i = 0; i < element.children.length; i++) {
825
825
  const child = element.children[i];
826
826
  const childPath = `${path}>${child.tagName}[${i}]`;
827
827
  const found = findTbljsonClass(child, depth + 1, childPath);
828
828
  if (found) {
829
- // log(`${logPrefix} NodeID#${nodeId}: ${indent}Returning found result from child: ${found}`);
829
+ // log(`${logPrefix} NodeID#${nodeId}: ${indent}Returning found result from child: ${found}`);
830
830
  return found;
831
831
  }
832
832
  }
833
833
  } else {
834
- // log(`${logPrefix} NodeID#${nodeId}: ${indent}Element has no children`);
834
+ // log(`${logPrefix} NodeID#${nodeId}: ${indent}Element has no children`);
835
835
  }
836
836
 
837
- // log(`${logPrefix} NodeID#${nodeId}: ${indent}No tbljson class found in this element or its children`);
837
+ // log(`${logPrefix} NodeID#${nodeId}: ${indent}No tbljson class found in this element or its children`);
838
838
  return null;
839
839
  }
840
840
 
841
841
  // Search for tbljson class starting from the node
842
- // log(`${logPrefix} NodeID#${nodeId}: Starting recursive search for tbljson class...`);
842
+ // log(`${logPrefix} NodeID#${nodeId}: Starting recursive search for tbljson class...`);
843
843
  encodedJsonString = findTbljsonClass(node, 0, 'ROOT');
844
844
 
845
845
  if (encodedJsonString) {
846
- // log(`${logPrefix} NodeID#${nodeId}: *** SUCCESS: Found encoded tbljson class: ${encodedJsonString} ***`);
846
+ // log(`${logPrefix} NodeID#${nodeId}: *** SUCCESS: Found encoded tbljson class: ${encodedJsonString} ***`);
847
847
  } else {
848
- // log(`${logPrefix} NodeID#${nodeId}: *** NO TBLJSON CLASS FOUND ***`);
848
+ // log(`${logPrefix} NodeID#${nodeId}: *** NO TBLJSON CLASS FOUND ***`);
849
849
  }
850
850
 
851
851
  // If no attribute found, it's not a table line managed by us
852
852
  if (!encodedJsonString) {
853
- // log(`${logPrefix} NodeID#${nodeId}: No tbljson-* class found. Assuming not a table line. END.`);
853
+ // log(`${logPrefix} NodeID#${nodeId}: No tbljson-* class found. Assuming not a table line. END.`);
854
854
 
855
855
  // DEBUG: Add detailed logging to understand why tbljson class is missing
856
- // log(`${logPrefix} NodeID#${nodeId}: DEBUG - Node tag: ${node.tagName}, Node classes:`, Array.from(node.classList || []));
857
- // log(`${logPrefix} NodeID#${nodeId}: DEBUG - Node innerHTML (first 200 chars): "${(node.innerHTML || '').substring(0, 200)}"`);
856
+ // log(`${logPrefix} NodeID#${nodeId}: DEBUG - Node tag: ${node.tagName}, Node classes:`, Array.from(node.classList || []));
857
+ // log(`${logPrefix} NodeID#${nodeId}: DEBUG - Node innerHTML (first 200 chars): "${(node.innerHTML || '').substring(0, 200)}"`);
858
858
 
859
859
  // Check if there are any child elements with classes
860
860
  if (node.children && node.children.length > 0) {
861
861
  for (let i = 0; i < Math.min(node.children.length, 5); i++) {
862
862
  const child = node.children[i];
863
- // log(`${logPrefix} NodeID#${nodeId}: DEBUG - Child ${i} tag: ${child.tagName}, classes:`, Array.from(child.classList || []));
863
+ // log(`${logPrefix} NodeID#${nodeId}: DEBUG - Child ${i} tag: ${child.tagName}, classes:`, Array.from(child.classList || []));
864
864
  }
865
865
  }
866
866
 
@@ -869,24 +869,24 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
869
869
  if (existingTable) {
870
870
  const existingTblId = existingTable.getAttribute('data-tblId');
871
871
  const existingRow = existingTable.getAttribute('data-row');
872
- // log(`${logPrefix} NodeID#${nodeId}: DEBUG - Found orphaned table! TblId: ${existingTblId}, Row: ${existingRow}`);
872
+ // log(`${logPrefix} NodeID#${nodeId}: DEBUG - Found orphaned table! TblId: ${existingTblId}, Row: ${existingRow}`);
873
873
 
874
874
  // This suggests the table exists but the tbljson class was lost
875
875
  // Check if we're in a post-resize situation
876
876
  if (existingTblId && existingRow !== null) {
877
- // log(`${logPrefix} NodeID#${nodeId}: POTENTIAL ISSUE - Table exists but no tbljson class. This may be a post-resize issue.`);
877
+ // log(`${logPrefix} NodeID#${nodeId}: POTENTIAL ISSUE - Table exists but no tbljson class. This may be a post-resize issue.`);
878
878
 
879
879
  // Try to look up what the metadata should be based on the table attributes
880
880
  const tableCells = existingTable.querySelectorAll('td');
881
- // log(`${logPrefix} NodeID#${nodeId}: Table has ${tableCells.length} cells`);
881
+ // log(`${logPrefix} NodeID#${nodeId}: Table has ${tableCells.length} cells`);
882
882
 
883
883
  // log the current line's attribute state if we can get line number
884
884
  if (lineNum !== undefined && args?.documentAttributeManager) {
885
885
  try {
886
886
  const currentLineAttr = args.documentAttributeManager.getAttributeOnLine(lineNum, ATTR_TABLE_JSON);
887
- // log(`${logPrefix} NodeID#${nodeId}: Current line ${lineNum} tbljson attribute: ${currentLineAttr || 'NULL'}`);
887
+ // log(`${logPrefix} NodeID#${nodeId}: Current line ${lineNum} tbljson attribute: ${currentLineAttr || 'NULL'}`);
888
888
  } catch (e) {
889
- // log(`${logPrefix} NodeID#${nodeId}: Error getting line attribute:`, e);
889
+ // log(`${logPrefix} NodeID#${nodeId}: Error getting line attribute:`, e);
890
890
  }
891
891
  }
892
892
  }
@@ -898,7 +898,7 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
898
898
  // *** NEW CHECK: If table already rendered, skip regeneration ***
899
899
  const existingTable = node.querySelector('table.dataTable[data-tblId]');
900
900
  if (existingTable) {
901
- // log(`${logPrefix} NodeID#${nodeId}: Table already exists in DOM. Skipping innerHTML replacement.`);
901
+ // log(`${logPrefix} NodeID#${nodeId}: Table already exists in DOM. Skipping innerHTML replacement.`);
902
902
  // Optionally, verify tblId matches metadata? For now, assume it's correct.
903
903
  // const existingTblId = existingTable.getAttribute('data-tblId');
904
904
  // try {
@@ -909,26 +909,26 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
909
909
  return cb(); // Do nothing further
910
910
  }
911
911
 
912
- // log(`${logPrefix} NodeID#${nodeId}: Decoding and parsing metadata...`);
912
+ // log(`${logPrefix} NodeID#${nodeId}: Decoding and parsing metadata...`);
913
913
  try {
914
914
  const decoded = dec(encodedJsonString);
915
- // log(`${logPrefix} NodeID#${nodeId}: Decoded string: ${decoded}`);
915
+ // log(`${logPrefix} NodeID#${nodeId}: Decoded string: ${decoded}`);
916
916
  if (!decoded) throw new Error('Decoded string is null or empty.');
917
917
  rowMetadata = JSON.parse(decoded);
918
- // log(`${logPrefix} NodeID#${nodeId}: Parsed rowMetadata:`, rowMetadata);
918
+ // log(`${logPrefix} NodeID#${nodeId}: Parsed rowMetadata:`, rowMetadata);
919
919
 
920
920
  // Validate essential metadata
921
921
  if (!rowMetadata || typeof rowMetadata.tblId === 'undefined' || typeof rowMetadata.row === 'undefined' || typeof rowMetadata.cols !== 'number') {
922
922
  throw new Error('Invalid or incomplete metadata (missing tblId, row, or cols).');
923
923
  }
924
- // log(`${logPrefix} NodeID#${nodeId}: Metadata validated successfully.`);
924
+ // log(`${logPrefix} NodeID#${nodeId}: Metadata validated successfully.`);
925
925
 
926
926
  } catch(e) {
927
- // log(`${logPrefix} NodeID#${nodeId}: FATAL ERROR - Failed to decode/parse/validate tbljson metadata. Rendering cannot proceed.`, e);
927
+ // log(`${logPrefix} NodeID#${nodeId}: FATAL ERROR - Failed to decode/parse/validate tbljson metadata. Rendering cannot proceed.`, e);
928
928
  console.error(`[ep_data_tables] ${funcName} NodeID#${nodeId}: Failed to decode/parse/validate tbljson.`, encodedJsonString, e);
929
929
  // Optionally render an error state in the node?
930
930
  node.innerHTML = '<div style="color:red; border: 1px solid red; padding: 5px;">[ep_data_tables] Error: Invalid table metadata attribute found.</div>';
931
- // log(`${logPrefix} NodeID#${nodeId}: Rendered error message in node. END.`);
931
+ // log(`${logPrefix} NodeID#${nodeId}: Rendered error message in node. END.`);
932
932
  return cb();
933
933
  }
934
934
  // --- End Metadata Parsing ---
@@ -942,23 +942,23 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
942
942
  // After an edit, aceKeyEvent updates atext, and node.innerHTML reflects that new "EditedCell1|Cell2" string.
943
943
  // When styling is applied, it will include spans like: <span class="author-xxx bold">Cell1</span>|<span class="author-yyy italic">Cell2</span>
944
944
  const delimitedTextFromLine = node.innerHTML;
945
- // log(`${logPrefix} NodeID#${nodeId}: Using node.innerHTML for delimited text to preserve styling.`);
946
- // log(`${logPrefix} NodeID#${nodeId}: Raw innerHTML length: ${delimitedTextFromLine?.length || 0}`);
947
- // log(`${logPrefix} NodeID#${nodeId}: Raw innerHTML (first 1000 chars): "${(delimitedTextFromLine || '').substring(0, 1000)}"`);
945
+ // log(`${logPrefix} NodeID#${nodeId}: Using node.innerHTML for delimited text to preserve styling.`);
946
+ // log(`${logPrefix} NodeID#${nodeId}: Raw innerHTML length: ${delimitedTextFromLine?.length || 0}`);
947
+ // log(`${logPrefix} NodeID#${nodeId}: Raw innerHTML (first 1000 chars): "${(delimitedTextFromLine || '').substring(0, 1000)}"`);
948
948
 
949
949
  // *** ENHANCED DEBUG: Analyze delimiter presence ***
950
950
  const delimiterCount = (delimitedTextFromLine || '').split(DELIMITER).length - 1;
951
- // log(`${logPrefix} NodeID#${nodeId}: Delimiter '${DELIMITER}' count in innerHTML: ${delimiterCount}`);
952
- // log(`${logPrefix} NodeID#${nodeId}: Expected delimiters for ${rowMetadata.cols} columns: ${rowMetadata.cols - 1}`);
951
+ // log(`${logPrefix} NodeID#${nodeId}: Delimiter '${DELIMITER}' count in innerHTML: ${delimiterCount}`);
952
+ // log(`${logPrefix} NodeID#${nodeId}: Expected delimiters for ${rowMetadata.cols} columns: ${rowMetadata.cols - 1}`);
953
953
 
954
954
  // log all delimiter positions
955
955
  let pos = -1;
956
956
  const delimiterPositions = [];
957
957
  while ((pos = delimitedTextFromLine.indexOf(DELIMITER, pos + 1)) !== -1) {
958
958
  delimiterPositions.push(pos);
959
- // log(`${logPrefix} NodeID#${nodeId}: Delimiter found at position ${pos}, context: "${delimitedTextFromLine.substring(Math.max(0, pos - 20), pos + 21)}"`);
959
+ // log(`${logPrefix} NodeID#${nodeId}: Delimiter found at position ${pos}, context: "${delimitedTextFromLine.substring(Math.max(0, pos - 20), pos + 21)}"`);
960
960
  }
961
- // log(`${logPrefix} NodeID#${nodeId}: All delimiter positions: [${delimiterPositions.join(', ')}]`);
961
+ // log(`${logPrefix} NodeID#${nodeId}: All delimiter positions: [${delimiterPositions.join(', ')}]`);
962
962
 
963
963
  // The DELIMITER const is defined at the top of this file.
964
964
  // NEW: Remove all hidden-delimiter <span> wrappers **before** we split so
@@ -971,37 +971,37 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
971
971
  .replace(/<span class="ep-data_tables-caret-anchor"[^>]*><\/span>/ig, '');
972
972
  const htmlSegments = sanitizedHTMLForSplit.split(DELIMITER);
973
973
 
974
- // log(`${logPrefix} NodeID#${nodeId}: *** SEGMENT ANALYSIS ***`);
975
- // log(`${logPrefix} NodeID#${nodeId}: Split resulted in ${htmlSegments.length} segments`);
974
+ // log(`${logPrefix} NodeID#${nodeId}: *** SEGMENT ANALYSIS ***`);
975
+ // log(`${logPrefix} NodeID#${nodeId}: Split resulted in ${htmlSegments.length} segments`);
976
976
  for (let i = 0; i < htmlSegments.length; i++) {
977
977
  const segment = htmlSegments[i] || '';
978
- // log(`${logPrefix} NodeID#${nodeId}: Segment[${i}] length: ${segment.length}`);
979
- // log(`${logPrefix} NodeID#${nodeId}: Segment[${i}] content (first 200 chars): "${segment.substring(0, 200)}"`);
978
+ // log(`${logPrefix} NodeID#${nodeId}: Segment[${i}] length: ${segment.length}`);
979
+ // log(`${logPrefix} NodeID#${nodeId}: Segment[${i}] content (first 200 chars): "${segment.substring(0, 200)}"`);
980
980
  if (segment.length > 200) {
981
- // log(`${logPrefix} NodeID#${nodeId}: Segment[${i}] content (chars 200-400): "${segment.substring(200, 400)}"`);
981
+ // log(`${logPrefix} NodeID#${nodeId}: Segment[${i}] content (chars 200-400): "${segment.substring(200, 400)}"`);
982
982
  }
983
983
  if (segment.length > 400) {
984
- // log(`${logPrefix} NodeID#${nodeId}: Segment[${i}] content (chars 400-600): "${segment.substring(400, 600)}"`);
984
+ // log(`${logPrefix} NodeID#${nodeId}: Segment[${i}] content (chars 400-600): "${segment.substring(400, 600)}"`);
985
985
  }
986
986
  // Check if segment contains image-related content
987
987
  if (segment.includes('image:') || segment.includes('image-placeholder') || segment.includes('currently-selected')) {
988
- // log(`${logPrefix} NodeID#${nodeId}: *** SEGMENT[${i}] CONTAINS IMAGE CONTENT ***`);
988
+ // log(`${logPrefix} NodeID#${nodeId}: *** SEGMENT[${i}] CONTAINS IMAGE CONTENT ***`);
989
989
  }
990
990
  }
991
991
 
992
- // log(`${logPrefix} NodeID#${nodeId}: Parsed HTML segments (${htmlSegments.length}):`, htmlSegments.map(s => (s || '').substring(0,50) + (s && s.length > 50 ? '...' : '')));
992
+ // log(`${logPrefix} NodeID#${nodeId}: Parsed HTML segments (${htmlSegments.length}):`, htmlSegments.map(s => (s || '').substring(0,50) + (s && s.length > 50 ? '...' : '')));
993
993
 
994
994
  // --- Enhanced Validation with Automatic Structure Reconstruction ---
995
995
  let finalHtmlSegments = htmlSegments;
996
996
 
997
997
  if (htmlSegments.length !== rowMetadata.cols) {
998
- // log(`${logPrefix} NodeID#${nodeId}: *** MISMATCH DETECTED *** - Attempting reconstruction.`);
998
+ // log(`${logPrefix} NodeID#${nodeId}: *** MISMATCH DETECTED *** - Attempting reconstruction.`);
999
999
 
1000
1000
  // Check if this is an image selection issue
1001
1001
  const hasImageSelected = delimitedTextFromLine.includes('currently-selected');
1002
1002
  const hasImageContent = delimitedTextFromLine.includes('image:');
1003
1003
  if (hasImageSelected) {
1004
- // log(`${logPrefix} NodeID#${nodeId}: *** POTENTIAL CAUSE: Image selection state may be affecting segment parsing ***`);
1004
+ // log(`${logPrefix} NodeID#${nodeId}: *** POTENTIAL CAUSE: Image selection state may be affecting segment parsing ***`);
1005
1005
  }
1006
1006
 
1007
1007
  // First attempt: reconstruct using DOM spans that carry tblCell-N classes
@@ -1073,14 +1073,14 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
1073
1073
  console.warn(`[ep_data_tables] ${funcName} NodeID#${nodeId}: Could not reconstruct to expected ${rowMetadata.cols} segments. Got ${finalHtmlSegments.length}.`);
1074
1074
  }
1075
1075
  } else {
1076
- // log(`${logPrefix} NodeID#${nodeId}: Segment count matches metadata cols (${rowMetadata.cols}). Using original segments.`);
1076
+ // log(`${logPrefix} NodeID#${nodeId}: Segment count matches metadata cols (${rowMetadata.cols}). Using original segments.`);
1077
1077
  }
1078
1078
 
1079
1079
  // --- 3. Build and Render Table ---
1080
- // log(`${logPrefix} NodeID#${nodeId}: Calling buildTableFromDelimitedHTML...`);
1080
+ // log(`${logPrefix} NodeID#${nodeId}: Calling buildTableFromDelimitedHTML...`);
1081
1081
  try {
1082
1082
  const newTableHTML = buildTableFromDelimitedHTML(rowMetadata, finalHtmlSegments);
1083
- // log(`${logPrefix} NodeID#${nodeId}: Received new table HTML from helper. Replacing content.`);
1083
+ // log(`${logPrefix} NodeID#${nodeId}: Received new table HTML from helper. Replacing content.`);
1084
1084
 
1085
1085
  // The old local findTbljsonElement is removed from here. We use the global one now.
1086
1086
  const tbljsonElement = findTbljsonElement(node);
@@ -1093,24 +1093,24 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
1093
1093
  const blockElements = ['center', 'div', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre', 'right', 'left', 'ul', 'ol', 'li', 'code'];
1094
1094
 
1095
1095
  if (blockElements.includes(parentTag)) {
1096
- // log(`${logPrefix} NodeID#${nodeId}: Preserving block element ${parentTag} and replacing its content with table.`);
1096
+ // log(`${logPrefix} NodeID#${nodeId}: Preserving block element ${parentTag} and replacing its content with table.`);
1097
1097
  tbljsonElement.parentElement.innerHTML = newTableHTML;
1098
1098
  } else {
1099
- // log(`${logPrefix} NodeID#${nodeId}: Parent element ${parentTag} is not a block element, replacing entire node content.`);
1099
+ // log(`${logPrefix} NodeID#${nodeId}: Parent element ${parentTag} is not a block element, replacing entire node content.`);
1100
1100
  node.innerHTML = newTableHTML;
1101
1101
  }
1102
1102
  } else {
1103
1103
  // Replace the node's content entirely with the generated table
1104
- // log(`${logPrefix} NodeID#${nodeId}: No nested block element found, replacing entire node content.`);
1104
+ // log(`${logPrefix} NodeID#${nodeId}: No nested block element found, replacing entire node content.`);
1105
1105
  node.innerHTML = newTableHTML;
1106
1106
  }
1107
1107
 
1108
- // log(`${logPrefix} NodeID#${nodeId}: Successfully replaced content with new table structure.`);
1108
+ // log(`${logPrefix} NodeID#${nodeId}: Successfully replaced content with new table structure.`);
1109
1109
  } catch (renderError) {
1110
- // log(`${logPrefix} NodeID#${nodeId}: ERROR during table building or rendering.`, renderError);
1110
+ // log(`${logPrefix} NodeID#${nodeId}: ERROR during table building or rendering.`, renderError);
1111
1111
  console.error(`[ep_data_tables] ${funcName} NodeID#${nodeId}: Error building/rendering table.`, renderError);
1112
1112
  node.innerHTML = '<div style="color:red; border: 1px solid red; padding: 5px;">[ep_data_tables] Error: Failed to render table structure.</div>';
1113
- // log(`${logPrefix} NodeID#${nodeId}: Rendered build/render error message in node. END.`);
1113
+ // log(`${logPrefix} NodeID#${nodeId}: Rendered build/render error message in node. END.`);
1114
1114
  return cb();
1115
1115
  }
1116
1116
  // --- End Table Building ---
@@ -1118,7 +1118,7 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
1118
1118
  // *** REMOVED CACHING LOGIC ***
1119
1119
  // The old logic based on tableRowNodes cache is completely removed.
1120
1120
 
1121
- // log(`${logPrefix}: ----- END ----- NodeID: ${nodeId}`);
1121
+ // log(`${logPrefix}: ----- END ----- NodeID: ${nodeId}`);
1122
1122
  return cb();
1123
1123
  };
1124
1124
 
@@ -1144,34 +1144,34 @@ exports.aceKeyEvent = (h, ctx) => {
1144
1144
 
1145
1145
  const startLogTime = Date.now();
1146
1146
  const logPrefix = '[ep_data_tables:aceKeyEvent]';
1147
- // log(`${logPrefix} START Key='${evt?.key}' Code=${evt?.keyCode} Type=${evt?.type} Modifiers={ctrl:${evt?.ctrlKey},alt:${evt?.altKey},meta:${evt?.metaKey},shift:${evt?.shiftKey}}`, { selStart: rep?.selStart, selEnd: rep?.selEnd });
1147
+ // log(`${logPrefix} START Key='${evt?.key}' Code=${evt?.keyCode} Type=${evt?.type} Modifiers={ctrl:${evt?.ctrlKey},alt:${evt?.altKey},meta:${evt?.metaKey},shift:${evt?.shiftKey}}`, { selStart: rep?.selStart, selEnd: rep?.selEnd });
1148
1148
 
1149
1149
  if (!rep || !rep.selStart || !editorInfo || !evt || !docManager) {
1150
- // log(`${logPrefix} Skipping - Missing critical context.`);
1150
+ // log(`${logPrefix} Skipping - Missing critical context.`);
1151
1151
  return false;
1152
1152
  }
1153
1153
 
1154
1154
  // Get caret info from event context - may be stale
1155
1155
  const reportedLineNum = rep.selStart[0];
1156
1156
  const reportedCol = rep.selStart[1];
1157
- // log(`${logPrefix} Reported caret from rep: Line=${reportedLineNum}, Col=${reportedCol}`);
1157
+ // log(`${logPrefix} Reported caret from rep: Line=${reportedLineNum}, Col=${reportedCol}`);
1158
1158
 
1159
1159
  // --- Get Table Metadata for the reported line ---
1160
1160
  let tableMetadata = null;
1161
1161
  let lineAttrString = null; // Store for potential use later
1162
1162
  try {
1163
1163
  // Add debugging to see what's happening with attribute retrieval
1164
- // log(`${logPrefix} DEBUG: Attempting to get ${ATTR_TABLE_JSON} attribute from line ${reportedLineNum}`);
1164
+ // log(`${logPrefix} DEBUG: Attempting to get ${ATTR_TABLE_JSON} attribute from line ${reportedLineNum}`);
1165
1165
  lineAttrString = docManager.getAttributeOnLine(reportedLineNum, ATTR_TABLE_JSON);
1166
- // log(`${logPrefix} DEBUG: getAttributeOnLine returned: ${lineAttrString ? `"${lineAttrString}"` : 'null/undefined'}`);
1166
+ // log(`${logPrefix} DEBUG: getAttributeOnLine returned: ${lineAttrString ? `"${lineAttrString}"` : 'null/undefined'}`);
1167
1167
 
1168
1168
  // Also check if there are any attributes on this line at all
1169
1169
  if (typeof docManager.getAttributesOnLine === 'function') {
1170
1170
  try {
1171
1171
  const allAttribs = docManager.getAttributesOnLine(reportedLineNum);
1172
- // log(`${logPrefix} DEBUG: All attributes on line ${reportedLineNum}:`, allAttribs);
1172
+ // log(`${logPrefix} DEBUG: All attributes on line ${reportedLineNum}:`, allAttribs);
1173
1173
  } catch(e) {
1174
- // log(`${logPrefix} DEBUG: Error getting all attributes:`, e);
1174
+ // log(`${logPrefix} DEBUG: Error getting all attributes:`, e);
1175
1175
  }
1176
1176
  }
1177
1177
 
@@ -1185,34 +1185,34 @@ exports.aceKeyEvent = (h, ctx) => {
1185
1185
  if (tableInDOM) {
1186
1186
  const domTblId = tableInDOM.getAttribute('data-tblId');
1187
1187
  const domRow = tableInDOM.getAttribute('data-row');
1188
- // log(`${logPrefix} DEBUG: Found table in DOM without attribute! TblId=${domTblId}, Row=${domRow}`);
1188
+ // log(`${logPrefix} DEBUG: Found table in DOM without attribute! TblId=${domTblId}, Row=${domRow}`);
1189
1189
  // Try to reconstruct the metadata from DOM
1190
1190
  const domCells = tableInDOM.querySelectorAll('td');
1191
1191
  if (domTblId && domRow !== null && domCells.length > 0) {
1192
- // log(`${logPrefix} DEBUG: Attempting to reconstruct metadata from DOM...`);
1192
+ // log(`${logPrefix} DEBUG: Attempting to reconstruct metadata from DOM...`);
1193
1193
  const reconstructedMetadata = {
1194
1194
  tblId: domTblId,
1195
1195
  row: parseInt(domRow, 10),
1196
1196
  cols: domCells.length
1197
1197
  };
1198
1198
  lineAttrString = JSON.stringify(reconstructedMetadata);
1199
- // log(`${logPrefix} DEBUG: Reconstructed metadata: ${lineAttrString}`);
1199
+ // log(`${logPrefix} DEBUG: Reconstructed metadata: ${lineAttrString}`);
1200
1200
  }
1201
1201
  }
1202
1202
  }
1203
1203
  } catch(e) {
1204
- // log(`${logPrefix} DEBUG: Error checking DOM for table:`, e);
1204
+ // log(`${logPrefix} DEBUG: Error checking DOM for table:`, e);
1205
1205
  }
1206
1206
  }
1207
1207
 
1208
1208
  if (lineAttrString) {
1209
1209
  tableMetadata = JSON.parse(lineAttrString);
1210
1210
  if (!tableMetadata || typeof tableMetadata.cols !== 'number') {
1211
- // log(`${logPrefix} Line ${reportedLineNum} has attribute, but metadata invalid/missing cols.`);
1211
+ // log(`${logPrefix} Line ${reportedLineNum} has attribute, but metadata invalid/missing cols.`);
1212
1212
  tableMetadata = null; // Ensure it's null if invalid
1213
1213
  }
1214
1214
  } else {
1215
- // log(`${logPrefix} DEBUG: No ${ATTR_TABLE_JSON} attribute found on line ${reportedLineNum}`);
1215
+ // log(`${logPrefix} DEBUG: No ${ATTR_TABLE_JSON} attribute found on line ${reportedLineNum}`);
1216
1216
  // Not a table line based on reported caret line
1217
1217
  }
1218
1218
  } catch(e) {
@@ -1223,7 +1223,7 @@ exports.aceKeyEvent = (h, ctx) => {
1223
1223
  // Get last known good state
1224
1224
  const editor = editorInfo.editor; // Get editor instance
1225
1225
  const lastClick = editor?.ep_data_tables_last_clicked; // Read shared state
1226
- // log(`${logPrefix} Reading stored click/caret info:`, lastClick);
1226
+ // log(`${logPrefix} Reading stored click/caret info:`, lastClick);
1227
1227
 
1228
1228
  // --- Determine the TRUE target line, cell, and caret position ---
1229
1229
  let currentLineNum = -1;
@@ -1238,22 +1238,22 @@ exports.aceKeyEvent = (h, ctx) => {
1238
1238
 
1239
1239
  // ** Scenario 1: Try to trust lastClick info **
1240
1240
  if (lastClick) {
1241
- // log(`${logPrefix} Attempting to validate stored click info for Line=${lastClick.lineNum}...`);
1241
+ // log(`${logPrefix} Attempting to validate stored click info for Line=${lastClick.lineNum}...`);
1242
1242
  let storedLineAttrString = null;
1243
1243
  let storedLineMetadata = null;
1244
1244
  try {
1245
- // log(`${logPrefix} DEBUG: Getting ${ATTR_TABLE_JSON} attribute from stored line ${lastClick.lineNum}`);
1245
+ // log(`${logPrefix} DEBUG: Getting ${ATTR_TABLE_JSON} attribute from stored line ${lastClick.lineNum}`);
1246
1246
  storedLineAttrString = docManager.getAttributeOnLine(lastClick.lineNum, ATTR_TABLE_JSON);
1247
- // log(`${logPrefix} DEBUG: Stored line attribute result: ${storedLineAttrString ? `"${storedLineAttrString}"` : 'null/undefined'}`);
1247
+ // log(`${logPrefix} DEBUG: Stored line attribute result: ${storedLineAttrString ? `"${storedLineAttrString}"` : 'null/undefined'}`);
1248
1248
 
1249
1249
  if (storedLineAttrString) {
1250
1250
  storedLineMetadata = JSON.parse(storedLineAttrString);
1251
- // log(`${logPrefix} DEBUG: Parsed stored metadata:`, storedLineMetadata);
1251
+ // log(`${logPrefix} DEBUG: Parsed stored metadata:`, storedLineMetadata);
1252
1252
  }
1253
1253
 
1254
1254
  // Check if metadata is valid and tblId matches
1255
1255
  if (storedLineMetadata && typeof storedLineMetadata.cols === 'number' && storedLineMetadata.tblId === lastClick.tblId) {
1256
- // log(`${logPrefix} Stored click info VALIDATED (Metadata OK and tblId matches). Trusting stored state.`);
1256
+ // log(`${logPrefix} Stored click info VALIDATED (Metadata OK and tblId matches). Trusting stored state.`);
1257
1257
  trustedLastClick = true;
1258
1258
  currentLineNum = lastClick.lineNum;
1259
1259
  targetCellIndex = lastClick.cellIndex;
@@ -1262,10 +1262,10 @@ exports.aceKeyEvent = (h, ctx) => {
1262
1262
 
1263
1263
  lineText = rep.lines.atIndex(currentLineNum)?.text || '';
1264
1264
  cellTexts = lineText.split(DELIMITER);
1265
- // log(`${logPrefix} Using Line=${currentLineNum}, CellIndex=${targetCellIndex}. Text: "${lineText}"`);
1265
+ // log(`${logPrefix} Using Line=${currentLineNum}, CellIndex=${targetCellIndex}. Text: "${lineText}"`);
1266
1266
 
1267
1267
  if (cellTexts.length !== metadataForTargetLine.cols) {
1268
- // log(`${logPrefix} WARNING: Stored cell count mismatch for trusted line ${currentLineNum}.`);
1268
+ // log(`${logPrefix} WARNING: Stored cell count mismatch for trusted line ${currentLineNum}.`);
1269
1269
  }
1270
1270
 
1271
1271
  cellStartCol = 0;
@@ -1273,20 +1273,20 @@ exports.aceKeyEvent = (h, ctx) => {
1273
1273
  cellStartCol += (cellTexts[i]?.length ?? 0) + DELIMITER.length;
1274
1274
  }
1275
1275
  precedingCellsOffset = cellStartCol;
1276
- // log(`${logPrefix} Calculated cellStartCol=${cellStartCol} from trusted cellIndex=${targetCellIndex}.`);
1276
+ // log(`${logPrefix} Calculated cellStartCol=${cellStartCol} from trusted cellIndex=${targetCellIndex}.`);
1277
1277
 
1278
1278
  if (typeof lastClick.relativePos === 'number' && lastClick.relativePos >= 0) {
1279
1279
  const currentCellTextLength = cellTexts[targetCellIndex]?.length ?? 0;
1280
1280
  relativeCaretPos = Math.max(0, Math.min(lastClick.relativePos, currentCellTextLength));
1281
- // log(`${logPrefix} Using and validated stored relative position: ${relativeCaretPos}.`);
1281
+ // log(`${logPrefix} Using and validated stored relative position: ${relativeCaretPos}.`);
1282
1282
  } else {
1283
1283
  relativeCaretPos = reportedCol - cellStartCol; // Use reportedCol for initial calc if relative is missing
1284
1284
  const currentCellTextLength = cellTexts[targetCellIndex]?.length ?? 0;
1285
1285
  relativeCaretPos = Math.max(0, Math.min(relativeCaretPos, currentCellTextLength));
1286
- // log(`${logPrefix} Stored relativePos missing, calculated from reportedCol (${reportedCol}): ${relativeCaretPos}`);
1286
+ // log(`${logPrefix} Stored relativePos missing, calculated from reportedCol (${reportedCol}): ${relativeCaretPos}`);
1287
1287
  }
1288
1288
  } else {
1289
- // log(`${logPrefix} Stored click info INVALID (Metadata missing/invalid or tblId mismatch). Clearing stored state.`);
1289
+ // log(`${logPrefix} Stored click info INVALID (Metadata missing/invalid or tblId mismatch). Clearing stored state.`);
1290
1290
  if (editor) editor.ep_data_tables_last_clicked = null;
1291
1291
  }
1292
1292
  } catch (e) {
@@ -1297,7 +1297,7 @@ exports.aceKeyEvent = (h, ctx) => {
1297
1297
 
1298
1298
  // ** Scenario 2: Fallback - Use reported line/col ONLY if stored info wasn't trusted **
1299
1299
  if (!trustedLastClick) {
1300
- // log(`${logPrefix} Fallback: Using reported caret position Line=${reportedLineNum}, Col=${reportedCol}.`);
1300
+ // log(`${logPrefix} Fallback: Using reported caret position Line=${reportedLineNum}, Col=${reportedCol}.`);
1301
1301
  // Fetch metadata for the reported line again, in case it wasn't fetched or was invalid earlier
1302
1302
  try {
1303
1303
  lineAttrString = docManager.getAttributeOnLine(reportedLineNum, ATTR_TABLE_JSON);
@@ -1314,11 +1314,11 @@ exports.aceKeyEvent = (h, ctx) => {
1314
1314
  if (tableInDOM) {
1315
1315
  const domTblId = tableInDOM.getAttribute('data-tblId');
1316
1316
  const domRow = tableInDOM.getAttribute('data-row');
1317
- // log(`${logPrefix} Fallback: Found table in DOM without attribute! TblId=${domTblId}, Row=${domRow}`);
1317
+ // log(`${logPrefix} Fallback: Found table in DOM without attribute! TblId=${domTblId}, Row=${domRow}`);
1318
1318
  // Try to reconstruct the metadata from DOM
1319
1319
  const domCells = tableInDOM.querySelectorAll('td');
1320
1320
  if (domTblId && domRow !== null && domCells.length > 0) {
1321
- // log(`${logPrefix} Fallback: Attempting to reconstruct metadata from DOM...`);
1321
+ // log(`${logPrefix} Fallback: Attempting to reconstruct metadata from DOM...`);
1322
1322
  const reconstructedMetadata = {
1323
1323
  tblId: domTblId,
1324
1324
  row: parseInt(domRow, 10),
@@ -1326,31 +1326,31 @@ exports.aceKeyEvent = (h, ctx) => {
1326
1326
  };
1327
1327
  lineAttrString = JSON.stringify(reconstructedMetadata);
1328
1328
  tableMetadata = reconstructedMetadata;
1329
- // log(`${logPrefix} Fallback: Reconstructed metadata: ${lineAttrString}`);
1329
+ // log(`${logPrefix} Fallback: Reconstructed metadata: ${lineAttrString}`);
1330
1330
  }
1331
1331
  }
1332
1332
  }
1333
1333
  } catch(e) {
1334
- // log(`${logPrefix} Fallback: Error checking DOM for table:`, e);
1334
+ // log(`${logPrefix} Fallback: Error checking DOM for table:`, e);
1335
1335
  }
1336
1336
  }
1337
1337
  } catch(e) { tableMetadata = null; } // Ignore errors here, handled below
1338
1338
 
1339
1339
  if (!tableMetadata) {
1340
- // log(`${logPrefix} Fallback: Reported line ${reportedLineNum} is not a valid table line. Allowing default.`);
1340
+ // log(`${logPrefix} Fallback: Reported line ${reportedLineNum} is not a valid table line. Allowing default.`);
1341
1341
  return false;
1342
1342
  }
1343
1343
 
1344
1344
  currentLineNum = reportedLineNum;
1345
1345
  metadataForTargetLine = tableMetadata;
1346
- // log(`${logPrefix} Fallback: Processing based on reported line ${currentLineNum}.`);
1346
+ // log(`${logPrefix} Fallback: Processing based on reported line ${currentLineNum}.`);
1347
1347
 
1348
1348
  lineText = rep.lines.atIndex(currentLineNum)?.text || '';
1349
1349
  cellTexts = lineText.split(DELIMITER);
1350
- // log(`${logPrefix} Fallback: Fetched text for reported line ${currentLineNum}: "${lineText}"`);
1350
+ // log(`${logPrefix} Fallback: Fetched text for reported line ${currentLineNum}: "${lineText}"`);
1351
1351
 
1352
1352
  if (cellTexts.length !== metadataForTargetLine.cols) {
1353
- // log(`${logPrefix} WARNING (Fallback): Cell count mismatch for reported line ${currentLineNum}.`);
1353
+ // log(`${logPrefix} WARNING (Fallback): Cell count mismatch for reported line ${currentLineNum}.`);
1354
1354
  }
1355
1355
 
1356
1356
  // Calculate target cell based on reportedCol
@@ -1364,7 +1364,7 @@ exports.aceKeyEvent = (h, ctx) => {
1364
1364
  relativeCaretPos = reportedCol - currentOffset;
1365
1365
  cellStartCol = currentOffset;
1366
1366
  precedingCellsOffset = cellStartCol;
1367
- // log(`${logPrefix} --> (Fallback Calc) Found target cell ${foundIndex}. RelativePos: ${relativeCaretPos}.`);
1367
+ // log(`${logPrefix} --> (Fallback Calc) Found target cell ${foundIndex}. RelativePos: ${relativeCaretPos}.`);
1368
1368
  break;
1369
1369
  }
1370
1370
  if (i < cellTexts.length - 1 && reportedCol === cellEndCol + DELIMITER.length) {
@@ -1372,7 +1372,7 @@ exports.aceKeyEvent = (h, ctx) => {
1372
1372
  relativeCaretPos = 0;
1373
1373
  cellStartCol = currentOffset + cellLength + DELIMITER.length;
1374
1374
  precedingCellsOffset = cellStartCol;
1375
- // log(`${logPrefix} --> (Fallback Calc) Caret at delimiter AFTER cell ${i}. Treating as start of cell ${foundIndex}.`);
1375
+ // log(`${logPrefix} --> (Fallback Calc) Caret at delimiter AFTER cell ${i}. Treating as start of cell ${foundIndex}.`);
1376
1376
  break;
1377
1377
  }
1378
1378
  currentOffset += cellLength + DELIMITER.length;
@@ -1385,9 +1385,9 @@ exports.aceKeyEvent = (h, ctx) => {
1385
1385
  for (let i = 0; i < foundIndex; i++) { cellStartCol += (cellTexts[i]?.length ?? 0) + DELIMITER.length; }
1386
1386
  precedingCellsOffset = cellStartCol;
1387
1387
  relativeCaretPos = cellTexts[foundIndex]?.length ?? 0;
1388
- // log(`${logPrefix} --> (Fallback Calc) Caret detected at END of last cell (${foundIndex}).`);
1388
+ // log(`${logPrefix} --> (Fallback Calc) Caret detected at END of last cell (${foundIndex}).`);
1389
1389
  } else {
1390
- // log(`${logPrefix} (Fallback Calc) FAILED to determine target cell for caret col ${reportedCol}. Allowing default handling.`);
1390
+ // log(`${logPrefix} (Fallback Calc) FAILED to determine target cell for caret col ${reportedCol}. Allowing default handling.`);
1391
1391
  return false;
1392
1392
  }
1393
1393
  }
@@ -1396,12 +1396,12 @@ exports.aceKeyEvent = (h, ctx) => {
1396
1396
 
1397
1397
  // --- Final Validation ---
1398
1398
  if (currentLineNum < 0 || targetCellIndex < 0 || !metadataForTargetLine || targetCellIndex >= metadataForTargetLine.cols) {
1399
- // log(`${logPrefix} FAILED final validation: Line=${currentLineNum}, Cell=${targetCellIndex}, Metadata=${!!metadataForTargetLine}. Allowing default.`);
1399
+ // log(`${logPrefix} FAILED final validation: Line=${currentLineNum}, Cell=${targetCellIndex}, Metadata=${!!metadataForTargetLine}. Allowing default.`);
1400
1400
  if (editor) editor.ep_data_tables_last_clicked = null;
1401
1401
  return false;
1402
1402
  }
1403
1403
 
1404
- // log(`${logPrefix} --> Final Target: Line=${currentLineNum}, CellIndex=${targetCellIndex}, RelativePos=${relativeCaretPos}`);
1404
+ // log(`${logPrefix} --> Final Target: Line=${currentLineNum}, CellIndex=${targetCellIndex}, RelativePos=${relativeCaretPos}`);
1405
1405
  // --- End Cell/Position Determination ---
1406
1406
 
1407
1407
  // --- START NEW: Handle Highlight Deletion/Replacement ---
@@ -1410,11 +1410,11 @@ exports.aceKeyEvent = (h, ctx) => {
1410
1410
  const hasSelection = selStartActual[0] !== selEndActual[0] || selStartActual[1] !== selEndActual[1];
1411
1411
 
1412
1412
  if (hasSelection) {
1413
- // log(`${logPrefix} [selection] Active selection detected. Start:[${selStartActual[0]},${selStartActual[1]}], End:[${selEndActual[0]},${selEndActual[1]}]`);
1414
- // log(`${logPrefix} [caretTrace] [selection] Initial rep.selStart: Line=${rep.selStart[0]}, Col=${rep.selStart[1]}`);
1413
+ // log(`${logPrefix} [selection] Active selection detected. Start:[${selStartActual[0]},${selStartActual[1]}], End:[${selEndActual[0]},${selEndActual[1]}]`);
1414
+ // log(`${logPrefix} [caretTrace] [selection] Initial rep.selStart: Line=${rep.selStart[0]}, Col=${rep.selStart[1]}`);
1415
1415
 
1416
1416
  if (selStartActual[0] !== currentLineNum || selEndActual[0] !== currentLineNum) {
1417
- // log(`${logPrefix} [selection] Selection spans multiple lines (${selStartActual[0]}-${selEndActual[0]}) or is not on the current focused table line (${currentLineNum}). Preventing default action.`);
1417
+ // log(`${logPrefix} [selection] Selection spans multiple lines (${selStartActual[0]}-${selEndActual[0]}) or is not on the current focused table line (${currentLineNum}). Preventing default action.`);
1418
1418
  evt.preventDefault();
1419
1419
  return true;
1420
1420
  }
@@ -1462,7 +1462,7 @@ exports.aceKeyEvent = (h, ctx) => {
1462
1462
  selectionEndColInLine = cellContentEndColInLine;
1463
1463
  }
1464
1464
 
1465
- // log(`${logPrefix} [selection] Cell context for selection: targetCellIndex=${targetCellIndex}, cellStartColInLine=${cellContentStartColInLine}, cellEndColInLine=${cellContentEndColInLine}, currentCellFullText='${currentCellFullText}'`);
1465
+ // log(`${logPrefix} [selection] Cell context for selection: targetCellIndex=${targetCellIndex}, cellStartColInLine=${cellContentStartColInLine}, cellEndColInLine=${cellContentEndColInLine}, currentCellFullText='${currentCellFullText}'`);
1466
1466
 
1467
1467
  const isSelectionEntirelyWithinCell =
1468
1468
  selectionStartColInLine >= cellContentStartColInLine &&
@@ -1494,10 +1494,10 @@ exports.aceKeyEvent = (h, ctx) => {
1494
1494
 
1495
1495
 
1496
1496
  if (isSelectionEntirelyWithinCell && (isCurrentKeyDelete || isCurrentKeyBackspace || isCurrentKeyTyping)) {
1497
- // log(`${logPrefix} [selection] Handling key='${evt.key}' (Type: ${evt.type}) for valid intra-cell selection.`);
1497
+ // log(`${logPrefix} [selection] Handling key='${evt.key}' (Type: ${evt.type}) for valid intra-cell selection.`);
1498
1498
 
1499
1499
  if (evt.type !== 'keydown') {
1500
- // log(`${logPrefix} [selection] Ignoring non-keydown event type ('${evt.type}') for selection handling. Allowing default.`);
1500
+ // log(`${logPrefix} [selection] Ignoring non-keydown event type ('${evt.type}') for selection handling. Allowing default.`);
1501
1501
  return false;
1502
1502
  }
1503
1503
  evt.preventDefault();
@@ -1507,20 +1507,20 @@ exports.aceKeyEvent = (h, ctx) => {
1507
1507
  let replacementText = '';
1508
1508
  let newAbsoluteCaretCol = selectionStartColInLine;
1509
1509
  const repBeforeEdit = editorInfo.ace_getRep(); // Get rep before edit for attribute helper
1510
- // log(`${logPrefix} [caretTrace] [selection] rep.selStart before ace_performDocumentReplaceRange: Line=${repBeforeEdit.selStart[0]}, Col=${repBeforeEdit.selStart[1]}`);
1510
+ // log(`${logPrefix} [caretTrace] [selection] rep.selStart before ace_performDocumentReplaceRange: Line=${repBeforeEdit.selStart[0]}, Col=${repBeforeEdit.selStart[1]}`);
1511
1511
 
1512
1512
  if (isCurrentKeyTyping) {
1513
1513
  replacementText = evt.key;
1514
1514
  newAbsoluteCaretCol = selectionStartColInLine + replacementText.length;
1515
- // log(`${logPrefix} [selection] -> Replacing selected range [[${rangeStart[0]},${rangeStart[1]}],[${rangeEnd[0]},${rangeEnd[1]}]] with text '${replacementText}'`);
1515
+ // log(`${logPrefix} [selection] -> Replacing selected range [[${rangeStart[0]},${rangeStart[1]}],[${rangeEnd[0]},${rangeEnd[1]}]] with text '${replacementText}'`);
1516
1516
  } else { // Delete or Backspace
1517
- // log(`${logPrefix} [selection] -> Deleting selected range [[${rangeStart[0]},${rangeStart[1]}],[${rangeEnd[0]},${rangeEnd[1]}]]`);
1517
+ // log(`${logPrefix} [selection] -> Deleting selected range [[${rangeStart[0]},${rangeStart[1]}],[${rangeEnd[0]},${rangeEnd[1]}]]`);
1518
1518
  // If whole cell is being wiped, keep a single space so cell isn't empty
1519
1519
  const isWholeCell = selectionStartColInLine <= cellContentStartColInLine && selectionEndColInLine >= cellContentEndColInLine;
1520
1520
  if (isWholeCell) {
1521
1521
  replacementText = ' ';
1522
1522
  newAbsoluteCaretCol = selectionStartColInLine + 1;
1523
- // log(`${logPrefix} [selection] Whole cell cleared – inserting single space to preserve caret/author span.`);
1523
+ // log(`${logPrefix} [selection] Whole cell cleared – inserting single space to preserve caret/author span.`);
1524
1524
  }
1525
1525
  }
1526
1526
 
@@ -1539,44 +1539,44 @@ exports.aceKeyEvent = (h, ctx) => {
1539
1539
  );
1540
1540
  }
1541
1541
  const repAfterReplace = editorInfo.ace_getRep();
1542
- // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_performDocumentReplaceRange: Line=${repAfterReplace.selStart[0]}, Col=${repAfterReplace.selStart[1]}`);
1542
+ // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_performDocumentReplaceRange: Line=${repAfterReplace.selStart[0]}, Col=${repAfterReplace.selStart[1]}`);
1543
1543
 
1544
1544
 
1545
- // log(`${logPrefix} [selection] -> Re-applying tbljson line attribute...`);
1545
+ // log(`${logPrefix} [selection] -> Re-applying tbljson line attribute...`);
1546
1546
  const applyHelper = editorInfo.ep_data_tables_applyMeta;
1547
1547
  if (applyHelper && typeof applyHelper === 'function' && repBeforeEdit) {
1548
1548
  const attrStringToApply = (trustedLastClick || reportedLineNum === currentLineNum) ? lineAttrString : null;
1549
1549
  applyHelper(currentLineNum, metadataForTargetLine.tblId, metadataForTargetLine.row, metadataForTargetLine.cols, repBeforeEdit, editorInfo, attrStringToApply, docManager);
1550
- // log(`${logPrefix} [selection] -> tbljson line attribute re-applied (using rep before edit).`);
1550
+ // log(`${logPrefix} [selection] -> tbljson line attribute re-applied (using rep before edit).`);
1551
1551
  } else {
1552
1552
  console.error(`${logPrefix} [selection] -> FAILED to re-apply tbljson attribute (helper or repBeforeEdit missing).`);
1553
1553
  const currentRepFallback = editorInfo.ace_getRep();
1554
1554
  if (applyHelper && typeof applyHelper === 'function' && currentRepFallback) {
1555
- // log(`${logPrefix} [selection] -> Retrying attribute application with current rep...`);
1555
+ // log(`${logPrefix} [selection] -> Retrying attribute application with current rep...`);
1556
1556
  applyHelper(currentLineNum, metadataForTargetLine.tblId, metadataForTargetLine.row, metadataForTargetLine.cols, currentRepFallback, editorInfo, null, docManager);
1557
- // log(`${logPrefix} [selection] -> tbljson line attribute re-applied (using current rep fallback).`);
1557
+ // log(`${logPrefix} [selection] -> tbljson line attribute re-applied (using current rep fallback).`);
1558
1558
  } else {
1559
1559
  console.error(`${logPrefix} [selection] -> FAILED to re-apply tbljson attribute even with fallback rep.`);
1560
1560
  }
1561
1561
  }
1562
1562
 
1563
- // log(`${logPrefix} [selection] -> Setting selection/caret to: [${currentLineNum}, ${newAbsoluteCaretCol}]`);
1564
- // log(`${logPrefix} [caretTrace] [selection] rep.selStart before ace_performSelectionChange: Line=${editorInfo.ace_getRep().selStart[0]}, Col=${editorInfo.ace_getRep().selStart[1]}`);
1563
+ // log(`${logPrefix} [selection] -> Setting selection/caret to: [${currentLineNum}, ${newAbsoluteCaretCol}]`);
1564
+ // log(`${logPrefix} [caretTrace] [selection] rep.selStart before ace_performSelectionChange: Line=${editorInfo.ace_getRep().selStart[0]}, Col=${editorInfo.ace_getRep().selStart[1]}`);
1565
1565
  editorInfo.ace_performSelectionChange([currentLineNum, newAbsoluteCaretCol], [currentLineNum, newAbsoluteCaretCol], false);
1566
1566
  const repAfterSelectionChange = editorInfo.ace_getRep();
1567
- // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_performSelectionChange: Line=${repAfterSelectionChange.selStart[0]}, Col=${repAfterSelectionChange.selStart[1]}`);
1567
+ // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_performSelectionChange: Line=${repAfterSelectionChange.selStart[0]}, Col=${repAfterSelectionChange.selStart[1]}`);
1568
1568
 
1569
1569
  // Add sync hint AFTER setting selection
1570
1570
  editorInfo.ace_fastIncorp(1);
1571
1571
  const repAfterFastIncorp = editorInfo.ace_getRep();
1572
- // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_fastIncorp: Line=${repAfterFastIncorp.selStart[0]}, Col=${repAfterFastIncorp.selStart[1]}`);
1573
- // log(`${logPrefix} [selection] -> Requested sync hint (fastIncorp 1).`);
1572
+ // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_fastIncorp: Line=${repAfterFastIncorp.selStart[0]}, Col=${repAfterFastIncorp.selStart[1]}`);
1573
+ // log(`${logPrefix} [selection] -> Requested sync hint (fastIncorp 1).`);
1574
1574
 
1575
1575
  // --- Re-assert selection ---
1576
- // log(`${logPrefix} [caretTrace] [selection] Attempting to re-assert selection post-fastIncorp to [${currentLineNum}, ${newAbsoluteCaretCol}]`);
1576
+ // log(`${logPrefix} [caretTrace] [selection] Attempting to re-assert selection post-fastIncorp to [${currentLineNum}, ${newAbsoluteCaretCol}]`);
1577
1577
  editorInfo.ace_performSelectionChange([currentLineNum, newAbsoluteCaretCol], [currentLineNum, newAbsoluteCaretCol], false);
1578
1578
  const repAfterReassert = editorInfo.ace_getRep();
1579
- // log(`${logPrefix} [caretTrace] [selection] rep.selStart after re-asserting selection: Line=${repAfterReassert.selStart[0]}, Col=${repAfterReassert.selStart[1]}`);
1579
+ // log(`${logPrefix} [caretTrace] [selection] rep.selStart after re-asserting selection: Line=${repAfterReassert.selStart[0]}, Col=${repAfterReassert.selStart[1]}`);
1580
1580
 
1581
1581
  const newRelativePos = newAbsoluteCaretCol - cellStartCol;
1582
1582
  if (editor) {
@@ -1586,15 +1586,15 @@ exports.aceKeyEvent = (h, ctx) => {
1586
1586
  cellIndex: targetCellIndex,
1587
1587
  relativePos: newRelativePos < 0 ? 0 : newRelativePos
1588
1588
  };
1589
- // log(`${logPrefix} [selection] -> Updated stored click/caret info:`, editor.ep_data_tables_last_clicked);
1589
+ // log(`${logPrefix} [selection] -> Updated stored click/caret info:`, editor.ep_data_tables_last_clicked);
1590
1590
  } else {
1591
- // log(`${logPrefix} [selection] -> Editor instance not found, cannot update ep_data_tables_last_clicked.`);
1591
+ // log(`${logPrefix} [selection] -> Editor instance not found, cannot update ep_data_tables_last_clicked.`);
1592
1592
  }
1593
1593
 
1594
- // log(`${logPrefix} END [selection] (Handled highlight modification) Key='${evt.key}' Type='${evt.type}'. Duration: ${Date.now() - startLogTime}ms`);
1594
+ // log(`${logPrefix} END [selection] (Handled highlight modification) Key='${evt.key}' Type='${evt.type}'. Duration: ${Date.now() - startLogTime}ms`);
1595
1595
  return true;
1596
1596
  } catch (error) {
1597
- // log(`${logPrefix} [selection] ERROR during highlight modification:`, error);
1597
+ // log(`${logPrefix} [selection] ERROR during highlight modification:`, error);
1598
1598
  console.error('[ep_data_tables] Error processing highlight modification:', error);
1599
1599
  return true; // Still return true as we prevented default.
1600
1600
  }
@@ -1605,12 +1605,12 @@ exports.aceKeyEvent = (h, ctx) => {
1605
1605
  // --- Check for Ctrl+X (Cut) key combination ---
1606
1606
  const isCutKey = (evt.ctrlKey || evt.metaKey) && (evt.key === 'x' || evt.key === 'X' || evt.keyCode === 88);
1607
1607
  if (isCutKey && hasSelection) {
1608
- log(`${logPrefix} Ctrl+X (Cut) detected with selection. Letting cut event handler manage this.`);
1608
+ // log(`${logPrefix} Ctrl+X (Cut) detected with selection. Letting cut event handler manage this.`);
1609
1609
  // Let the cut event handler handle this - we don't need to preventDefault here
1610
1610
  // as the cut event will handle the operation and prevent default
1611
1611
  return false; // Allow the cut event to be triggered
1612
1612
  } else if (isCutKey && !hasSelection) {
1613
- log(`${logPrefix} Ctrl+X (Cut) detected but no selection. Allowing default.`);
1613
+ // log(`${logPrefix} Ctrl+X (Cut) detected but no selection. Allowing default.`);
1614
1614
  return false; // Allow default - nothing to cut
1615
1615
  }
1616
1616
 
@@ -1621,7 +1621,7 @@ exports.aceKeyEvent = (h, ctx) => {
1621
1621
  const isNavigationKey = [33, 34, 35, 36, 37, 38, 39, 40].includes(evt.keyCode);
1622
1622
  const isTabKey = evt.key === 'Tab';
1623
1623
  const isEnterKey = evt.key === 'Enter';
1624
- // log(`${logPrefix} Key classification: Typing=${isTypingKey}, Backspace=${isBackspaceKey}, Delete=${isDeleteKey}, Nav=${isNavigationKey}, Tab=${isTabKey}, Enter=${isEnterKey}, Cut=${isCutKey}`);
1624
+ // log(`${logPrefix} Key classification: Typing=${isTypingKey}, Backspace=${isBackspaceKey}, Delete=${isDeleteKey}, Nav=${isNavigationKey}, Tab=${isTabKey}, Enter=${isEnterKey}, Cut=${isCutKey}`);
1625
1625
 
1626
1626
  /*
1627
1627
  * Prevent caret placement *after* the invisible caret-anchor.
@@ -1636,7 +1636,7 @@ exports.aceKeyEvent = (h, ctx) => {
1636
1636
  if (evt.type === 'keydown' && !evt.ctrlKey && !evt.metaKey && !evt.altKey) {
1637
1637
  // Right-arrow – if at the very end of a cell, move to the next cell.
1638
1638
  if (evt.keyCode === 39 && relativeCaretPos >= currentCellTextLengthEarly && targetCellIndex < metadataForTargetLine.cols - 1) {
1639
- // log(`${logPrefix} ArrowRight at cell boundary – navigating to next cell to avoid anchor zone.`);
1639
+ // log(`${logPrefix} ArrowRight at cell boundary – navigating to next cell to avoid anchor zone.`);
1640
1640
  evt.preventDefault();
1641
1641
  navigateToNextCell(currentLineNum, targetCellIndex, metadataForTargetLine, false, editorInfo, docManager);
1642
1642
  return true;
@@ -1644,7 +1644,7 @@ exports.aceKeyEvent = (h, ctx) => {
1644
1644
 
1645
1645
  // Left-arrow – if at the very start of a cell, move to the previous cell.
1646
1646
  if (evt.keyCode === 37 && relativeCaretPos === 0 && targetCellIndex > 0) {
1647
- // log(`${logPrefix} ArrowLeft at cell boundary – navigating to previous cell to avoid anchor zone.`);
1647
+ // log(`${logPrefix} ArrowLeft at cell boundary – navigating to previous cell to avoid anchor zone.`);
1648
1648
  evt.preventDefault();
1649
1649
  navigateToNextCell(currentLineNum, targetCellIndex, metadataForTargetLine, true, editorInfo, docManager);
1650
1650
  return true;
@@ -1655,45 +1655,45 @@ exports.aceKeyEvent = (h, ctx) => {
1655
1655
 
1656
1656
  // 1. Allow non-Tab navigation keys immediately
1657
1657
  if (isNavigationKey && !isTabKey) {
1658
- // log(`${logPrefix} Allowing navigation key: ${evt.key}. Clearing click state.`);
1658
+ // log(`${logPrefix} Allowing navigation key: ${evt.key}. Clearing click state.`);
1659
1659
  if (editor) editor.ep_data_tables_last_clicked = null; // Clear state on navigation
1660
1660
  return false;
1661
1661
  }
1662
1662
 
1663
1663
  // 2. Handle Tab - Navigate to next cell (only on keydown to avoid double navigation)
1664
1664
  if (isTabKey) {
1665
- // log(`${logPrefix} Tab key pressed. Event type: ${evt.type}`);
1665
+ // log(`${logPrefix} Tab key pressed. Event type: ${evt.type}`);
1666
1666
  evt.preventDefault();
1667
1667
 
1668
1668
  // Only process keydown events for navigation to avoid double navigation
1669
1669
  if (evt.type !== 'keydown') {
1670
- // log(`${logPrefix} Ignoring Tab ${evt.type} event to prevent double navigation.`);
1670
+ // log(`${logPrefix} Ignoring Tab ${evt.type} event to prevent double navigation.`);
1671
1671
  return true;
1672
1672
  }
1673
1673
 
1674
- // log(`${logPrefix} Processing Tab keydown - implementing cell navigation.`);
1674
+ // log(`${logPrefix} Processing Tab keydown - implementing cell navigation.`);
1675
1675
  const success = navigateToNextCell(currentLineNum, targetCellIndex, metadataForTargetLine, evt.shiftKey, editorInfo, docManager);
1676
1676
  if (!success) {
1677
- // log(`${logPrefix} Tab navigation failed, cell navigation not possible.`);
1677
+ // log(`${logPrefix} Tab navigation failed, cell navigation not possible.`);
1678
1678
  }
1679
1679
  return true;
1680
1680
  }
1681
1681
 
1682
1682
  // 3. Handle Enter - Navigate to cell below (only on keydown to avoid double navigation)
1683
1683
  if (isEnterKey) {
1684
- // log(`${logPrefix} Enter key pressed. Event type: ${evt.type}`);
1684
+ // log(`${logPrefix} Enter key pressed. Event type: ${evt.type}`);
1685
1685
  evt.preventDefault();
1686
1686
 
1687
1687
  // Only process keydown events for navigation to avoid double navigation
1688
1688
  if (evt.type !== 'keydown') {
1689
- // log(`${logPrefix} Ignoring Enter ${evt.type} event to prevent double navigation.`);
1689
+ // log(`${logPrefix} Ignoring Enter ${evt.type} event to prevent double navigation.`);
1690
1690
  return true;
1691
1691
  }
1692
1692
 
1693
- // log(`${logPrefix} Processing Enter keydown - implementing cell navigation.`);
1693
+ // log(`${logPrefix} Processing Enter keydown - implementing cell navigation.`);
1694
1694
  const success = navigateToCellBelow(currentLineNum, targetCellIndex, metadataForTargetLine, editorInfo, docManager);
1695
1695
  if (!success) {
1696
- // log(`${logPrefix} Enter navigation failed, cell navigation not possible.`);
1696
+ // log(`${logPrefix} Enter navigation failed, cell navigation not possible.`);
1697
1697
  }
1698
1698
  return true;
1699
1699
  }
@@ -1702,25 +1702,25 @@ exports.aceKeyEvent = (h, ctx) => {
1702
1702
  const currentCellTextLength = cellTexts[targetCellIndex]?.length ?? 0;
1703
1703
  // Backspace at the very beginning of cell > 0
1704
1704
  if (isBackspaceKey && relativeCaretPos === 0 && targetCellIndex > 0) {
1705
- // log(`${logPrefix} Intercepted Backspace at start of cell ${targetCellIndex}. Preventing default.`);
1705
+ // log(`${logPrefix} Intercepted Backspace at start of cell ${targetCellIndex}. Preventing default.`);
1706
1706
  evt.preventDefault();
1707
1707
  return true;
1708
1708
  }
1709
1709
  // NEW: Backspace at very beginning of first cell – would merge with previous line
1710
1710
  if (isBackspaceKey && relativeCaretPos === 0 && targetCellIndex === 0) {
1711
- // log(`${logPrefix} Intercepted Backspace at start of first cell (line boundary). Preventing merge.`);
1711
+ // log(`${logPrefix} Intercepted Backspace at start of first cell (line boundary). Preventing merge.`);
1712
1712
  evt.preventDefault();
1713
1713
  return true;
1714
1714
  }
1715
1715
  // Delete at the very end of cell < last cell
1716
1716
  if (isDeleteKey && relativeCaretPos === currentCellTextLength && targetCellIndex < metadataForTargetLine.cols - 1) {
1717
- // log(`${logPrefix} Intercepted Delete at end of cell ${targetCellIndex}. Preventing default.`);
1717
+ // log(`${logPrefix} Intercepted Delete at end of cell ${targetCellIndex}. Preventing default.`);
1718
1718
  evt.preventDefault();
1719
1719
  return true;
1720
1720
  }
1721
1721
  // NEW: Delete at very end of last cell – would merge with next line
1722
1722
  if (isDeleteKey && relativeCaretPos === currentCellTextLength && targetCellIndex === metadataForTargetLine.cols - 1) {
1723
- // log(`${logPrefix} Intercepted Delete at end of last cell (line boundary). Preventing merge.`);
1723
+ // log(`${logPrefix} Intercepted Delete at end of last cell (line boundary). Preventing merge.`);
1724
1724
  evt.preventDefault();
1725
1725
  return true;
1726
1726
  }
@@ -1732,7 +1732,7 @@ exports.aceKeyEvent = (h, ctx) => {
1732
1732
  // Guard: internal Backspace at relativePos 1 (would delete delimiter) & Delete at relativePos 0
1733
1733
  if ((isInternalBackspace && relativeCaretPos === 1 && targetCellIndex > 0) ||
1734
1734
  (isInternalDelete && relativeCaretPos === 0 && targetCellIndex > 0)) {
1735
- // log(`${logPrefix} Attempt to erase protected delimiter – operation blocked.`);
1735
+ // log(`${logPrefix} Attempt to erase protected delimiter – operation blocked.`);
1736
1736
  evt.preventDefault();
1737
1737
  return true;
1738
1738
  }
@@ -1740,25 +1740,25 @@ exports.aceKeyEvent = (h, ctx) => {
1740
1740
  if (isTypingKey || isInternalBackspace || isInternalDelete) {
1741
1741
  // --- PREVENT TYPING DIRECTLY AFTER DELIMITER (relativeCaretPos===0) ---
1742
1742
  if (isTypingKey && relativeCaretPos === 0 && targetCellIndex > 0) {
1743
- // log(`${logPrefix} Caret at forbidden position 0 (just after delimiter). Auto-advancing to position 1.`);
1743
+ // log(`${logPrefix} Caret at forbidden position 0 (just after delimiter). Auto-advancing to position 1.`);
1744
1744
  const safePosAbs = cellStartCol + 1;
1745
1745
  editorInfo.ace_performSelectionChange([currentLineNum, safePosAbs], [currentLineNum, safePosAbs], false);
1746
1746
  editorInfo.ace_updateBrowserSelectionFromRep();
1747
1747
  relativeCaretPos = 1;
1748
- // log(`${logPrefix} Caret moved to safe position. New relativeCaretPos=${relativeCaretPos}`);
1748
+ // log(`${logPrefix} Caret moved to safe position. New relativeCaretPos=${relativeCaretPos}`);
1749
1749
  }
1750
1750
  // *** Use the validated currentLineNum and currentCol derived from relativeCaretPos ***
1751
1751
  const currentCol = cellStartCol + relativeCaretPos;
1752
- // log(`${logPrefix} Handling INTERNAL key='${evt.key}' Type='${evt.type}' at Line=${currentLineNum}, Col=${currentCol} (CellIndex=${targetCellIndex}, RelativePos=${relativeCaretPos}).`);
1753
- // log(`${logPrefix} [caretTrace] Initial rep.selStart for internal edit: Line=${rep.selStart[0]}, Col=${rep.selStart[1]}`);
1752
+ // log(`${logPrefix} Handling INTERNAL key='${evt.key}' Type='${evt.type}' at Line=${currentLineNum}, Col=${currentCol} (CellIndex=${targetCellIndex}, RelativePos=${relativeCaretPos}).`);
1753
+ // log(`${logPrefix} [caretTrace] Initial rep.selStart for internal edit: Line=${rep.selStart[0]}, Col=${rep.selStart[1]}`);
1754
1754
 
1755
1755
  // Only process keydown events for modifications
1756
1756
  if (evt.type !== 'keydown') {
1757
- // log(`${logPrefix} Ignoring non-keydown event type ('${evt.type}') for handled key.`);
1757
+ // log(`${logPrefix} Ignoring non-keydown event type ('${evt.type}') for handled key.`);
1758
1758
  return false;
1759
1759
  }
1760
1760
 
1761
- // log(`${logPrefix} Preventing default browser action for keydown event.`);
1761
+ // log(`${logPrefix} Preventing default browser action for keydown event.`);
1762
1762
  evt.preventDefault();
1763
1763
 
1764
1764
  let newAbsoluteCaretCol = -1;
@@ -1766,56 +1766,56 @@ exports.aceKeyEvent = (h, ctx) => {
1766
1766
 
1767
1767
  try {
1768
1768
  repBeforeEdit = editorInfo.ace_getRep(); // Get rep *before* making changes
1769
- // log(`${logPrefix} [caretTrace] rep.selStart before ace_performDocumentReplaceRange: Line=${repBeforeEdit.selStart[0]}, Col=${repBeforeEdit.selStart[1]}`);
1769
+ // log(`${logPrefix} [caretTrace] rep.selStart before ace_performDocumentReplaceRange: Line=${repBeforeEdit.selStart[0]}, Col=${repBeforeEdit.selStart[1]}`);
1770
1770
 
1771
1771
  if (isTypingKey) {
1772
1772
  const insertPos = [currentLineNum, currentCol];
1773
- // log(`${logPrefix} -> Inserting text '${evt.key}' at [${insertPos}]`);
1773
+ // log(`${logPrefix} -> Inserting text '${evt.key}' at [${insertPos}]`);
1774
1774
  editorInfo.ace_performDocumentReplaceRange(insertPos, insertPos, evt.key);
1775
1775
  newAbsoluteCaretCol = currentCol + 1;
1776
1776
 
1777
1777
  } else if (isInternalBackspace) {
1778
1778
  const delRangeStart = [currentLineNum, currentCol - 1];
1779
1779
  const delRangeEnd = [currentLineNum, currentCol];
1780
- // log(`${logPrefix} -> Deleting (Backspace) range [${delRangeStart}]-[${delRangeEnd}]`);
1780
+ // log(`${logPrefix} -> Deleting (Backspace) range [${delRangeStart}]-[${delRangeEnd}]`);
1781
1781
  editorInfo.ace_performDocumentReplaceRange(delRangeStart, delRangeEnd, '');
1782
1782
  newAbsoluteCaretCol = currentCol - 1;
1783
1783
 
1784
1784
  } else if (isInternalDelete) {
1785
1785
  const delRangeStart = [currentLineNum, currentCol];
1786
1786
  const delRangeEnd = [currentLineNum, currentCol + 1];
1787
- // log(`${logPrefix} -> Deleting (Delete) range [${delRangeStart}]-[${delRangeEnd}]`);
1787
+ // log(`${logPrefix} -> Deleting (Delete) range [${delRangeStart}]-[${delRangeEnd}]`);
1788
1788
  editorInfo.ace_performDocumentReplaceRange(delRangeStart, delRangeEnd, '');
1789
1789
  newAbsoluteCaretCol = currentCol; // Caret stays at the same column for delete
1790
1790
  }
1791
1791
  const repAfterReplace = editorInfo.ace_getRep();
1792
- // log(`${logPrefix} [caretTrace] rep.selStart after ace_performDocumentReplaceRange: Line=${repAfterReplace.selStart[0]}, Col=${repAfterReplace.selStart[1]}`);
1792
+ // log(`${logPrefix} [caretTrace] rep.selStart after ace_performDocumentReplaceRange: Line=${repAfterReplace.selStart[0]}, Col=${repAfterReplace.selStart[1]}`);
1793
1793
 
1794
1794
 
1795
1795
  // *** CRITICAL: Re-apply the line attribute after ANY modification ***
1796
- // log(`${logPrefix} -> Re-applying tbljson line attribute...`);
1796
+ // log(`${logPrefix} -> Re-applying tbljson line attribute...`);
1797
1797
 
1798
1798
  // DEBUG: Log the values before calculating attrStringToApply
1799
- // log(`${logPrefix} DEBUG: Before calculating attrStringToApply - trustedLastClick=${trustedLastClick}, reportedLineNum=${reportedLineNum}, currentLineNum=${currentLineNum}`);
1800
- // log(`${logPrefix} DEBUG: lineAttrString value:`, lineAttrString ? `"${lineAttrString}"` : 'null/undefined');
1799
+ // log(`${logPrefix} DEBUG: Before calculating attrStringToApply - trustedLastClick=${trustedLastClick}, reportedLineNum=${reportedLineNum}, currentLineNum=${currentLineNum}`);
1800
+ // log(`${logPrefix} DEBUG: lineAttrString value:`, lineAttrString ? `"${lineAttrString}"` : 'null/undefined');
1801
1801
 
1802
1802
  const applyHelper = editorInfo.ep_data_tables_applyMeta;
1803
1803
  if (applyHelper && typeof applyHelper === 'function' && repBeforeEdit) {
1804
1804
  // Pass the original lineAttrString if available AND if it belongs to the currentLineNum
1805
1805
  const attrStringToApply = (trustedLastClick || reportedLineNum === currentLineNum) ? lineAttrString : null;
1806
1806
 
1807
- // log(`${logPrefix} DEBUG: Calculated attrStringToApply:`, attrStringToApply ? `"${attrStringToApply}"` : 'null/undefined');
1808
- // log(`${logPrefix} DEBUG: Condition result: (${trustedLastClick} || ${reportedLineNum} === ${currentLineNum}) = ${trustedLastClick || reportedLineNum === currentLineNum}`);
1807
+ // log(`${logPrefix} DEBUG: Calculated attrStringToApply:`, attrStringToApply ? `"${attrStringToApply}"` : 'null/undefined');
1808
+ // log(`${logPrefix} DEBUG: Condition result: (${trustedLastClick} || ${reportedLineNum} === ${currentLineNum}) = ${trustedLastClick || reportedLineNum === currentLineNum}`);
1809
1809
 
1810
1810
  applyHelper(currentLineNum, metadataForTargetLine.tblId, metadataForTargetLine.row, metadataForTargetLine.cols, repBeforeEdit, editorInfo, attrStringToApply, docManager);
1811
- // log(`${logPrefix} -> tbljson line attribute re-applied (using rep before edit).`);
1811
+ // log(`${logPrefix} -> tbljson line attribute re-applied (using rep before edit).`);
1812
1812
  } else {
1813
1813
  console.error(`${logPrefix} -> FAILED to re-apply tbljson attribute (helper or repBeforeEdit missing).`);
1814
1814
  const currentRepFallback = editorInfo.ace_getRep();
1815
1815
  if (applyHelper && typeof applyHelper === 'function' && currentRepFallback) {
1816
- // log(`${logPrefix} -> Retrying attribute application with current rep...`);
1816
+ // log(`${logPrefix} -> Retrying attribute application with current rep...`);
1817
1817
  applyHelper(currentLineNum, metadataForTargetLine.tblId, metadataForTargetLine.row, metadataForTargetLine.cols, currentRepFallback, editorInfo, null, docManager); // Cannot guarantee old attr string is valid here
1818
- // log(`${logPrefix} -> tbljson line attribute re-applied (using current rep fallback).`);
1818
+ // log(`${logPrefix} -> tbljson line attribute re-applied (using current rep fallback).`);
1819
1819
  } else {
1820
1820
  console.error(`${logPrefix} -> FAILED to re-apply tbljson attribute even with fallback rep.`);
1821
1821
  }
@@ -1824,26 +1824,26 @@ exports.aceKeyEvent = (h, ctx) => {
1824
1824
  // Set caret position immediately
1825
1825
  if (newAbsoluteCaretCol >= 0) {
1826
1826
  const newCaretPos = [currentLineNum, newAbsoluteCaretCol]; // Use the trusted currentLineNum
1827
- // log(`${logPrefix} -> Setting selection immediately to:`, newCaretPos);
1828
- // log(`${logPrefix} [caretTrace] rep.selStart before ace_performSelectionChange: Line=${editorInfo.ace_getRep().selStart[0]}, Col=${editorInfo.ace_getRep().selStart[1]}`);
1827
+ // log(`${logPrefix} -> Setting selection immediately to:`, newCaretPos);
1828
+ // log(`${logPrefix} [caretTrace] rep.selStart before ace_performSelectionChange: Line=${editorInfo.ace_getRep().selStart[0]}, Col=${editorInfo.ace_getRep().selStart[1]}`);
1829
1829
  try {
1830
1830
  editorInfo.ace_performSelectionChange(newCaretPos, newCaretPos, false);
1831
1831
  const repAfterSelectionChange = editorInfo.ace_getRep();
1832
- // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_performSelectionChange: Line=${repAfterSelectionChange.selStart[0]}, Col=${repAfterSelectionChange.selStart[1]}`);
1833
- // log(`${logPrefix} -> Selection set immediately.`);
1832
+ // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_performSelectionChange: Line=${repAfterSelectionChange.selStart[0]}, Col=${repAfterSelectionChange.selStart[1]}`);
1833
+ // log(`${logPrefix} -> Selection set immediately.`);
1834
1834
 
1835
1835
  // Add sync hint AFTER setting selection
1836
1836
  editorInfo.ace_fastIncorp(1);
1837
1837
  const repAfterFastIncorp = editorInfo.ace_getRep();
1838
- // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_fastIncorp: Line=${repAfterFastIncorp.selStart[0]}, Col=${repAfterFastIncorp.selStart[1]}`);
1839
- // log(`${logPrefix} -> Requested sync hint (fastIncorp 1).`);
1838
+ // log(`${logPrefix} [caretTrace] [selection] rep.selStart after ace_fastIncorp: Line=${repAfterFastIncorp.selStart[0]}, Col=${repAfterFastIncorp.selStart[1]}`);
1839
+ // log(`${logPrefix} -> Requested sync hint (fastIncorp 1).`);
1840
1840
 
1841
1841
  // --- Re-assert selection ---
1842
1842
  const targetCaretPosForReassert = [currentLineNum, newAbsoluteCaretCol];
1843
- // log(`${logPrefix} [caretTrace] Attempting to re-assert selection post-fastIncorp to [${targetCaretPosForReassert[0]}, ${targetCaretPosForReassert[1]}]`);
1843
+ // log(`${logPrefix} [caretTrace] Attempting to re-assert selection post-fastIncorp to [${targetCaretPosForReassert[0]}, ${targetCaretPosForReassert[1]}]`);
1844
1844
  editorInfo.ace_performSelectionChange(targetCaretPosForReassert, targetCaretPosForReassert, false);
1845
1845
  const repAfterReassert = editorInfo.ace_getRep();
1846
- // log(`${logPrefix} [caretTrace] [selection] rep.selStart after re-asserting selection: Line=${repAfterReassert.selStart[0]}, Col=${repAfterReassert.selStart[1]}`);
1846
+ // log(`${logPrefix} [caretTrace] [selection] rep.selStart after re-asserting selection: Line=${repAfterReassert.selStart[0]}, Col=${repAfterReassert.selStart[1]}`);
1847
1847
 
1848
1848
  // Store the updated caret info for the next event
1849
1849
  const newRelativePos = newAbsoluteCaretCol - cellStartCol;
@@ -1853,19 +1853,19 @@ exports.aceKeyEvent = (h, ctx) => {
1853
1853
  cellIndex: targetCellIndex,
1854
1854
  relativePos: newRelativePos
1855
1855
  };
1856
- // log(`${logPrefix} -> Updated stored click/caret info:`, editor.ep_data_tables_last_clicked);
1857
- // log(`${logPrefix} [caretTrace] Updated ep_data_tables_last_clicked. Line=${editor.ep_data_tables_last_clicked.lineNum}, Cell=${editor.ep_data_tables_last_clicked.cellIndex}, RelPos=${editor.ep_data_tables_last_clicked.relativePos}`);
1856
+ // log(`${logPrefix} -> Updated stored click/caret info:`, editor.ep_data_tables_last_clicked);
1857
+ // log(`${logPrefix} [caretTrace] Updated ep_data_tables_last_clicked. Line=${editor.ep_data_tables_last_clicked.lineNum}, Cell=${editor.ep_data_tables_last_clicked.cellIndex}, RelPos=${editor.ep_data_tables_last_clicked.relativePos}`);
1858
1858
 
1859
1859
 
1860
1860
  } catch (selError) {
1861
1861
  console.error(`${logPrefix} -> ERROR setting selection immediately:`, selError);
1862
1862
  }
1863
1863
  } else {
1864
- // log(`${logPrefix} -> Warning: newAbsoluteCaretCol not set, skipping selection update.`);
1864
+ // log(`${logPrefix} -> Warning: newAbsoluteCaretCol not set, skipping selection update.`);
1865
1865
  }
1866
1866
 
1867
1867
  } catch (error) {
1868
- // log(`${logPrefix} ERROR during manual key handling:`, error);
1868
+ // log(`${logPrefix} ERROR during manual key handling:`, error);
1869
1869
  console.error('[ep_data_tables] Error processing key event update:', error);
1870
1870
  // Maybe return false to allow default as a fallback on error?
1871
1871
  // For now, return true as we prevented default.
@@ -1873,7 +1873,7 @@ exports.aceKeyEvent = (h, ctx) => {
1873
1873
  }
1874
1874
 
1875
1875
  const endLogTime = Date.now();
1876
- // log(`${logPrefix} END (Handled Internal Edit Manually) Key='${evt.key}' Type='${evt.type}' -> Returned true. Duration: ${endLogTime - startLogTime}ms`);
1876
+ // log(`${logPrefix} END (Handled Internal Edit Manually) Key='${evt.key}' Type='${evt.type}' -> Returned true. Duration: ${endLogTime - startLogTime}ms`);
1877
1877
  return true; // We handled the key event
1878
1878
 
1879
1879
  } // End if(isTypingKey || isInternalBackspace || isInternalDelete)
@@ -1881,90 +1881,90 @@ exports.aceKeyEvent = (h, ctx) => {
1881
1881
 
1882
1882
  // Fallback for any other keys or edge cases not handled above
1883
1883
  const endLogTimeFinal = Date.now();
1884
- // log(`${logPrefix} END (Fell Through / Unhandled Case) Key='${evt.key}' Type='${evt.type}'. Allowing default. Duration: ${endLogTimeFinal - startLogTime}ms`);
1884
+ // log(`${logPrefix} END (Fell Through / Unhandled Case) Key='${evt.key}' Type='${evt.type}'. Allowing default. Duration: ${endLogTimeFinal - startLogTime}ms`);
1885
1885
  // Clear click state if it wasn't handled?
1886
1886
  // if (editor?.ep_data_tables_last_clicked) editor.ep_data_tables_last_clicked = null;
1887
- // log(`${logPrefix} [caretTrace] Final rep.selStart at end of aceKeyEvent (if unhandled): Line=${rep.selStart[0]}, Col=${rep.selStart[1]}`);
1887
+ // log(`${logPrefix} [caretTrace] Final rep.selStart at end of aceKeyEvent (if unhandled): Line=${rep.selStart[0]}, Col=${rep.selStart[1]}`);
1888
1888
  return false; // Allow default browser/ACE handling
1889
1889
  };
1890
1890
 
1891
1891
  // ───────────────────── ace init + public helpers ─────────────────────
1892
1892
  exports.aceInitialized = (h, ctx) => {
1893
1893
  const logPrefix = '[ep_data_tables:aceInitialized]';
1894
- // log(`${logPrefix} START`, { hook_name: h, context: ctx });
1894
+ // log(`${logPrefix} START`, { hook_name: h, context: ctx });
1895
1895
  const ed = ctx.editorInfo;
1896
1896
  const docManager = ctx.documentAttributeManager;
1897
1897
 
1898
- // log(`${logPrefix} Attaching ep_data_tables_applyMeta helper to editorInfo.`);
1898
+ // log(`${logPrefix} Attaching ep_data_tables_applyMeta helper to editorInfo.`);
1899
1899
  ed.ep_data_tables_applyMeta = applyTableLineMetadataAttribute;
1900
- // log(`${logPrefix}: Attached applyTableLineMetadataAttribute helper to ed.ep_data_tables_applyMeta successfully.`);
1900
+ // log(`${logPrefix}: Attached applyTableLineMetadataAttribute helper to ed.ep_data_tables_applyMeta successfully.`);
1901
1901
 
1902
1902
  // Store the documentAttributeManager reference for later use
1903
- // log(`${logPrefix} Storing documentAttributeManager reference on editorInfo.`);
1903
+ // log(`${logPrefix} Storing documentAttributeManager reference on editorInfo.`);
1904
1904
  ed.ep_data_tables_docManager = docManager;
1905
- // log(`${logPrefix}: Stored documentAttributeManager reference as ed.ep_data_tables_docManager.`);
1905
+ // log(`${logPrefix}: Stored documentAttributeManager reference as ed.ep_data_tables_docManager.`);
1906
1906
 
1907
1907
  // *** ENHANCED: Paste event listener + Column resize listeners ***
1908
- // log(`${logPrefix} Preparing to attach paste and resize listeners via ace_callWithAce.`);
1908
+ // log(`${logPrefix} Preparing to attach paste and resize listeners via ace_callWithAce.`);
1909
1909
  ed.ace_callWithAce((ace) => {
1910
1910
  const callWithAceLogPrefix = '[ep_data_tables:aceInitialized:callWithAceForListeners]';
1911
- // log(`${callWithAceLogPrefix} Entered ace_callWithAce callback for listeners.`);
1911
+ // log(`${callWithAceLogPrefix} Entered ace_callWithAce callback for listeners.`);
1912
1912
 
1913
1913
  if (!ace || !ace.editor) {
1914
1914
  console.error(`${callWithAceLogPrefix} ERROR: ace or ace.editor is not available. Cannot attach listeners.`);
1915
- // log(`${callWithAceLogPrefix} Aborting listener attachment due to missing ace.editor.`);
1915
+ // log(`${callWithAceLogPrefix} Aborting listener attachment due to missing ace.editor.`);
1916
1916
  return;
1917
1917
  }
1918
1918
  const editor = ace.editor;
1919
- // log(`${callWithAceLogPrefix} ace.editor obtained successfully.`);
1919
+ // log(`${callWithAceLogPrefix} ace.editor obtained successfully.`);
1920
1920
 
1921
1921
  // Store editor reference for later use in table operations
1922
- // log(`${logPrefix} Storing editor reference on editorInfo.`);
1922
+ // log(`${logPrefix} Storing editor reference on editorInfo.`);
1923
1923
  ed.ep_data_tables_editor = editor;
1924
- // log(`${logPrefix}: Stored editor reference as ed.ep_data_tables_editor.`);
1924
+ // log(`${logPrefix}: Stored editor reference as ed.ep_data_tables_editor.`);
1925
1925
 
1926
1926
  // Attempt to find the inner iframe body, similar to ep_image_insert
1927
1927
  let $inner;
1928
1928
  try {
1929
- // log(`${callWithAceLogPrefix} Attempting to find inner iframe body for listener attachment.`);
1929
+ // log(`${callWithAceLogPrefix} Attempting to find inner iframe body for listener attachment.`);
1930
1930
  const $iframeOuter = $('iframe[name="ace_outer"]');
1931
1931
  if ($iframeOuter.length === 0) {
1932
1932
  console.error(`${callWithAceLogPrefix} ERROR: Could not find outer iframe (ace_outer).`);
1933
- // log(`${callWithAceLogPrefix} Failed to find ace_outer.`);
1933
+ // log(`${callWithAceLogPrefix} Failed to find ace_outer.`);
1934
1934
  return;
1935
1935
  }
1936
- // log(`${callWithAceLogPrefix} Found ace_outer:`, $iframeOuter);
1936
+ // log(`${callWithAceLogPrefix} Found ace_outer:`, $iframeOuter);
1937
1937
 
1938
1938
  const $iframeInner = $iframeOuter.contents().find('iframe[name="ace_inner"]');
1939
1939
  if ($iframeInner.length === 0) {
1940
1940
  console.error(`${callWithAceLogPrefix} ERROR: Could not find inner iframe (ace_inner).`);
1941
- // log(`${callWithAceLogPrefix} Failed to find ace_inner within ace_outer.`);
1941
+ // log(`${callWithAceLogPrefix} Failed to find ace_inner within ace_outer.`);
1942
1942
  return;
1943
1943
  }
1944
- // log(`${callWithAceLogPrefix} Found ace_inner:`, $iframeInner);
1944
+ // log(`${callWithAceLogPrefix} Found ace_inner:`, $iframeInner);
1945
1945
 
1946
1946
  const innerDocBody = $iframeInner.contents().find('body');
1947
1947
  if (innerDocBody.length === 0) {
1948
1948
  console.error(`${callWithAceLogPrefix} ERROR: Could not find body element in inner iframe.`);
1949
- // log(`${callWithAceLogPrefix} Failed to find body in ace_inner.`);
1949
+ // log(`${callWithAceLogPrefix} Failed to find body in ace_inner.`);
1950
1950
  return;
1951
1951
  }
1952
1952
  $inner = $(innerDocBody[0]); // Ensure it's a jQuery object of the body itself
1953
- // log(`${callWithAceLogPrefix} Successfully found inner iframe body:`, $inner);
1953
+ // log(`${callWithAceLogPrefix} Successfully found inner iframe body:`, $inner);
1954
1954
  } catch (e) {
1955
1955
  console.error(`${callWithAceLogPrefix} ERROR: Exception while trying to find inner iframe body:`, e);
1956
- // log(`${callWithAceLogPrefix} Exception details:`, { message: e.message, stack: e.stack });
1956
+ // log(`${callWithAceLogPrefix} Exception details:`, { message: e.message, stack: e.stack });
1957
1957
  return;
1958
1958
  }
1959
1959
 
1960
1960
  if (!$inner || $inner.length === 0) {
1961
1961
  console.error(`${callWithAceLogPrefix} ERROR: $inner is not valid after attempting to find iframe body. Cannot attach listeners.`);
1962
- // log(`${callWithAceLogPrefix} $inner is invalid. Aborting.`);
1962
+ // log(`${callWithAceLogPrefix} $inner is invalid. Aborting.`);
1963
1963
  return;
1964
1964
  }
1965
1965
 
1966
1966
  // *** CUT EVENT LISTENER ***
1967
- log(`${callWithAceLogPrefix} Attaching cut event listener to $inner (inner iframe body).`);
1967
+ // log(`${callWithAceLogPrefix} Attaching cut event listener to $inner (inner iframe body).`);
1968
1968
  $inner.on('cut', (evt) => {
1969
1969
  const cutLogPrefix = '[ep_data_tables:cutHandler]';
1970
1970
  console.log(`${cutLogPrefix} CUT EVENT TRIGGERED. Event object:`, evt);
@@ -2170,29 +2170,29 @@ exports.aceInitialized = (h, ctx) => {
2170
2170
  });
2171
2171
 
2172
2172
  // *** BEFOREINPUT EVENT LISTENER FOR CONTEXT-MENU DELETE ***
2173
- // log(`${callWithAceLogPrefix} Attaching beforeinput event listener to $inner (inner iframe body).`);
2173
+ // log(`${callWithAceLogPrefix} Attaching beforeinput event listener to $inner (inner iframe body).`);
2174
2174
  $inner.on('beforeinput', (evt) => {
2175
2175
  const deleteLogPrefix = '[ep_data_tables:beforeinputDeleteHandler]';
2176
- // log(`${deleteLogPrefix} BEFOREINPUT EVENT TRIGGERED. inputType: "${evt.originalEvent.inputType}", event object:`, evt);
2176
+ // log(`${deleteLogPrefix} BEFOREINPUT EVENT TRIGGERED. inputType: "${evt.originalEvent.inputType}", event object:`, evt);
2177
2177
 
2178
2178
  // Only intercept deletion-related input events
2179
2179
  if (!evt.originalEvent.inputType || !evt.originalEvent.inputType.startsWith('delete')) {
2180
- // log(`${deleteLogPrefix} Not a deletion event (inputType: "${evt.originalEvent.inputType}"). Allowing default.`);
2180
+ // log(`${deleteLogPrefix} Not a deletion event (inputType: "${evt.originalEvent.inputType}"). Allowing default.`);
2181
2181
  return; // Allow default for non-delete events
2182
2182
  }
2183
2183
 
2184
- // log(`${deleteLogPrefix} Getting current editor representation (rep).`);
2184
+ // log(`${deleteLogPrefix} Getting current editor representation (rep).`);
2185
2185
  const rep = ed.ace_getRep();
2186
2186
  if (!rep || !rep.selStart) {
2187
- // log(`${deleteLogPrefix} WARNING: Could not get representation or selection. Allowing default delete.`);
2187
+ // log(`${deleteLogPrefix} WARNING: Could not get representation or selection. Allowing default delete.`);
2188
2188
  console.warn(`${deleteLogPrefix} Could not get rep or selStart.`);
2189
2189
  return; // Allow default
2190
2190
  }
2191
- // log(`${deleteLogPrefix} Rep obtained. selStart:`, rep.selStart, `selEnd:`, rep.selEnd);
2191
+ // log(`${deleteLogPrefix} Rep obtained. selStart:`, rep.selStart, `selEnd:`, rep.selEnd);
2192
2192
  const selStart = rep.selStart;
2193
2193
  const selEnd = rep.selEnd;
2194
2194
  const lineNum = selStart[0];
2195
- // log(`${deleteLogPrefix} Current line number: ${lineNum}. Column start: ${selStart[1]}, Column end: ${selEnd[1]}.`);
2195
+ // log(`${deleteLogPrefix} Current line number: ${lineNum}. Column start: ${selStart[1]}, Column end: ${selEnd[1]}.`);
2196
2196
 
2197
2197
  // Android Chrome IME: collapsed backspace/forward-delete often comes via beforeinput
2198
2198
  const isAndroidChrome = isAndroidUA();
@@ -2291,12 +2291,12 @@ exports.aceInitialized = (h, ctx) => {
2291
2291
 
2292
2292
  // Check if selection spans multiple lines
2293
2293
  if (selStart[0] !== selEnd[0]) {
2294
- // log(`${deleteLogPrefix} WARNING: Selection spans multiple lines. Preventing delete to protect table structure.`);
2294
+ // log(`${deleteLogPrefix} WARNING: Selection spans multiple lines. Preventing delete to protect table structure.`);
2295
2295
  evt.preventDefault();
2296
2296
  return;
2297
2297
  }
2298
2298
 
2299
- // log(`${deleteLogPrefix} Checking if line ${lineNum} is a table line by fetching '${ATTR_TABLE_JSON}' attribute.`);
2299
+ // log(`${deleteLogPrefix} Checking if line ${lineNum} is a table line by fetching '${ATTR_TABLE_JSON}' attribute.`);
2300
2300
  let lineAttrString = docManager.getAttributeOnLine(lineNum, ATTR_TABLE_JSON);
2301
2301
  let tableMetadata = null;
2302
2302
 
@@ -2313,11 +2313,11 @@ exports.aceInitialized = (h, ctx) => {
2313
2313
  }
2314
2314
 
2315
2315
  if (!tableMetadata || typeof tableMetadata.cols !== 'number' || typeof tableMetadata.tblId === 'undefined' || typeof tableMetadata.row === 'undefined') {
2316
- // log(`${deleteLogPrefix} Line ${lineNum} is NOT a recognised table line. Allowing default delete.`);
2316
+ // log(`${deleteLogPrefix} Line ${lineNum} is NOT a recognised table line. Allowing default delete.`);
2317
2317
  return; // Not a table line
2318
2318
  }
2319
2319
 
2320
- // log(`${deleteLogPrefix} Line ${lineNum} IS a table line. Metadata:`, tableMetadata);
2320
+ // log(`${deleteLogPrefix} Line ${lineNum} IS a table line. Metadata:`, tableMetadata);
2321
2321
 
2322
2322
  // Validate selection is within cell boundaries
2323
2323
  const lineText = rep.lines.atIndex(lineNum)?.text || '';
@@ -2368,25 +2368,25 @@ exports.aceInitialized = (h, ctx) => {
2368
2368
  }
2369
2369
 
2370
2370
  if (targetCellIndex === -1 || selEnd[1] > cellEndCol) {
2371
- // log(`${deleteLogPrefix} WARNING: Selection spans cell boundaries or is outside cells. Preventing delete to protect table structure.`);
2371
+ // log(`${deleteLogPrefix} WARNING: Selection spans cell boundaries or is outside cells. Preventing delete to protect table structure.`);
2372
2372
  evt.preventDefault();
2373
2373
  return;
2374
2374
  }
2375
2375
 
2376
2376
  // If we reach here, the selection is entirely within a single cell - intercept delete and preserve table structure
2377
- // log(`${deleteLogPrefix} Selection is entirely within cell ${targetCellIndex}. Intercepting delete to preserve table structure.`);
2377
+ // log(`${deleteLogPrefix} Selection is entirely within cell ${targetCellIndex}. Intercepting delete to preserve table structure.`);
2378
2378
  evt.preventDefault();
2379
2379
 
2380
2380
  try {
2381
2381
  // No clipboard operations needed for delete - just perform the deletion within the cell using ace operations
2382
- // log(`${deleteLogPrefix} Performing deletion via ed.ace_callWithAce.`);
2382
+ // log(`${deleteLogPrefix} Performing deletion via ed.ace_callWithAce.`);
2383
2383
  ed.ace_callWithAce((aceInstance) => {
2384
2384
  const callAceLogPrefix = `${deleteLogPrefix}[ace_callWithAceOps]`;
2385
- // log(`${callAceLogPrefix} Entered ace_callWithAce for delete operations. selStart:`, selStart, `selEnd:`, selEnd);
2385
+ // log(`${callAceLogPrefix} Entered ace_callWithAce for delete operations. selStart:`, selStart, `selEnd:`, selEnd);
2386
2386
 
2387
- // log(`${callAceLogPrefix} Calling aceInstance.ace_performDocumentReplaceRange to delete selected text.`);
2387
+ // log(`${callAceLogPrefix} Calling aceInstance.ace_performDocumentReplaceRange to delete selected text.`);
2388
2388
  aceInstance.ace_performDocumentReplaceRange(selStart, selEnd, '');
2389
- // log(`${callAceLogPrefix} ace_performDocumentReplaceRange successful.`);
2389
+ // log(`${callAceLogPrefix} ace_performDocumentReplaceRange successful.`);
2390
2390
 
2391
2391
  // --- Ensure cell is not left empty (zero-length) ---
2392
2392
  const repAfterDeletion = aceInstance.ace_getRep();
@@ -2395,7 +2395,7 @@ exports.aceInitialized = (h, ctx) => {
2395
2395
  const cellTextAfterDeletion = cellsAfterDeletion[targetCellIndex] || '';
2396
2396
 
2397
2397
  if (cellTextAfterDeletion.length === 0) {
2398
- // log(`${callAceLogPrefix} Cell ${targetCellIndex} became empty after delete – inserting single space to preserve structure.`);
2398
+ // log(`${callAceLogPrefix} Cell ${targetCellIndex} became empty after delete – inserting single space to preserve structure.`);
2399
2399
  const insertPos = [lineNum, selStart[1]]; // Start of the now-empty cell
2400
2400
  aceInstance.ace_performDocumentReplaceRange(insertPos, insertPos, ' ');
2401
2401
 
@@ -2407,9 +2407,9 @@ exports.aceInitialized = (h, ctx) => {
2407
2407
  );
2408
2408
  }
2409
2409
 
2410
- // log(`${callAceLogPrefix} Preparing to re-apply tbljson attribute to line ${lineNum}.`);
2410
+ // log(`${callAceLogPrefix} Preparing to re-apply tbljson attribute to line ${lineNum}.`);
2411
2411
  const repAfterDelete = aceInstance.ace_getRep();
2412
- // log(`${callAceLogPrefix} Fetched rep after delete for applyMeta. Line ${lineNum} text now: "${repAfterDelete.lines.atIndex(lineNum).text}"`);
2412
+ // log(`${callAceLogPrefix} Fetched rep after delete for applyMeta. Line ${lineNum} text now: "${repAfterDelete.lines.atIndex(lineNum).text}"`);
2413
2413
 
2414
2414
  ed.ep_data_tables_applyMeta(
2415
2415
  lineNum,
@@ -2421,22 +2421,22 @@ exports.aceInitialized = (h, ctx) => {
2421
2421
  null,
2422
2422
  docManager
2423
2423
  );
2424
- // log(`${callAceLogPrefix} tbljson attribute re-applied successfully via ep_data_tables_applyMeta.`);
2424
+ // log(`${callAceLogPrefix} tbljson attribute re-applied successfully via ep_data_tables_applyMeta.`);
2425
2425
 
2426
2426
  // Determine new caret position – one char forward if we inserted a space
2427
2427
  const newCaretAbsoluteCol = (cellTextAfterDeletion.length === 0) ? selStart[1] + 1 : selStart[1];
2428
2428
  const newCaretPos = [lineNum, newCaretAbsoluteCol];
2429
- // log(`${callAceLogPrefix} Setting caret position to: [${newCaretPos}].`);
2429
+ // log(`${callAceLogPrefix} Setting caret position to: [${newCaretPos}].`);
2430
2430
  aceInstance.ace_performSelectionChange(newCaretPos, newCaretPos, false);
2431
- // log(`${callAceLogPrefix} Selection change successful.`);
2431
+ // log(`${callAceLogPrefix} Selection change successful.`);
2432
2432
 
2433
- // log(`${callAceLogPrefix} Delete operations within ace_callWithAce completed successfully.`);
2433
+ // log(`${callAceLogPrefix} Delete operations within ace_callWithAce completed successfully.`);
2434
2434
  }, 'tableDeleteTextOperations', true);
2435
2435
 
2436
- // log(`${deleteLogPrefix} Delete operation completed successfully.`);
2436
+ // log(`${deleteLogPrefix} Delete operation completed successfully.`);
2437
2437
  } catch (error) {
2438
2438
  console.error(`${deleteLogPrefix} ERROR during delete operation:`, error);
2439
- // log(`${deleteLogPrefix} Delete operation failed. Error details:`, { message: error.message, stack: error.stack });
2439
+ // log(`${deleteLogPrefix} Delete operation failed. Error details:`, { message: error.message, stack: error.stack });
2440
2440
  }
2441
2441
  });
2442
2442
 
@@ -2754,12 +2754,12 @@ exports.aceInitialized = (h, ctx) => {
2754
2754
  });
2755
2755
 
2756
2756
  // *** DRAG AND DROP EVENT LISTENERS ***
2757
- // log(`${callWithAceLogPrefix} Attaching drag and drop event listeners to $inner (inner iframe body).`);
2757
+ // log(`${callWithAceLogPrefix} Attaching drag and drop event listeners to $inner (inner iframe body).`);
2758
2758
 
2759
2759
  // Prevent drops that could damage table structure
2760
2760
  $inner.on('drop', (evt) => {
2761
2761
  const dropLogPrefix = '[ep_data_tables:dropHandler]';
2762
- // log(`${dropLogPrefix} DROP EVENT TRIGGERED. Event object:`, evt);
2762
+ // log(`${dropLogPrefix} DROP EVENT TRIGGERED. Event object:`, evt);
2763
2763
 
2764
2764
  // Block drops directly targeted at a table element regardless of selection state
2765
2765
  const targetEl = evt.target;
@@ -2773,19 +2773,19 @@ exports.aceInitialized = (h, ctx) => {
2773
2773
  return;
2774
2774
  }
2775
2775
 
2776
- // log(`${dropLogPrefix} Getting current editor representation (rep).`);
2776
+ // log(`${dropLogPrefix} Getting current editor representation (rep).`);
2777
2777
  const rep = ed.ace_getRep();
2778
2778
  if (!rep || !rep.selStart) {
2779
- // log(`${dropLogPrefix} WARNING: Could not get representation or selection. Allowing default drop.`);
2779
+ // log(`${dropLogPrefix} WARNING: Could not get representation or selection. Allowing default drop.`);
2780
2780
  return; // Allow default
2781
2781
  }
2782
2782
 
2783
2783
  const selStart = rep.selStart;
2784
2784
  const lineNum = selStart[0];
2785
- // log(`${dropLogPrefix} Current line number: ${lineNum}.`);
2785
+ // log(`${dropLogPrefix} Current line number: ${lineNum}.`);
2786
2786
 
2787
2787
  // Check if we're dropping onto a table line
2788
- // log(`${dropLogPrefix} Checking if line ${lineNum} is a table line by fetching '${ATTR_TABLE_JSON}' attribute.`);
2788
+ // log(`${dropLogPrefix} Checking if line ${lineNum} is a table line by fetching '${ATTR_TABLE_JSON}' attribute.`);
2789
2789
  let lineAttrString = docManager.getAttributeOnLine(lineNum, ATTR_TABLE_JSON);
2790
2790
  let isTableLine = !!lineAttrString;
2791
2791
 
@@ -2795,7 +2795,7 @@ exports.aceInitialized = (h, ctx) => {
2795
2795
  }
2796
2796
 
2797
2797
  if (isTableLine) {
2798
- // log(`${dropLogPrefix} Line ${lineNum} IS a table line. Preventing drop to protect table structure.`);
2798
+ // log(`${dropLogPrefix} Line ${lineNum} IS a table line. Preventing drop to protect table structure.`);
2799
2799
  evt.preventDefault();
2800
2800
  evt.stopPropagation();
2801
2801
  console.warn('[ep_data_tables] Drop operation prevented to protect table structure. Please use copy/paste within table cells.');
@@ -2826,7 +2826,7 @@ exports.aceInitialized = (h, ctx) => {
2826
2826
  const lineNum = selStart[0];
2827
2827
 
2828
2828
  // Check if we're dragging over a table line
2829
- // log(`${dragLogPrefix} Checking if line ${lineNum} is a table line by fetching '${ATTR_TABLE_JSON}' attribute.`);
2829
+ // log(`${dragLogPrefix} Checking if line ${lineNum} is a table line by fetching '${ATTR_TABLE_JSON}' attribute.`);
2830
2830
  let lineAttrString = docManager.getAttributeOnLine(lineNum, ATTR_TABLE_JSON);
2831
2831
  let isTableLine = !!lineAttrString;
2832
2832
 
@@ -2835,7 +2835,7 @@ exports.aceInitialized = (h, ctx) => {
2835
2835
  }
2836
2836
 
2837
2837
  if (isTableLine) {
2838
- // log(`${dragLogPrefix} Preventing dragover on table line ${lineNum} to control drop handling.`);
2838
+ // log(`${dragLogPrefix} Preventing dragover on table line ${lineNum} to control drop handling.`);
2839
2839
  evt.preventDefault();
2840
2840
  }
2841
2841
  });
@@ -2853,67 +2853,67 @@ exports.aceInitialized = (h, ctx) => {
2853
2853
  });
2854
2854
 
2855
2855
  // *** EXISTING PASTE LISTENER ***
2856
- // log(`${callWithAceLogPrefix} Attaching paste event listener to $inner (inner iframe body).`);
2856
+ // log(`${callWithAceLogPrefix} Attaching paste event listener to $inner (inner iframe body).`);
2857
2857
  $inner.on('paste', (evt) => {
2858
2858
  const pasteLogPrefix = '[ep_data_tables:pasteHandler]';
2859
- // log(`${pasteLogPrefix} PASTE EVENT TRIGGERED. Event object:`, evt);
2859
+ // log(`${pasteLogPrefix} PASTE EVENT TRIGGERED. Event object:`, evt);
2860
2860
 
2861
- // log(`${pasteLogPrefix} Getting current editor representation (rep).`);
2861
+ // log(`${pasteLogPrefix} Getting current editor representation (rep).`);
2862
2862
  const rep = ed.ace_getRep();
2863
2863
  if (!rep || !rep.selStart) {
2864
- // log(`${pasteLogPrefix} WARNING: Could not get representation or selection. Allowing default paste.`);
2864
+ // log(`${pasteLogPrefix} WARNING: Could not get representation or selection. Allowing default paste.`);
2865
2865
  console.warn(`${pasteLogPrefix} Could not get rep or selStart.`);
2866
2866
  return; // Allow default
2867
2867
  }
2868
- // log(`${pasteLogPrefix} Rep obtained. selStart:`, rep.selStart, `selEnd:`, rep.selEnd);
2868
+ // log(`${pasteLogPrefix} Rep obtained. selStart:`, rep.selStart, `selEnd:`, rep.selEnd);
2869
2869
  const selStart = rep.selStart;
2870
2870
  const selEnd = rep.selEnd;
2871
2871
  const lineNum = selStart[0];
2872
- // log(`${pasteLogPrefix} Current line number: ${lineNum}. Column start: ${selStart[1]}, Column end: ${selEnd[1]}.`);
2872
+ // log(`${pasteLogPrefix} Current line number: ${lineNum}. Column start: ${selStart[1]}, Column end: ${selEnd[1]}.`);
2873
2873
 
2874
2874
  // NEW: Check if selection spans multiple lines
2875
2875
  if (selStart[0] !== selEnd[0]) {
2876
- // log(`${pasteLogPrefix} WARNING: Selection spans multiple lines. Preventing paste to protect table structure.`);
2876
+ // log(`${pasteLogPrefix} WARNING: Selection spans multiple lines. Preventing paste to protect table structure.`);
2877
2877
  evt.preventDefault();
2878
2878
  return;
2879
2879
  }
2880
2880
 
2881
- // log(`${pasteLogPrefix} Checking if line ${lineNum} is a table line by fetching '${ATTR_TABLE_JSON}' attribute.`);
2881
+ // log(`${pasteLogPrefix} Checking if line ${lineNum} is a table line by fetching '${ATTR_TABLE_JSON}' attribute.`);
2882
2882
  let lineAttrString = docManager.getAttributeOnLine(lineNum, ATTR_TABLE_JSON);
2883
2883
  let tableMetadata = null;
2884
2884
 
2885
2885
  if (!lineAttrString) {
2886
2886
  // Block-styled row? Reconstruct metadata from the DOM.
2887
- // log(`${pasteLogPrefix} No '${ATTR_TABLE_JSON}' attribute found. Checking if this is a block-styled table row via DOM reconstruction.`);
2887
+ // log(`${pasteLogPrefix} No '${ATTR_TABLE_JSON}' attribute found. Checking if this is a block-styled table row via DOM reconstruction.`);
2888
2888
  const fallbackMeta = getTableLineMetadata(lineNum, ed, docManager);
2889
2889
  if (fallbackMeta) {
2890
2890
  tableMetadata = fallbackMeta;
2891
2891
  lineAttrString = JSON.stringify(fallbackMeta);
2892
- // log(`${pasteLogPrefix} Block-styled table row detected. Reconstructed metadata:`, fallbackMeta);
2892
+ // log(`${pasteLogPrefix} Block-styled table row detected. Reconstructed metadata:`, fallbackMeta);
2893
2893
  }
2894
2894
  }
2895
2895
 
2896
2896
  if (!lineAttrString) {
2897
- // log(`${pasteLogPrefix} Line ${lineNum} is NOT a table line (no '${ATTR_TABLE_JSON}' attribute found and no DOM reconstruction possible). Allowing default paste.`);
2897
+ // log(`${pasteLogPrefix} Line ${lineNum} is NOT a table line (no '${ATTR_TABLE_JSON}' attribute found and no DOM reconstruction possible). Allowing default paste.`);
2898
2898
  return; // Not a table line
2899
2899
  }
2900
- // log(`${pasteLogPrefix} Line ${lineNum} IS a table line. Attribute string: "${lineAttrString}".`);
2900
+ // log(`${pasteLogPrefix} Line ${lineNum} IS a table line. Attribute string: "${lineAttrString}".`);
2901
2901
 
2902
2902
  try {
2903
- // log(`${pasteLogPrefix} Parsing table metadata from attribute string.`);
2903
+ // log(`${pasteLogPrefix} Parsing table metadata from attribute string.`);
2904
2904
  if (!tableMetadata) {
2905
2905
  tableMetadata = JSON.parse(lineAttrString);
2906
2906
  }
2907
- // log(`${pasteLogPrefix} Parsed table metadata:`, tableMetadata);
2907
+ // log(`${pasteLogPrefix} Parsed table metadata:`, tableMetadata);
2908
2908
  if (!tableMetadata || typeof tableMetadata.cols !== 'number' || typeof tableMetadata.tblId === 'undefined' || typeof tableMetadata.row === 'undefined') {
2909
- // log(`${pasteLogPrefix} WARNING: Invalid or incomplete table metadata on line ${lineNum}. Allowing default paste. Metadata:`, tableMetadata);
2909
+ // log(`${pasteLogPrefix} WARNING: Invalid or incomplete table metadata on line ${lineNum}. Allowing default paste. Metadata:`, tableMetadata);
2910
2910
  console.warn(`${pasteLogPrefix} Invalid table metadata for line ${lineNum}.`);
2911
2911
  return; // Allow default
2912
2912
  }
2913
- // log(`${pasteLogPrefix} Table metadata validated successfully: tblId=${tableMetadata.tblId}, row=${tableMetadata.row}, cols=${tableMetadata.cols}.`);
2913
+ // log(`${pasteLogPrefix} Table metadata validated successfully: tblId=${tableMetadata.tblId}, row=${tableMetadata.row}, cols=${tableMetadata.cols}.`);
2914
2914
  } catch(e) {
2915
2915
  console.error(`${pasteLogPrefix} ERROR parsing table metadata for line ${lineNum}:`, e);
2916
- // log(`${pasteLogPrefix} Metadata parse error. Allowing default paste. Error details:`, { message: e.message, stack: e.stack });
2916
+ // log(`${pasteLogPrefix} Metadata parse error. Allowing default paste. Error details:`, { message: e.message, stack: e.stack });
2917
2917
  return; // Allow default
2918
2918
  }
2919
2919
 
@@ -2944,29 +2944,29 @@ exports.aceInitialized = (h, ctx) => {
2944
2944
  selEnd[1] = cellEndCol; // clamp
2945
2945
  }
2946
2946
  if (targetCellIndex === -1 || selEnd[1] > cellEndCol) {
2947
- // log(`${pasteLogPrefix} WARNING: Selection spans cell boundaries or is outside cells. Preventing paste to protect table structure.`);
2947
+ // log(`${pasteLogPrefix} WARNING: Selection spans cell boundaries or is outside cells. Preventing paste to protect table structure.`);
2948
2948
  evt.preventDefault();
2949
2949
  return;
2950
2950
  }
2951
2951
 
2952
- // log(`${pasteLogPrefix} Accessing clipboard data.`);
2952
+ // log(`${pasteLogPrefix} Accessing clipboard data.`);
2953
2953
  const clipboardData = evt.originalEvent.clipboardData || window.clipboardData;
2954
2954
  if (!clipboardData) {
2955
- // log(`${pasteLogPrefix} WARNING: No clipboard data found. Allowing default paste.`);
2955
+ // log(`${pasteLogPrefix} WARNING: No clipboard data found. Allowing default paste.`);
2956
2956
  return; // Allow default
2957
2957
  }
2958
- // log(`${pasteLogPrefix} Clipboard data object obtained:`, clipboardData);
2958
+ // log(`${pasteLogPrefix} Clipboard data object obtained:`, clipboardData);
2959
2959
 
2960
2960
  // Allow default handling (so ep_hyperlinked_text plugin can process) if rich HTML is present
2961
2961
  const types = clipboardData.types || [];
2962
2962
  if (types.includes('text/html') && clipboardData.getData('text/html')) {
2963
- // log(`${pasteLogPrefix} Detected text/html in clipboard – deferring to other plugins and default paste.`);
2963
+ // log(`${pasteLogPrefix} Detected text/html in clipboard – deferring to other plugins and default paste.`);
2964
2964
  return; // Do not intercept
2965
2965
  }
2966
2966
 
2967
- // log(`${pasteLogPrefix} Getting 'text/plain' from clipboard.`);
2967
+ // log(`${pasteLogPrefix} Getting 'text/plain' from clipboard.`);
2968
2968
  const pastedTextRaw = clipboardData.getData('text/plain');
2969
- // log(`${pasteLogPrefix} Pasted text raw: "${pastedTextRaw}" (Type: ${typeof pastedTextRaw})`);
2969
+ // log(`${pasteLogPrefix} Pasted text raw: "${pastedTextRaw}" (Type: ${typeof pastedTextRaw})`);
2970
2970
 
2971
2971
  // ENHANCED: More thorough sanitization of pasted content
2972
2972
  let pastedText = pastedTextRaw
@@ -2976,18 +2976,18 @@ exports.aceInitialized = (h, ctx) => {
2976
2976
  .replace(/\s+/g, " ") // Normalize whitespace
2977
2977
  .trim(); // Trim leading/trailing whitespace
2978
2978
 
2979
- // log(`${pasteLogPrefix} Pasted text after sanitization: "${pastedText}"`);
2979
+ // log(`${pasteLogPrefix} Pasted text after sanitization: "${pastedText}"`);
2980
2980
 
2981
2981
  if (typeof pastedText !== 'string' || pastedText.length === 0) {
2982
- // log(`${pasteLogPrefix} No plain text in clipboard or text is empty (after sanitization). Allowing default paste.`);
2982
+ // log(`${pasteLogPrefix} No plain text in clipboard or text is empty (after sanitization). Allowing default paste.`);
2983
2983
  const types = clipboardData.types;
2984
- // log(`${pasteLogPrefix} Clipboard types available:`, types);
2984
+ // log(`${pasteLogPrefix} Clipboard types available:`, types);
2985
2985
  if (types && types.includes('text/html')) {
2986
- // log(`${pasteLogPrefix} Clipboard also contains HTML:`, clipboardData.getData('text/html'));
2986
+ // log(`${pasteLogPrefix} Clipboard also contains HTML:`, clipboardData.getData('text/html'));
2987
2987
  }
2988
2988
  return; // Allow default if no plain text
2989
2989
  }
2990
- // log(`${pasteLogPrefix} Plain text obtained from clipboard: "${pastedText}". Length: ${pastedText.length}.`);
2990
+ // log(`${pasteLogPrefix} Plain text obtained from clipboard: "${pastedText}". Length: ${pastedText.length}.`);
2991
2991
 
2992
2992
  // NEW: Check if paste would exceed cell boundaries
2993
2993
  const currentCellText = cells[targetCellIndex] || '';
@@ -3001,18 +3001,18 @@ exports.aceInitialized = (h, ctx) => {
3001
3001
  // see fit or set to `Infinity` to remove the cap entirely.
3002
3002
  const MAX_CELL_LENGTH = 8000;
3003
3003
  if (newCellLength > MAX_CELL_LENGTH) {
3004
- // log(`${pasteLogPrefix} WARNING: Paste would exceed maximum cell length (${newCellLength} > ${MAX_CELL_LENGTH}). Truncating paste.`);
3004
+ // log(`${pasteLogPrefix} WARNING: Paste would exceed maximum cell length (${newCellLength} > ${MAX_CELL_LENGTH}). Truncating paste.`);
3005
3005
  const truncatedPaste = pastedText.substring(0, MAX_CELL_LENGTH - (currentCellText.length - selectionLength));
3006
3006
  if (truncatedPaste.length === 0) {
3007
- // log(`${pasteLogPrefix} Paste would be completely truncated. Preventing paste.`);
3007
+ // log(`${pasteLogPrefix} Paste would be completely truncated. Preventing paste.`);
3008
3008
  evt.preventDefault();
3009
3009
  return;
3010
3010
  }
3011
- // log(`${pasteLogPrefix} Using truncated paste: "${truncatedPaste}"`);
3011
+ // log(`${pasteLogPrefix} Using truncated paste: "${truncatedPaste}"`);
3012
3012
  pastedText = truncatedPaste;
3013
3013
  }
3014
3014
 
3015
- // log(`${pasteLogPrefix} INTERCEPTING paste of plain text into table line ${lineNum}. PREVENTING DEFAULT browser action.`);
3015
+ // log(`${pasteLogPrefix} INTERCEPTING paste of plain text into table line ${lineNum}. PREVENTING DEFAULT browser action.`);
3016
3016
  evt.preventDefault();
3017
3017
  // Prevent other plugins from handling the same paste event once we
3018
3018
  // have intercepted it inside a table cell.
@@ -3020,20 +3020,20 @@ exports.aceInitialized = (h, ctx) => {
3020
3020
  if (typeof evt.stopImmediatePropagation === 'function') evt.stopImmediatePropagation();
3021
3021
 
3022
3022
  try {
3023
- // log(`${pasteLogPrefix} Preparing to perform paste operations via ed.ace_callWithAce.`);
3023
+ // log(`${pasteLogPrefix} Preparing to perform paste operations via ed.ace_callWithAce.`);
3024
3024
  ed.ace_callWithAce((aceInstance) => {
3025
3025
  const callAceLogPrefix = `${pasteLogPrefix}[ace_callWithAceOps]`;
3026
- // log(`${callAceLogPrefix} Entered ace_callWithAce for paste operations. selStart:`, selStart, `selEnd:`, selEnd);
3026
+ // log(`${callAceLogPrefix} Entered ace_callWithAce for paste operations. selStart:`, selStart, `selEnd:`, selEnd);
3027
3027
 
3028
- // log(`${callAceLogPrefix} Original line text from initial rep: "${rep.lines.atIndex(lineNum).text}". SelStartCol: ${selStart[1]}, SelEndCol: ${selEnd[1]}.`);
3028
+ // log(`${callAceLogPrefix} Original line text from initial rep: "${rep.lines.atIndex(lineNum).text}". SelStartCol: ${selStart[1]}, SelEndCol: ${selEnd[1]}.`);
3029
3029
 
3030
- // log(`${callAceLogPrefix} Calling aceInstance.ace_performDocumentReplaceRange to insert text: "${pastedText}".`);
3030
+ // log(`${callAceLogPrefix} Calling aceInstance.ace_performDocumentReplaceRange to insert text: "${pastedText}".`);
3031
3031
  aceInstance.ace_performDocumentReplaceRange(selStart, selEnd, pastedText);
3032
- // log(`${callAceLogPrefix} ace_performDocumentReplaceRange successful.`);
3032
+ // log(`${callAceLogPrefix} ace_performDocumentReplaceRange successful.`);
3033
3033
 
3034
- // log(`${callAceLogPrefix} Preparing to re-apply tbljson attribute to line ${lineNum}.`);
3034
+ // log(`${callAceLogPrefix} Preparing to re-apply tbljson attribute to line ${lineNum}.`);
3035
3035
  const repAfterReplace = aceInstance.ace_getRep();
3036
- // log(`${callAceLogPrefix} Fetched rep after replace for applyMeta. Line ${lineNum} text now: "${repAfterReplace.lines.atIndex(lineNum).text}"`);
3036
+ // log(`${callAceLogPrefix} Fetched rep after replace for applyMeta. Line ${lineNum} text now: "${repAfterReplace.lines.atIndex(lineNum).text}"`);
3037
3037
 
3038
3038
  ed.ep_data_tables_applyMeta(
3039
3039
  lineNum,
@@ -3045,17 +3045,17 @@ exports.aceInitialized = (h, ctx) => {
3045
3045
  null,
3046
3046
  docManager
3047
3047
  );
3048
- // log(`${callAceLogPrefix} tbljson attribute re-applied successfully via ep_data_tables_applyMeta.`);
3048
+ // log(`${callAceLogPrefix} tbljson attribute re-applied successfully via ep_data_tables_applyMeta.`);
3049
3049
 
3050
3050
  const newCaretCol = selStart[1] + pastedText.length;
3051
3051
  const newCaretPos = [lineNum, newCaretCol];
3052
- // log(`${callAceLogPrefix} New calculated caret position: [${newCaretPos}]. Setting selection.`);
3052
+ // log(`${callAceLogPrefix} New calculated caret position: [${newCaretPos}]. Setting selection.`);
3053
3053
  aceInstance.ace_performSelectionChange(newCaretPos, newCaretPos, false);
3054
- // log(`${callAceLogPrefix} Selection change successful.`);
3054
+ // log(`${callAceLogPrefix} Selection change successful.`);
3055
3055
 
3056
- // log(`${callAceLogPrefix} Requesting fastIncorp(10) for sync.`);
3056
+ // log(`${callAceLogPrefix} Requesting fastIncorp(10) for sync.`);
3057
3057
  aceInstance.ace_fastIncorp(10);
3058
- // log(`${callAceLogPrefix} fastIncorp requested.`);
3058
+ // log(`${callAceLogPrefix} fastIncorp requested.`);
3059
3059
 
3060
3060
  // Update stored click/caret info
3061
3061
  if (editor && editor.ep_data_tables_last_clicked && editor.ep_data_tables_last_clicked.tblId === tableMetadata.tblId) {
@@ -3066,23 +3066,23 @@ exports.aceInitialized = (h, ctx) => {
3066
3066
  cellIndex: targetCellIndex,
3067
3067
  relativePos: newRelativePos < 0 ? 0 : newRelativePos,
3068
3068
  };
3069
- // log(`${callAceLogPrefix} Updated stored click/caret info:`, editor.ep_data_tables_last_clicked);
3069
+ // log(`${callAceLogPrefix} Updated stored click/caret info:`, editor.ep_data_tables_last_clicked);
3070
3070
  }
3071
3071
 
3072
- // log(`${callAceLogPrefix} Paste operations within ace_callWithAce completed successfully.`);
3072
+ // log(`${callAceLogPrefix} Paste operations within ace_callWithAce completed successfully.`);
3073
3073
  }, 'tablePasteTextOperations', true);
3074
- // log(`${pasteLogPrefix} ed.ace_callWithAce for paste operations was called.`);
3074
+ // log(`${pasteLogPrefix} ed.ace_callWithAce for paste operations was called.`);
3075
3075
 
3076
3076
  } catch (error) {
3077
3077
  console.error(`${pasteLogPrefix} CRITICAL ERROR during paste handling operation:`, error);
3078
- // log(`${pasteLogPrefix} Error details:`, { message: error.message, stack: error.stack });
3079
- // log(`${pasteLogPrefix} Paste handling FAILED. END OF HANDLER.`);
3078
+ // log(`${pasteLogPrefix} Error details:`, { message: error.message, stack: error.stack });
3079
+ // log(`${pasteLogPrefix} Paste handling FAILED. END OF HANDLER.`);
3080
3080
  }
3081
3081
  });
3082
- // log(`${callWithAceLogPrefix} Paste event listener attached.`);
3082
+ // log(`${callWithAceLogPrefix} Paste event listener attached.`);
3083
3083
 
3084
3084
  // *** NEW: Column resize listeners ***
3085
- // log(`${callWithAceLogPrefix} Attaching column resize listeners...`);
3085
+ // log(`${callWithAceLogPrefix} Attaching column resize listeners...`);
3086
3086
 
3087
3087
  // Get the iframe documents for proper event delegation
3088
3088
  const $iframeOuter = $('iframe[name="ace_outer"]');
@@ -3090,16 +3090,16 @@ exports.aceInitialized = (h, ctx) => {
3090
3090
  const innerDoc = $iframeInner.contents();
3091
3091
  const outerDoc = $iframeOuter.contents();
3092
3092
 
3093
- // log(`${callWithAceLogPrefix} Found iframe documents: outer=${outerDoc.length}, inner=${innerDoc.length}`);
3093
+ // log(`${callWithAceLogPrefix} Found iframe documents: outer=${outerDoc.length}, inner=${innerDoc.length}`);
3094
3094
 
3095
3095
  // Mousedown on resize handles
3096
3096
  $inner.on('mousedown', '.ep-data_tables-resize-handle', (evt) => {
3097
3097
  const resizeLogPrefix = '[ep_data_tables:resizeMousedown]';
3098
- // log(`${resizeLogPrefix} Resize handle mousedown detected`);
3098
+ // log(`${resizeLogPrefix} Resize handle mousedown detected`);
3099
3099
 
3100
3100
  // Only handle left mouse button clicks
3101
3101
  if (evt.button !== 0) {
3102
- // log(`${resizeLogPrefix} Ignoring non-left mouse button: ${evt.button}`);
3102
+ // log(`${resizeLogPrefix} Ignoring non-left mouse button: ${evt.button}`);
3103
3103
  return;
3104
3104
  }
3105
3105
 
@@ -3110,7 +3110,7 @@ exports.aceInitialized = (h, ctx) => {
3110
3110
  const isImageResizeHandle = $target.hasClass('image-resize-handle') || $target.closest('.image-resize-handle').length > 0;
3111
3111
 
3112
3112
  if (isImageRelated || isImageResizeHandle) {
3113
- // log(`${resizeLogPrefix} Click detected on image-related element or image resize handle, ignoring for table resize`);
3113
+ // log(`${resizeLogPrefix} Click detected on image-related element or image resize handle, ignoring for table resize`);
3114
3114
  return;
3115
3115
  }
3116
3116
 
@@ -3122,7 +3122,7 @@ exports.aceInitialized = (h, ctx) => {
3122
3122
  const table = handle.closest('table.dataTable');
3123
3123
  const lineNode = table.closest('div.ace-line');
3124
3124
 
3125
- // log(`${resizeLogPrefix} Parsed resize target: columnIndex=${columnIndex}, table=${!!table}, lineNode=${!!lineNode}`);
3125
+ // log(`${resizeLogPrefix} Parsed resize target: columnIndex=${columnIndex}, table=${!!table}, lineNode=${!!lineNode}`);
3126
3126
 
3127
3127
  if (table && lineNode && !isNaN(columnIndex)) {
3128
3128
  // Get table metadata
@@ -3136,7 +3136,7 @@ exports.aceInitialized = (h, ctx) => {
3136
3136
 
3137
3137
  const lineNum = rep.lines.indexOfKey(lineNode.id);
3138
3138
 
3139
- // log(`${resizeLogPrefix} Table info: tblId=${tblId}, lineNum=${lineNum}`);
3139
+ // log(`${resizeLogPrefix} Table info: tblId=${tblId}, lineNum=${lineNum}`);
3140
3140
 
3141
3141
  if (tblId && lineNum !== -1) {
3142
3142
  try {
@@ -3144,17 +3144,17 @@ exports.aceInitialized = (h, ctx) => {
3144
3144
  if (lineAttrString) {
3145
3145
  const metadata = JSON.parse(lineAttrString);
3146
3146
  if (metadata.tblId === tblId) {
3147
- // log(`${resizeLogPrefix} Starting resize with metadata:`, metadata);
3147
+ // log(`${resizeLogPrefix} Starting resize with metadata:`, metadata);
3148
3148
  startColumnResize(table, columnIndex, evt.clientX, metadata, lineNum);
3149
- // log(`${resizeLogPrefix} Started resize for column ${columnIndex}`);
3149
+ // log(`${resizeLogPrefix} Started resize for column ${columnIndex}`);
3150
3150
 
3151
3151
  // DEBUG: Verify global state is set
3152
- // log(`${resizeLogPrefix} Global resize state: isResizing=${isResizing}, targetTable=${!!resizeTargetTable}, targetColumn=${resizeTargetColumn}`);
3152
+ // log(`${resizeLogPrefix} Global resize state: isResizing=${isResizing}, targetTable=${!!resizeTargetTable}, targetColumn=${resizeTargetColumn}`);
3153
3153
  } else {
3154
- // log(`${resizeLogPrefix} Table ID mismatch: ${metadata.tblId} vs ${tblId}`);
3154
+ // log(`${resizeLogPrefix} Table ID mismatch: ${metadata.tblId} vs ${tblId}`);
3155
3155
  }
3156
3156
  } else {
3157
- // log(`${resizeLogPrefix} No table metadata found for line ${lineNum}, trying DOM reconstruction...`);
3157
+ // log(`${resizeLogPrefix} No table metadata found for line ${lineNum}, trying DOM reconstruction...`);
3158
3158
 
3159
3159
  // Fallback: Reconstruct metadata from DOM (same logic as ace_doDatatableOptions)
3160
3160
  const rep = ed.ace_getRep();
@@ -3188,37 +3188,37 @@ exports.aceInitialized = (h, ctx) => {
3188
3188
  cols: domCells.length,
3189
3189
  columnWidths: columnWidths
3190
3190
  };
3191
- // log(`${resizeLogPrefix} Reconstructed metadata from DOM:`, reconstructedMetadata);
3191
+ // log(`${resizeLogPrefix} Reconstructed metadata from DOM:`, reconstructedMetadata);
3192
3192
 
3193
3193
  startColumnResize(table, columnIndex, evt.clientX, reconstructedMetadata, lineNum);
3194
- // log(`${resizeLogPrefix} Started resize for column ${columnIndex} using reconstructed metadata`);
3194
+ // log(`${resizeLogPrefix} Started resize for column ${columnIndex} using reconstructed metadata`);
3195
3195
 
3196
3196
  // DEBUG: Verify global state is set
3197
- // log(`${resizeLogPrefix} Global resize state: isResizing=${isResizing}, targetTable=${!!resizeTargetTable}, targetColumn=${resizeTargetColumn}`);
3197
+ // log(`${resizeLogPrefix} Global resize state: isResizing=${isResizing}, targetTable=${!!resizeTargetTable}, targetColumn=${resizeTargetColumn}`);
3198
3198
  } else {
3199
- // log(`${resizeLogPrefix} DOM table found but no cells detected`);
3199
+ // log(`${resizeLogPrefix} DOM table found but no cells detected`);
3200
3200
  }
3201
3201
  } else {
3202
- // log(`${resizeLogPrefix} DOM table found but tblId mismatch or missing row: domTblId=${domTblId}, domRow=${domRow}`);
3202
+ // log(`${resizeLogPrefix} DOM table found but tblId mismatch or missing row: domTblId=${domTblId}, domRow=${domRow}`);
3203
3203
  }
3204
3204
  } else {
3205
- // log(`${resizeLogPrefix} No table found in DOM for line ${lineNum}`);
3205
+ // log(`${resizeLogPrefix} No table found in DOM for line ${lineNum}`);
3206
3206
  }
3207
3207
  } else {
3208
- // log(`${resizeLogPrefix} Could not get line entry or lineNode for line ${lineNum}`);
3208
+ // log(`${resizeLogPrefix} Could not get line entry or lineNode for line ${lineNum}`);
3209
3209
  }
3210
3210
  } else {
3211
- // log(`${resizeLogPrefix} Could not get rep or rep.lines for DOM reconstruction`);
3211
+ // log(`${resizeLogPrefix} Could not get rep or rep.lines for DOM reconstruction`);
3212
3212
  }
3213
3213
  }
3214
3214
  } catch (e) {
3215
3215
  console.error(`${resizeLogPrefix} Error getting table metadata:`, e);
3216
3216
  }
3217
3217
  } else {
3218
- // log(`${resizeLogPrefix} Invalid line number (${lineNum}) or table ID (${tblId})`);
3218
+ // log(`${resizeLogPrefix} Invalid line number (${lineNum}) or table ID (${tblId})`);
3219
3219
  }
3220
3220
  } else {
3221
- // log(`${resizeLogPrefix} Invalid resize target:`, { table: !!table, lineNode: !!lineNode, columnIndex });
3221
+ // log(`${resizeLogPrefix} Invalid resize target:`, { table: !!table, lineNode: !!lineNode, columnIndex });
3222
3222
  }
3223
3223
  });
3224
3224
 
@@ -3237,57 +3237,57 @@ exports.aceInitialized = (h, ctx) => {
3237
3237
 
3238
3238
  // Mouseup handler with enhanced debugging
3239
3239
  const handleMouseup = (evt) => {
3240
- // log(`${mouseupLogPrefix} Mouseup detected on ${evt.target.tagName || 'unknown'}. isResizing: ${isResizing}`);
3240
+ // log(`${mouseupLogPrefix} Mouseup detected on ${evt.target.tagName || 'unknown'}. isResizing: ${isResizing}`);
3241
3241
 
3242
3242
  if (isResizing) {
3243
- // log(`${mouseupLogPrefix} Processing resize completion...`);
3243
+ // log(`${mouseupLogPrefix} Processing resize completion...`);
3244
3244
  evt.preventDefault();
3245
3245
  evt.stopPropagation();
3246
3246
 
3247
3247
  // Add a small delay to ensure all DOM updates are complete
3248
3248
  setTimeout(() => {
3249
- // log(`${mouseupLogPrefix} Executing finishColumnResize after delay...`);
3249
+ // log(`${mouseupLogPrefix} Executing finishColumnResize after delay...`);
3250
3250
  finishColumnResize(ed, docManager);
3251
- // log(`${mouseupLogPrefix} Resize completion finished.`);
3251
+ // log(`${mouseupLogPrefix} Resize completion finished.`);
3252
3252
  }, 50);
3253
3253
  } else {
3254
- // log(`${mouseupLogPrefix} Not in resize mode, ignoring mouseup.`);
3254
+ // log(`${mouseupLogPrefix} Not in resize mode, ignoring mouseup.`);
3255
3255
  }
3256
3256
  };
3257
3257
 
3258
3258
  // Attach to multiple contexts to ensure we catch the event
3259
- // log(`${callWithAceLogPrefix} Attaching global mousemove/mouseup handlers to multiple contexts...`);
3259
+ // log(`${callWithAceLogPrefix} Attaching global mousemove/mouseup handlers to multiple contexts...`);
3260
3260
 
3261
3261
  // 1. Main document (outside iframes)
3262
3262
  $(document).on('mousemove', handleMousemove);
3263
3263
  $(document).on('mouseup', handleMouseup);
3264
- // log(`${callWithAceLogPrefix} Attached to main document`);
3264
+ // log(`${callWithAceLogPrefix} Attached to main document`);
3265
3265
 
3266
3266
  // 2. Outer iframe document
3267
3267
  if (outerDoc.length > 0) {
3268
3268
  outerDoc.on('mousemove', handleMousemove);
3269
3269
  outerDoc.on('mouseup', handleMouseup);
3270
- // log(`${callWithAceLogPrefix} Attached to outer iframe document`);
3270
+ // log(`${callWithAceLogPrefix} Attached to outer iframe document`);
3271
3271
  }
3272
3272
 
3273
3273
  // 3. Inner iframe document
3274
3274
  if (innerDoc.length > 0) {
3275
3275
  innerDoc.on('mousemove', handleMousemove);
3276
3276
  innerDoc.on('mouseup', handleMouseup);
3277
- // log(`${callWithAceLogPrefix} Attached to inner iframe document`);
3277
+ // log(`${callWithAceLogPrefix} Attached to inner iframe document`);
3278
3278
  }
3279
3279
 
3280
3280
  // 4. Inner iframe body (the editing area)
3281
3281
  $inner.on('mousemove', handleMousemove);
3282
3282
  $inner.on('mouseup', handleMouseup);
3283
- // log(`${callWithAceLogPrefix} Attached to inner iframe body`);
3283
+ // log(`${callWithAceLogPrefix} Attached to inner iframe body`);
3284
3284
 
3285
3285
  // 5. Add a failsafe - listen for any mouse events during resize
3286
3286
  const failsafeMouseup = (evt) => {
3287
3287
  if (isResizing) {
3288
- // log(`${mouseupLogPrefix} FAILSAFE: Detected mouse event during resize: ${evt.type}`);
3288
+ // log(`${mouseupLogPrefix} FAILSAFE: Detected mouse event during resize: ${evt.type}`);
3289
3289
  if (evt.type === 'mouseup' || evt.type === 'mousedown' || evt.type === 'click') {
3290
- // log(`${mouseupLogPrefix} FAILSAFE: Triggering resize completion due to ${evt.type}`);
3290
+ // log(`${mouseupLogPrefix} FAILSAFE: Triggering resize completion due to ${evt.type}`);
3291
3291
  setTimeout(() => {
3292
3292
  if (isResizing) { // Double-check we're still resizing
3293
3293
  finishColumnResize(ed, docManager);
@@ -3301,7 +3301,7 @@ exports.aceInitialized = (h, ctx) => {
3301
3301
  document.addEventListener('mouseup', failsafeMouseup, true);
3302
3302
  document.addEventListener('mousedown', failsafeMouseup, true);
3303
3303
  document.addEventListener('click', failsafeMouseup, true);
3304
- // log(`${callWithAceLogPrefix} Attached failsafe event handlers`);
3304
+ // log(`${callWithAceLogPrefix} Attached failsafe event handlers`);
3305
3305
 
3306
3306
  // *** DRAG PREVENTION FOR TABLE ELEMENTS ***
3307
3307
  const preventTableDrag = (evt) => {
@@ -3309,7 +3309,7 @@ exports.aceInitialized = (h, ctx) => {
3309
3309
  // Block ANY drag gesture that originates within a table (including spans/text inside cells)
3310
3310
  const inTable = target && typeof target.closest === 'function' && target.closest('table.dataTable');
3311
3311
  if (inTable) {
3312
- // log('[ep_data_tables:dragPrevention] Preventing drag operation originating from inside table');
3312
+ // log('[ep_data_tables:dragPrevention] Preventing drag operation originating from inside table');
3313
3313
  evt.preventDefault();
3314
3314
  evt.stopPropagation();
3315
3315
  if (evt.originalEvent && evt.originalEvent.dataTransfer) {
@@ -3323,7 +3323,7 @@ exports.aceInitialized = (h, ctx) => {
3323
3323
  $inner.on('dragstart', preventTableDrag);
3324
3324
  $inner.on('drag', preventTableDrag);
3325
3325
  $inner.on('dragend', preventTableDrag);
3326
- // log(`${callWithAceLogPrefix} Attached drag prevention handlers to inner body`);
3326
+ // log(`${callWithAceLogPrefix} Attached drag prevention handlers to inner body`);
3327
3327
 
3328
3328
  // Attach drag prevention broadly to cover iframe boundaries and the host document
3329
3329
  if (innerDoc.length > 0) {
@@ -3344,15 +3344,15 @@ exports.aceInitialized = (h, ctx) => {
3344
3344
  // Setup the global handlers
3345
3345
  setupGlobalHandlers();
3346
3346
 
3347
- // log(`${callWithAceLogPrefix} Column resize listeners attached successfully.`);
3347
+ // log(`${callWithAceLogPrefix} Column resize listeners attached successfully.`);
3348
3348
 
3349
3349
  }, 'tablePasteAndResizeListeners', true);
3350
- // log(`${logPrefix} ace_callWithAce for listeners setup completed.`);
3350
+ // log(`${logPrefix} ace_callWithAce for listeners setup completed.`);
3351
3351
 
3352
3352
  // Helper function to apply the metadata attribute to a line
3353
3353
  function applyTableLineMetadataAttribute (lineNum, tblId, rowIndex, numCols, rep, editorInfo, attributeString = null, documentAttributeManager = null) {
3354
3354
  const funcName = 'applyTableLineMetadataAttribute';
3355
- // log(`${logPrefix}:${funcName}: START - Applying METADATA attribute to line ${lineNum}`, {tblId, rowIndex, numCols});
3355
+ // log(`${logPrefix}:${funcName}: START - Applying METADATA attribute to line ${lineNum}`, {tblId, rowIndex, numCols});
3356
3356
 
3357
3357
  let finalMetadata;
3358
3358
 
@@ -3363,14 +3363,14 @@ exports.aceInitialized = (h, ctx) => {
3363
3363
  if (providedMetadata.columnWidths && Array.isArray(providedMetadata.columnWidths) && providedMetadata.columnWidths.length === numCols) {
3364
3364
  // Already has valid columnWidths, use as-is
3365
3365
  finalMetadata = providedMetadata;
3366
- // log(`${logPrefix}:${funcName}: Using provided metadata with existing columnWidths`);
3366
+ // log(`${logPrefix}:${funcName}: Using provided metadata with existing columnWidths`);
3367
3367
  } else {
3368
3368
  // Has metadata but missing/invalid columnWidths, extract from DOM
3369
3369
  finalMetadata = providedMetadata;
3370
- // log(`${logPrefix}:${funcName}: Provided metadata missing columnWidths, attempting DOM extraction`);
3370
+ // log(`${logPrefix}:${funcName}: Provided metadata missing columnWidths, attempting DOM extraction`);
3371
3371
  }
3372
3372
  } catch (e) {
3373
- // log(`${logPrefix}:${funcName}: Error parsing provided attributeString, will reconstruct:`, e);
3373
+ // log(`${logPrefix}:${funcName}: Error parsing provided attributeString, will reconstruct:`, e);
3374
3374
  finalMetadata = null;
3375
3375
  }
3376
3376
  }
@@ -3401,13 +3401,13 @@ exports.aceInitialized = (h, ctx) => {
3401
3401
  columnWidths.push(100 / numCols);
3402
3402
  }
3403
3403
  });
3404
- // log(`${logPrefix}:${funcName}: Extracted column widths from DOM: ${columnWidths.map(w => w.toFixed(1) + '%').join(', ')}`);
3404
+ // log(`${logPrefix}:${funcName}: Extracted column widths from DOM: ${columnWidths.map(w => w.toFixed(1) + '%').join(', ')}`);
3405
3405
  }
3406
3406
  }
3407
3407
  }
3408
3408
  }
3409
3409
  } catch (e) {
3410
- // log(`${logPrefix}:${funcName}: Error extracting column widths from DOM:`, e);
3410
+ // log(`${logPrefix}:${funcName}: Error extracting column widths from DOM:`, e);
3411
3411
  }
3412
3412
 
3413
3413
  // Build final metadata
@@ -3424,26 +3424,26 @@ exports.aceInitialized = (h, ctx) => {
3424
3424
  }
3425
3425
 
3426
3426
  const finalAttributeString = JSON.stringify(finalMetadata);
3427
- // log(`${logPrefix}:${funcName}: Final metadata attribute string: ${finalAttributeString}`);
3427
+ // log(`${logPrefix}:${funcName}: Final metadata attribute string: ${finalAttributeString}`);
3428
3428
 
3429
3429
  try {
3430
3430
  // Get current line info
3431
3431
  const lineEntry = rep.lines.atIndex(lineNum);
3432
3432
  if (!lineEntry) {
3433
- // log(`${logPrefix}:${funcName}: ERROR - Could not find line entry for line number ${lineNum}`);
3433
+ // log(`${logPrefix}:${funcName}: ERROR - Could not find line entry for line number ${lineNum}`);
3434
3434
  return;
3435
3435
  }
3436
3436
  const lineLength = Math.max(1, lineEntry.text.length);
3437
- // log(`${logPrefix}:${funcName}: Line ${lineNum} text length: ${lineLength}`);
3437
+ // log(`${logPrefix}:${funcName}: Line ${lineNum} text length: ${lineLength}`);
3438
3438
 
3439
3439
  // Simple attribute application - just add the tbljson attribute
3440
3440
  const attributes = [[ATTR_TABLE_JSON, finalAttributeString]];
3441
3441
  const start = [lineNum, 0];
3442
3442
  const end = [lineNum, lineLength];
3443
3443
 
3444
- // log(`${logPrefix}:${funcName}: Applying tbljson attribute to range [${start}]-[${end}]`);
3444
+ // log(`${logPrefix}:${funcName}: Applying tbljson attribute to range [${start}]-[${end}]`);
3445
3445
  editorInfo.ace_performDocumentApplyAttributesToRange(start, end, attributes);
3446
- // log(`${logPrefix}:${funcName}: Successfully applied tbljson attribute to line ${lineNum}`);
3446
+ // log(`${logPrefix}:${funcName}: Successfully applied tbljson attribute to line ${lineNum}`);
3447
3447
 
3448
3448
  } catch(e) {
3449
3449
  console.error(`[ep_data_tables] ${logPrefix}:${funcName}: Error applying metadata attribute on line ${lineNum}:`, e);
@@ -3453,59 +3453,59 @@ exports.aceInitialized = (h, ctx) => {
3453
3453
  /** Insert a fresh rows×cols blank table at the caret */
3454
3454
  ed.ace_createTableViaAttributes = (rows = 2, cols = 2) => {
3455
3455
  const funcName = 'ace_createTableViaAttributes';
3456
- // log(`${funcName}: START - Refactored Phase 4 (Get Selection Fix)`, { rows, cols });
3456
+ // log(`${funcName}: START - Refactored Phase 4 (Get Selection Fix)`, { rows, cols });
3457
3457
  rows = Math.max(1, rows); cols = Math.max(1, cols);
3458
- // log(`${funcName}: Ensuring minimum 1 row, 1 col.`);
3458
+ // log(`${funcName}: Ensuring minimum 1 row, 1 col.`);
3459
3459
 
3460
3460
  // --- Phase 1: Prepare Data ---
3461
3461
  const tblId = rand();
3462
- // log(`${funcName}: Generated table ID: ${tblId}`);
3462
+ // log(`${funcName}: Generated table ID: ${tblId}`);
3463
3463
  const initialCellContent = ' '; // Start with a single space per cell
3464
3464
  const lineTxt = Array.from({ length: cols }).fill(initialCellContent).join(DELIMITER);
3465
- // log(`${funcName}: Constructed initial line text for ${cols} cols: "${lineTxt}"`);
3465
+ // log(`${funcName}: Constructed initial line text for ${cols} cols: "${lineTxt}"`);
3466
3466
  const block = Array.from({ length: rows }).fill(lineTxt).join('\n') + '\n';
3467
- // log(`${funcName}: Constructed block for ${rows} rows:\n${block}`);
3467
+ // log(`${funcName}: Constructed block for ${rows} rows:\n${block}`);
3468
3468
 
3469
3469
  // Get current selection BEFORE making changes using ace_getRep()
3470
- // log(`${funcName}: Getting current representation and selection...`);
3470
+ // log(`${funcName}: Getting current representation and selection...`);
3471
3471
  const currentRepInitial = ed.ace_getRep();
3472
3472
  if (!currentRepInitial || !currentRepInitial.selStart || !currentRepInitial.selEnd) {
3473
3473
  console.error(`[ep_data_tables] ${funcName}: Could not get current representation or selection via ace_getRep(). Aborting.`);
3474
- // log(`${funcName}: END - Error getting initial rep/selection`);
3474
+ // log(`${funcName}: END - Error getting initial rep/selection`);
3475
3475
  return;
3476
3476
  }
3477
3477
  const start = currentRepInitial.selStart;
3478
3478
  const end = currentRepInitial.selEnd;
3479
3479
  const initialStartLine = start[0]; // Store the starting line number
3480
- // log(`${funcName}: Current selection from initial rep:`, { start, end });
3480
+ // log(`${funcName}: Current selection from initial rep:`, { start, end });
3481
3481
 
3482
3482
  // --- Phase 2: Insert Text Block ---
3483
- // log(`${funcName}: Phase 2 - Inserting text block...`);
3483
+ // log(`${funcName}: Phase 2 - Inserting text block...`);
3484
3484
  ed.ace_performDocumentReplaceRange(start, end, block);
3485
- // log(`${funcName}: Inserted block of delimited text lines.`);
3486
- // log(`${funcName}: Requesting text sync (ace_fastIncorp 20)...`);
3485
+ // log(`${funcName}: Inserted block of delimited text lines.`);
3486
+ // log(`${funcName}: Requesting text sync (ace_fastIncorp 20)...`);
3487
3487
  ed.ace_fastIncorp(20); // Sync text insertion
3488
- // log(`${funcName}: Text sync requested.`);
3488
+ // log(`${funcName}: Text sync requested.`);
3489
3489
 
3490
3490
  // --- Phase 3: Apply Metadata Attributes ---
3491
- // log(`${funcName}: Phase 3 - Applying metadata attributes to ${rows} inserted lines...`);
3491
+ // log(`${funcName}: Phase 3 - Applying metadata attributes to ${rows} inserted lines...`);
3492
3492
  // Need rep to be updated after text insertion to apply attributes correctly
3493
3493
  const currentRep = ed.ace_getRep(); // Get potentially updated rep
3494
3494
  if (!currentRep || !currentRep.lines) {
3495
3495
  console.error(`[ep_data_tables] ${funcName}: Could not get updated rep after text insertion. Cannot apply attributes reliably.`);
3496
- // log(`${funcName}: END - Error getting updated rep`);
3496
+ // log(`${funcName}: END - Error getting updated rep`);
3497
3497
  // Maybe attempt to continue without rep? Risky.
3498
3498
  return;
3499
3499
  }
3500
- // log(`${funcName}: Fetched updated rep for attribute application.`);
3500
+ // log(`${funcName}: Fetched updated rep for attribute application.`);
3501
3501
 
3502
3502
  for (let r = 0; r < rows; r++) {
3503
3503
  const lineNumToApply = initialStartLine + r;
3504
- // log(`${funcName}: -> Processing row ${r} on line ${lineNumToApply}`);
3504
+ // log(`${funcName}: -> Processing row ${r} on line ${lineNumToApply}`);
3505
3505
 
3506
3506
  const lineEntry = currentRep.lines.atIndex(lineNumToApply);
3507
3507
  if (!lineEntry) {
3508
- // log(`${funcName}: Could not find line entry for ${lineNumToApply}, skipping attribute application.`);
3508
+ // log(`${funcName}: Could not find line entry for ${lineNumToApply}, skipping attribute application.`);
3509
3509
  continue;
3510
3510
  }
3511
3511
  const lineText = lineEntry.text || '';
@@ -3518,7 +3518,7 @@ exports.aceInitialized = (h, ctx) => {
3518
3518
  if (cellContent.length > 0) { // Only apply to non-empty cells
3519
3519
  const cellStart = [lineNumToApply, offset];
3520
3520
  const cellEnd = [lineNumToApply, offset + cellContent.length];
3521
- // log(`${funcName}: Applying ${ATTR_CELL} attribute to Line ${lineNumToApply} Col ${c} Range ${offset}-${offset + cellContent.length}`);
3521
+ // log(`${funcName}: Applying ${ATTR_CELL} attribute to Line ${lineNumToApply} Col ${c} Range ${offset}-${offset + cellContent.length}`);
3522
3522
  ed.ace_performDocumentApplyAttributesToRange(cellStart, cellEnd, [[ATTR_CELL, String(c)]]);
3523
3523
  }
3524
3524
  offset += cellContent.length;
@@ -3531,30 +3531,30 @@ exports.aceInitialized = (h, ctx) => {
3531
3531
  // Note: documentAttributeManager not available in this context for new table creation
3532
3532
  applyTableLineMetadataAttribute(lineNumToApply, tblId, r, cols, currentRep, ed, null, null);
3533
3533
  }
3534
- // log(`${funcName}: Finished applying metadata attributes.`);
3535
- // log(`${funcName}: Requesting attribute sync (ace_fastIncorp 20)...`);
3534
+ // log(`${funcName}: Finished applying metadata attributes.`);
3535
+ // log(`${funcName}: Requesting attribute sync (ace_fastIncorp 20)...`);
3536
3536
  ed.ace_fastIncorp(20); // Final sync after attributes
3537
- // log(`${funcName}: Attribute sync requested.`);
3537
+ // log(`${funcName}: Attribute sync requested.`);
3538
3538
 
3539
3539
  // --- Phase 4: Set Caret Position ---
3540
- // log(`${funcName}: Phase 4 - Setting final caret position...`);
3540
+ // log(`${funcName}: Phase 4 - Setting final caret position...`);
3541
3541
  const finalCaretLine = initialStartLine + rows; // Line number after the last inserted row
3542
3542
  const finalCaretPos = [finalCaretLine, 0];
3543
- // log(`${funcName}: Target caret position:`, finalCaretPos);
3543
+ // log(`${funcName}: Target caret position:`, finalCaretPos);
3544
3544
  try {
3545
3545
  ed.ace_performSelectionChange(finalCaretPos, finalCaretPos, false);
3546
- // log(`${funcName}: Successfully set caret position.`);
3546
+ // log(`${funcName}: Successfully set caret position.`);
3547
3547
  } catch(e) {
3548
3548
  console.error(`[ep_data_tables] ${funcName}: Error setting caret position after table creation:`, e);
3549
- // log(`[ep_data_tables] ${funcName}: Error details:`, { message: e.message, stack: e.stack });
3549
+ // log(`[ep_data_tables] ${funcName}: Error details:`, { message: e.message, stack: e.stack });
3550
3550
  }
3551
3551
 
3552
- // log(`${funcName}: END - Refactored Phase 4`);
3552
+ // log(`${funcName}: END - Refactored Phase 4`);
3553
3553
  };
3554
3554
 
3555
3555
  ed.ace_doDatatableOptions = (action) => {
3556
3556
  const funcName = 'ace_doDatatableOptions';
3557
- // log(`${funcName}: START - Processing action: ${action}`);
3557
+ // log(`${funcName}: START - Processing action: ${action}`);
3558
3558
 
3559
3559
  // Get the last clicked cell info to determine which table to operate on
3560
3560
  const editor = ed.ep_data_tables_editor;
@@ -3565,12 +3565,12 @@ exports.aceInitialized = (h, ctx) => {
3565
3565
 
3566
3566
  const lastClick = editor.ep_data_tables_last_clicked;
3567
3567
  if (!lastClick || !lastClick.tblId) {
3568
- // log(`${funcName}: No table selected. Please click on a table cell first.`);
3568
+ // log(`${funcName}: No table selected. Please click on a table cell first.`);
3569
3569
  console.warn('[ep_data_tables] No table selected. Please click on a table cell first.');
3570
3570
  return;
3571
3571
  }
3572
3572
 
3573
- // log(`${funcName}: Operating on table ${lastClick.tblId}, clicked line ${lastClick.lineNum}, cell ${lastClick.cellIndex}`);
3573
+ // log(`${funcName}: Operating on table ${lastClick.tblId}, clicked line ${lastClick.lineNum}, cell ${lastClick.cellIndex}`);
3574
3574
 
3575
3575
  try {
3576
3576
  // Get current representation and document manager
@@ -3587,7 +3587,7 @@ exports.aceInitialized = (h, ctx) => {
3587
3587
  return;
3588
3588
  }
3589
3589
 
3590
- // log(`${funcName}: Successfully obtained documentAttributeManager from stored reference.`);
3590
+ // log(`${funcName}: Successfully obtained documentAttributeManager from stored reference.`);
3591
3591
 
3592
3592
  // Find all lines that belong to this table
3593
3593
  const tableLines = [];
@@ -3616,7 +3616,7 @@ exports.aceInitialized = (h, ctx) => {
3616
3616
  cols: domCells.length
3617
3617
  };
3618
3618
  lineAttrString = JSON.stringify(reconstructedMetadata);
3619
- // log(`${funcName}: Reconstructed metadata from DOM for line ${lineIndex}: ${lineAttrString}`);
3619
+ // log(`${funcName}: Reconstructed metadata from DOM for line ${lineIndex}: ${lineAttrString}`);
3620
3620
  }
3621
3621
  }
3622
3622
  }
@@ -3644,13 +3644,13 @@ exports.aceInitialized = (h, ctx) => {
3644
3644
  }
3645
3645
 
3646
3646
  if (tableLines.length === 0) {
3647
- // log(`${funcName}: No table lines found for table ${lastClick.tblId}`);
3647
+ // log(`${funcName}: No table lines found for table ${lastClick.tblId}`);
3648
3648
  return;
3649
3649
  }
3650
3650
 
3651
3651
  // Sort by row number to ensure correct order
3652
3652
  tableLines.sort((a, b) => a.row - b.row);
3653
- // log(`${funcName}: Found ${tableLines.length} table lines`);
3653
+ // log(`${funcName}: Found ${tableLines.length} table lines`);
3654
3654
 
3655
3655
  // Determine table dimensions and target indices with robust matching
3656
3656
  const numRows = tableLines.length;
@@ -3664,7 +3664,7 @@ exports.aceInitialized = (h, ctx) => {
3664
3664
 
3665
3665
  // If that fails, try to match by finding the row that contains the clicked table
3666
3666
  if (targetRowIndex === -1) {
3667
- // log(`${funcName}: Direct line number match failed, searching by DOM structure...`);
3667
+ // log(`${funcName}: Direct line number match failed, searching by DOM structure...`);
3668
3668
  const clickedLineEntry = currentRep.lines.atIndex(lastClick.lineNum);
3669
3669
  if (clickedLineEntry && clickedLineEntry.lineNode) {
3670
3670
  const clickedTable = clickedLineEntry.lineNode.querySelector('table.dataTable[data-tblId="' + lastClick.tblId + '"]');
@@ -3673,7 +3673,7 @@ exports.aceInitialized = (h, ctx) => {
3673
3673
  if (clickedRowAttr !== null) {
3674
3674
  const clickedRowNum = parseInt(clickedRowAttr, 10);
3675
3675
  targetRowIndex = tableLines.findIndex(line => line.row === clickedRowNum);
3676
- // log(`${funcName}: Found target row by DOM attribute matching: row ${clickedRowNum}, index ${targetRowIndex}`);
3676
+ // log(`${funcName}: Found target row by DOM attribute matching: row ${clickedRowNum}, index ${targetRowIndex}`);
3677
3677
  }
3678
3678
  }
3679
3679
  }
@@ -3681,13 +3681,13 @@ exports.aceInitialized = (h, ctx) => {
3681
3681
 
3682
3682
  // If still not found, default to first row but log the issue
3683
3683
  if (targetRowIndex === -1) {
3684
- // log(`${funcName}: Warning: Could not find target row, defaulting to row 0`);
3684
+ // log(`${funcName}: Warning: Could not find target row, defaulting to row 0`);
3685
3685
  targetRowIndex = 0;
3686
3686
  }
3687
3687
 
3688
3688
  const targetColIndex = lastClick.cellIndex || 0;
3689
3689
 
3690
- // log(`${funcName}: Table dimensions: ${numRows} rows x ${numCols} cols. Target: row ${targetRowIndex}, col ${targetColIndex}`);
3690
+ // log(`${funcName}: Table dimensions: ${numRows} rows x ${numCols} cols. Target: row ${targetRowIndex}, col ${targetColIndex}`);
3691
3691
 
3692
3692
  // Perform table operations with both text and metadata updates
3693
3693
  let newNumCols = numCols;
@@ -3695,23 +3695,23 @@ exports.aceInitialized = (h, ctx) => {
3695
3695
 
3696
3696
  switch (action) {
3697
3697
  case 'addTblRowA': // Insert row above
3698
- // log(`${funcName}: Inserting row above row ${targetRowIndex}`);
3698
+ // log(`${funcName}: Inserting row above row ${targetRowIndex}`);
3699
3699
  success = addTableRowAboveWithText(tableLines, targetRowIndex, numCols, lastClick.tblId, ed, docManager);
3700
3700
  break;
3701
3701
 
3702
3702
  case 'addTblRowB': // Insert row below
3703
- // log(`${funcName}: Inserting row below row ${targetRowIndex}`);
3703
+ // log(`${funcName}: Inserting row below row ${targetRowIndex}`);
3704
3704
  success = addTableRowBelowWithText(tableLines, targetRowIndex, numCols, lastClick.tblId, ed, docManager);
3705
3705
  break;
3706
3706
 
3707
3707
  case 'addTblColL': // Insert column left
3708
- // log(`${funcName}: Inserting column left of column ${targetColIndex}`);
3708
+ // log(`${funcName}: Inserting column left of column ${targetColIndex}`);
3709
3709
  newNumCols = numCols + 1;
3710
3710
  success = addTableColumnLeftWithText(tableLines, targetColIndex, ed, docManager);
3711
3711
  break;
3712
3712
 
3713
3713
  case 'addTblColR': // Insert column right
3714
- // log(`${funcName}: Inserting column right of column ${targetColIndex}`);
3714
+ // log(`${funcName}: Inserting column right of column ${targetColIndex}`);
3715
3715
  newNumCols = numCols + 1;
3716
3716
  success = addTableColumnRightWithText(tableLines, targetColIndex, ed, docManager);
3717
3717
  break;
@@ -3720,10 +3720,10 @@ exports.aceInitialized = (h, ctx) => {
3720
3720
  // Show confirmation prompt for row deletion
3721
3721
  const rowConfirmMessage = `Are you sure you want to delete Row ${targetRowIndex + 1} and all content within?`;
3722
3722
  if (!confirm(rowConfirmMessage)) {
3723
- // log(`${funcName}: Row deletion cancelled by user`);
3723
+ // log(`${funcName}: Row deletion cancelled by user`);
3724
3724
  return;
3725
3725
  }
3726
- // log(`${funcName}: Deleting row ${targetRowIndex}`);
3726
+ // log(`${funcName}: Deleting row ${targetRowIndex}`);
3727
3727
  success = deleteTableRowWithText(tableLines, targetRowIndex, ed, docManager);
3728
3728
  break;
3729
3729
 
@@ -3731,16 +3731,16 @@ exports.aceInitialized = (h, ctx) => {
3731
3731
  // Show confirmation prompt for column deletion
3732
3732
  const colConfirmMessage = `Are you sure you want to delete Column ${targetColIndex + 1} and all content within?`;
3733
3733
  if (!confirm(colConfirmMessage)) {
3734
- // log(`${funcName}: Column deletion cancelled by user`);
3734
+ // log(`${funcName}: Column deletion cancelled by user`);
3735
3735
  return;
3736
3736
  }
3737
- // log(`${funcName}: Deleting column ${targetColIndex}`);
3737
+ // log(`${funcName}: Deleting column ${targetColIndex}`);
3738
3738
  newNumCols = numCols - 1;
3739
3739
  success = deleteTableColumnWithText(tableLines, targetColIndex, ed, docManager);
3740
3740
  break;
3741
3741
 
3742
3742
  default:
3743
- // log(`${funcName}: Unknown action: ${action}`);
3743
+ // log(`${funcName}: Unknown action: ${action}`);
3744
3744
  return;
3745
3745
  }
3746
3746
 
@@ -3749,11 +3749,11 @@ exports.aceInitialized = (h, ctx) => {
3749
3749
  return;
3750
3750
  }
3751
3751
 
3752
- // log(`${funcName}: Table operation completed successfully with text and metadata synchronization`);
3752
+ // log(`${funcName}: Table operation completed successfully with text and metadata synchronization`);
3753
3753
 
3754
3754
  } catch (error) {
3755
3755
  console.error(`[ep_data_tables] ${funcName}: Error during table operation:`, error);
3756
- // log(`${funcName}: Error details:`, { message: error.message, stack: error.stack });
3756
+ // log(`${funcName}: Error details:`, { message: error.message, stack: error.stack });
3757
3757
  }
3758
3758
  };
3759
3759
 
@@ -3806,7 +3806,7 @@ exports.aceInitialized = (h, ctx) => {
3806
3806
  columnWidths.push(100 / numCols);
3807
3807
  }
3808
3808
  });
3809
- // log('[ep_data_tables] addTableRowAbove: Extracted column widths from DOM:', columnWidths);
3809
+ // log('[ep_data_tables] addTableRowAbove: Extracted column widths from DOM:', columnWidths);
3810
3810
  }
3811
3811
  }
3812
3812
  }
@@ -3884,7 +3884,7 @@ exports.aceInitialized = (h, ctx) => {
3884
3884
  columnWidths.push(100 / numCols);
3885
3885
  }
3886
3886
  });
3887
- // log('[ep_data_tables] addTableRowBelow: Extracted column widths from DOM:', columnWidths);
3887
+ // log('[ep_data_tables] addTableRowBelow: Extracted column widths from DOM:', columnWidths);
3888
3888
  }
3889
3889
  }
3890
3890
  }
@@ -3949,7 +3949,7 @@ exports.aceInitialized = (h, ctx) => {
3949
3949
  if (cellContent.length > 0) { // Only apply to non-empty cells
3950
3950
  const cellStart = [tableLine.lineIndex, offset];
3951
3951
  const cellEnd = [tableLine.lineIndex, offset + cellContent.length];
3952
- // log(`[ep_data_tables] ${funcName}: Applying ${ATTR_CELL} attribute to Line ${tableLine.lineIndex} Col ${c} Range ${offset}-${offset + cellContent.length}`);
3952
+ // log(`[ep_data_tables] ${funcName}: Applying ${ATTR_CELL} attribute to Line ${tableLine.lineIndex} Col ${c} Range ${offset}-${offset + cellContent.length}`);
3953
3953
  editorInfo.ace_performDocumentApplyAttributesToRange(cellStart, cellEnd, [[ATTR_CELL, String(c)]]);
3954
3954
  }
3955
3955
  offset += cellContent.length;
@@ -3964,7 +3964,7 @@ exports.aceInitialized = (h, ctx) => {
3964
3964
  const newColCount = tableLine.cols + 1;
3965
3965
  const equalWidth = 100 / newColCount;
3966
3966
  const normalizedWidths = Array(newColCount).fill(equalWidth);
3967
- // log(`[ep_data_tables] addTableColumnLeft: Reset all column widths to equal distribution: ${newColCount} columns at ${equalWidth.toFixed(1)}% each`);
3967
+ // log(`[ep_data_tables] addTableColumnLeft: Reset all column widths to equal distribution: ${newColCount} columns at ${equalWidth.toFixed(1)}% each`);
3968
3968
 
3969
3969
  // Apply updated metadata
3970
3970
  const newMetadata = { ...tableLine.metadata, cols: tableLine.cols + 1, columnWidths: normalizedWidths };
@@ -4016,7 +4016,7 @@ exports.aceInitialized = (h, ctx) => {
4016
4016
  if (cellContent.length > 0) { // Only apply to non-empty cells
4017
4017
  const cellStart = [tableLine.lineIndex, offset];
4018
4018
  const cellEnd = [tableLine.lineIndex, offset + cellContent.length];
4019
- // log(`[ep_data_tables] ${funcName}: Applying ${ATTR_CELL} attribute to Line ${tableLine.lineIndex} Col ${c} Range ${offset}-${offset + cellContent.length}`);
4019
+ // log(`[ep_data_tables] ${funcName}: Applying ${ATTR_CELL} attribute to Line ${tableLine.lineIndex} Col ${c} Range ${offset}-${offset + cellContent.length}`);
4020
4020
  editorInfo.ace_performDocumentApplyAttributesToRange(cellStart, cellEnd, [[ATTR_CELL, String(c)]]);
4021
4021
  }
4022
4022
  offset += cellContent.length;
@@ -4031,7 +4031,7 @@ exports.aceInitialized = (h, ctx) => {
4031
4031
  const newColCount = tableLine.cols + 1;
4032
4032
  const equalWidth = 100 / newColCount;
4033
4033
  const normalizedWidths = Array(newColCount).fill(equalWidth);
4034
- // log(`[ep_data_tables] addTableColumnRight: Reset all column widths to equal distribution: ${newColCount} columns at ${equalWidth.toFixed(1)}% each`);
4034
+ // log(`[ep_data_tables] addTableColumnRight: Reset all column widths to equal distribution: ${newColCount} columns at ${equalWidth.toFixed(1)}% each`);
4035
4035
 
4036
4036
  // Apply updated metadata
4037
4037
  const newMetadata = { ...tableLine.metadata, cols: tableLine.cols + 1, columnWidths: normalizedWidths };
@@ -4054,7 +4054,7 @@ exports.aceInitialized = (h, ctx) => {
4054
4054
  // Special handling for deleting the first row (row index 0)
4055
4055
  // Insert a blank line to prevent the table from getting stuck at line 1
4056
4056
  if (targetRowIndex === 0) {
4057
- // log('[ep_data_tables] Deleting first row (row 0) - inserting blank line to prevent table from getting stuck');
4057
+ // log('[ep_data_tables] Deleting first row (row 0) - inserting blank line to prevent table from getting stuck');
4058
4058
  const insertStart = [targetLine.lineIndex, 0];
4059
4059
  editorInfo.ace_performDocumentReplaceRange(insertStart, insertStart, '\n');
4060
4060
 
@@ -4094,7 +4094,7 @@ exports.aceInitialized = (h, ctx) => {
4094
4094
  columnWidths.push(100 / targetLine.metadata.cols);
4095
4095
  }
4096
4096
  });
4097
- // log('[ep_data_tables] deleteTableRow: Extracted column widths from DOM:', columnWidths);
4097
+ // log('[ep_data_tables] deleteTableRow: Extracted column widths from DOM:', columnWidths);
4098
4098
  break;
4099
4099
  }
4100
4100
  }
@@ -4131,7 +4131,7 @@ exports.aceInitialized = (h, ctx) => {
4131
4131
  const cells = lineText.split(DELIMITER);
4132
4132
 
4133
4133
  if (targetColIndex >= cells.length) {
4134
- // log(`[ep_data_tables] Warning: Target column ${targetColIndex} doesn't exist in line with ${cells.length} columns`);
4134
+ // log(`[ep_data_tables] Warning: Target column ${targetColIndex} doesn't exist in line with ${cells.length} columns`);
4135
4135
  continue;
4136
4136
  }
4137
4137
 
@@ -4156,7 +4156,7 @@ exports.aceInitialized = (h, ctx) => {
4156
4156
  deleteStart -= DELIMITER.length;
4157
4157
  }
4158
4158
 
4159
- // log(`[ep_data_tables] Deleting column ${targetColIndex} from line ${tableLine.lineIndex}: chars ${deleteStart}-${deleteEnd} from "${lineText}"`);
4159
+ // log(`[ep_data_tables] Deleting column ${targetColIndex} from line ${tableLine.lineIndex}: chars ${deleteStart}-${deleteEnd} from "${lineText}"`);
4160
4160
 
4161
4161
  // Perform the precise deletion
4162
4162
  const rangeStart = [tableLine.lineIndex, deleteStart];
@@ -4170,7 +4170,7 @@ exports.aceInitialized = (h, ctx) => {
4170
4170
  if (newColCount > 0) {
4171
4171
  const equalWidth = 100 / newColCount;
4172
4172
  const normalizedWidths = Array(newColCount).fill(equalWidth);
4173
- // log(`[ep_data_tables] deleteTableColumn: Reset all column widths to equal distribution: ${newColCount} columns at ${equalWidth.toFixed(1)}% each`);
4173
+ // log(`[ep_data_tables] deleteTableColumn: Reset all column widths to equal distribution: ${newColCount} columns at ${equalWidth.toFixed(1)}% each`);
4174
4174
 
4175
4175
  // Update metadata
4176
4176
  const newMetadata = { ...tableLine.metadata, cols: newColCount, columnWidths: normalizedWidths };
@@ -4188,7 +4188,7 @@ exports.aceInitialized = (h, ctx) => {
4188
4188
 
4189
4189
  // ... existing code ...
4190
4190
 
4191
- // log('aceInitialized: END - helpers defined.');
4191
+ // log('aceInitialized: END - helpers defined.');
4192
4192
  };
4193
4193
 
4194
4194
  // ───────────────────── required no‑op stubs ─────────────────────
@@ -4198,11 +4198,11 @@ exports.aceEndLineAndCharForPoint = () => { return undefined; };
4198
4198
  // NEW: Style protection for table cells
4199
4199
  exports.aceSetAuthorStyle = (hook, ctx) => {
4200
4200
  const logPrefix = '[ep_data_tables:aceSetAuthorStyle]';
4201
- // log(`${logPrefix} START`, { hook, ctx });
4201
+ // log(`${logPrefix} START`, { hook, ctx });
4202
4202
 
4203
4203
  // If no selection or no style to apply, allow default
4204
4204
  if (!ctx || !ctx.rep || !ctx.rep.selStart || !ctx.rep.selEnd || !ctx.key) {
4205
- // log(`${logPrefix} No selection or style key. Allowing default.`);
4205
+ // log(`${logPrefix} No selection or style key. Allowing default.`);
4206
4206
  return;
4207
4207
  }
4208
4208
 
@@ -4212,14 +4212,14 @@ exports.aceSetAuthorStyle = (hook, ctx) => {
4212
4212
 
4213
4213
  // If selection spans multiple lines, prevent style application
4214
4214
  if (startLine !== endLine) {
4215
- // log(`${logPrefix} Selection spans multiple lines. Preventing style application to protect table structure.`);
4215
+ // log(`${logPrefix} Selection spans multiple lines. Preventing style application to protect table structure.`);
4216
4216
  return false;
4217
4217
  }
4218
4218
 
4219
4219
  // Check if the line is a table line
4220
4220
  const lineAttrString = ctx.documentAttributeManager?.getAttributeOnLine(startLine, ATTR_TABLE_JSON);
4221
4221
  if (!lineAttrString) {
4222
- // log(`${logPrefix} Line ${startLine} is not a table line. Allowing default style application.`);
4222
+ // log(`${logPrefix} Line ${startLine} is not a table line. Allowing default style application.`);
4223
4223
  return;
4224
4224
  }
4225
4225
 
@@ -4230,7 +4230,7 @@ exports.aceSetAuthorStyle = (hook, ctx) => {
4230
4230
  ];
4231
4231
 
4232
4232
  if (BLOCKED_STYLES.includes(ctx.key)) {
4233
- // log(`${logPrefix} Blocked potentially harmful style '${ctx.key}' from being applied to table cell.`);
4233
+ // log(`${logPrefix} Blocked potentially harmful style '${ctx.key}' from being applied to table cell.`);
4234
4234
  return false;
4235
4235
  }
4236
4236
 
@@ -4238,7 +4238,7 @@ exports.aceSetAuthorStyle = (hook, ctx) => {
4238
4238
  try {
4239
4239
  const tableMetadata = JSON.parse(lineAttrString);
4240
4240
  if (!tableMetadata || typeof tableMetadata.cols !== 'number') {
4241
- // log(`${logPrefix} Invalid table metadata. Preventing style application.`);
4241
+ // log(`${logPrefix} Invalid table metadata. Preventing style application.`);
4242
4242
  return false;
4243
4243
  }
4244
4244
 
@@ -4264,7 +4264,7 @@ exports.aceSetAuthorStyle = (hook, ctx) => {
4264
4264
 
4265
4265
  // If selection spans multiple cells, prevent style application
4266
4266
  if (selectionStartCell !== selectionEndCell) {
4267
- // log(`${logPrefix} Selection spans multiple cells. Preventing style application to protect table structure.`);
4267
+ // log(`${logPrefix} Selection spans multiple cells. Preventing style application to protect table structure.`);
4268
4268
  return false;
4269
4269
  }
4270
4270
 
@@ -4273,15 +4273,15 @@ exports.aceSetAuthorStyle = (hook, ctx) => {
4273
4273
  const cellEndCol = cellStartCol + cells[selectionStartCell].length;
4274
4274
 
4275
4275
  if (ctx.rep.selStart[1] <= cellStartCol || ctx.rep.selEnd[1] >= cellEndCol) {
4276
- // log(`${logPrefix} Selection includes cell delimiters. Preventing style application to protect table structure.`);
4276
+ // log(`${logPrefix} Selection includes cell delimiters. Preventing style application to protect table structure.`);
4277
4277
  return false;
4278
4278
  }
4279
4279
 
4280
- // log(`${logPrefix} Style '${ctx.key}' allowed within cell boundaries.`);
4280
+ // log(`${logPrefix} Style '${ctx.key}' allowed within cell boundaries.`);
4281
4281
  return; // Allow the style to be applied
4282
4282
  } catch (e) {
4283
4283
  console.error(`${logPrefix} Error processing style application:`, e);
4284
- // log(`${logPrefix} Error details:`, { message: e.message, stack: e.stack });
4284
+ // log(`${logPrefix} Error details:`, { message: e.message, stack: e.stack });
4285
4285
  return false; // Prevent style application on error
4286
4286
  }
4287
4287
  };
@@ -4298,7 +4298,7 @@ exports.aceRegisterBlockElements = () => ['table'];
4298
4298
  // NEW: Column resize helper functions (adapted from images plugin)
4299
4299
  const startColumnResize = (table, columnIndex, startX, metadata, lineNum) => {
4300
4300
  const funcName = 'startColumnResize';
4301
- // log(`${funcName}: Starting resize for column ${columnIndex}`);
4301
+ // log(`${funcName}: Starting resize for column ${columnIndex}`);
4302
4302
 
4303
4303
  isResizing = true;
4304
4304
  resizeStartX = startX;
@@ -4312,7 +4312,7 @@ const startColumnResize = (table, columnIndex, startX, metadata, lineNum) => {
4312
4312
  const numCols = metadata.cols;
4313
4313
  resizeOriginalWidths = metadata.columnWidths ? [...metadata.columnWidths] : Array(numCols).fill(100 / numCols);
4314
4314
 
4315
- // log(`${funcName}: Original widths:`, resizeOriginalWidths);
4315
+ // log(`${funcName}: Original widths:`, resizeOriginalWidths);
4316
4316
 
4317
4317
  // Create visual overlay instead of modifying table directly
4318
4318
  createResizeOverlay(table, columnIndex);
@@ -4378,7 +4378,7 @@ const createResizeOverlay = (table, columnIndex) => {
4378
4378
 
4379
4379
  const totalTableHeight = maxBottom - minTop;
4380
4380
 
4381
- // log(`createResizeOverlay: Found ${allTableRows.length} table rows, total height: ${totalTableHeight}px`);
4381
+ // log(`createResizeOverlay: Found ${allTableRows.length} table rows, total height: ${totalTableHeight}px`);
4382
4382
 
4383
4383
  // Calculate positioning using the same method as image plugin
4384
4384
  let innerBodyRect, innerIframeRect, outerBodyRect;
@@ -4465,7 +4465,7 @@ const createResizeOverlay = (table, columnIndex) => {
4465
4465
  // Append to outer body like image plugin does with its outline
4466
4466
  padOuter.append(resizeOverlay);
4467
4467
 
4468
- // log('createResizeOverlay: Created Google Docs style blue line overlay spanning entire table height');
4468
+ // log('createResizeOverlay: Created Google Docs style blue line overlay spanning entire table height');
4469
4469
  };
4470
4470
 
4471
4471
  const updateColumnResize = (currentX) => {
@@ -4525,19 +4525,19 @@ const updateColumnResize = (currentX) => {
4525
4525
 
4526
4526
  const finishColumnResize = (editorInfo, docManager) => {
4527
4527
  if (!isResizing || !resizeTargetTable) {
4528
- // log('finishColumnResize: Not in resize mode');
4528
+ // log('finishColumnResize: Not in resize mode');
4529
4529
  return;
4530
4530
  }
4531
4531
 
4532
4532
  const funcName = 'finishColumnResize';
4533
- // log(`${funcName}: Finishing resize`);
4533
+ // log(`${funcName}: Finishing resize`);
4534
4534
 
4535
4535
  // Calculate final widths from actual mouse movement
4536
4536
  const tableRect = resizeTargetTable.getBoundingClientRect();
4537
4537
  const deltaX = resizeCurrentX - resizeStartX;
4538
4538
  const deltaPercent = (deltaX / tableRect.width) * 100;
4539
4539
 
4540
- // log(`${funcName}: Mouse moved ${deltaX}px (${deltaPercent.toFixed(1)}%)`);
4540
+ // log(`${funcName}: Mouse moved ${deltaX}px (${deltaPercent.toFixed(1)}%)`);
4541
4541
 
4542
4542
  const finalWidths = [...resizeOriginalWidths];
4543
4543
  const currentColumn = resizeTargetColumn;
@@ -4551,7 +4551,7 @@ const finishColumnResize = (editorInfo, docManager) => {
4551
4551
  finalWidths[currentColumn] += actualTransfer;
4552
4552
  finalWidths[nextColumn] -= actualTransfer;
4553
4553
 
4554
- // log(`${funcName}: Transferred ${actualTransfer.toFixed(1)}% from column ${nextColumn} to column ${currentColumn}`);
4554
+ // log(`${funcName}: Transferred ${actualTransfer.toFixed(1)}% from column ${nextColumn} to column ${currentColumn}`);
4555
4555
  }
4556
4556
 
4557
4557
  // Normalize widths
@@ -4562,7 +4562,7 @@ const finishColumnResize = (editorInfo, docManager) => {
4562
4562
  });
4563
4563
  }
4564
4564
 
4565
- // log(`${funcName}: Final normalized widths:`, finalWidths.map(w => w.toFixed(1) + '%'));
4565
+ // log(`${funcName}: Final normalized widths:`, finalWidths.map(w => w.toFixed(1) + '%'));
4566
4566
 
4567
4567
  // Clean up overlay
4568
4568
  if (resizeOverlay) {
@@ -4582,7 +4582,7 @@ const finishColumnResize = (editorInfo, docManager) => {
4582
4582
  // Apply updated metadata to ALL rows in the table (not just the resized row)
4583
4583
  editorInfo.ace_callWithAce((ace) => {
4584
4584
  const callWithAceLogPrefix = `${funcName}[ace_callWithAce]`;
4585
- // log(`${callWithAceLogPrefix}: Finding and updating all table rows with tblId: ${resizeTableMetadata.tblId}`);
4585
+ // log(`${callWithAceLogPrefix}: Finding and updating all table rows with tblId: ${resizeTableMetadata.tblId}`);
4586
4586
 
4587
4587
  try {
4588
4588
  const rep = ace.ace_getRep();
@@ -4639,7 +4639,7 @@ const finishColumnResize = (editorInfo, docManager) => {
4639
4639
  cols: domCells.length,
4640
4640
  columnWidths: columnWidths
4641
4641
  };
4642
- // log(`${callWithAceLogPrefix}: Reconstructed metadata from DOM for line ${lineIndex}:`, reconstructedMetadata);
4642
+ // log(`${callWithAceLogPrefix}: Reconstructed metadata from DOM for line ${lineIndex}:`, reconstructedMetadata);
4643
4643
  tableLines.push({
4644
4644
  lineIndex,
4645
4645
  metadata: reconstructedMetadata
@@ -4654,7 +4654,7 @@ const finishColumnResize = (editorInfo, docManager) => {
4654
4654
  }
4655
4655
  }
4656
4656
 
4657
- // log(`${callWithAceLogPrefix}: Found ${tableLines.length} table lines to update`);
4657
+ // log(`${callWithAceLogPrefix}: Found ${tableLines.length} table lines to update`);
4658
4658
 
4659
4659
  // Update all table lines with new column widths
4660
4660
  for (const tableLine of tableLines) {
@@ -4672,7 +4672,7 @@ const finishColumnResize = (editorInfo, docManager) => {
4672
4672
  const rangeStart = [tableLine.lineIndex, 0];
4673
4673
  const rangeEnd = [tableLine.lineIndex, lineLength];
4674
4674
 
4675
- // log(`${callWithAceLogPrefix}: Updating line ${tableLine.lineIndex} (row ${tableLine.metadata.row}) with new column widths`);
4675
+ // log(`${callWithAceLogPrefix}: Updating line ${tableLine.lineIndex} (row ${tableLine.metadata.row}) with new column widths`);
4676
4676
 
4677
4677
  // Apply the updated metadata attribute directly
4678
4678
  ace.ace_performDocumentApplyAttributesToRange(rangeStart, rangeEnd, [
@@ -4680,15 +4680,15 @@ const finishColumnResize = (editorInfo, docManager) => {
4680
4680
  ]);
4681
4681
  }
4682
4682
 
4683
- // log(`${callWithAceLogPrefix}: Successfully applied updated column widths to all ${tableLines.length} table rows`);
4683
+ // log(`${callWithAceLogPrefix}: Successfully applied updated column widths to all ${tableLines.length} table rows`);
4684
4684
 
4685
4685
  } catch (error) {
4686
4686
  console.error(`${callWithAceLogPrefix}: Error applying updated metadata:`, error);
4687
- // log(`${callWithAceLogPrefix}: Error details:`, { message: error.message, stack: error.stack });
4687
+ // log(`${callWithAceLogPrefix}: Error details:`, { message: error.message, stack: error.stack });
4688
4688
  }
4689
4689
  }, 'applyTableResizeToAllRows', true);
4690
4690
 
4691
- // log(`${funcName}: Column width update initiated for all table rows via ace_callWithAce`);
4691
+ // log(`${funcName}: Column width update initiated for all table rows via ace_callWithAce`);
4692
4692
 
4693
4693
  // Reset state
4694
4694
  resizeStartX = 0;
@@ -4699,16 +4699,16 @@ const finishColumnResize = (editorInfo, docManager) => {
4699
4699
  resizeTableMetadata = null;
4700
4700
  resizeLineNum = -1;
4701
4701
 
4702
- // log(`${funcName}: Resize complete - state reset`);
4702
+ // log(`${funcName}: Resize complete - state reset`);
4703
4703
  };
4704
4704
 
4705
4705
  // NEW: Undo/Redo protection
4706
4706
  exports.aceUndoRedo = (hook, ctx) => {
4707
4707
  const logPrefix = '[ep_data_tables:aceUndoRedo]';
4708
- // log(`${logPrefix} START`, { hook, ctx });
4708
+ // log(`${logPrefix} START`, { hook, ctx });
4709
4709
 
4710
4710
  if (!ctx || !ctx.rep || !ctx.rep.selStart || !ctx.rep.selEnd) {
4711
- // log(`${logPrefix} No selection or context. Allowing default.`);
4711
+ // log(`${logPrefix} No selection or context. Allowing default.`);
4712
4712
  return;
4713
4713
  }
4714
4714
 
@@ -4729,11 +4729,11 @@ exports.aceUndoRedo = (hook, ctx) => {
4729
4729
  }
4730
4730
 
4731
4731
  if (!hasTableLines) {
4732
- // log(`${logPrefix} No table lines affected. Allowing default undo/redo.`);
4732
+ // log(`${logPrefix} No table lines affected. Allowing default undo/redo.`);
4733
4733
  return;
4734
4734
  }
4735
4735
 
4736
- // log(`${logPrefix} Table lines affected:`, { tableLines });
4736
+ // log(`${logPrefix} Table lines affected:`, { tableLines });
4737
4737
 
4738
4738
  // Validate table structure after undo/redo
4739
4739
  try {
@@ -4743,7 +4743,7 @@ exports.aceUndoRedo = (hook, ctx) => {
4743
4743
 
4744
4744
  const tableMetadata = JSON.parse(lineAttrString);
4745
4745
  if (!tableMetadata || typeof tableMetadata.cols !== 'number') {
4746
- // log(`${logPrefix} Invalid table metadata after undo/redo. Attempting recovery.`);
4746
+ // log(`${logPrefix} Invalid table metadata after undo/redo. Attempting recovery.`);
4747
4747
  // Attempt to recover table structure
4748
4748
  const lineText = ctx.rep.lines.atIndex(line)?.text || '';
4749
4749
  const cells = lineText.split(DELIMITER);
@@ -4758,16 +4758,16 @@ exports.aceUndoRedo = (hook, ctx) => {
4758
4758
 
4759
4759
  // Apply the recovered metadata
4760
4760
  ctx.documentAttributeManager.setAttributeOnLine(line, ATTR_TABLE_JSON, JSON.stringify(newMetadata));
4761
- // log(`${logPrefix} Recovered table structure for line ${line}`);
4761
+ // log(`${logPrefix} Recovered table structure for line ${line}`);
4762
4762
  } else {
4763
4763
  // If we can't recover, remove the table attribute
4764
4764
  ctx.documentAttributeManager.removeAttributeOnLine(line, ATTR_TABLE_JSON);
4765
- // log(`${logPrefix} Removed invalid table attribute from line ${line}`);
4765
+ // log(`${logPrefix} Removed invalid table attribute from line ${line}`);
4766
4766
  }
4767
4767
  }
4768
4768
  }
4769
4769
  } catch (e) {
4770
4770
  console.error(`${logPrefix} Error during undo/redo validation:`, e);
4771
- // log(`${logPrefix} Error details:`, { message: e.message, stack: e.stack });
4771
+ // log(`${logPrefix} Error details:`, { message: e.message, stack: e.stack });
4772
4772
  }
4773
4773
  };