`
})
// 注入 th 属性与样式
res = res.replace(/| ]*)?>/gi, (match, attrs = '') => {
let cleanAttrs = attrs.replace(/\s+border\s*=\s*["'][^"']*["']/gi, '')
if (/style\s*=\s*["']/i.test(cleanAttrs)) {
cleanAttrs = cleanAttrs.replace(/style\s*=\s*["']([^"']*)["']/i, (m, s) => `style="${s}; ${TH_STYLE}"`)
} else {
cleanAttrs = ` style="${TH_STYLE}"` + cleanAttrs
}
return ` | `
})
// 注入 td 属性与样式
res = res.replace(/ | ]*)?>/gi, (match, attrs = '') => {
let cleanAttrs = attrs.replace(/\s+border\s*=\s*["'][^"']*["']/gi, '')
if (/style\s*=\s*["']/i.test(cleanAttrs)) {
cleanAttrs = cleanAttrs.replace(/style\s*=\s*["']([^"']*)["']/i, (m, s) => `style="${s}; ${TD_STYLE}"`)
} else {
cleanAttrs = ` style="${TD_STYLE}"` + cleanAttrs
}
return ` | `
})
return res
}
export function createEmptyCell(tagName = 'td') {
const cell = document.createElement(tagName)
cell.innerHTML = '
'
cell.setAttribute('border', '1')
if (tagName === 'th') {
cell.style.cssText = TH_STYLE
} else {
cell.style.cssText = TD_STYLE
}
return cell
}
export function buildTableHtml(rows = 3, cols = 3) {
let html = ``
for (let r = 0; r < rows; r += 1) {
html += ``
for (let c = 0; c < cols; c += 1) {
if (r === 0) {
html += `
| `
} else {
html += `
| `
}
}
html += ' '
}
html += '
'
return html
}
export function getCurrentCell(editorEl) {
const sel = window.getSelection()
if (!sel || sel.rangeCount === 0) return null
let node = sel.anchorNode
if (node?.nodeType === Node.TEXT_NODE) node = node.parentElement
const cell = node?.closest?.('td, th')
if (!cell || !editorEl?.contains(cell)) return null
return cell
}
export function addRowBefore(cell) {
const row = cell.closest('tr')
const newRow = row.cloneNode(true)
newRow.style.cssText = TR_STYLE
newRow.querySelectorAll('td, th').forEach((item) => {
item.innerHTML = '
'
item.removeAttribute('colspan')
item.removeAttribute('rowspan')
item.setAttribute('border', '1')
item.style.cssText = item.tagName.toLowerCase() === 'th' ? TH_STYLE : TD_STYLE
})
row.before(newRow)
return newRow.cells[cell.cellIndex] || newRow.cells[0]
}
export function addRowAfter(cell) {
const row = cell.closest('tr')
const newRow = row.cloneNode(true)
newRow.style.cssText = TR_STYLE
newRow.querySelectorAll('td, th').forEach((item) => {
item.innerHTML = '
'
item.removeAttribute('colspan')
item.removeAttribute('rowspan')
item.setAttribute('border', '1')
item.style.cssText = item.tagName.toLowerCase() === 'th' ? TH_STYLE : TD_STYLE
})
row.after(newRow)
return newRow.cells[cell.cellIndex] || newRow.cells[0]
}
export function deleteRow(cell) {
const row = cell.closest('tr')
const section = row?.parentElement
if (!row || !section || section.querySelectorAll('tr').length <= 1) return null
const focusCell =
row.nextElementSibling?.cells[cell.cellIndex] ||
row.previousElementSibling?.cells[cell.cellIndex] ||
null
row.remove()
return focusCell
}
export function addColBefore(cell) {
const index = cell.cellIndex
const table = cell.closest('table')
table.querySelectorAll('tr').forEach((row) => {
const refCell = row.cells[index]
if (!refCell) return
refCell.before(createEmptyCell(refCell.tagName.toLowerCase()))
})
return cell.parentElement.cells[index]
}
export function addColAfter(cell) {
const index = cell.cellIndex
const table = cell.closest('table')
table.querySelectorAll('tr').forEach((row) => {
const refCell = row.cells[index]
if (!refCell) return
refCell.after(createEmptyCell(refCell.tagName.toLowerCase()))
})
return cell.parentElement.cells[index + 1]
}
export function deleteCol(cell) {
const index = cell.cellIndex
const table = cell.closest('table')
if (cell.parentElement.cells.length <= 1) return null
let focusCell = null
table.querySelectorAll('tr').forEach((row) => {
const target = row.cells[index]
if (!target) return
if (row === cell.parentElement) {
focusCell = row.cells[index + 1] || row.cells[index - 1] || null
}
target.remove()
})
return focusCell
}
export function deleteTable(cell) {
cell.closest('table')?.remove()
}
|