Improve table editing
This commit is contained in:
@@ -262,8 +262,94 @@ window.EditorTables = (function () {
|
||||
return formatTableText(newLines.join('\n'), Math.min(newCursor, newLines.join('\n').length));
|
||||
}
|
||||
|
||||
// Absolute cursor offset at the start of the `col`-th cell's content on
|
||||
// `lineIdx` of a *formatted* table (i.e. just past the "| " / " | " that
|
||||
// opens the cell). Clamps to the last cell if col overflows the row.
|
||||
function cellCursor(text, lineIdx, col) {
|
||||
var lines = text.split('\n');
|
||||
var offset = 0;
|
||||
for (var i = 0; i < lineIdx; i++) offset += lines[i].length + 1;
|
||||
var line = lines[lineIdx] || '';
|
||||
var pipes = [];
|
||||
for (var c = 0; c < line.length; c++) if (line.charAt(c) === '|') pipes.push(c);
|
||||
if (pipes.length === 0) return Math.min(offset, text.length);
|
||||
var p = pipes[Math.min(col, pipes.length - 1)];
|
||||
return Math.min(offset + p + 2, text.length);
|
||||
}
|
||||
|
||||
// Shared engine for the Enter / Tab / Shift-Tab cell navigation. Reformats
|
||||
// the table and drops the cursor into the target cell, appending an empty
|
||||
// row when navigation runs past the last row. Returns null when the cursor
|
||||
// is not in a table (so the caller can fall back to the editor default).
|
||||
function moveInTable(text, cursorPos, mode) {
|
||||
var range = findTableRange(text, cursorPos);
|
||||
if (!range) return null;
|
||||
var colIdx = getCursorColumn(text, cursorPos);
|
||||
if (colIdx === null) return null;
|
||||
|
||||
var sepRel = -1, colCount = 0;
|
||||
for (var i = range.start; i <= range.end; i++) {
|
||||
var cells = parseTableRow(range.lines[i]);
|
||||
if (cells.length > colCount) colCount = cells.length;
|
||||
if (sepRel === -1 && isSeparatorRow(cells)) sepRel = i - range.start;
|
||||
}
|
||||
if (sepRel === -1) return null;
|
||||
|
||||
var lastRel = range.end - range.start;
|
||||
var rowRel = range.cursorLine - range.start;
|
||||
var targetRow = rowRel, targetCol = colIdx;
|
||||
|
||||
if (mode === 'enter') {
|
||||
targetRow = rowRel + 1;
|
||||
if (targetRow === sepRel) targetRow++;
|
||||
} else if (mode === 'tab') {
|
||||
targetCol = colIdx + 1;
|
||||
if (targetCol >= colCount) {
|
||||
targetCol = 0;
|
||||
targetRow = rowRel + 1;
|
||||
if (targetRow === sepRel) targetRow++;
|
||||
}
|
||||
} else if (mode === 'shifttab') {
|
||||
targetCol = colIdx - 1;
|
||||
if (targetCol < 0) {
|
||||
targetCol = colCount - 1;
|
||||
targetRow = rowRel - 1;
|
||||
if (targetRow === sepRel) targetRow--;
|
||||
}
|
||||
if (targetRow < 0) return null;
|
||||
}
|
||||
|
||||
var lines = range.lines.slice();
|
||||
if (targetRow > lastRel) {
|
||||
var emptyCells = [];
|
||||
for (var c = 0; c < colCount; c++) emptyCells.push('');
|
||||
var emptyLine = '| ' + emptyCells.join(' | ') + ' |';
|
||||
while (lastRel < targetRow) {
|
||||
lines.splice(range.start + lastRel + 1, 0, emptyLine);
|
||||
lastRel++;
|
||||
}
|
||||
}
|
||||
|
||||
var tableStartOffset = 0;
|
||||
for (var i = 0; i < range.start; i++) tableStartOffset += lines[i].length + 1;
|
||||
var formatted = formatTableText(lines.join('\n'), tableStartOffset);
|
||||
if (!formatted) return null;
|
||||
|
||||
return {
|
||||
text: formatted.text,
|
||||
cursor: cellCursor(formatted.text, range.start + targetRow, targetCol),
|
||||
};
|
||||
}
|
||||
|
||||
function nextRowSameColumn(text, cursorPos) { return moveInTable(text, cursorPos, 'enter'); }
|
||||
function nextCell(text, cursorPos) { return moveInTable(text, cursorPos, 'tab'); }
|
||||
function prevCell(text, cursorPos) { return moveInTable(text, cursorPos, 'shifttab'); }
|
||||
|
||||
return {
|
||||
formatTableText: formatTableText,
|
||||
nextRowSameColumn: nextRowSameColumn,
|
||||
nextCell: nextCell,
|
||||
prevCell: prevCell,
|
||||
setColumnAlignment: setColumnAlignment,
|
||||
insertColumn: insertColumn,
|
||||
deleteColumn: deleteColumn,
|
||||
|
||||
Reference in New Issue
Block a user