Un tableau

This commit is contained in:
David Bruant 2024-06-15 16:29:16 +02:00
parent d011746d55
commit f27349dcf9
4 changed files with 142 additions and 44 deletions

View File

@ -39,7 +39,7 @@ export default {
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
//production && terser()
],
watch: {
clearScreen: false

View File

@ -1,5 +1,5 @@
<script>
import getTableRawContentFromFile from './getTableRawContentFromFile.js'
import {getTableRawContentFromFile, tableRawContentToObjects} from './getTableRawContentFromFile.js'
const ODS_TYPE = "application/vnd.oasis.opendocument.spreadsheet";
const XLSX_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
@ -12,27 +12,60 @@
$: file = files && files[0]
$: console.log('file', file)
$: tableRawContent = file && getTableRawContentFromFile(file)
$: console.log('tableRawContent', tableRawContent)
$: tableObjectSheets = tableRawContent && tableRawContent.then(tableRawContentToObjects) || []
</script>
<h1>Import fichier .ods et .xslx</h1>
<section>
<h2>Import</h2>
<label>
Fichier à importer:
<input bind:files type="file" id="file-input" accept="{ ['.ods', '.xlsx', ODS_TYPE, XLSX_TYPE].join(',') }" />
</label>
</section>
<section>
<h2>Résultat</h2>
{#await tableObjectSheets}
(fichier en cours d'analyse)
{:then tableObjectSheets}
{#each [...tableObjectSheets] as [sheetName, data]}
<details>
<summary>{sheetName} ({data.length} lignes)</summary>
<table>
<thead>
<tr>
{#each Object.keys(data[0]) as column}
<th>{column}</th>
{/each}
</tr>
</thead>
<tbody>
{#each data as row}
<tr>
{#each Object.keys(data[0]) as column}
<td><div class="cell-content">{row[column]}</div></td>
{/each}
</tr>
{/each}
</tbody>
</table>
</details>
{/each}
{/await}
</section>
<style lang="scss">
:global(main) {
text-align: center;
padding: 1em;
max-width: 240px;
max-width: 80rem;
margin: 0 auto;
@media (min-width: 640px) {
@ -40,4 +73,30 @@
}
}
table{
thead{
tr{
background: #EEE;
}
}
tr{
border-bottom: 1px solid #CCC;
}
td, th{
vertical-align: top;
padding: 0.5rem;
}
td{
.cell-content{
max-height: 6rem;
max-width: 16rem;
overflow: scroll;
}
}
}
</style>

View File

@ -2,7 +2,5 @@ import App from './App.svelte';
const app = new App({
target: document.querySelector('.svelte-main'),
props: {
name: 'from Svelte'
}
props: {}
});

View File

@ -15,7 +15,7 @@ function parseXML(str){
/**
* @typedef TableCellRawContent
* @prop {string} value
* @prop {string | null | undefined} value
* @prop {'float' | 'percentage' | 'currency' | 'date' | 'time' | 'boolean' | 'string' | 'b' | 'd' | 'e' | 'inlineStr' | 'n' | 's' | 'str'} type
*
*/
@ -24,39 +24,6 @@ const ODS_TYPE = "application/vnd.oasis.opendocument.spreadsheet";
const XLSX_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
/**
* Converts a cell value to the appropriate JavaScript type based on its cell type.
* @param {string} value - The value of the cell.
* @param {TableCellRawContent['type']} cellType - The type of the cell.
* @returns {any} The converted value.
*/
function convertCellValue(value, cellType) {
if(value === ''){
return ''
}
switch (cellType) {
case 'float':
case 'percentage':
case 'currency':
case 'n': // number
return parseFloat(value);
case 'date':
case 'd': // date
return new Date(value);
case 'boolean':
case 'b': // boolean
return value === '1' || value === 'true';
case 's': // shared string
case 'inlineStr': // inline string
case 'string':
case 'e': // error
case 'time':
default:
return value;
}
}
/**
* Extracts raw table content from an ODS file.
* @param {File} file - The ODS file.
@ -66,7 +33,6 @@ function convertCellValue(value, cellType) {
*/
async function getTableRawContentFromODSFile(file, unzip, parseXML) {
const zip = await unzip(file);
console.log('zip', zip)
const entries = zip.entries;
// Extract the content.xml file which contains the spreadsheet data
@ -179,7 +145,7 @@ async function getTableRawContentFromXSLXFile(file, unzip, parseXML) {
* @param {File} file
* @returns {Promise<Map<SheetName, TableCellRawContent[][]>>}
*/
export default function getTableRawContentFromFile(file){
export function getTableRawContentFromFile(file){
if(file.type === ODS_TYPE)
return getTableRawContentFromODSFile(file, unzip, parseXML)
@ -190,3 +156,78 @@ export default function getTableRawContentFromFile(file){
}
/**
* Converts a cell value to the appropriate JavaScript type based on its cell type.
* @param {TableCellRawContent} _
* @returns {number | boolean | string | Date} The converted value.
*/
function convertCellValue({value, type}) {
if(value === ''){
return ''
}
if(value === null || value === undefined){
return ''
}
switch (type) {
case 'float':
case 'percentage':
case 'currency':
case 'n': // number
return parseFloat(value);
case 'date':
case 'd': // date
return new Date(value);
case 'boolean':
case 'b': // boolean
return value === '1' || value === 'true';
case 's': // shared string
case 'inlineStr': // inline string
case 'string':
case 'e': // error
case 'time':
default:
return value;
}
}
/**
*
* @param {TableCellRawContent[][]} rawContent
* @returns {any[]}
*/
function rawContentToObjects(rawContent){
let [firstRow, ...dataRows] = rawContent
/** @type {string[]} */
//@ts-expect-error trust me, this is true after the filter
const columns = firstRow.filter(({value}) => typeof value === 'string' && value.length >= 1).map(r => r.value)
return dataRows.map(row => {
const obj = Object.create(null)
let empty = true
columns.forEach((column, i) => {
const rawValue = row[i]
obj[column] = rawValue ? convertCellValue(rawValue) : ''
empty = empty && (obj[column] === '')
})
return empty ? undefined : obj
}).filter(x => x !== undefined) // remove empty rows
}
/**
*
* @param {Map<SheetName, TableCellRawContent[][]>} rawContentSheets
* @returns {Map<SheetName, any[]>}
*/
export function tableRawContentToObjects(rawContentSheets){
return new Map(
[...rawContentSheets].map(([sheetName, rawContent]) => {
return [sheetName, rawContentToObjects(rawContent)]
})
)
}