UNPKG

vxe-table-select-area

Version:

一个基于 vxe-table 的可区域选中复制、粘贴的组件

431 lines (369 loc) 10.3 kB
/* eslint-disable brace-style */ /* eslint-disable no-void */ const regUniversalNewLine = /^(\r\n|\n\r|\r|\n)/ const regNextCellNoQuotes = /^[^\t\r\n]+/ const regNextEmptyCell = /^\t/ /** * @decodeSpreadsheetStr * @desc Decode spreadsheet string into array. refer from http://github.com/warpech/sheetclip/ * @param {string} str The string to parse. * @returns {array} */ export function decodeSpreadsheetStr (str) { let arr = [['']] if (str.length === 0) { return arr } let column = 0 let row = 0 let lastLength while (str.length > 0) { if (lastLength === str.length) { // In the case If in last cycle we didn't match anything, we have to leave the infinite loop break } lastLength = str.length if (str.match(regNextEmptyCell)) { str = str.replace(regNextEmptyCell, '') column += 1 arr[row][column] = '' } else if (str.match(regUniversalNewLine)) { str = str.replace(regUniversalNewLine, '') column = 0 row += 1 arr[row] = [''] } else { let nextCell = '' if (str.startsWith('"')) { let quoteNo = 0 let isStillCell = true while (isStillCell) { const nextChar = str.slice(0, 1) if (nextChar === '"') { quoteNo += 1 } nextCell += nextChar str = str.slice(1) if ( str.length === 0 || (str.match(/^[\t\r\n]/) && quoteNo % 2 === 0) ) { isStillCell = false } } nextCell = nextCell .replace(/^"/, '') .replace(/"$/, '') .replace(/["]*/g, (match) => new Array(Math.floor(match.length / 2)) .fill('"') .join('') ) } else { const matchedText = str.match(regNextCellNoQuotes) nextCell = matchedText ? matchedText[0] : '' str = str.slice(nextCell.length) } arr[row][column] = nextCell } } // 去除 excel 最后一个多余的换行数据 if (Array.isArray(arr) && arr.length > 1) { if (arr[arr.length - 1].length === 1 && arr[arr.length - 1][0] === '') { arr = arr.slice(0, arr.length - 1) } } return arr } /** * @decodeSpreadsheetStr * @desc encode array to spreadsheet string. refer from http://github.com/warpech/sheetclip/ * @param {array} str The string to parse. * @returns {string} */ export function encodeToSpreadsheetStr (arr) { let r let rLen let c let cLen let str = '' let val for (r = 0, rLen = arr.length; r < rLen; r += 1) { cLen = arr[r].length for (c = 0; c < cLen; c += 1) { if (c > 0) { str += '\t' } val = arr[r][c] if (typeof val === 'string') { if (val.indexOf('\n') > -1) { str += `"${val.replace(/"/g, '""')}"` } else { str += val } } else if (val === null || val === void 0) { // void 0 resolves to undefined str += '' } else { str += val } } if (r !== rLen - 1) { str += '\n' } } return str } /** * @onBeforeCopy * @desc on before copy * @param {Event} event * @return {selectionRangeIndexes,selectionRangeKeys,data} */ export function onBeforeCopy ({ cellSelectionRangeData, selectionRangeData, colgroups, allRowKeys }) { const { leftColKey, rightColKey, topRowKey, bottomRowKey } = cellSelectionRangeData const selectionRangeIndexes = { startColIndex: colgroups.findIndex((x) => x.key === leftColKey), endColIndex: colgroups.findIndex((x) => x.key === rightColKey), startRowIndex: allRowKeys.indexOf(topRowKey), endRowIndex: allRowKeys.indexOf(bottomRowKey) } const selectionRangeKeys = { startColKey: leftColKey, endColKey: rightColKey, startRowKey: topRowKey, endRowKey: bottomRowKey } const response = { selectionRangeIndexes, selectionRangeKeys, data: selectionRangeData } return response } /** * @onAfterCopy * @desc on after copy * @param {Event} event * @return */ export function onAfterCopy ({ event, selectionRangeData }) { const spreadsheetStr = encodeToSpreadsheetStr(selectionRangeData) if (event.clipboardData) { event.clipboardData.setData('text/plain', spreadsheetStr) } // IE browser else if (window.clipboardData) { window.clipboardData.setData('Text', spreadsheetStr) } } /** * @onBeforePaste * @desc on before paste * @param {Event} event * @return */ export function onBeforePaste ({ event, cellSelectionRangeData, colgroups, allRowKeys }) { let pastedData if (event.clipboardData) { pastedData = event.clipboardData.getData('text/plain') } // IE browser else if (window.clipboardData) { pastedData = window.clipboardData.getData('Text') } if (typeof pastedData !== 'string') { return null } const decodePasteData = decodeSpreadsheetStr(pastedData) const startColIndex = colgroups.findIndex( (x) => x.key === cellSelectionRangeData.leftColKey ) const endColIndex = Math.min( startColIndex + decodePasteData[0].length - 1, colgroups.length - 1 ) const startRowIndex = allRowKeys.indexOf(cellSelectionRangeData.topRowKey) const endRowIndex = Math.min( startRowIndex + decodePasteData.length - 1, allRowKeys.length - 1 ) const response = { selectionRangeIndexes: { startColIndex, endColIndex, startRowIndex, endRowIndex }, selectionRangeKeys: { startColKey: colgroups[startColIndex].key, endColKey: colgroups[endColIndex].key, startRowKey: allRowKeys[startRowIndex], endRowKey: allRowKeys[endRowIndex] }, data: [] } const sourceFieldNames = colgroups .slice(startColIndex, endColIndex + 1) .map((x) => x.field) response.data = decodePasteData .slice(0, endRowIndex - startRowIndex + 1) .map((rowData) => { const newRow = {} rowData.forEach((cellData, cellIndex) => { if (cellIndex <= endColIndex - startColIndex) { newRow[sourceFieldNames[cellIndex]] = cellData } }) return newRow }) return response } /** * @onAfterPaste * @desc on after paste * @param {Event} event * @return */ export function onAfterPaste ({ tableData, beforePasteResponse }) { const { data: pasteData, selectionRangeIndexes } = beforePasteResponse pasteData.forEach((rowData, rowIndex) => { Object.assign( tableData[selectionRangeIndexes.startRowIndex + rowIndex], rowData ) }) } /** * @onBeforeCut * @desc on before cut * @param {Event} event * @return {selectionRangeIndexes,selectionRangeKeys,data} */ export function onBeforeCut ({ cellSelectionRangeData, selectionRangeData, colgroups, allRowKeys }) { const { leftColKey, rightColKey, topRowKey, bottomRowKey } = cellSelectionRangeData const selectionRangeIndexes = { startColIndex: colgroups.findIndex((x) => x.key === leftColKey), endColIndex: colgroups.findIndex((x) => x.key === rightColKey), startRowIndex: allRowKeys.indexOf(topRowKey), endRowIndex: allRowKeys.indexOf(bottomRowKey) } const selectionRangeKeys = { startColKey: leftColKey, endColKey: rightColKey, startRowKey: topRowKey, endRowKey: bottomRowKey } const response = { selectionRangeIndexes, selectionRangeKeys, data: selectionRangeData } return response } /** * @onAfterCut * @desc on after cut * @param {Event} event * @return */ export function onAfterCut ({ event, tableData, colgroups, selectionRangeData, selectionRangeIndexes }) { const spreadsheetStr = encodeToSpreadsheetStr(selectionRangeData) const { endColIndex, endRowIndex, startColIndex, startRowIndex } = selectionRangeIndexes // 移除制定的表格数据 const fieldNames = colgroups .slice(startColIndex, endColIndex + 1) .map((x) => x.field) tableData.forEach((rowData, rowIndex) => { if (rowIndex >= startRowIndex && rowIndex <= endRowIndex) { fieldNames.forEach((fieldName) => { rowData[fieldName] = '' }) } }) if (event.clipboardData) { event.clipboardData.setData('text/plain', spreadsheetStr) } // IE browser else if (window.clipboardData) { window.clipboardData.setData('Text', spreadsheetStr) } } /** * @onBeforeDelete * @desc on before delete * @param {Event} event * @return {selectionRangeIndexes,selectionRangeKeys,data} */ export function onBeforeDelete ({ cellSelectionRangeData, selectionRangeData, colgroups, allRowKeys }) { const { leftColKey, rightColKey, topRowKey, bottomRowKey } = cellSelectionRangeData const selectionRangeIndexes = { startColIndex: colgroups.findIndex((x) => x.key === leftColKey), endColIndex: colgroups.findIndex((x) => x.key === rightColKey), startRowIndex: allRowKeys.indexOf(topRowKey), endRowIndex: allRowKeys.indexOf(bottomRowKey) } const selectionRangeKeys = { startColKey: leftColKey, endColKey: rightColKey, startRowKey: topRowKey, endRowKey: bottomRowKey } const response = { selectionRangeIndexes, selectionRangeKeys, data: selectionRangeData } return response } /** * @onAfterDelete * @desc on after delete * @param {Event} event * @return */ export function onAfterDelete ({ tableData, colgroups, selectionRangeIndexes }) { const { endColIndex, endRowIndex, startColIndex, startRowIndex } = selectionRangeIndexes // 移除制定的表格数据 const fieldNames = colgroups .slice(startColIndex, endColIndex + 1) .map((x) => x.field) tableData.forEach((rowData, rowIndex) => { if (rowIndex >= startRowIndex && rowIndex <= endRowIndex) { fieldNames.forEach((fieldName) => { rowData[fieldName] = '' }) } }) }