forked from sheetjs/docs.sheetjs.com
		
	
		
			
				
	
	
		
			158 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html>
 | 
						||
<!-- sheetjs (C) 2013-present  SheetJS http://sheetjs.com -->
 | 
						||
<!-- vim: set ts=2: -->
 | 
						||
<html lang="en" style="height: 100%">
 | 
						||
<head>
 | 
						||
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 | 
						||
  <title>SheetJS React Demo</title>
 | 
						||
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
 | 
						||
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
 | 
						||
  <script src="https://unpkg.com/react/umd/react.production.min.js"></script>
 | 
						||
  <script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
 | 
						||
  <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
 | 
						||
  <script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
 | 
						||
  <style>body, #app { height: 100%; }</style>
 | 
						||
</head>
 | 
						||
<body>
 | 
						||
  <div class="container-fluid"><h1><a href="http://sheetjs.com">SheetJS × React Demo</a></h1><br /></div>
 | 
						||
  <div id="app" class="container-fluid"></div>
 | 
						||
  <script type="text/babel">
 | 
						||
    /* sheetjs (C) 2013-present  SheetJS -- http://sheetjs.com */
 | 
						||
    /* Notes:
 | 
						||
       - usage: `ReactDOM.render( <SheetJSApp />, document.getElementById('app') );`
 | 
						||
       - xlsx.full.min.js is loaded in the head of the HTML page
 | 
						||
       - this script should be referenced with type="text/babel"
 | 
						||
       - babel.js in-browser transpiler should be loaded before this script
 | 
						||
    */
 | 
						||
    const { read, writeFile } = XLSX;
 | 
						||
    const { decode_range, encode_col, sheet_to_json, aoa_to_sheet, book_new, book_append_sheet } = XLSX.utils;
 | 
						||
 | 
						||
    /* generate an array of column objects */
 | 
						||
    const make_cols = refstr => Array.from({length: decode_range(refstr).e.c + 1}, (_, i) => ({ name: encode_col(i), key: i}));
 | 
						||
 | 
						||
    /* main component */
 | 
						||
    function SheetJSApp() {
 | 
						||
      const [data, setData] = React.useState([]);
 | 
						||
      const [cols, setCols] = React.useState([]);
 | 
						||
 | 
						||
      const handleFile = (file) => {
 | 
						||
        const reader = new FileReader();
 | 
						||
        reader.onload = (e) => {
 | 
						||
          /* Parse data */
 | 
						||
          const ab = e.target.result;
 | 
						||
          const wb = read(ab, { type: 'array' });
 | 
						||
          /* Get first worksheet */
 | 
						||
          const wsname = wb.SheetNames[0];
 | 
						||
          const ws = wb.Sheets[wsname];
 | 
						||
          /* Convert array of arrays */
 | 
						||
          const data = sheet_to_json(ws, { header: 1 });
 | 
						||
          /* Update state */
 | 
						||
          setData(data);
 | 
						||
          setCols(make_cols(ws['!ref']))
 | 
						||
        };
 | 
						||
        reader.readAsArrayBuffer(file);
 | 
						||
      }
 | 
						||
 | 
						||
      const exportFile = () => {
 | 
						||
        /* convert state to workbook */
 | 
						||
        const ws = aoa_to_sheet(data);
 | 
						||
        const wb = book_new();
 | 
						||
        book_append_sheet(wb, ws, "SheetJS");
 | 
						||
        /* generate XLSX file and send to client */
 | 
						||
        writeFile(wb, "sheetjs.xlsx")
 | 
						||
      };
 | 
						||
 | 
						||
      return (
 | 
						||
        <DragDropFile handleFile={handleFile}>
 | 
						||
          <div className="row"><div className="col-xs-12">
 | 
						||
            <DataInput handleFile={handleFile} />
 | 
						||
          </div></div>
 | 
						||
          <div className="row"><div className="col-xs-12">
 | 
						||
            {data.length ? <button className="btn btn-success" onClick={exportFile}>Export</button> : ""}
 | 
						||
          </div></div>
 | 
						||
          <div className="row"><div className="col-xs-12">
 | 
						||
            <OutTable data={data} cols={cols} />
 | 
						||
          </div></div>
 | 
						||
        </DragDropFile>
 | 
						||
      );
 | 
						||
    }
 | 
						||
 | 
						||
    /* -------------------------------------------------------------------------- */
 | 
						||
 | 
						||
    /*
 | 
						||
      Simple HTML5 file drag-and-drop wrapper
 | 
						||
      usage: <DragDropFile handleFile={handleFile}>...</DragDropFile>
 | 
						||
        handleFile(file:File):void;
 | 
						||
    */
 | 
						||
 | 
						||
    function DragDropFile({ handleFile, children }) {
 | 
						||
      const suppress = (e) => { e.stopPropagation(); e.preventDefault(); };
 | 
						||
      const handleDrop = (e) => {
 | 
						||
        e.stopPropagation(); e.preventDefault();
 | 
						||
        const files = e.dataTransfer.files;
 | 
						||
        if (files && files[0]) handleFile(files[0]);
 | 
						||
      };
 | 
						||
 | 
						||
      return ( <div onDrop={handleDrop} onDragEnter={suppress} onDragOver={suppress}>{children}</div> );
 | 
						||
    }
 | 
						||
 | 
						||
    /*
 | 
						||
      Simple HTML5 file input wrapper
 | 
						||
      usage: <DataInput handleFile={callback} />
 | 
						||
        handleFile(file:File):void;
 | 
						||
    */
 | 
						||
 | 
						||
    function DataInput({ handleFile }) {
 | 
						||
      const handleChange = (e) => {
 | 
						||
        const files = e.target.files;
 | 
						||
        if (files && files[0]) handleFile(files[0]);
 | 
						||
      };
 | 
						||
 | 
						||
      return (
 | 
						||
        <form className="form-inline">
 | 
						||
          <div className="form-group">
 | 
						||
            <label htmlFor="file">Drag or choose a spreadsheet file</label><br />
 | 
						||
            <input type="file" className="form-control" id="file" accept={SheetJSFT} onChange={handleChange} />
 | 
						||
          </div>
 | 
						||
        </form>
 | 
						||
      )
 | 
						||
    }
 | 
						||
    /* list of supported file types */
 | 
						||
    const SheetJSFT = [
 | 
						||
      "xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm"
 | 
						||
    ].map(x => `.${x}`).join(",");
 | 
						||
 | 
						||
    /*
 | 
						||
      Simple HTML Table
 | 
						||
      usage: <OutTable data={data} cols={cols} />
 | 
						||
        data:Array<Array<any> >;
 | 
						||
        cols:Array<{name:string, key:number|string}>;
 | 
						||
    */
 | 
						||
    function OutTable({ data, cols }) {
 | 
						||
      return (
 | 
						||
        <div className="table-responsive">
 | 
						||
          <table className="table table-striped">
 | 
						||
            <thead>
 | 
						||
              <tr>{cols.map((c) => <th key={c.key}>{c.name}</th>)}</tr>
 | 
						||
            </thead>
 | 
						||
            <tbody>
 | 
						||
              {data.map((r, i) => <tr key={i}>
 | 
						||
                {cols.map(c => <td key={c.key}>{r[c.key]}</td>)}
 | 
						||
              </tr>)}
 | 
						||
            </tbody>
 | 
						||
          </table>
 | 
						||
        </div>
 | 
						||
      );
 | 
						||
    }
 | 
						||
 | 
						||
    /* React 18 uses ReactDOM.createRoot; < 18 should use ReactDOM.render */
 | 
						||
    const root_elt = document.getElementById('app');
 | 
						||
    if(typeof ReactDOM.createRoot !== "undefined") {
 | 
						||
      const root = ReactDOM.createRoot(root_elt);
 | 
						||
      root.render(<SheetJSApp/>);
 | 
						||
    } else {
 | 
						||
      ReactDOM.render(<SheetJSApp />, root_elt);
 | 
						||
    }
 | 
						||
  </script>
 | 
						||
</body>
 | 
						||
</html> |