🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
DemoInstallSign in
Socket

simple-csv-editor

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

simple-csv-editor - npm Package Compare versions

Comparing version

to
1.3.0

16

.eslintrc.json
{
"env": {
"browser": true,
"es2023": true
"es2022": true
},

@@ -10,3 +10,3 @@ "extends": [

"parserOptions": {
"ecmaVersion": 2023
"ecmaVersion": 2022
},

@@ -19,3 +19,13 @@ "rules": {

"no-new": 0,
"no-console": ["error", { "allow": ["error"] }]
"no-console": [
"error",
{
"allow": [
"error"
]
}
],
"no-continue": 0,
"no-alert": 0,
"max-len": 0
},

@@ -22,0 +32,0 @@ "globals": {

15

package.json
{
"name": "simple-csv-editor",
"version": "1.2.0",
"version": "1.3.0",
"description": "A table editor for easily editing and retrieving CSV data.",

@@ -15,6 +15,15 @@ "main": "src/simple-csv-editor.js",

"keywords": [
"simple",
"csv",
"editor",
"js",
"es-modules"
"json",
"module",
"synchronized",
"synced",
"html",
"table",
"papaparse",
"parser",
"unstyled",
"api"
],

@@ -21,0 +30,0 @@ "author": "Daniel Geymayer",

@@ -9,2 +9,8 @@ # Simple CSV Editor

## Installation
```bash
npm install --save simple-csv-editor
```
## Usage

@@ -18,3 +24,5 @@

<!-- PapaParse dependency, very important for the editor to work! -->
<!-- PapaParse CSV parser dependency - very important for the editor to work!
Of course you can also use the library via "npm i papaparse" or download it yourself.
At least the vendored version here guarantees compatibility with the editor. -->
<script src="papaparse.min.js"></script>

@@ -45,4 +53,12 @@

## Versioning
This project uses semantic versioning.
- Major version change: Expect breaking changes
- Minor version change: New features
- Patch version change: Minor bugfixes, Refactoring, etc.
## Dependencies
- [PapaParse](https://www.papaparse.com)

@@ -6,2 +6,16 @@ class SimpleCsvEditor {

onChange = null,
warnOnDelete = true,
showControls = true,
controlLabels = {
addRowBefore: '+ ↑',
addRowAfter: '+ ↓',
addColumnBefore: '+ ←',
addColumnAfter: '+ →',
deleteRow: '✖',
deleteColumn: '✖',
deleteAll: '✖',
deleteRowWarning: 'DELETE THIS ROW?',
deleteColumnWarning: 'DELETE THIS COLUMN?',
deleteAllWarning: 'DELETE ALL DATA?',
},
delimiter = null,

@@ -24,2 +38,5 @@ quoteChar = '"',

this.onChange = onChange;
this.warnOnDelete = warnOnDelete;
this.showControls = showControls;
this.controlLabels = controlLabels;

@@ -46,2 +63,70 @@ this.papaParseConfig = {

static #buildBasicButton(label) {
const button = document.createElement('button');
button.type = 'button';
button.innerText = label;
button.tabIndex = -1;
return button;
}
#buildAddRowButton(offsetIdx, label) {
const button = SimpleCsvEditor.#buildBasicButton(label);
button.addEventListener('click', (event) => {
this.addRow(event.target.parentElement.parentElement.rowIndex + offsetIdx);
});
return button;
}
#buildAddColumnButton(offsetIdx, label) {
const button = SimpleCsvEditor.#buildBasicButton(label);
button.addEventListener('click', (event) => {
this.addColumn(event.target.parentElement.cellIndex + offsetIdx);
});
return button;
}
#buildDeleteRowButton(label) {
const button = SimpleCsvEditor.#buildBasicButton(label);
button.addEventListener('click', (event) => {
if (!this.warnOnDelete || window.confirm(this.controlLabels.deleteRowWarning)) {
this.deleteRow(event.target.parentElement.parentElement.rowIndex);
}
});
return button;
}
#buildDeleteColumnButton(label) {
const button = SimpleCsvEditor.#buildBasicButton(label);
button.addEventListener('click', (event) => {
if (!this.warnOnDelete || window.confirm(this.controlLabels.deleteColumnWarning)) {
this.deleteColumn(event.target.parentElement.cellIndex);
}
});
return button;
}
#buildDeleteAllButton(label) {
const button = SimpleCsvEditor.#buildBasicButton(label);
button.addEventListener('click', () => {
if (!this.warnOnDelete || window.confirm(this.controlLabels.deleteAllWarning)) {
this.deleteAll();
}
});
return button;
}
#addColumnControlCell(row, cellIdx) {
const cell = row.insertCell(cellIdx);
cell.appendChild(this.#buildAddColumnButton(0, this.controlLabels.addColumnBefore));
cell.appendChild(this.#buildDeleteColumnButton(this.controlLabels.deleteColumn));
cell.appendChild(this.#buildAddColumnButton(1, this.controlLabels.addColumnAfter));
}
#addRowControlCell(row, cellIdx) {
const cell = row.insertCell(cellIdx);
cell.appendChild(this.#buildAddRowButton(0, this.controlLabels.addRowBefore));
cell.appendChild(this.#buildDeleteRowButton(this.controlLabels.deleteRow));
cell.appendChild(this.#buildAddRowButton(1, this.controlLabels.addRowAfter));
}
static #checkCursorPosition(cell) {

@@ -92,3 +177,3 @@ const selection = window.getSelection();

#addCellToRow(row, cellIdx = -1) {
#addDataCellToRow(row, cellIdx) {
const newCell = row.insertCell(cellIdx);

@@ -100,3 +185,2 @@ newCell.contentEditable = true;

newCell.addEventListener('keydown', (event) => {
const rowIdx = event.target.parentElement.rowIndex;
const { rows } = row.parentElement;

@@ -106,6 +190,5 @@ switch (event.key) {

event.preventDefault();
const newRowIdx = (event.shiftKey) ? rowIdx : rowIdx + 1;
const newRowIdx = event.shiftKey ? row.rowIndex : row.rowIndex + 1;
this.addRow(newRowIdx);
rows[newRowIdx].cells[newCell.cellIndex].focus();
this.#triggerOnChange();
break;

@@ -115,7 +198,7 @@ }

event.preventDefault();
SimpleCsvEditor.#jumpToEndOfCell(rows[rowIdx - 1]?.cells[newCell.cellIndex]);
SimpleCsvEditor.#jumpToEndOfCell(rows[row.rowIndex - 1]?.cells[newCell.cellIndex]);
break;
case 'ArrowDown':
event.preventDefault();
SimpleCsvEditor.#jumpToEndOfCell(rows[rowIdx + 1]?.cells[newCell.cellIndex]);
SimpleCsvEditor.#jumpToEndOfCell(rows[row.rowIndex + 1]?.cells[newCell.cellIndex]);
break;

@@ -139,9 +222,17 @@ case 'ArrowLeft':

getCsv() {
return Array.from(this.table.rows).slice(this.showControls ? 1 : 0)
.map((row) => Array.from(row.cells).slice(0, this.showControls ? -1 : undefined)
.map((cell) => cell.textContent)
.join(this.papaParseConfig.delimiter))
.join(this.detectedLineBreak) + (this.lastLineEmpty ? this.detectedLineBreak : '');
}
setCsv(data) {
const result = Papa.parse(data, this.papaParseConfig);
if (result.errors.length > 0) {
for (const error of result.errors) {
console.error(error);
for (const error of result.errors) {
if (error.type === 'Delimiter' && error.code === 'UndetectableDelimiter') {
continue;
}
return;
console.error(error);
}

@@ -157,6 +248,12 @@

if (this.table.rows[lineIdx] == null) {
this.addRow();
const numCells = (lineIdx <= 0) ? lineTokens.length : this.table.rows[lineIdx - 1].cells.length;
const newRow = this.table.insertRow(-1);
for (let cellIdx = 0; cellIdx < numCells; cellIdx += 1) {
this.#addDataCellToRow(newRow, -1);
}
}
if (this.table.rows[lineIdx].cells[tokenIdx] == null) {
this.addColumn();
for (const row of this.table.rows) {
this.#addDataCellToRow(row, -1);
}
}

@@ -166,43 +263,70 @@ this.table.rows[lineIdx].cells[tokenIdx].textContent = token;

}
if (this.table.rows.length <= 0) {
this.#addDataCellToRow(this.table.insertRow(0), 0);
}
if (this.showControls) {
const columnControlsRow = this.table.insertRow(0);
for (let cellIdx = 0; cellIdx < this.table.rows[1].cells.length; cellIdx += 1) {
this.#addColumnControlCell(columnControlsRow, -1);
}
for (const row of this.table.rows) {
if (row.rowIndex === 0) {
row.insertCell(-1).appendChild(this.#buildDeleteAllButton(this.controlLabels.deleteAll));
} else {
this.#addRowControlCell(row, -1);
}
}
}
}
getCsv() {
return Array.from(this.table.rows)
.map((row) => Array.from(row.cells)
.map((cell) => cell.textContent)
.join(this.papaParseConfig.delimiter))
.join(this.detectedLineBreak) + (this.lastLineEmpty ? this.detectedLineBreak : '');
}
addRow(rowIdx = -1) {
const firstRow = (this.table.rows.length > 0) ? this.table.rows[0] : null;
addRow(rowIdx) {
const firstDataRowIdx = this.showControls ? 1 : 0;
const firstDataRow = (this.table.rows.length > firstDataRowIdx) ? this.table.rows[firstDataRowIdx] : null;
const newRow = this.table.insertRow(rowIdx);
for (let cellIdx = 0; cellIdx < (firstRow ?? newRow).cells.length; cellIdx += 1) {
this.#addCellToRow(newRow);
const numCells = (firstDataRow ?? newRow).cells.length;
for (let cellIdx = 0; cellIdx < numCells; cellIdx += 1) {
if (this.showControls && cellIdx === numCells - 1) {
this.#addRowControlCell(newRow, -1);
} else {
this.#addDataCellToRow(newRow, -1);
}
}
this.#triggerOnChange();
}
addColumn(cellIdx = -1) {
addColumn(cellIdx) {
for (const row of this.table.rows) {
this.#addCellToRow(row, cellIdx);
if (this.showControls && row.rowIndex === 0) {
this.#addColumnControlCell(row, cellIdx);
} else {
this.#addDataCellToRow(row, cellIdx);
}
}
this.#triggerOnChange();
}
deleteRow(rowIdx = -1) {
if (this.table.rows.length <= 1) {
deleteRow(rowIdx) {
if (this.table.rows.length <= (this.showControls ? 2 : 1)) {
return;
}
this.table.deleteRow(rowIdx);
this.#triggerOnChange();
}
deleteColumn(cellIdx = -1) {
if (this.table.rows[0].cells.length <= 1) {
deleteColumn(columnIdx) {
if (this.table.rows[0].cells.length <= (this.showControls ? 2 : 1)) {
return;
}
for (const row of this.table.rows) {
row.deleteCell(cellIdx);
row.deleteCell(columnIdx);
}
this.#triggerOnChange();
}
deleteAll() {
this.setCsv('');
this.#triggerOnChange();
}
}
export default SimpleCsvEditor;

Sorry, the diff of this file is not supported yet