ClipboardConfig
Since v0.1.1
Configuration options for the clipboard plugin *
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
includeHeaders? | boolean | Include column headers in copied text (default: false) |
delimiter? | string | Column delimiter character (default: ‘\t’ for tab) |
newline? | string | Row delimiter/newline character (default: ‘\n’) |
quoteStrings? | boolean | Wrap string values with quotes (default: false) |
escapeFormulas? | boolean | Neutralize spreadsheet formula injection (CWE-1236) by prefixing string values that start with =, +, -, @, TAB or CR with a single quote, so a paste into Excel / LibreOffice / Sheets renders them as text instead of evaluating them (default: true). v3.5.0+ |
processCell? | (value: unknown, field: string, row: unknown) => string | Custom cell value processor for copy operations |
fillSelection? | boolean | When true, pasting into a multi-cell selection larger than the clipboard source tiles (repeats) the source to fill the whole selection: a single copied cell fills every selected cell, a 1×2 source fills as val1, val2, val1, val2, and a 2×2 block tiles across the selection. v3.0.0+ |
pasteHandler? | PasteHandler | unknown | Custom paste handler that fully replaces defaultPasteHandler. |
Property Details
Section titled “Property Details”fillSelection
Section titled “fillSelection”When true, pasting into a multi-cell selection larger than the clipboard
source tiles (repeats) the source to fill the whole selection: a single
copied cell fills every selected cell, a 1×2 source fills as
val1, val2, val1, val2, and a 2×2 block tiles across the selection.
Only applies when a bounded (multi-cell) selection is active — it never
grows the grid. Defaults to false (paste writes only the source extent).
Default: false
pasteHandler
Section titled “pasteHandler”Custom paste handler that fully replaces defaultPasteHandler.
⚠️ Prefer not to override this. The default handler is no longer a thin “write text into cells” routine — it now implements substantial behavior that is easy to get subtly wrong when reimplemented:
- editability resolution via the editing plugin (
getCellEditableResolver, including row-conditionaleditable); - per-column BaseColumnConfig.onPaste reject / transform, plus the
paste-rejectedevent; - structured (
rawRows) same-grid / cross-window values so object cells round-trip losslessly (not degraded to display text); - fill-selection tiling of a smaller source across a bounded selection;
- routing edits through
grid.updateRows(…, 'paste')so paste participates in dirty tracking, undo/redo history, cancelable validation, and the'paste'commit source — with a direct-write fallback for id-less rows; - growing the grid for unbounded single-cell-expansion pastes.
Use an extension point instead of overriding, wherever possible:
- reject / transform per cell → column BaseColumnConfig.onPaste;
- coerce / veto committed values globally → the cancelable
cell-commitevent (detail.source === 'paste'distinguishes a paste); - observe the raw paste → the
pasteevent; - react to rejected cells → the
paste-rejectedevent.
Other values:
null— disable auto-paste entirely (thepasteevent still fires).- a function returning
false— you handled it; skip the default.
If you must override (e.g. bespoke target placement or side effects),
you are responsible for re-implementing the behaviors above. At minimum,
honor per-column onPaste with the exported resolveColumnPaste and
fire emitPasteRejected so onPaste and paste-rejected keep working:
import { resolveColumnPaste, emitPasteRejected } from '@toolbox-web/grid/plugins/clipboard';
pasteHandler: (detail, grid) => { const rejected = []; for (const cell of myCells(detail)) { const res = resolveColumnPaste(cell.column.onPaste, { value: cell.value, field: cell.field, row: cell.row, rowIndex: cell.rowIndex, oldValue: cell.oldValue, sourceField: cell.sourceField, }); if (res.accepted) writeCell(cell, res.value); else rejected.push({ field: cell.field, rowIndex: cell.rowIndex, row: cell.row, value: cell.value, reason: res.reason }); } emitPasteRejected(grid, rejected); return false; // handled}Default: defaultPasteHandler (auto-applies paste data)