Compare commits
No commits in common. "main" and "v0.30.0" have entirely different histories.
@ -21,7 +21,7 @@
|
||||
"test": "ava"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://source.netsyms.com/PostalPortal/odfjs.git"
|
||||
"url": "https://github.com/odfjs/odfjs.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
|
||||
13
readme.md
13
readme.md
@ -18,7 +18,7 @@ Small lib to parse/understand .odf files (.odt, .ods) in the browser and node.js
|
||||
### Install
|
||||
|
||||
```sh
|
||||
npm i https://github.com/odfjs/odfjs.git#v0.30.0
|
||||
npm i https://github.com/odfjs/odfjs.git#v0.29.0
|
||||
```
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ import {tableRawContentToObjects, tableWithoutEmptyRows, getODSTableRawContent}
|
||||
/**
|
||||
* @param {ArrayBuffer} odsFile - content of an .ods file
|
||||
* @return {Promise<any[]>}
|
||||
*/
|
||||
*/
|
||||
async function getFileData(odsFile){
|
||||
return getODSTableRawContent(odsFile)
|
||||
.then(tableWithoutEmptyRows)
|
||||
@ -38,9 +38,9 @@ async function getFileData(odsFile){
|
||||
}
|
||||
```
|
||||
|
||||
The return value is an array of objects where
|
||||
the **keys** are the column names in the first row and
|
||||
the **values** are automatically converted from the .ods files (which type numbers, strings, booleans and dates)
|
||||
The return value is an array of objects where
|
||||
the **keys** are the column names in the first row and
|
||||
the **values** are automatically converted from the .ods files (which type numbers, strings, booleans and dates)
|
||||
to the appropriate JavaScript value
|
||||
|
||||
|
||||
@ -88,7 +88,7 @@ odf.js proposes a template syntax
|
||||
In an .odt file, write the following:
|
||||
|
||||
```txt
|
||||
Hey {nom}!
|
||||
Hey {nom}!
|
||||
|
||||
Your birthdate is {dateNaissance}
|
||||
```
|
||||
@ -158,3 +158,4 @@ npm run dev
|
||||
I hope to be credited for the work on this repo
|
||||
|
||||
Everything written by me and contributors to this repo is licenced under **CC0 1.0 (Public Domain)**
|
||||
|
||||
|
||||
@ -6,15 +6,11 @@ import {serializeToString, createDocument} from './DOMUtils.js'
|
||||
/** @import {SheetCellRawContent, SheetName, SheetRawContent} from './types.js' */
|
||||
|
||||
const stylesXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<office:document-styles
|
||||
<office:document-styles
|
||||
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
||||
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
||||
office:version="1.2">
|
||||
<office:styles>
|
||||
<style:style style:name="boldcell" style:family="table-cell">
|
||||
<style:text-properties fo:font-weight="bold"/>
|
||||
</style:style>
|
||||
</office:styles>
|
||||
<office:styles/>
|
||||
<office:automatic-styles/>
|
||||
<office:master-styles/>
|
||||
</office:document-styles>`;
|
||||
@ -31,11 +27,11 @@ const manifestXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
* @param {Map<SheetName, SheetRawContent>} sheetsData
|
||||
* @returns {Promise<ArrayBuffer>}
|
||||
*/
|
||||
export async function createOdsFile(sheetsData, currencyData = null) {
|
||||
export async function createOdsFile(sheetsData) {
|
||||
// Create a new zip writer
|
||||
const zipWriter = new ZipWriter(new BlobWriter('application/vnd.oasis.opendocument.spreadsheet'));
|
||||
|
||||
// The “mimetype” file shall be the first file of the zip file.
|
||||
// The “mimetype” file shall be the first file of the zip file.
|
||||
// It shall not be compressed, and it shall not use an 'extra field' in its header.
|
||||
// https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part2-packages/OpenDocument-v1.3-os-part2-packages.html#__RefHeading__752809_826425813
|
||||
zipWriter.add(
|
||||
@ -49,7 +45,7 @@ export async function createOdsFile(sheetsData, currencyData = null) {
|
||||
}
|
||||
);
|
||||
|
||||
const contentXml = generateContentFileXMLString(sheetsData, currencyData);
|
||||
const contentXml = generateContentFileXMLString(sheetsData);
|
||||
zipWriter.add("content.xml", new TextReader(contentXml), {level: 9});
|
||||
|
||||
zipWriter.add("styles.xml", new TextReader(stylesXml));
|
||||
@ -64,10 +60,10 @@ export async function createOdsFile(sheetsData, currencyData = null) {
|
||||
|
||||
/**
|
||||
* Generate the content.xml file with spreadsheet data
|
||||
* @param {Map<SheetName, SheetRawContent>} sheetsData
|
||||
* @param {Map<SheetName, SheetRawContent>} sheetsData
|
||||
* @returns {string}
|
||||
*/
|
||||
function generateContentFileXMLString(sheetsData, currencyData) {
|
||||
function generateContentFileXMLString(sheetsData) {
|
||||
const doc = createDocument('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'office:document-content');
|
||||
const root = doc.documentElement;
|
||||
|
||||
@ -79,52 +75,6 @@ function generateContentFileXMLString(sheetsData, currencyData) {
|
||||
root.setAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0');
|
||||
root.setAttribute('office:version', '1.2');
|
||||
|
||||
const styleNode = doc.createElement("office:automatic-styles");
|
||||
|
||||
var currencyStyleName = "currencyStyle";
|
||||
if (currencyData != null) {
|
||||
currencyStyleName = `currency${currencyData.currencyCode.toUpperCase()}`;
|
||||
const numberStyle = doc.createElement("number:currency-style");
|
||||
numberStyle.setAttribute("style:name", currencyStyleName);
|
||||
|
||||
const numberCurrencySymbolStyle = doc.createElement("number:currency-symbol");
|
||||
numberCurrencySymbolStyle.setAttribute("number:language", "en");
|
||||
numberCurrencySymbolStyle.setAttribute("number:country", currencyData.countryCode.toUpperCase());
|
||||
numberCurrencySymbolStyle.textContent = currencyData.currencySymbol;
|
||||
numberStyle.appendChild(numberCurrencySymbolStyle);
|
||||
|
||||
const numberCurrencyStyle = doc.createElement("number:number");
|
||||
numberCurrencyStyle.setAttribute("number:min-integer-digits", "1");
|
||||
numberCurrencyStyle.setAttribute("number:decimal-places", `${currencyData.decimalPlaces}`);
|
||||
numberCurrencyStyle.setAttribute("number:min-decimal-places", `${currencyData.decimalPlaces}`);
|
||||
numberCurrencyStyle.setAttribute("number:grouping", "true");
|
||||
numberStyle.appendChild(numberCurrencyStyle);
|
||||
|
||||
styleNode.appendChild(numberStyle);
|
||||
|
||||
const currencyCellStyleNode = doc.createElement("style:style");
|
||||
currencyCellStyleNode.setAttribute("style:name", "currencycell");
|
||||
currencyCellStyleNode.setAttribute("style:family", "table-cell");
|
||||
currencyCellStyleNode.setAttribute("style:data-style-name", currencyStyleName);
|
||||
|
||||
const currencyCellTableCellProperties = doc.createElement("style:table-cell-properties");
|
||||
|
||||
currencyCellStyleNode.appendChild(currencyCellTableCellProperties);
|
||||
|
||||
styleNode.appendChild(currencyCellStyleNode);
|
||||
}
|
||||
|
||||
const boldCellStyleNode = doc.createElement("style:style");
|
||||
boldCellStyleNode.setAttribute("style:name", "boldcell");
|
||||
boldCellStyleNode.setAttribute("style:family", "table-cell");
|
||||
const boldCellTextPropsNode = doc.createElement("style:text-properties");
|
||||
boldCellTextPropsNode.setAttribute("fo:font-weight", "bold");
|
||||
boldCellStyleNode.appendChild(boldCellTextPropsNode);
|
||||
styleNode.appendChild(boldCellStyleNode);
|
||||
|
||||
|
||||
root.appendChild(styleNode);
|
||||
|
||||
const bodyNode = doc.createElement('office:body');
|
||||
root.appendChild(bodyNode);
|
||||
|
||||
@ -137,30 +87,8 @@ function generateContentFileXMLString(sheetsData, currencyData) {
|
||||
tableNode.setAttribute('table:name', sheetName);
|
||||
spreadsheetNode.appendChild(tableNode);
|
||||
|
||||
var columnsWidthChars = {};
|
||||
for (let r = 0; r < sheetData.length; r++) {
|
||||
for (let c = 0; c < sheetData[r].length; c++) {
|
||||
var len = ((sheetData[r][c].display ?? sheetData[r][c].value) + "").length;
|
||||
if (typeof columnsWidthChars[c] == "undefined") {
|
||||
columnsWidthChars[c] = len;
|
||||
}
|
||||
columnsWidthChars[c] = Math.max(columnsWidthChars[c], len);
|
||||
}
|
||||
}
|
||||
|
||||
for (var prop in columnsWidthChars) {
|
||||
var columnNode = doc.createElement('table:table-column');
|
||||
columnNode.setAttribute("table:style-name", "colwidth" + columnsWidthChars[prop]);
|
||||
tableNode.appendChild(columnNode);
|
||||
|
||||
var columnWidthNode = doc.createElement("style:style");
|
||||
columnWidthNode.setAttribute("style:name", "colwidth" + columnsWidthChars[prop]);
|
||||
columnWidthNode.setAttribute("style:family", "table-column");
|
||||
const columnWidthPropsNode = doc.createElement("style:table-column-properties");
|
||||
columnWidthPropsNode.setAttribute("style:column-width", `${columnsWidthChars[prop] * 0.26}cm`);
|
||||
columnWidthNode.appendChild(columnWidthPropsNode);
|
||||
styleNode.appendChild(columnWidthNode);
|
||||
}
|
||||
const columnNode = doc.createElement('table:table-column');
|
||||
tableNode.appendChild(columnNode);
|
||||
|
||||
// Iterate through rows
|
||||
sheetData.forEach((row) => {
|
||||
@ -173,10 +101,6 @@ function generateContentFileXMLString(sheetsData, currencyData) {
|
||||
const cellType = convertCellType(cell.type);
|
||||
cellNode.setAttribute('office:value-type', cellType);
|
||||
|
||||
if (cell.style && cell.style == "bold") {
|
||||
cellNode.setAttribute('table:style-name', "boldcell");
|
||||
}
|
||||
|
||||
// Add value attribute based on type
|
||||
if (cell.value !== null && cell.value !== undefined) {
|
||||
switch (cellType) {
|
||||
@ -187,14 +111,6 @@ function generateContentFileXMLString(sheetsData, currencyData) {
|
||||
cellNode.setAttribute('office:value', cell.value.toString());
|
||||
cellNode.setAttribute('office:value-type', 'percentage');
|
||||
break;
|
||||
case 'currency':
|
||||
cellNode.setAttribute('office:value', cell.value.toString());
|
||||
cellNode.setAttribute('office:value-type', 'currency');
|
||||
if (currencyData != null) {
|
||||
cellNode.setAttribute("table:style-name", "currencycell");
|
||||
cellNode.setAttribute('office:currency', currencyData.currencyCode.toUpperCase());
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
cellNode.setAttribute('office:date-value', cell.value.toString());
|
||||
break;
|
||||
@ -210,11 +126,7 @@ function generateContentFileXMLString(sheetsData, currencyData) {
|
||||
|
||||
if (cellType !== 'string') {
|
||||
const textNode = doc.createElement('text:p');
|
||||
if (typeof cell.display != "undefined") {
|
||||
textNode.textContent = cell.display.toString();
|
||||
} else {
|
||||
textNode.textContent = cell.value.toString();
|
||||
}
|
||||
textNode.textContent = cell.value.toString();
|
||||
cellNode.appendChild(textNode);
|
||||
}
|
||||
}
|
||||
@ -229,7 +141,7 @@ function generateContentFileXMLString(sheetsData, currencyData) {
|
||||
|
||||
/**
|
||||
* Convert cell type to OpenDocument format type
|
||||
* @param {SheetCellRawContent['type']} type
|
||||
* @param {SheetCellRawContent['type']} type
|
||||
* @returns {SheetCellRawContent['type']}
|
||||
*/
|
||||
function convertCellType(type) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user