Security (React)

The sample demonstrates how to export FlexGrid content to password-protected PDF file and how to set PDF file permissions.

The sample uses wijmo.pdf.security module to enhance wijmo.pdf with security capabilities.

The IFlexGridExportSettings' documentOptions property is used to provide security settings, such as userPassword and permissions, to the underlying PdfDocument.

Learn about FlexGrid | FlexGrid API Reference

This example uses React.

app.jsx
index.html
app.css
data.jsx
Copy to CodeMine
import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import ReactDOM from 'react-dom/client'; import React, { useRef, useState } from 'react'; import useEvent from 'react-use-event-hook'; import { PdfVersion, PdfPrintPermission } from '@mescius/wijmo.pdf'; import { FlexGridPdfConverter } from '@mescius/wijmo.grid.pdf'; import '@mescius/wijmo.pdf.security'; import * as wjInput from '@mescius/wijmo.react.input'; import * as wjcGrid from '@mescius/wijmo.react.grid'; import './app.css'; import { data } from './data'; function App() { const [userPassword, setUserPassword] = useState(''); const [ownerPassword, setOwnerPassword] = useState(''); const [version, setVersion] = useState(PdfVersion.v1_3); const [permissions, setPermissions] = useState({ annotating: false, contentAccessibility: false, copying: false, documentAssembly: false, fillingForms: false, modifying: false, printing: PdfPrintPermission.NotAllowed }); const flexGridRef = useRef(null); const initializeGrid = useEvent((ctl) => { flexGridRef.current = ctl; }); const exportPdf = () => { const p = permissions, settings = { documentOptions: { userPassword: userPassword, ownerPassword: ownerPassword, version: version, permissions: { annotating: p.annotating, contentAccessibility: p.contentAccessibility, copying: p.copying, documentAssembly: p.documentAssembly, fillingForms: p.fillingForms, modifying: p.modifying, printing: p.printing } }, styles: { cellStyle: { backgroundColor: '#ffffff', borderColor: '#c6c6c6' }, altCellStyle: { backgroundColor: '#f9f9f9' }, groupCellStyle: { backgroundColor: '#dddddd' }, headerCellStyle: { backgroundColor: '#eaeaea' } } }; // FlexGridPdfConverter.export(flexGridRef.current, 'FlexGrid.pdf', settings); }; const userPasswordChange = (event) => { setUserPassword(event.target.value); }; const ownerPasswordChange = (event) => { setOwnerPassword(event.target.value); }; const versionChanged = useEvent((menu) => { if (menu.selectedValue) { setVersion(menu.selectedValue); } }); const permChanged = (stateProp, checked) => { setPermissions(Object.assign(Object.assign({}, permissions), { [stateProp]: checked })); }; const printingChanged = (event) => { let val = event.target.value; setPermissions(Object.assign(Object.assign({}, permissions), { printing: val })); }; return (<div className="container-fluid"> <div className="panel panel-default"> <div className="panel-heading"> Security settings </div> <div className="panel-body"> <div className="row"> <div className="col-sm-3"> <input type="text" className="form-control" placeholder="User password" onChange={userPasswordChange} value={userPassword}/> </div> <div className="col-sm-3"> <input type="text" className="form-control" placeholder="Owner password" onChange={ownerPasswordChange} value={ownerPassword}/> </div> </div> <hr /> <div className="row"> <div className="col-sm-3"> <wjInput.Menu header='PDF version' itemClicked={versionChanged} value={version}> <wjInput.MenuItem value={PdfVersion.v1_3}>1.3</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_4}>1.4</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_5}>1.5</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_6}>1.6</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_7}>1.7</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_7Ext3}>1.7 ExtensionLevel 3</wjInput.MenuItem> </wjInput.Menu> </div> </div> <hr /> <div className="row"> <div className="col"> <b>Permissions</b> (require owner password) </div> </div> <div className="row"> <div className="col-sm-3"> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.annotating} onChange={(event) => permChanged('annotating', event.target.checked)}/>Annotating </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.contentAccessibility} onChange={(event) => permChanged('contentAccessibility', event.target.checked)}/>ContentAccessibility </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.copying} onChange={(event) => permChanged('copying', event.target.checked)}/>Copying </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.documentAssembly} onChange={(event) => permChanged('documentAssembly', event.target.checked)}/>DocumentAssembly </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.fillingForms} onChange={(event) => permChanged('fillingForms', event.target.checked)}/>FillingForms </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.modifying} onChange={(event) => permChanged('modifying', event.target.checked)}/>Modifying </label> </div> </div> </div> <div className="row"> <div className="col-sm-2">Printing</div> </div> <div className="row"> <div className="col-sm-6"> <label className="radio-inline"> <input name="printing" type="radio" value={PdfPrintPermission.NotAllowed} checked={permissions.printing == PdfPrintPermission.NotAllowed} onChange={printingChanged}/>NotAllowed </label> <label className="radio-inline"> <input name="printing" type="radio" value={PdfPrintPermission.AllowLowResolution} checked={permissions.printing == PdfPrintPermission.AllowLowResolution} onChange={printingChanged}/>AllowLowResolution </label> <label className="radio-inline"> <input name="printing" type="radio" value={PdfPrintPermission.AllowHighResolution} checked={permissions.printing == PdfPrintPermission.AllowHighResolution} onChange={printingChanged}/>AllowHighResolution </label> </div> </div> </div> </div> {/* Export button */} <button className="btn btn-default" onClick={exportPdf}> Export</button> {/* FlexGrid */} <wjcGrid.FlexGrid className="grid" autoGenerateColumns={false} headersVisibility="Column" selectionMode="ListBox" itemsSource={data} initialized={initializeGrid}> <wjcGrid.FlexGridColumn header="ID" binding="id"/> <wjcGrid.FlexGridColumn header="Start Date" binding="start" format="d"/> <wjcGrid.FlexGridColumn header="End Date" binding="end" format="d"/> <wjcGrid.FlexGridColumn header="Country" binding="country"/> </wjcGrid.FlexGrid> </div>); } const container = document.getElementById('app'); if (container) { const root = ReactDOM.createRoot(container); root.render(<App />); }
import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import ReactDOM from 'react-dom/client'; import React, { useRef, useState } from 'react'; import useEvent from 'react-use-event-hook'; import { PdfVersion, PdfPrintPermission } from '@mescius/wijmo.pdf'; import { FlexGridPdfConverter } from '@mescius/wijmo.grid.pdf'; import '@mescius/wijmo.pdf.security'; import * as wjInput from '@mescius/wijmo.react.input'; import * as wjcGrid from '@mescius/wijmo.react.grid'; import './app.css'; import { data } from './data'; function App() { const [userPassword, setUserPassword] = useState(''); const [ownerPassword, setOwnerPassword] = useState(''); const [version, setVersion] = useState(PdfVersion.v1_3); const [permissions, setPermissions] = useState({ annotating: false, contentAccessibility: false, copying: false, documentAssembly: false, fillingForms: false, modifying: false, printing: PdfPrintPermission.NotAllowed }); const flexGridRef = useRef(null); const initializeGrid = useEvent((ctl) => { flexGridRef.current = ctl; }); const exportPdf = () => { const p = permissions, settings = { documentOptions: { userPassword: userPassword, ownerPassword: ownerPassword, version: version, permissions: { annotating: p.annotating, contentAccessibility: p.contentAccessibility, copying: p.copying, documentAssembly: p.documentAssembly, fillingForms: p.fillingForms, modifying: p.modifying, printing: p.printing } }, styles: { cellStyle: { backgroundColor: '#ffffff', borderColor: '#c6c6c6' }, altCellStyle: { backgroundColor: '#f9f9f9' }, groupCellStyle: { backgroundColor: '#dddddd' }, headerCellStyle: { backgroundColor: '#eaeaea' } } }; // FlexGridPdfConverter.export(flexGridRef.current, 'FlexGrid.pdf', settings); }; const userPasswordChange = (event) => { setUserPassword(event.target.value); }; const ownerPasswordChange = (event) => { setOwnerPassword(event.target.value); }; const versionChanged = useEvent((menu) => { if (menu.selectedValue) { setVersion(menu.selectedValue); } }); const permChanged = (stateProp, checked) => { setPermissions(Object.assign(Object.assign({}, permissions), { [stateProp]: checked })); }; const printingChanged = (event) => { let val = event.target.value; setPermissions(Object.assign(Object.assign({}, permissions), { printing: val })); }; return (<div className="container-fluid"> <div className="panel panel-default"> <div className="panel-heading"> Security settings </div> <div className="panel-body"> <div className="row"> <div className="col-sm-3"> <input type="text" className="form-control" placeholder="User password" onChange={userPasswordChange} value={userPassword}/> </div> <div className="col-sm-3"> <input type="text" className="form-control" placeholder="Owner password" onChange={ownerPasswordChange} value={ownerPassword}/> </div> </div> <hr /> <div className="row"> <div className="col-sm-3"> <wjInput.Menu header='PDF version' itemClicked={versionChanged} value={version}> <wjInput.MenuItem value={PdfVersion.v1_3}>1.3</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_4}>1.4</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_5}>1.5</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_6}>1.6</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_7}>1.7</wjInput.MenuItem> <wjInput.MenuItem value={PdfVersion.v1_7Ext3}>1.7 ExtensionLevel 3</wjInput.MenuItem> </wjInput.Menu> </div> </div> <hr /> <div className="row"> <div className="col"> <b>Permissions</b> (require owner password) </div> </div> <div className="row"> <div className="col-sm-3"> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.annotating} onChange={(event) => permChanged('annotating', event.target.checked)}/>Annotating </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.contentAccessibility} onChange={(event) => permChanged('contentAccessibility', event.target.checked)}/>ContentAccessibility </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.copying} onChange={(event) => permChanged('copying', event.target.checked)}/>Copying </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.documentAssembly} onChange={(event) => permChanged('documentAssembly', event.target.checked)}/>DocumentAssembly </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.fillingForms} onChange={(event) => permChanged('fillingForms', event.target.checked)}/>FillingForms </label> </div> <div className="checkbox"> <label> <input type="checkbox" checked={permissions.modifying} onChange={(event) => permChanged('modifying', event.target.checked)}/>Modifying </label> </div> </div> </div> <div className="row"> <div className="col-sm-2">Printing</div> </div> <div className="row"> <div className="col-sm-6"> <label className="radio-inline"> <input name="printing" type="radio" value={PdfPrintPermission.NotAllowed} checked={permissions.printing == PdfPrintPermission.NotAllowed} onChange={printingChanged}/>NotAllowed </label> <label className="radio-inline"> <input name="printing" type="radio" value={PdfPrintPermission.AllowLowResolution} checked={permissions.printing == PdfPrintPermission.AllowLowResolution} onChange={printingChanged}/>AllowLowResolution </label> <label className="radio-inline"> <input name="printing" type="radio" value={PdfPrintPermission.AllowHighResolution} checked={permissions.printing == PdfPrintPermission.AllowHighResolution} onChange={printingChanged}/>AllowHighResolution </label> </div> </div> </div> </div> {/* Export button */} <button className="btn btn-default" onClick={exportPdf}> Export</button> {/* FlexGrid */} <wjcGrid.FlexGrid className="grid" autoGenerateColumns={false} headersVisibility="Column" selectionMode="ListBox" itemsSource={data} initialized={initializeGrid}> <wjcGrid.FlexGridColumn header="ID" binding="id"/> <wjcGrid.FlexGridColumn header="Start Date" binding="start" format="d"/> <wjcGrid.FlexGridColumn header="End Date" binding="end" format="d"/> <wjcGrid.FlexGridColumn header="Country" binding="country"/> </wjcGrid.FlexGrid> </div>); } const container = document.getElementById('app'); if (container) { const root = ReactDOM.createRoot(container); root.render(<App />); }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Security</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.40/system.src.js" integrity="sha512-G6mEj6h18+m3MvzdviSDfPle/TfH0//cXcB33AKlNR/Rha0yQsKefDZKRTkIZos97HEGq2JMV1RT5ybMoQ3WsQ==" crossorigin="anonymous"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div id="app"></div> </body> </html>
.grid { margin-top: 20px; height: 300px; }
function getData(count) { // const countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece']; const products = ['Widget', 'Gadget', 'Doohickey']; const colors = ['Orange', 'White', 'Red', 'Green', 'Blue']; // let data = []; let dt = new Date(); // // add count items for (let i = 0; i < count; i++) { // constants used to create data items let date = new Date(dt.getFullYear(), i % 12, 25, i % 24, i % 60, i % 60), countryId = Math.floor(Math.random() * countries.length), productId = Math.floor(Math.random() * products.length), colorId = Math.floor(Math.random() * colors.length); // // create the item let item = { id: i, start: date, end: date, country: countries[countryId], product: products[productId], color: colors[colorId], amount: Math.random() * 10000 - 5000, amount2: Math.random() * 10000 - 5000, discount: Math.random() / 4, active: i % 4 == 0 }; // // add the item to the list data.push(item); } return data; } export const data = getData(10);
(function (global) { window.process = { env: { NODE_ENV: "production" } } System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true, react: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { 'jszip': 'npm:jszip/dist/jszip.js', '@mescius/wijmo': 'npm:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js', '@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures', '@mescius/wijmo.chart': 'npm:@mescius/wijmo.chart/index.js', '@mescius/wijmo.chart.analytics': 'npm:@mescius/wijmo.chart.analytics/index.js', '@mescius/wijmo.chart.animation': 'npm:@mescius/wijmo.chart.animation/index.js', '@mescius/wijmo.chart.annotation': 'npm:@mescius/wijmo.chart.annotation/index.js', '@mescius/wijmo.chart.finance': 'npm:@mescius/wijmo.chart.finance/index.js', '@mescius/wijmo.chart.finance.analytics': 'npm:@mescius/wijmo.chart.finance.analytics/index.js', '@mescius/wijmo.chart.hierarchical': 'npm:@mescius/wijmo.chart.hierarchical/index.js', '@mescius/wijmo.chart.interaction': 'npm:@mescius/wijmo.chart.interaction/index.js', '@mescius/wijmo.chart.radar': 'npm:@mescius/wijmo.chart.radar/index.js', '@mescius/wijmo.chart.render': 'npm:@mescius/wijmo.chart.render/index.js', '@mescius/wijmo.chart.webgl': 'npm:@mescius/wijmo.chart.webgl/index.js', '@mescius/wijmo.chart.map': 'npm:@mescius/wijmo.chart.map/index.js', '@mescius/wijmo.gauge': 'npm:@mescius/wijmo.gauge/index.js', '@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js', '@mescius/wijmo.grid.detail': 'npm:@mescius/wijmo.grid.detail/index.js', '@mescius/wijmo.grid.filter': 'npm:@mescius/wijmo.grid.filter/index.js', '@mescius/wijmo.grid.search': 'npm:@mescius/wijmo.grid.search/index.js', '@mescius/wijmo.grid.style': 'npm:@mescius/wijmo.grid.style/index.js', '@mescius/wijmo.grid.grouppanel': 'npm:@mescius/wijmo.grid.grouppanel/index.js', '@mescius/wijmo.grid.multirow': 'npm:@mescius/wijmo.grid.multirow/index.js', '@mescius/wijmo.grid.transposed': 'npm:@mescius/wijmo.grid.transposed/index.js', '@mescius/wijmo.grid.transposedmultirow': 'npm:@mescius/wijmo.grid.transposedmultirow/index.js', '@mescius/wijmo.grid.pdf': 'npm:@mescius/wijmo.grid.pdf/index.js', '@mescius/wijmo.grid.sheet': 'npm:@mescius/wijmo.grid.sheet/index.js', '@mescius/wijmo.grid.xlsx': 'npm:@mescius/wijmo.grid.xlsx/index.js', '@mescius/wijmo.grid.selector': 'npm:@mescius/wijmo.grid.selector/index.js', '@mescius/wijmo.grid.cellmaker': 'npm:@mescius/wijmo.grid.cellmaker/index.js', '@mescius/wijmo.grid.immutable': 'npm:@mescius/wijmo.grid.immutable/index.js', '@mescius/wijmo.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/index.js', '@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js', '@mescius/wijmo.odata': 'npm:@mescius/wijmo.odata/index.js', '@mescius/wijmo.olap': 'npm:@mescius/wijmo.olap/index.js', '@mescius/wijmo.rest': 'npm:@mescius/wijmo.rest/index.js', '@mescius/wijmo.pdf': 'npm:@mescius/wijmo.pdf/index.js', '@mescius/wijmo.pdf.security': 'npm:@mescius/wijmo.pdf.security/index.js', '@mescius/wijmo.viewer': 'npm:@mescius/wijmo.viewer/index.js', '@mescius/wijmo.xlsx': 'npm:@mescius/wijmo.xlsx/index.js', '@mescius/wijmo.undo': 'npm:@mescius/wijmo.undo/index.js', '@mescius/wijmo.interop.grid': 'npm:@mescius/wijmo.interop.grid/index.js', '@mescius/wijmo.barcode': 'npm:@mescius/wijmo.barcode/index.js', '@mescius/wijmo.barcode.common': 'npm:@mescius/wijmo.barcode.common/index.js', '@mescius/wijmo.barcode.composite': 'npm:@mescius/wijmo.barcode.composite/index.js', '@mescius/wijmo.barcode.specialized': 'npm:@mescius/wijmo.barcode.specialized/index.js', "@mescius/wijmo.react.chart.analytics": "npm:@mescius/wijmo.react.chart.analytics/index.js", "@mescius/wijmo.react.chart.animation": "npm:@mescius/wijmo.react.chart.animation/index.js", "@mescius/wijmo.react.chart.annotation": "npm:@mescius/wijmo.react.chart.annotation/index.js", "@mescius/wijmo.react.chart.finance.analytics": "npm:@mescius/wijmo.react.chart.finance.analytics/index.js", "@mescius/wijmo.react.chart.finance": "npm:@mescius/wijmo.react.chart.finance/index.js", "@mescius/wijmo.react.chart.hierarchical": "npm:@mescius/wijmo.react.chart.hierarchical/index.js", "@mescius/wijmo.react.chart.interaction": "npm:@mescius/wijmo.react.chart.interaction/index.js", "@mescius/wijmo.react.chart.radar": "npm:@mescius/wijmo.react.chart.radar/index.js", "@mescius/wijmo.react.chart": "npm:@mescius/wijmo.react.chart/index.js", "@mescius/wijmo.react.core": "npm:@mescius/wijmo.react.core/index.js", '@mescius/wijmo.react.chart.map': 'npm:@mescius/wijmo.react.chart.map/index.js', "@mescius/wijmo.react.gauge": "npm:@mescius/wijmo.react.gauge/index.js", "@mescius/wijmo.react.grid.detail": "npm:@mescius/wijmo.react.grid.detail/index.js", "@mescius/wijmo.react.grid.filter": "npm:@mescius/wijmo.react.grid.filter/index.js", "@mescius/wijmo.react.grid.grouppanel": "npm:@mescius/wijmo.react.grid.grouppanel/index.js", '@mescius/wijmo.react.grid.search': 'npm:@mescius/wijmo.react.grid.search/index.js', "@mescius/wijmo.react.grid.multirow": "npm:@mescius/wijmo.react.grid.multirow/index.js", "@mescius/wijmo.react.grid.sheet": "npm:@mescius/wijmo.react.grid.sheet/index.js", '@mescius/wijmo.react.grid.transposed': 'npm:@mescius/wijmo.react.grid.transposed/index.js', '@mescius/wijmo.react.grid.transposedmultirow': 'npm:@mescius/wijmo.react.grid.transposedmultirow/index.js', '@mescius/wijmo.react.grid.immutable': 'npm:@mescius/wijmo.react.grid.immutable/index.js', "@mescius/wijmo.react.grid": "npm:@mescius/wijmo.react.grid/index.js", "@mescius/wijmo.react.input": "npm:@mescius/wijmo.react.input/index.js", "@mescius/wijmo.react.olap": "npm:@mescius/wijmo.react.olap/index.js", "@mescius/wijmo.react.viewer": "npm:@mescius/wijmo.react.viewer/index.js", "@mescius/wijmo.react.nav": "npm:@mescius/wijmo.react.nav/index.js", "@mescius/wijmo.react.base": "npm:@mescius/wijmo.react.base/index.js", '@mescius/wijmo.react.barcode.common': 'npm:@mescius/wijmo.react.barcode.common/index.js', '@mescius/wijmo.react.barcode.composite': 'npm:@mescius/wijmo.react.barcode.composite/index.js', '@mescius/wijmo.react.barcode.specialized': 'npm:@mescius/wijmo.react.barcode.specialized/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'react': 'npm:react/index.js', 'react-dom': 'npm:react-dom/index.js', 'react-dom/client': 'npm:react-dom/client.js', "scheduler": "npm:scheduler/index.js", 'redux': 'npm:redux/dist/redux.min.js', 'react-redux': 'npm:react-redux/dist/react-redux.min.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js', "react-use-event-hook": "npm:react-use-event-hook/dist/esm/useEvent.js", }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'jsx' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);