diff --git a/.babelrc b/.babelrc index a29ac9986..1320b9a32 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,3 @@ { - "presets": [ - "@babel/preset-env" - ] + "presets": ["@babel/preset-env"] } diff --git a/.claude/instructions.md b/.claude/instructions.md index 1e2937315..7df1dff55 100644 --- a/.claude/instructions.md +++ b/.claude/instructions.md @@ -7,17 +7,20 @@ This is a **curated fork** of ExcelJS maintained by Protobi. This document conta **ALWAYS ask for user review before committing code changes.** Do NOT commit automatically, even if: + - Tests pass - Code looks good - Changes seem minor **Workflow:** + 1. Make changes 2. Show user what changed (git diff or summary) 3. **Wait for explicit approval** 4. Then commit and push The user may want to: + - Review the changes - Test manually - Make additional edits @@ -30,12 +33,14 @@ Only exception: purely documentary changes explicitly requested (and even then, **EVERY commit must reference a GitHub issue.** **Workflow:** + 1. Before starting work, check if a relevant issue exists 2. If no issue exists, create one first describing the problem/feature 3. In commit messages, reference the issue using format: `Update #99 Description of change` 4. After committing, add a comment on the issue with the commit hash **Commit Message Format:** + ``` Update #4 Fix XML special character escaping in pivot tables @@ -44,12 +49,14 @@ Detailed description of what was changed and why. ``` **Why:** + - Provides context and discussion history for every change - Makes it easier to track what changes solved which problems - Helps when reviewing git history or creating release notes - Enables better collaboration and code review **Creating Issues:** + ```bash # Create an issue gh issue create --repo protobi/exceljs --title "Brief description" --body "Detailed description" @@ -74,12 +81,14 @@ Use semantic versioning with pre-release identifier: ``` **Rules:** + - Base version matches upstream (e.g., `4.4.0` from exceljs/exceljs) - Pre-release identifier is always `-protobi` - Counter increments for each fork release (`.1`, `.2`, `.3`, etc.) - When upstream releases new version (e.g., 4.5.0), reset counter: `4.5.0-protobi.1` **Examples:** + ``` 4.4.0-protobi.1 ← First fork release based on upstream 4.4.0 4.4.0-protobi.2 ← Second fork release (still based on 4.4.0) @@ -91,6 +100,7 @@ Use semantic versioning with pre-release identifier: **Critical:** npm only picks up changes from git dependencies when `package.json` version changes. In consuming projects using: + ```json "exceljs": "git+https://***@github.com/protobi/exceljs.git" ``` @@ -102,12 +112,14 @@ This has been verified through years of production use with Protobi packages. ### When to Bump Version Bump version for: + - ✅ New features added to the fork - ✅ Bug fixes in fork-specific code - ✅ Adopted upstream PRs that add functionality - ✅ Any change you want consuming projects to pick up Do NOT bump for: + - ❌ Documentation-only changes (README, FORK.md, etc.) - ❌ Internal tooling/CI changes - ❌ Commits that will be reverted @@ -191,12 +203,14 @@ git commit -m "Reset version for upstream PR" ### What Makes a Clean Upstream PR Include: + - ✅ Feature code changes - ✅ Tests for the feature - ✅ Documentation (API docs, usage examples) - ✅ package.json at upstream version (4.4.0) Exclude: + - ❌ Fork identity in README (the note linking to FORK.md is okay) - ❌ FORK.md file - ❌ Fork-specific CONTRIBUTING.md content @@ -235,6 +249,7 @@ git push origin master --tags Use conventional commits for clarity: **For fork releases:** + ``` Release v4.4.0-protobi.2: Add feature X @@ -244,6 +259,7 @@ Release v4.4.0-protobi.2: Add feature X ``` **For features:** + ``` Add support for multiple pivot tables (#1) @@ -252,6 +268,7 @@ Add support for multiple pivot tables (#1) ``` **For upstream PRs:** + ``` Adopt upstream PR #2850: [Feature name] @@ -274,6 +291,7 @@ If tests fail, fix them before releasing. ## Documentation Standards When adding features: + 1. **Code changes** - Implement the feature 2. **Tests** - Add comprehensive tests 3. **README.md** - Document API and usage with examples @@ -318,6 +336,7 @@ git tag -l "v*-protobi*" ## Questions? Refer to: + - [FORK.md](../FORK.md) - Complete fork documentation and workflows - [CONTRIBUTING.md](../CONTRIBUTING.md) - Contribution guidelines - This file - Version and PR management diff --git a/.eslintrc b/.eslintrc index 03557ea7a..1931cff9d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,12 +14,13 @@ }, "rules": { "arrow-parens": ["error", "as-needed"], + "import/extensions": ["off"], "class-methods-use-this": ["off"], "comma-dangle": ["error", {"arrays": "always-multiline", "objects": "always-multiline", "imports": "always-multiline", "exports": "always-multiline", "functions": "never"}], "default-case": ["off"], "func-names": ["off", "never"], "global-require": ["off"], - "max-len": ["error", {"code": 120, "ignoreComments": true, "ignoreStrings": true}], + "max-len": ["error", {"code": 120, "ignoreComments": true, "ignoreStrings": true, "ignoreTemplateLiterals": true}], "no-console": ["error", { "allow": ["warn"] }], "no-continue": ["off"], "no-mixed-operators": ["error", {"allowSamePrecedence": true}], @@ -41,9 +42,9 @@ "prefer-destructuring": ["warn", {"array": false, "object": true}], "prefer-object-spread": ["off"], "prefer-rest-params": ["off"], - "quotes": ["error", "single"], + "quotes": ["error", "single", {"avoidEscape": true}], "semi": ["error", "always"], - "space-before-function-paren": ["error", {"anonymous": "never", "named": "never", "asyncArrow": "always"}], + "space-before-function-paren": ["error", {"anonymous": "ignore", "named": "never", "asyncArrow": "always"}], "strict": ["off"] } } diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dccc9a560..5b23939b6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -27,7 +27,6 @@ expect(ws.getCell('A1').value).to.equal(7); - ## Possible solution (optional, but very helpful): ```javascript diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 4209929eb..e8ba47d6e 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -2,7 +2,7 @@ name: 💬 Questions / Help title: '[Q] PLEASE USE DISCUSSIONS' label: ':speech_balloon: Question' -about: https://github.com/exceljs/exceljs/discussions/categories/q-a +about: https://github.com/exceljs/exceljs/discussions/categories/q-a --- ## 💬 Questions and Help diff --git a/.github/workflows/asset-size.yml b/.github/workflows/asset-size.yml index f9c813146..9ad0f964e 100644 --- a/.github/workflows/asset-size.yml +++ b/.github/workflows/asset-size.yml @@ -13,7 +13,7 @@ jobs: fetch-depth: 0 - uses: chrysanthos/simple-asset-size-reporter@1.0.2 with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" + repo-token: '${{ secrets.GITHUB_TOKEN }}' files: '["dist/*.js"]' - with-same: "false" - build-assets: "npm run install-build" + with-same: 'false' + build-assets: 'npm run install-build' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7e696d799..30289bea3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,9 +2,9 @@ name: Tests on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ '**' ] + branches: ['**'] jobs: test: diff --git a/.prettierrc b/.prettierrc index 9f4d9560f..d49c5c4f3 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,7 @@ { "bracketSpacing": false, "printWidth": 100, - "trailingComma": "all", + "trailingComma": "es5", "arrowParens": "avoid", "singleQuote": true } diff --git a/CLAUDE.md b/CLAUDE.md index 3ab0b5421..2fce33a54 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1 +1 @@ -- 2885 \ No newline at end of file +- 2885 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0ba3f8965..206b4861f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,6 +87,7 @@ npm run test:coverage ## Questions? Open an issue! But remember: + - This fork serves our production needs first - We can't provide general Excel library support - Response times may vary based on our workload diff --git a/FORK.md b/FORK.md index 216edd925..2303d9b1d 100644 --- a/FORK.md +++ b/FORK.md @@ -5,6 +5,7 @@ This is a **temporary fork** of [exceljs/exceljs](https://github.com/exceljs/exc ## Why This Fork Exists Upstream exceljs has 100+ open PRs, some over a year old. We needed these fixes for production use, so we: + 1. Adopted well-tested upstream PRs 2. Added critical pivot table features 3. Published to npm for community benefit @@ -35,6 +36,7 @@ This AI-assisted workflow enables rapid response to community issues while maint Implements complete round-trip preservation for Excel files containing pivot tables, charts, and drawings. Previously, reading an Excel file with pivot tables/charts and writing it back would result in Excel corruption warnings and loss of pivot table/chart data. **Hybrid Preservation Approach:** + - Stores raw XML for pivot tables, charts, and drawings - Extracts minimal metadata (cacheId, relationships) for structural integrity - Doesn't attempt to fully model complex Excel structures @@ -66,6 +68,7 @@ Implements complete round-trip preservation for Excel files containing pivot tab - Fixes row height discrepancies during round-trip **Implementation Details:** + - 16 files modified, 593 insertions, 40 deletions - Added `test/test-roundtrip-pivot.js` for verification - Updated test expectations for dyDescent preservation @@ -73,6 +76,7 @@ Implements complete round-trip preservation for Excel files containing pivot tab - Relationship mappings preserved correctly **Testing:** + - ✅ 1091/1091 tests passing (unit + integration + end-to-end) - ✅ Round-trip test with real-world pivot table/chart files - ✅ Excel opens files without corruption warnings @@ -80,6 +84,7 @@ Implements complete round-trip preservation for Excel files containing pivot tab - ✅ Charts display correctly after round-trip **Known Limitations:** + - Write-only pivot table creation still supported (existing functionality) - Reading/modifying existing pivot table definitions not yet implemented - This implementation enables preservation, not programmatic access @@ -92,16 +97,19 @@ Implements complete round-trip preservation for Excel files containing pivot tab Fixes a critical bug where comment protection properties (`locked`, `lockText`) and positioning (`editAs`) were not being parsed correctly during file reading, causing them to return `null` instead of their actual values. **Root Cause:** + - SAX XML parser strips `x:` namespace prefix (Excel namespace) but preserves `v:` prefix (VML namespace) - VML xform classes were using prefixed tag names (`x:Locked`, `x:ClientData`) in their maps - Parser delivered unprefixed tag names (`Locked`, `ClientData`), causing lookup failures **The Fix:** + - Updated 5 VML xform classes to use unprefixed tag names for parsing - Render methods still write prefixed XML for Excel compatibility - Added comments documenting the SAX parser behavior **Files Modified:** + - `lib/xlsx/xform/comment/vml-client-data-xform.js` - `lib/xlsx/xform/comment/vml-shape-xform.js` - `lib/xlsx/xform/comment/vml-anchor-xform.js` @@ -109,6 +117,7 @@ Fixes a critical bug where comment protection properties (`locked`, `lockText`) - `lib/xlsx/xform/comment/style/vml-position-xform.js` **Testing:** + - ✅ 1091/1091 tests passing (vs 1089 passing before fix) - ✅ Fixed 2 previously failing integration tests: - "writes notes" - comment protection properties now round-trip correctly @@ -116,12 +125,14 @@ Fixes a critical bug where comment protection properties (`locked`, `lockText`) - ✅ Verified this bug also exists in upstream ExcelJS (not fixed there yet) **Impact:** + - Comment protection properties (`note.protection.locked`, `note.protection.lockText`) now parse correctly - Comment margins (`note.margins`) now preserve correctly during round-trip - Comment positioning (`note.editAs`) now reads back correctly - Excel files with protected comments can now be read and written without losing properties **Related Issues:** + - Inspired by [ExcelTS Issue #41](https://github.com/cjnoname/excelts/issues/41) - Addresses Excel corruption: "Removed Part: /xl/pivotTables/pivotTable1.xml" - Fixes missing content type declarations @@ -158,6 +169,7 @@ Fixes a critical bug where comment protection properties (`locked`, `lockText`) - glob 7.x remains only in devDependencies (acceptable) **Testing:** + - ✅ 884/884 unit tests passing - ✅ Integration tests passing - ✅ End-to-end tests passing @@ -180,6 +192,7 @@ Fixes a critical bug where comment protection properties (`locked`, `lockText`) - Provide default color: Excel blue `#638EC6` **Testing:** + - Added integration test with real HAN CELL file - Added unit tests for data bar default values - All 198 tests passing (2 pre-existing unrelated failures) @@ -199,6 +212,7 @@ Fixes a critical bug where comment protection properties (`locked`, `lockText`) - Browser builds now CSP-compliant for modern build tools (Vite, Webpack 5+) **Testing:** + - All existing tests passing - Verified dist bundles contain no eval/runInThisContext calls @@ -211,10 +225,12 @@ Fixes a critical bug where comment protection properties (`locked`, `lockText`) **Security & Dependency Updates** **Production Dependencies:** + - `archiver`: ^5.0.0 → ^5.3.2 - `unzipper`: 0.10.11 → 0.12.3 **Dev Dependencies (Major Updates):** + - `mocha`: ^7.2.0 → ^11.7.5 (fixes ReDoS in debug, js-yaml, minimatch) - `chai-xml`: ^0.3.2 → ^0.4.1 (fixes xml2js prototype pollution) - `got`: ^9.0.0 → ^11.8.6 (downgraded from 14 for test compatibility) @@ -224,11 +240,13 @@ Fixes a critical bug where comment protection properties (`locked`, `lockText`) - `prettier-eslint-cli`: ^5.0.0 → ^8.0.1 **Security Improvements:** -- Reduced npm audit vulnerabilities from 38 → 15 + +- Reduced npm audit vulnerabilities from 38 → 15 - All remaining vulnerabilities are in dev/test dependencies only - No production code security issues **Testing:** + - ✅ Unit tests: 883 passing, 1 pending - ✅ Integration tests: 198 passing - ✅ End-to-end tests: 1 passing @@ -236,13 +254,15 @@ Fixes a critical bug where comment protection properties (`locked`, `lockText`) - ⚠️ Browser tests: Disabled (puppeteer@19 compatibility issues) **Known Limitations:** + - `glob@7.x` remains in dependency tree (deprecated but no active CVEs) - Only affects glob 10.x-11.x CLI (CVE-2025-64756), not 7.x library API - - Upgrading to archiver 7.x requires StreamBuf refactoring (_read/_write methods) + - Upgrading to archiver 7.x requires StreamBuf refactoring (\_read/\_write methods) - Browser tests disabled via `.disable-test-browser` (puppeteer hangs) - `got` kept at v11 instead of v14 due to breaking API changes in end-to-end tests **Related Issues:** + - [#11](https://github.com/protobi/exceljs/issues/11) - npm audit vulnerabilities (protobi fork) - [#2984](https://github.com/exceljs/exceljs/issues/2984) - Security vulnerabilities in transitive dependencies (upstream) - [#3006](https://github.com/exceljs/exceljs/issues/3006) - glob 7.x dependency discussion (upstream) @@ -261,46 +281,46 @@ Multiple pivot tables support, pivot table count metric, streaming limitations d ### ✅ Features Already Submitted to Upstream (Waiting for Merge) -| Feature/Fix | Our Issue | Upstream PR | Status | Date | -|-------------|-----------|-------------|--------|------| -| Pivot table count metric | [#12](https://github.com/protobi/exceljs/issues/12) | [#2885](https://github.com/exceljs/exceljs/pull/2885) | ⏳ Open | Feb 2025 | -| Boolean XML parsing fix | [#18](https://github.com/protobi/exceljs/issues/18) | [#2851](https://github.com/exceljs/exceljs/pull/2851) | ⏳ Open | Nov 2024 | -| ExcelToDate validation | [#19](https://github.com/protobi/exceljs/issues/19) | [#2956](https://github.com/exceljs/exceljs/pull/2956) | ⏳ Open | Aug 2025 | -| DynamicFilter parsing | [#20](https://github.com/protobi/exceljs/issues/20) | [#2973](https://github.com/exceljs/exceljs/pull/2973) | ⏳ Open | Sep 2025 | -| SharedString fix | [#21](https://github.com/protobi/exceljs/issues/21) | [#2915](https://github.com/exceljs/exceljs/pull/2915) | ⏳ Open | Apr 2025 | -| Autofilter undefined guard | [#22](https://github.com/protobi/exceljs/issues/22) | [#2978](https://github.com/exceljs/exceljs/pull/2978) | ⏳ Open (partial) | Sep 2025 | -| Image reuse fix | [#24](https://github.com/protobi/exceljs/issues/24) | [#2876](https://github.com/exceljs/exceljs/pull/2876) | ⏳ Open | Feb 2024 | -| Conditional formatting + hyperlinks corruption fix | [#25](https://github.com/protobi/exceljs/issues/25) | [#2803](https://github.com/exceljs/exceljs/pull/2803) | ⏳ Open | Sep 2024 | -| Conditional formatting stopIfTrue & operators | [#26](https://github.com/protobi/exceljs/issues/26) | [#2736](https://github.com/exceljs/exceljs/pull/2736) | ⏳ Open | Jul 2024 | +| Feature/Fix | Our Issue | Upstream PR | Status | Date | +| -------------------------------------------------- | --------------------------------------------------- | ----------------------------------------------------- | ----------------- | -------- | +| Pivot table count metric | [#12](https://github.com/protobi/exceljs/issues/12) | [#2885](https://github.com/exceljs/exceljs/pull/2885) | ⏳ Open | Feb 2025 | +| Boolean XML parsing fix | [#18](https://github.com/protobi/exceljs/issues/18) | [#2851](https://github.com/exceljs/exceljs/pull/2851) | ⏳ Open | Nov 2024 | +| ExcelToDate validation | [#19](https://github.com/protobi/exceljs/issues/19) | [#2956](https://github.com/exceljs/exceljs/pull/2956) | ⏳ Open | Aug 2025 | +| DynamicFilter parsing | [#20](https://github.com/protobi/exceljs/issues/20) | [#2973](https://github.com/exceljs/exceljs/pull/2973) | ⏳ Open | Sep 2025 | +| SharedString fix | [#21](https://github.com/protobi/exceljs/issues/21) | [#2915](https://github.com/exceljs/exceljs/pull/2915) | ⏳ Open | Apr 2025 | +| Autofilter undefined guard | [#22](https://github.com/protobi/exceljs/issues/22) | [#2978](https://github.com/exceljs/exceljs/pull/2978) | ⏳ Open (partial) | Sep 2025 | +| Image reuse fix | [#24](https://github.com/protobi/exceljs/issues/24) | [#2876](https://github.com/exceljs/exceljs/pull/2876) | ⏳ Open | Feb 2024 | +| Conditional formatting + hyperlinks corruption fix | [#25](https://github.com/protobi/exceljs/issues/25) | [#2803](https://github.com/exceljs/exceljs/pull/2803) | ⏳ Open | Sep 2024 | +| Conditional formatting stopIfTrue & operators | [#26](https://github.com/protobi/exceljs/issues/26) | [#2736](https://github.com/exceljs/exceljs/pull/2736) | ⏳ Open | Jul 2024 | **Total:** 9 PRs adopted from upstream, waiting for official merge ### 📝 Fork-Specific Features (Submitted to Upstream) -| Feature/Fix | Our Issue | Upstream PR | Status | Date | -|-------------|-----------|-------------|--------|------| -| Multiple pivot tables support | [#5](https://github.com/protobi/exceljs/issues/5) | [#2995](https://github.com/exceljs/exceljs/pull/2995) | ⏳ Open | Nov 2025 | -| XML special character escaping | [#3](https://github.com/protobi/exceljs/issues/3) | [#2996](https://github.com/exceljs/exceljs/pull/2996) | ⏳ Open | Nov 2025 | -| Pivot table column width control | [#8](https://github.com/protobi/exceljs/issues/8) | [#2997](https://github.com/exceljs/exceljs/pull/2997) | ⏳ Open | Nov 2025 | -| HAN CELL file support | - | [#3017](https://github.com/exceljs/exceljs/pull/3017) | ⏳ Open | Jan 2026 | -| Data bar conditional formatting defaults | - | [#3018](https://github.com/exceljs/exceljs/pull/3018) | ⏳ Open | Jan 2026 | +| Feature/Fix | Our Issue | Upstream PR | Status | Date | +| ---------------------------------------- | ------------------------------------------------- | ----------------------------------------------------- | ------- | -------- | +| Multiple pivot tables support | [#5](https://github.com/protobi/exceljs/issues/5) | [#2995](https://github.com/exceljs/exceljs/pull/2995) | ⏳ Open | Nov 2025 | +| XML special character escaping | [#3](https://github.com/protobi/exceljs/issues/3) | [#2996](https://github.com/exceljs/exceljs/pull/2996) | ⏳ Open | Nov 2025 | +| Pivot table column width control | [#8](https://github.com/protobi/exceljs/issues/8) | [#2997](https://github.com/exceljs/exceljs/pull/2997) | ⏳ Open | Nov 2025 | +| HAN CELL file support | - | [#3017](https://github.com/exceljs/exceljs/pull/3017) | ⏳ Open | Jan 2026 | +| Data bar conditional formatting defaults | - | [#3018](https://github.com/exceljs/exceljs/pull/3018) | ⏳ Open | Jan 2026 | **Status:** All original contributions submitted, waiting for upstream review -### Community Fork Contributions (Adopted & Submitted) +### Community Fork Contributions (Adopted & Submitted) -| Feature/Fix | Our Issue | Source | Upstream PR | Status | Date | -|-------------|-----------|--------|-------------|--------|------| +| Feature/Fix | Our Issue | Source | Upstream PR | Status | Date | +| ------------------ | --------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------- | ------- | -------- | | Table addRow() fix | [#23](https://github.com/protobi/exceljs/issues/23) | [rmartin93/exceljs-fork](https://github.com/rmartin93/exceljs-fork) | [#2998](https://github.com/exceljs/exceljs/pull/2998) | ⏳ Open | Nov 2025 | **Status:** Adopted from community fork, submitted to upstream -### Security & Maintenance +### Security & Maintenance -| Feature/Fix | Our Issue | Upstream PR | Status | -|-------------|-----------|-------------|--------| -| Add package-lock.json | [#10](https://github.com/protobi/exceljs/issues/10) | - | Fork-specific | -| Run npm audit fix | [#11](https://github.com/protobi/exceljs/issues/11) | - | Fork-specific | +| Feature/Fix | Our Issue | Upstream PR | Status | +| --------------------- | --------------------------------------------------- | ----------- | ------------- | +| Add package-lock.json | [#10](https://github.com/protobi/exceljs/issues/10) | - | Fork-specific | +| Run npm audit fix | [#11](https://github.com/protobi/exceljs/issues/11) | - | Fork-specific | **Status:** Security improvements for our fork deployment @@ -329,6 +349,7 @@ npm install exceljs ### When to Switch Back to Official Monitor these conditions: + 1. Upstream releases version with our features 2. All critical PRs merged (#2885, #2915, etc.) 3. Our unique features submitted and merged @@ -355,6 +376,7 @@ npm install exceljs When upstream catches up, we will: 1. **Add deprecation notice** to npm package + ```bash npm deprecate @protobi/exceljs "Use official 'exceljs' package - our changes have been merged upstream" ``` @@ -374,21 +396,25 @@ When upstream catches up, we will: **Why it matters:** Upstream only supports one pivot table per workbook. We support multiple pivot tables from the same source data with unique cache IDs. **Code:** + ```javascript // ✅ Works in @protobi/exceljs // ❌ Crashes in official exceljs const worksheet1 = workbook.addWorksheet('Data'); -worksheet1.addRows([/* data */]); +worksheet1.addRows([ + /* data */ +]); const worksheet2 = workbook.addWorksheet('Pivot1'); -worksheet2.addPivotTable({ sourceSheet: worksheet1, /* ... */ }); +worksheet2.addPivotTable({sourceSheet: worksheet1 /* ... */}); const worksheet3 = workbook.addWorksheet('Pivot2'); -worksheet3.addPivotTable({ sourceSheet: worksheet1, /* ... */ }); // Works! +worksheet3.addPivotTable({sourceSheet: worksheet1 /* ... */}); // Works! ``` **Files changed:** + - `lib/doc/pivot-table.js` - Unique cache IDs per pivot table - `lib/xlsx/xform/book/workbook-xform.js` - Support multiple cache definitions @@ -399,6 +425,7 @@ worksheet3.addPivotTable({ sourceSheet: worksheet1, /* ... */ }); // Works! **Why it matters:** Count is a fundamental Excel pivot table aggregation. Upstream only supports sum. **Code:** + ```javascript // ✅ Works in @protobi/exceljs // ❌ Not available in official exceljs (yet) @@ -413,6 +440,7 @@ worksheet.addPivotTable({ ``` **Files changed:** + - `lib/doc/pivot-table.js` - Accept count metric - `lib/xlsx/xform/pivot-table/pivot-table-xform.js` - Generate XML with subtotal="count" @@ -423,6 +451,7 @@ worksheet.addPivotTable({ **Why it matters:** Loading Excel files with tables and adding rows to them crashes in official exceljs. This is critical for template-based workflows. **Code:** + ```javascript // ✅ Works in @protobi/exceljs // ❌ Crashes in official exceljs with "Cannot read properties of undefined (reading 'length')" @@ -441,12 +470,14 @@ await workbook.xlsx.writeFile('output.xlsx'); ``` **What it fixes:** + - "Cannot read properties of undefined (reading 'length')" error - Missing worksheet references in loaded tables - Table references not expanding dynamically when rows are added - Excel filter buttons disappearing after save **Files changed:** + - `lib/doc/table.js` - Dynamic table reference updates, autoFilterRef handling - `lib/doc/worksheet.js` - Table loading compatibility fixes @@ -463,12 +494,14 @@ See "Status Tracking" section above for 6 bug fixes adopted from upstream PRs. This fork maintains **100% API compatibility** with official exceljs. **What this means:** + - ✅ Drop-in replacement: `require('exceljs')` works identically - ✅ All official features work exactly the same - ✅ Additional features are opt-in (won't break existing code) - ✅ Switching back to official requires zero code changes **Version mapping:** + ``` Official exceljs: 4.4.0 This fork: 4.4.0-protobi.2 @@ -492,6 +525,7 @@ Please contribute to **upstream exceljs**, not this fork! ### For Fork-Specific Issues Only use our repo for: + - Issues with our specific features (#5, #8) - Questions about migration - Fork maintenance @@ -515,6 +549,7 @@ npm run test:integration -- --grep "Pivot Tables" ### Test Updates vs Upstream **New Test Files Added:** + - `spec/integration/workbook/pivot-tables-with-count.spec.js` (78 lines) - Tests pivot table with `metric: 'count'` feature - Validates XML generation for count aggregation @@ -524,11 +559,13 @@ npm run test:integration -- --grep "Pivot Tables" - Validates same image added multiple times maintains correct references **Test Infrastructure Changes:** + - Browser tests disabled (puppeteer compatibility issues with updated dependencies) - Dev test dependencies updated: mocha 7→11, chai-xml 0.3→0.4 - End-to-end tests: got API updated (v9→v11) **Test Results:** + - Unit tests: 883 passing, 1 pending (unchanged from upstream) - Integration tests: 198 passing (includes 2 new tests above) - End-to-end tests: 1 passing @@ -543,10 +580,12 @@ npm run test:integration -- --grep "Pivot Tables" ### 4.4.0-protobi.2 (2025-11-07) **Added:** + - Pivot table count metric (upstream PR #2885) - 5 bug fixes from upstream PRs **Fixed:** + - Boolean XML attribute parsing (#2851) - ExcelToDate validation (#2956) - DynamicFilter parsing (#2973) @@ -554,12 +593,14 @@ npm run test:integration -- --grep "Pivot Tables" - Autofilter undefined guard (#2978) **Security:** + - Added package-lock.json - Ran npm audit fix (reduced vulnerabilities) ### 4.4.0-protobi.1 (2025-11-06) **Initial fork release:** + - Multiple pivot tables from same source - XML special character escaping fixes - Column width control for pivot tables @@ -569,11 +610,13 @@ npm run test:integration -- --grep "Pivot Tables" ## Monitoring Upstream We actively monitor upstream for: + 1. **Our PRs being merged** - Track at https://github.com/exceljs/exceljs/pulls 2. **New releases** - Watch https://github.com/exceljs/exceljs/releases 3. **Breaking changes** - Review changelogs for compatibility **Current watch list:** + - 9 adopted PRs awaiting merge (#2851, #2876, #2915, #2956, #2973, #2978, #2885, #2803, #2736) - 3 original PRs awaiting merge (#2995, #2996, #2997) - 1 community fork contribution awaiting merge (#2998) @@ -589,6 +632,7 @@ We actively monitor upstream for: - **Questions:** [GitHub Discussions](https://github.com/protobi/exceljs/discussions) For official exceljs support: + - Upstream discussions: https://github.com/exceljs/exceljs/discussions --- diff --git a/MODEL.md b/MODEL.md index 36d54bf5b..a43a47d11 100644 --- a/MODEL.md +++ b/MODEL.md @@ -6,9 +6,9 @@ The workbook and its components define a simple JavaScript Object model which ca ```javascript { - worksheets: [ - // array of worksheet models - ] + worksheets: [ + // array of worksheet models + ]; } ``` diff --git a/README.md b/README.md index 1c8e80eab..a51d8adec 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,11 @@ Reverse engineered from Excel spreadsheet files as a project. ## Why Use This Fork? If you need **today**: -- Multiple pivot tables from same source data -- Pivot table count metric (`metric: 'count'`) -- **Pivot table and chart round-trip preservation** (read files with existing pivot tables/charts, write them back without corruption) -- Critical bug fixes (XML parsing, date handling, streaming) + +- Multiple pivot tables from same source data +- Pivot table count metric (`metric: 'count'`) +- **Pivot table and chart round-trip preservation** (read files with existing pivot tables/charts, write them back without corruption) +- Critical bug fixes (XML parsing, date handling, streaming) All features are submitted to upstream. [See merge status →](FORK.md) @@ -51,15 +52,17 @@ See [FORK.md](FORK.md) for detailed tracking of upstream PRs. **Latest Version:** 4.4.0-protobi.9 (Feb 2026) This fork receives active security maintenance: -- Dependencies regularly updated -- Security vulnerabilities addressed (60% reduction in latest release) -- All core tests passing (unit, integration, end-to-end) + +- Dependencies regularly updated +- Security vulnerabilities addressed (60% reduction in latest release) +- All core tests passing (unit, integration, end-to-end) See [FORK.md Release History](FORK.md#fork-release-history) for details. ## Fork Release Notes **4.4.0-protobi.9** (February 2026) - Pivot Table & Chart Round-Trip Preservation + Critical Bug Fixes + - **Round-trip preservation for pivot tables and charts** - Read Excel files with existing pivot tables and charts, write them back without corruption - Hybrid preservation approach: stores raw XML while extracting minimal metadata for structural integrity - Preserves pivot table cache definitions, cache records, and relationships @@ -70,11 +73,13 @@ See [FORK.md Release History](FORK.md#fork-release-history) for details. - All 1091 tests passing **4.4.0-protobi.8** (January 2026) + - Form Control Checkbox support - Page fields for pivot tables - Archiver upgrade to 7.x (security fixes) **4.4.0-protobi.5** (December 2025) + - Security & dependency updates - Reduced vulnerabilities by 60% @@ -82,19 +87,19 @@ See [FORK.md](FORK.md#fork-release-history) for detailed changelog. ## Commercial Support -This is our fork with features we need. Use at your own risk. +This is our fork with features we need. Use at your own risk. We maintain what we require and share the code publicly in case it's useful to others. That said, we've put a fair bit of time to understanding ExcelJS. -If there are features or bug fixes that are important to your business, -we can offer professional support for consulting, and priority bug fixes. +If there are features or bug fixes that are important to your business, +we can offer professional support for consulting, and priority bug fixes. Contact: [info@protobi.com](mailto:info@protobi.com) --- # Translations -* [中文文档](README_zh.md) +- [中文文档](README_zh.md) # Installation @@ -104,49 +109,49 @@ npm install exceljs # New Features! -* **Multiple Pivot Tables Support** - The library now supports adding multiple pivot tables per workbook. Previously limited to one pivot table per file, you can now create as many pivot tables as needed across different worksheets. See [Pivot Tables](#pivot-tables) for details. -* Merged [Add pivot table with limitations #2551](https://github.com/exceljs/exceljs/pull/2551).
Many thanks to Protobi and Michael for this contribution! -* Merged [fix: styles rendering in case when "numFmt" is present in conditional formatting rules (resolves #1814) #1815](https://github.com/exceljs/exceljs/pull/1815).
Many thanks to [@andreykrupskii](https://github.com/andreykrupskii) for this contribution! -* Merged [inlineStr cell type support #1575 #1576](https://github.com/exceljs/exceljs/pull/1576).
Many thanks to [@drdmitry](https://github.com/drdmitry) for this contribution! -* Merged [Fix parsing of boolean attributes #1849](https://github.com/exceljs/exceljs/pull/1849).
Many thanks to [@bno1](https://github.com/bno1) for this contribution! -* Merged [add optional custom auto-filter to table #1670](https://github.com/exceljs/exceljs/pull/1670).
Many thanks to [@thambley](https://github.com/thambley) for this contribution! -* Merged [Deep copy inherited style #1850](https://github.com/exceljs/exceljs/pull/1850).
Many thanks to [@ikzhr](https://github.com/ikzhr) for this contribution! -* Merged [Upgrade actions/cache and actions/setup-node #1846](https://github.com/exceljs/exceljs/pull/1846).
Many thanks to [@cclauss](https://github.com/cclauss) for this contribution! -* Merged [Check object keys in isEqual #1831](https://github.com/exceljs/exceljs/pull/1831).
Many thanks to [@bno1](https://github.com/bno1) for this contribution! -* Merged [Add v17 to testing workflow #1856](https://github.com/exceljs/exceljs/pull/1856).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! -* Merged [Upgrade jszip to its latest version to date. This version does not have any vulnerability found by Snyk so far #1895](https://github.com/exceljs/exceljs/pull/1895).
Many thanks to [@ValerioSevilla](https://github.com/ValerioSevilla) for this contribution! -* Merged [Update README.md #1677](https://github.com/exceljs/exceljs/pull/1677).
Many thanks to [@xjrcode](https://github.com/xjrcode) for this contribution! -* Merged [(docs): set prototype of RegExp correctly. #1700](https://github.com/exceljs/exceljs/pull/1700).
Many thanks to [@joeldenning](https://github.com/joeldenning) for this contribution! -* Merged [Added timeouts to github actions #1733](https://github.com/exceljs/exceljs/pull/1733).
Many thanks to [@alexbjorlig](https://github.com/alexbjorlig) for this contribution! -* Merged [fix issue 1676 #1701](https://github.com/exceljs/exceljs/pull/1701).
Many thanks to [@skypesky](https://github.com/skypesky) for this contribution! -* Merged [ExcelJS/ExcelJS#2237 : Update CI Tests, Drop support for Node v8 #2242](https://github.com/exceljs/exceljs/pull/2242).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! -* Merged [Fix types for getWorksheet() #2223](https://github.com/exceljs/exceljs/pull/2223).
Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution! -* Merged [add characters cannot be used for worksheet name #2126](https://github.com/exceljs/exceljs/pull/2126).
Many thanks to [@tkm-kj](https://github.com/tkm-kj) for this contribution! -* Merged [Fix issue #1753 Reject promise when workbook reader is writing to temporary file stream and error occurs #1756](https://github.com/exceljs/exceljs/pull/1756).
Many thanks to [@pauliusg](https://github.com/pauliusg) for this contribution! -* Merged [README.md to have correct link for Streaming XLSX #2186](https://github.com/exceljs/exceljs/pull/2186).
Many thanks to [@wulfsolter](https://github.com/wulfsolter) for this contribution! -* Merged [Added a polyfill of promise.finally to support lower versions of Firefox. #1982](https://github.com/exceljs/exceljs/pull/1982).
Many thanks to [@DemoJj](https://github.com/DemoJj) for this contribution! -* Merged [Fix read this.worksheet before assign it #1934](https://github.com/exceljs/exceljs/pull/1934).
Many thanks to [@ZyqGitHub1](https://github.com/ZyqGitHub1) for this contribution! -* Merged [chore: upgrade jszip to ^3.10.1 #2211](https://github.com/exceljs/exceljs/pull/2211).
Many thanks to [@jarrod-cocoon](https://github.com/jarrod-cocoon) for this contribution! -* Merged [fixed spelling error in README.md file #2208](https://github.com/exceljs/exceljs/pull/2208).
Many thanks to [@HugoP27](https://github.com/HugoP27) for this contribution! -* Merged [fix: Fix xlsx.writeFile() not catching error when error occurs #2244](https://github.com/exceljs/exceljs/pull/2244).
Many thanks to [@zurmokeeper](https://github.com/zurmokeeper) for this contribution! -* Merged [Improve worksheets' naming validation logic. #2257](https://github.com/exceljs/exceljs/pull/2257).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! -* Merged [fix issue 2125 - spliceRows remove last row #2140](https://github.com/exceljs/exceljs/pull/2140).
Many thanks to [@babu-ch](https://github.com/babu-ch) for this contribution! -* Merged [fix: fix the loss of column attributes due to incorrect column order #2222](https://github.com/exceljs/exceljs/pull/2222).
Many thanks to [@cpaiyueyue](https://github.com/cpaiyueyue) for this contribution! -* Merged [Fix: Sheet Properties Types #2327](https://github.com/exceljs/exceljs/pull/2327).
Many thanks to [@albeniraouf](https://github.com/albeniraouf) for this contribution! -* Merged [Use node 18 LTS for tsc, and benchmark. Add node 20. to test matrix. … #2354](https://github.com/exceljs/exceljs/pull/2354).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! -* Merged [Add missing tooltip attribute to CellHyperlinkValue index.d.ts #2350](https://github.com/exceljs/exceljs/pull/2350).
Many thanks to [@NiklasPor](https://github.com/NiklasPor) for this contribution! -* Merged [Increase resilience to generating large workbooks #2320](https://github.com/exceljs/exceljs/pull/2320).
Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution! -* Merged [repair all 'c2fo.io' links ('c2fo.github.io') #2324](https://github.com/exceljs/exceljs/pull/2324).
Many thanks to [@justintunev7](https://github.com/justintunev7) for this contribution! -* Merged [fix: fix type definitions about last column, formula values and protection #2309](https://github.com/exceljs/exceljs/pull/2309).
Many thanks to [@gltjk](https://github.com/gltjk) for this contribution! -* Merged [fix: add spinCount field for WorksheetProtection type #2284](https://github.com/exceljs/exceljs/pull/2284).
Many thanks to [@damingerdai](https://github.com/damingerdai) for this contribution! -* Merged [Add type definition for WorksheetModel.merges #2281](https://github.com/exceljs/exceljs/pull/2281).
Many thanks to [@ytjmt](https://github.com/ytjmt) for this contribution! +- **Multiple Pivot Tables Support** - The library now supports adding multiple pivot tables per workbook. Previously limited to one pivot table per file, you can now create as many pivot tables as needed across different worksheets. See [Pivot Tables](#pivot-tables) for details. +- Merged [Add pivot table with limitations #2551](https://github.com/exceljs/exceljs/pull/2551).
Many thanks to Protobi and Michael for this contribution! +- Merged [fix: styles rendering in case when "numFmt" is present in conditional formatting rules (resolves #1814) #1815](https://github.com/exceljs/exceljs/pull/1815).
Many thanks to [@andreykrupskii](https://github.com/andreykrupskii) for this contribution! +- Merged [inlineStr cell type support #1575 #1576](https://github.com/exceljs/exceljs/pull/1576).
Many thanks to [@drdmitry](https://github.com/drdmitry) for this contribution! +- Merged [Fix parsing of boolean attributes #1849](https://github.com/exceljs/exceljs/pull/1849).
Many thanks to [@bno1](https://github.com/bno1) for this contribution! +- Merged [add optional custom auto-filter to table #1670](https://github.com/exceljs/exceljs/pull/1670).
Many thanks to [@thambley](https://github.com/thambley) for this contribution! +- Merged [Deep copy inherited style #1850](https://github.com/exceljs/exceljs/pull/1850).
Many thanks to [@ikzhr](https://github.com/ikzhr) for this contribution! +- Merged [Upgrade actions/cache and actions/setup-node #1846](https://github.com/exceljs/exceljs/pull/1846).
Many thanks to [@cclauss](https://github.com/cclauss) for this contribution! +- Merged [Check object keys in isEqual #1831](https://github.com/exceljs/exceljs/pull/1831).
Many thanks to [@bno1](https://github.com/bno1) for this contribution! +- Merged [Add v17 to testing workflow #1856](https://github.com/exceljs/exceljs/pull/1856).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! +- Merged [Upgrade jszip to its latest version to date. This version does not have any vulnerability found by Snyk so far #1895](https://github.com/exceljs/exceljs/pull/1895).
Many thanks to [@ValerioSevilla](https://github.com/ValerioSevilla) for this contribution! +- Merged [Update README.md #1677](https://github.com/exceljs/exceljs/pull/1677).
Many thanks to [@xjrcode](https://github.com/xjrcode) for this contribution! +- Merged [(docs): set prototype of RegExp correctly. #1700](https://github.com/exceljs/exceljs/pull/1700).
Many thanks to [@joeldenning](https://github.com/joeldenning) for this contribution! +- Merged [Added timeouts to github actions #1733](https://github.com/exceljs/exceljs/pull/1733).
Many thanks to [@alexbjorlig](https://github.com/alexbjorlig) for this contribution! +- Merged [fix issue 1676 #1701](https://github.com/exceljs/exceljs/pull/1701).
Many thanks to [@skypesky](https://github.com/skypesky) for this contribution! +- Merged [ExcelJS/ExcelJS#2237 : Update CI Tests, Drop support for Node v8 #2242](https://github.com/exceljs/exceljs/pull/2242).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! +- Merged [Fix types for getWorksheet() #2223](https://github.com/exceljs/exceljs/pull/2223).
Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution! +- Merged [add characters cannot be used for worksheet name #2126](https://github.com/exceljs/exceljs/pull/2126).
Many thanks to [@tkm-kj](https://github.com/tkm-kj) for this contribution! +- Merged [Fix issue #1753 Reject promise when workbook reader is writing to temporary file stream and error occurs #1756](https://github.com/exceljs/exceljs/pull/1756).
Many thanks to [@pauliusg](https://github.com/pauliusg) for this contribution! +- Merged [README.md to have correct link for Streaming XLSX #2186](https://github.com/exceljs/exceljs/pull/2186).
Many thanks to [@wulfsolter](https://github.com/wulfsolter) for this contribution! +- Merged [Added a polyfill of promise.finally to support lower versions of Firefox. #1982](https://github.com/exceljs/exceljs/pull/1982).
Many thanks to [@DemoJj](https://github.com/DemoJj) for this contribution! +- Merged [Fix read this.worksheet before assign it #1934](https://github.com/exceljs/exceljs/pull/1934).
Many thanks to [@ZyqGitHub1](https://github.com/ZyqGitHub1) for this contribution! +- Merged [chore: upgrade jszip to ^3.10.1 #2211](https://github.com/exceljs/exceljs/pull/2211).
Many thanks to [@jarrod-cocoon](https://github.com/jarrod-cocoon) for this contribution! +- Merged [fixed spelling error in README.md file #2208](https://github.com/exceljs/exceljs/pull/2208).
Many thanks to [@HugoP27](https://github.com/HugoP27) for this contribution! +- Merged [fix: Fix xlsx.writeFile() not catching error when error occurs #2244](https://github.com/exceljs/exceljs/pull/2244).
Many thanks to [@zurmokeeper](https://github.com/zurmokeeper) for this contribution! +- Merged [Improve worksheets' naming validation logic. #2257](https://github.com/exceljs/exceljs/pull/2257).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! +- Merged [fix issue 2125 - spliceRows remove last row #2140](https://github.com/exceljs/exceljs/pull/2140).
Many thanks to [@babu-ch](https://github.com/babu-ch) for this contribution! +- Merged [fix: fix the loss of column attributes due to incorrect column order #2222](https://github.com/exceljs/exceljs/pull/2222).
Many thanks to [@cpaiyueyue](https://github.com/cpaiyueyue) for this contribution! +- Merged [Fix: Sheet Properties Types #2327](https://github.com/exceljs/exceljs/pull/2327).
Many thanks to [@albeniraouf](https://github.com/albeniraouf) for this contribution! +- Merged [Use node 18 LTS for tsc, and benchmark. Add node 20. to test matrix. … #2354](https://github.com/exceljs/exceljs/pull/2354).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! +- Merged [Add missing tooltip attribute to CellHyperlinkValue index.d.ts #2350](https://github.com/exceljs/exceljs/pull/2350).
Many thanks to [@NiklasPor](https://github.com/NiklasPor) for this contribution! +- Merged [Increase resilience to generating large workbooks #2320](https://github.com/exceljs/exceljs/pull/2320).
Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution! +- Merged [repair all 'c2fo.io' links ('c2fo.github.io') #2324](https://github.com/exceljs/exceljs/pull/2324).
Many thanks to [@justintunev7](https://github.com/justintunev7) for this contribution! +- Merged [fix: fix type definitions about last column, formula values and protection #2309](https://github.com/exceljs/exceljs/pull/2309).
Many thanks to [@gltjk](https://github.com/gltjk) for this contribution! +- Merged [fix: add spinCount field for WorksheetProtection type #2284](https://github.com/exceljs/exceljs/pull/2284).
Many thanks to [@damingerdai](https://github.com/damingerdai) for this contribution! +- Merged [Add type definition for WorksheetModel.merges #2281](https://github.com/exceljs/exceljs/pull/2281).
Many thanks to [@ytjmt](https://github.com/ytjmt) for this contribution! # Contributions Contributions are very welcome! It helps me know what features are desired or what bugs are causing the most pain. I have just one request; If you submit a pull request for a bugfix, please add a unit-test or integration-test (in the spec folder) that catches the problem. - Even a PR that just has a failing test is fine - I can analyse what the test is doing and fix the code from that. +Even a PR that just has a failing test is fine - I can analyse what the test is doing and fix the code from that. Note: Please try to avoid modifying the package version in a PR. Versions are updated on release and any change will most likely result in merge collisions. @@ -278,9 +283,9 @@ const ExcelJS = require('exceljs/dist/es5'); ``` **Note:** The ES5 build has an implicit dependency on a number of polyfills which are no longer - explicitly added by exceljs. - You will need to add "core-js" and "regenerator-runtime" to your dependencies and - include the following requires in your code before the exceljs import: +explicitly added by exceljs. +You will need to add "core-js" and "regenerator-runtime" to your dependencies and +include the following requires in your code before the exceljs import: ```javascript // polyfills required by exceljs @@ -305,7 +310,7 @@ const {RegExp} = global; try { new RegExp('a', 'u'); } catch (err) { - global.RegExp = function(pattern, flags) { + global.RegExp = function (pattern, flags) { if (flags && flags.includes('u')) { return new RegExp(rewritePattern(pattern, flags, generateRegexpuOptions({flags, pattern}))); } @@ -320,18 +325,19 @@ try { ExcelJS publishes two browserified bundles inside the dist/ folder: One with implicit dependencies on core-js polyfills... + ```html ``` And one without... + ```html ``` - # Interface[⬆](#contents) ## Create a Workbook[⬆](#contents) @@ -369,10 +375,15 @@ The Workbook views controls how many separate windows Excel will open when viewi ```javascript workbook.views = [ { - x: 0, y: 0, width: 10000, height: 20000, - firstSheet: 0, activeTab: 1, visibility: 'visible' - } -] + x: 0, + y: 0, + width: 10000, + height: 20000, + firstSheet: 0, + activeTab: 1, + visibility: 'visible', + }, +]; ``` ## Add a Worksheet[⬆](#contents) @@ -387,22 +398,22 @@ For Example: ```javascript // create a sheet with a red tab colour using the hexadecimal alpha-red-green-blue format -const sheet = workbook.addWorksheet('My Sheet', {properties:{tabColor:{argb:'FFCC0000'}}}); +const sheet = workbook.addWorksheet('My Sheet', {properties: {tabColor: {argb: 'FFCC0000'}}}); // create a sheet where the grid lines are hidden const sheet = workbook.addWorksheet('My Sheet', {views: [{showGridLines: false}]}); // create a sheet with the first row and column frozen -const sheet = workbook.addWorksheet('My Sheet', {views:[{state: 'frozen', xSplit: 1, ySplit:1}]}); +const sheet = workbook.addWorksheet('My Sheet', {views: [{state: 'frozen', xSplit: 1, ySplit: 1}]}); // Create worksheets with headers and footers const sheet = workbook.addWorksheet('My Sheet', { - headerFooter:{firstHeader: "Hello Exceljs", firstFooter: "Hello World"} + headerFooter: {firstHeader: 'Hello Exceljs', firstFooter: 'Hello World'}, }); // create new sheet with pageSetup settings for A4 - landscape -const worksheet = workbook.addWorksheet('My Sheet', { - pageSetup:{paperSize: 9, orientation:'landscape'} +const worksheet = workbook.addWorksheet('My Sheet', { + pageSetup: {paperSize: 9, orientation: 'landscape'}, }); ``` @@ -417,14 +428,15 @@ For Example: const sheet = workbook.addWorksheet('My Sheet'); // Remove the worksheet using worksheet id -workbook.removeWorksheet(sheet.id) +workbook.removeWorksheet(sheet.id); ``` ## Access Worksheets[⬆](#contents) + ```javascript // Iterate over all sheets // Note: workbook.worksheets.forEach will still work but this is better -workbook.eachSheet(function(worksheet, sheetId) { +workbook.eachSheet(function (worksheet, sheetId) { // ... }); @@ -441,7 +453,6 @@ const worksheet = workbook.getWorksheet(1); // access by `worksheets` array: workbook.worksheets[0]; //the first one; - ``` It's important to know that `workbook.getWorksheet(1) != Workbook.worksheets[0]` and `workbook.getWorksheet(1) != Workbook.worksheets[1]`, @@ -466,10 +477,10 @@ Worksheets support a property bucket to allow control over some features of the ```javascript // create new sheet with properties -const worksheet = workbook.addWorksheet('sheet', {properties:{tabColor:{argb:'FF00FF00'}}}); +const worksheet = workbook.addWorksheet('sheet', {properties: {tabColor: {argb: 'FF00FF00'}}}); // create a new sheet writer with properties -const worksheetWriter = workbookWriter.addWorksheet('sheet', {properties:{outlineLevelCol:1}}); +const worksheetWriter = workbookWriter.addWorksheet('sheet', {properties: {outlineLevelCol: 1}}); // adjust properties afterwards (not supported by worksheet-writer) worksheet.properties.outlineLevelCol = 2; @@ -478,26 +489,25 @@ worksheet.properties.defaultRowHeight = 15; **Supported Properties** -| Name | Default | Description | -| ---------------- | ---------- | ----------- | -| tabColor | undefined | Color of the tabs | +| Name | Default | Description | +| ---------------- | ---------- | ---------------------------------- | +| tabColor | undefined | Color of the tabs | | outlineLevelCol | 0 | The worksheet column outline level | -| outlineLevelRow | 0 | The worksheet row outline level | -| defaultRowHeight | 15 | Default row height | -| defaultColWidth | (optional) | Default column width | -| dyDescent | 55 | TBD | +| outlineLevelRow | 0 | The worksheet row outline level | +| defaultRowHeight | 15 | Default row height | +| defaultColWidth | (optional) | Default column width | +| dyDescent | 55 | TBD | ### Worksheet Metrics[⬆](#contents) Some new metrics have been added to Worksheet... -| Name | Description | -| ----------------- | ----------- | -| rowCount | The total row size of the document. Equal to the row number of the last row that has values. | +| Name | Description | +| ----------------- | --------------------------------------------------------------------------------------------------------------------- | +| rowCount | The total row size of the document. Equal to the row number of the last row that has values. | | actualRowCount | A count of the number of rows that have values. If a mid-document row is empty, it will not be included in the count. | -| columnCount | The total column size of the document. Equal to the maximum cell count from all of the rows | -| actualColumnCount | A count of the number of columns that have values. | - +| columnCount | The total column size of the document. Equal to the maximum cell count from all of the rows | +| actualColumnCount | A count of the number of columns that have values. | ## Page Setup[⬆](#contents) @@ -505,20 +515,23 @@ All properties that can affect the printing of a sheet are held in a pageSetup o ```javascript // create new sheet with pageSetup settings for A4 - landscape -const worksheet = workbook.addWorksheet('sheet', { - pageSetup:{paperSize: 9, orientation:'landscape'} +const worksheet = workbook.addWorksheet('sheet', { + pageSetup: {paperSize: 9, orientation: 'landscape'}, }); // create a new sheet writer with pageSetup settings for fit-to-page const worksheetWriter = workbookWriter.addWorksheet('sheet', { - pageSetup:{fitToPage: true, fitToHeight: 5, fitToWidth: 7} + pageSetup: {fitToPage: true, fitToHeight: 5, fitToWidth: 7}, }); // adjust pageSetup settings afterwards worksheet.pageSetup.margins = { - left: 0.7, right: 0.7, - top: 0.75, bottom: 0.75, - header: 0.3, footer: 0.3 + left: 0.7, + right: 0.7, + top: 0.75, + bottom: 0.75, + header: 0.3, + footer: 0.3, }; // Set Print Area for a sheet @@ -536,46 +549,46 @@ worksheet.pageSetup.printTitlesColumn = 'A:C'; **Supported pageSetup settings** -| Name | Default | Description | -| --------------------- | ------------- | ----------- | -| margins | | Whitespace on the borders of the page. Units are inches. | -| orientation | 'portrait' | Orientation of the page - i.e. taller (portrait) or wider (landscape) | -| horizontalDpi | 4294967295 | Horizontal Dots per Inch. Default value is -1 | -| verticalDpi | 4294967295 | Vertical Dots per Inch. Default value is -1 | -| fitToPage | | Whether to use fitToWidth and fitToHeight or scale settings. Default is based on presence of these settings in the pageSetup object - if both are present, scale wins (i.e. default will be false) | -| pageOrder | 'downThenOver'| Which order to print the pages - one of ['downThenOver', 'overThenDown'] | -| blackAndWhite | false | Print without colour | -| draft | false | Print with less quality (and ink) | -| cellComments | 'None' | Where to place comments - one of ['atEnd', 'asDisplayed', 'None'] | -| errors | 'displayed' | Where to show errors - one of ['dash', 'blank', 'NA', 'displayed'] | -| scale | 100 | Percentage value to increase or reduce the size of the print. Active when fitToPage is false | -| fitToWidth | 1 | How many pages wide the sheet should print on to. Active when fitToPage is true | -| fitToHeight | 1 | How many pages high the sheet should print on to. Active when fitToPage is true | -| paperSize | | What paper size to use (see below) | -| showRowColHeaders | false | Whether to show the row numbers and column letters | -| showGridLines | false | Whether to show grid lines | -| firstPageNumber | | Which number to use for the first page | -| horizontalCentered | false | Whether to center the sheet data horizontally | -| verticalCentered | false | Whether to center the sheet data vertically | +| Name | Default | Description | +| ------------------ | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| margins | | Whitespace on the borders of the page. Units are inches. | +| orientation | 'portrait' | Orientation of the page - i.e. taller (portrait) or wider (landscape) | +| horizontalDpi | 4294967295 | Horizontal Dots per Inch. Default value is -1 | +| verticalDpi | 4294967295 | Vertical Dots per Inch. Default value is -1 | +| fitToPage | | Whether to use fitToWidth and fitToHeight or scale settings. Default is based on presence of these settings in the pageSetup object - if both are present, scale wins (i.e. default will be false) | +| pageOrder | 'downThenOver' | Which order to print the pages - one of ['downThenOver', 'overThenDown'] | +| blackAndWhite | false | Print without colour | +| draft | false | Print with less quality (and ink) | +| cellComments | 'None' | Where to place comments - one of ['atEnd', 'asDisplayed', 'None'] | +| errors | 'displayed' | Where to show errors - one of ['dash', 'blank', 'NA', 'displayed'] | +| scale | 100 | Percentage value to increase or reduce the size of the print. Active when fitToPage is false | +| fitToWidth | 1 | How many pages wide the sheet should print on to. Active when fitToPage is true | +| fitToHeight | 1 | How many pages high the sheet should print on to. Active when fitToPage is true | +| paperSize | | What paper size to use (see below) | +| showRowColHeaders | false | Whether to show the row numbers and column letters | +| showGridLines | false | Whether to show grid lines | +| firstPageNumber | | Which number to use for the first page | +| horizontalCentered | false | Whether to center the sheet data horizontally | +| verticalCentered | false | Whether to center the sheet data vertically | **Example Paper Sizes** | Name | Value | | ----------------------------- | --------- | | Letter | undefined | -| Legal | 5 | -| Executive | 7 | -| A3 | 8 | -| A4 | 9 | -| A5 | 11 | -| B5 (JIS) | 13 | -| Envelope #10 | 20 | -| Envelope DL | 27 | -| Envelope C5 | 28 | -| Envelope B5 | 34 | -| Envelope Monarch | 37 | -| Double Japan Postcard Rotated | 82 | -| 16K 197x273 mm | 119 | +| Legal | 5 | +| Executive | 7 | +| A3 | 8 | +| A4 | 9 | +| A5 | 11 | +| B5 (JIS) | 13 | +| Envelope #10 | 20 | +| Envelope DL | 27 | +| Envelope C5 | 28 | +| Envelope B5 | 34 | +| Envelope Monarch | 37 | +| Double Japan Postcard Rotated | 82 | +| 16K 197x273 mm | 119 | ## Headers and Footers[⬆](#contents) @@ -586,121 +599,118 @@ In addition, you can set different texts for the first page and even page. Note: Images are not currently supported. ```javascript - // Create worksheets with headers and footers var sheet = workbook.addWorksheet('sheet', { - headerFooter:{firstHeader: "Hello Exceljs", firstFooter: "Hello World"} + headerFooter: {firstHeader: 'Hello Exceljs', firstFooter: 'Hello World'}, }); // Create worksheets with headers and footers var worksheetWriter = workbookWriter.addWorksheet('sheet', { - headerFooter:{firstHeader: "Hello Exceljs", firstFooter: "Hello World"} + headerFooter: {firstHeader: 'Hello Exceljs', firstFooter: 'Hello World'}, }); // Set footer (default centered), result: "Page 2 of 16" -worksheet.headerFooter.oddFooter = "Page &P of &N"; +worksheet.headerFooter.oddFooter = 'Page &P of &N'; // Set the footer (default centered) to bold, resulting in: "Page 2 of 16" -worksheet.headerFooter.oddFooter = "Page &P of &N"; +worksheet.headerFooter.oddFooter = 'Page &P of &N'; // Set the left footer to 18px and italicize. Result: "Page 2 of 16" -worksheet.headerFooter.oddFooter = "&LPage &P of &N"; +worksheet.headerFooter.oddFooter = '&LPage &P of &N'; // Set the middle header to gray Aril, the result: "52 exceljs" -worksheet.headerFooter.oddHeader = "&C&KCCCCCC&\"Aril\"52 exceljs"; +worksheet.headerFooter.oddHeader = '&C&KCCCCCC&"Aril"52 exceljs'; // Set the left, center, and right text of the footer. Result: “Exceljs” in the footer left. “demo.xlsx” in the footer center. “Page 2” in the footer right -worksheet.headerFooter.oddFooter = "&Lexceljs&C&F&RPage &P"; +worksheet.headerFooter.oddFooter = '&Lexceljs&C&F&RPage &P'; // Add different header & footer for the first page worksheet.headerFooter.differentFirst = true; -worksheet.headerFooter.firstHeader = "Hello Exceljs"; -worksheet.headerFooter.firstFooter = "Hello World" +worksheet.headerFooter.firstHeader = 'Hello Exceljs'; +worksheet.headerFooter.firstFooter = 'Hello World'; ``` **Supported headerFooter settings** -| Name | Default | Description | -| ----------------- | --------- | ----------- | -| differentFirst | false | Set the value of differentFirst as true, which indicates that headers/footers for first page are different from the other pages | -| differentOddEven | false | Set the value of differentOddEven as true, which indicates that headers/footers for odd and even pages are different | -| oddHeader | null | Set header string for odd(default) pages, could format the string | -| oddFooter | null | Set footer string for odd(default) pages, could format the string | -| evenHeader | null | Set header string for even pages, could format the string | -| evenFooter | null | Set footer string for even pages, could format the string | -| firstHeader | null | Set header string for the first page, could format the string | -| firstFooter | null | Set footer string for the first page, could format the string | +| Name | Default | Description | +| ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- | +| differentFirst | false | Set the value of differentFirst as true, which indicates that headers/footers for first page are different from the other pages | +| differentOddEven | false | Set the value of differentOddEven as true, which indicates that headers/footers for odd and even pages are different | +| oddHeader | null | Set header string for odd(default) pages, could format the string | +| oddFooter | null | Set footer string for odd(default) pages, could format the string | +| evenHeader | null | Set header string for even pages, could format the string | +| evenFooter | null | Set footer string for even pages, could format the string | +| firstHeader | null | Set header string for the first page, could format the string | +| firstFooter | null | Set footer string for the first page, could format the string | **Script Commands** -| Commands | Description | -| ------------ | ----------- | -| &L | Set position to the left | -| &C | Set position to the center | -| &R | Set position to the right | -| &P | The current page number | -| &N | The total number of pages | -| &D | The current date | -| &T | The current time | -| &G | A picture | -| &A | The worksheet name | -| &F | The file name | -| &B | Make text bold | -| &I | Italicize text | -| &U | Underline text | -| &"font name" | font name, for example &"Aril" | -| &font size | font size, for example 12 | +| Commands | Description | +| ------------ | -------------------------------- | +| &L | Set position to the left | +| &C | Set position to the center | +| &R | Set position to the right | +| &P | The current page number | +| &N | The total number of pages | +| &D | The current date | +| &T | The current time | +| &G | A picture | +| &A | The worksheet name | +| &F | The file name | +| &B | Make text bold | +| &I | Italicize text | +| &U | Underline text | +| &"font name" | font name, for example &"Aril" | +| &font size | font size, for example 12 | | &KHEXCode | font color, for example &KCCCCCC | ## Worksheet Views[⬆](#contents) Worksheets now support a list of views, that control how Excel presents the sheet: -* frozen - where a number of rows and columns to the top and left are frozen in place. Only the bottom right section will scroll -* split - where the view is split into 4 sections, each semi-independently scrollable. +- frozen - where a number of rows and columns to the top and left are frozen in place. Only the bottom right section will scroll +- split - where the view is split into 4 sections, each semi-independently scrollable. Each view also supports various properties: -| Name | Default | Description | -| ----------------- | --------- | ----------- | -| state | 'normal' | Controls the view state - one of normal, frozen or split | -| rightToLeft | false | Sets the worksheet view's orientation to right-to-left | -| activeCell | undefined | The currently selected cell | -| showRuler | true | Shows or hides the ruler in Page Layout | -| showRowColHeaders | true | Shows or hides the row and column headers (e.g. A1, B1 at the top and 1,2,3 on the left | -| showGridLines | true | Shows or hides the gridlines (shown for cells where borders have not been defined) | -| zoomScale | 100 | Percentage zoom to use for the view | -| zoomScaleNormal | 100 | Normal zoom for the view | +| Name | Default | Description | +| ----------------- | --------- | --------------------------------------------------------------------------------------------------------------- | +| state | 'normal' | Controls the view state - one of normal, frozen or split | +| rightToLeft | false | Sets the worksheet view's orientation to right-to-left | +| activeCell | undefined | The currently selected cell | +| showRuler | true | Shows or hides the ruler in Page Layout | +| showRowColHeaders | true | Shows or hides the row and column headers (e.g. A1, B1 at the top and 1,2,3 on the left | +| showGridLines | true | Shows or hides the gridlines (shown for cells where borders have not been defined) | +| zoomScale | 100 | Percentage zoom to use for the view | +| zoomScaleNormal | 100 | Normal zoom for the view | | style | undefined | Presentation style - one of pageBreakPreview or pageLayout. Note pageLayout is not compatible with frozen views | ### Frozen Views[⬆](#contents) Frozen views support the following extra properties: -| Name | Default | Description | -| ----------------- | --------- | ----------- | -| xSplit | 0 | How many columns to freeze. To freeze rows only, set this to 0 or undefined | -| ySplit | 0 | How many rows to freeze. To freeze columns only, set this to 0 or undefined | -| topLeftCell | special | Which cell will be top-left in the bottom-right pane. Note: cannot be a frozen cell. Defaults to first unfrozen cell | +| Name | Default | Description | +| ----------- | ------- | -------------------------------------------------------------------------------------------------------------------- | +| xSplit | 0 | How many columns to freeze. To freeze rows only, set this to 0 or undefined | +| ySplit | 0 | How many rows to freeze. To freeze columns only, set this to 0 or undefined | +| topLeftCell | special | Which cell will be top-left in the bottom-right pane. Note: cannot be a frozen cell. Defaults to first unfrozen cell | ```javascript -worksheet.views = [ - {state: 'frozen', xSplit: 2, ySplit: 3, topLeftCell: 'G10', activeCell: 'A1'} -]; +worksheet.views = [{state: 'frozen', xSplit: 2, ySplit: 3, topLeftCell: 'G10', activeCell: 'A1'}]; ``` ### Split Views[⬆](#contents) Split views support the following extra properties: -| Name | Default | Description | -| ----------------- | --------- | ----------- | -| xSplit | 0 | How many points from the left to place the splitter. To split vertically, set this to 0 or undefined | -| ySplit | 0 | How many points from the top to place the splitter. To split horizontally, set this to 0 or undefined | -| topLeftCell | undefined | Which cell will be top-left in the bottom-right pane. | -| activePane | undefined | Which pane will be active - one of topLeft, topRight, bottomLeft and bottomRight | +| Name | Default | Description | +| ----------- | --------- | ----------------------------------------------------------------------------------------------------- | +| xSplit | 0 | How many points from the left to place the splitter. To split vertically, set this to 0 or undefined | +| ySplit | 0 | How many points from the top to place the splitter. To split horizontally, set this to 0 or undefined | +| topLeftCell | undefined | Which cell will be top-left in the bottom-right pane. | +| activePane | undefined | Which pane will be active - one of topLeft, topRight, bottomLeft and bottomRight | ```javascript worksheet.views = [ - {state: 'split', xSplit: 2000, ySplit: 3000, topLeftCell: 'G10', activeCell: 'A1'} + {state: 'split', xSplit: 2000, ySplit: 3000, topLeftCell: 'G10', activeCell: 'A1'}, ]; ``` @@ -720,20 +730,20 @@ following values: worksheet.autoFilter = { from: 'A1', to: 'C1', -} +}; // Set an auto filter from the cell in row 3 and column 1 // to the cell in row 5 and column 12 worksheet.autoFilter = { from: { row: 3, - column: 1 + column: 1, }, to: { row: 5, - column: 12 - } -} + column: 12, + }, +}; // Set an auto filter from D3 to the // cell in row 7 and column 5 @@ -741,9 +751,9 @@ worksheet.autoFilter = { from: 'D3', to: { row: 7, - column: 5 - } -} + column: 5, + }, +}; ``` ## Columns[⬆](#contents) @@ -753,9 +763,9 @@ worksheet.autoFilter = { // Note: these column structures are a workbook-building convenience only, // apart from the column width, they will not be fully persisted. worksheet.columns = [ - { header: 'Id', key: 'id', width: 10 }, - { header: 'Name', key: 'name', width: 32 }, - { header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1 } + {header: 'Id', key: 'id', width: 10}, + {header: 'Name', key: 'name', width: 32}, + {header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1}, ]; // Access an individual columns by key, letter and 1-based column number @@ -788,34 +798,33 @@ expect(worksheet.getColumn(4).collapsed).to.equal(false); expect(worksheet.getColumn(5).collapsed).to.equal(true); // iterate over all current cells in this column -dobCol.eachCell(function(cell, rowNumber) { +dobCol.eachCell(function (cell, rowNumber) { // ... }); // iterate over all current cells in this column including empty cells -dobCol.eachCell({ includeEmpty: true }, function(cell, rowNumber) { +dobCol.eachCell({includeEmpty: true}, function (cell, rowNumber) { // ... }); // add a column of new values -worksheet.getColumn(6).values = [1,2,3,4,5]; +worksheet.getColumn(6).values = [1, 2, 3, 4, 5]; // add a sparse column of values -worksheet.getColumn(7).values = [,,2,3,,5,,7,,,,11]; +worksheet.getColumn(7).values = [, , 2, 3, , 5, , 7, , , , 11]; // cut one or more columns (columns to the right are shifted left) // If column properties have been defined, they will be cut or moved accordingly // Known Issue: If a splice causes any merged cells to move, the results may be unpredictable -worksheet.spliceColumns(3,2); +worksheet.spliceColumns(3, 2); // remove one column and insert two more. // Note: columns 4 and above will be shifted right by 1 column. // Also: If the worksheet has more rows than values in the column inserts, // the rows will still be shifted as if the values existed -const newCol3Values = [1,2,3,4,5]; +const newCol3Values = [1, 2, 3, 4, 5]; const newCol4Values = ['one', 'two', 'three', 'four', 'five']; worksheet.spliceColumns(3, 1, newCol3Values, newCol4Values); - ``` ## Rows[⬆](#contents) @@ -844,7 +853,6 @@ worksheet.getRow(5).outlineLevel = 1; expect(worksheet.getRow(4).collapsed).to.equal(false); expect(worksheet.getRow(5).collapsed).to.equal(true); - row.getCell(1).value = 5; // A5's value set to 5 row.getCell('name').value = 'Zeb'; // B5's value set to 'Zeb' - assuming column 2 is still keyed by name row.getCell('C').value = new Date(); // C5's value set to now @@ -855,13 +863,13 @@ row = worksheet.getRow(4).values; expect(row[5]).toEqual('Kyle'); // assign row values by contiguous array (where array element 0 has a value) -row.values = [1,2,3]; +row.values = [1, 2, 3]; expect(row.getCell(1).value).toEqual(1); expect(row.getCell(2).value).toEqual(2); expect(row.getCell(3).value).toEqual(3); // assign row values by sparse array (where array element 0 is undefined) -const values = [] +const values = []; values[5] = 7; values[10] = 'Hello, World!'; row.values = values; @@ -873,29 +881,29 @@ expect(row.getCell(10).value).toEqual('Hello, World!'); row.values = { id: 13, name: 'Thing 1', - dob: new Date() + dob: new Date(), }; // Insert a page break below the row row.addPageBreak(); // Iterate over all rows that have values in a worksheet -worksheet.eachRow(function(row, rowNumber) { +worksheet.eachRow(function (row, rowNumber) { console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values)); }); // Iterate over all rows (including empty rows) in a worksheet -worksheet.eachRow({ includeEmpty: true }, function(row, rowNumber) { +worksheet.eachRow({includeEmpty: true}, function (row, rowNumber) { console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values)); }); // Iterate over all non-null cells in a row -row.eachCell(function(cell, colNumber) { +row.eachCell(function (cell, colNumber) { console.log('Cell ' + colNumber + ' = ' + cell.value); }); // Iterate over all cells in a row (including empty cells) -row.eachCell({ includeEmpty: true }, function(cell, colNumber) { +row.eachCell({includeEmpty: true}, function (cell, colNumber) { console.log('Cell ' + colNumber + ' = ' + cell.value); }); @@ -911,8 +919,8 @@ const numValues = row.actualCellCount; ```javascript // Add a couple of Rows by key-value, after the last current row, using the column keys -worksheet.addRow({id: 1, name: 'John Doe', dob: new Date(1970,1,1)}); -worksheet.addRow({id: 2, name: 'Jane Doe', dob: new Date(1965,1,7)}); +worksheet.addRow({id: 1, name: 'John Doe', dob: new Date(1970, 1, 1)}); +worksheet.addRow({id: 2, name: 'Jane Doe', dob: new Date(1965, 1, 7)}); // Add a row by contiguous Array (assign to columns A, B & C) worksheet.addRow([3, 'Sam', new Date()]); @@ -931,8 +939,8 @@ const newRow = worksheet.addRow(rowValues, 'i'); // Add an array of rows const rows = [ - [5,'Bob',new Date()], // row by array - {id:6, name: 'Barbara', dob: new Date()} + [5, 'Bob', new Date()], // row by array + {id: 6, name: 'Barbara', dob: new Date()}, ]; // add new rows and return them as array of row objects const newRows = worksheet.addRows(rows); @@ -942,10 +950,11 @@ const newRows = worksheet.addRows(rows); // and return them as array of row objects const newRowsStyled = worksheet.addRows(rows, 'i'); ``` -| Parameter | Description | Default Value | -| -------------- | ----------------- | -------- | -| value/s | The new row/s values | | -| style | 'i' for inherit from row above, 'i+' to include empty cells, 'n' for none | *'n'* | + +| Parameter | Description | Default Value | +| --------- | ------------------------------------------------------------------------- | ------------- | +| value/s | The new row/s values | | +| style | 'i' for inherit from row above, 'i+' to include empty cells, 'n' for none | _'n'_ | ## Handling Individual Cells[⬆](#contents) @@ -963,7 +972,6 @@ myInput.value = cell.text; // use html-safe string for rendering... const html = '
' + cell.html + '
'; - ``` ## Merged Cells[⬆](#contents) @@ -991,18 +999,18 @@ expect(worksheet.getCell('B5').style.font).not.toBe(myFonts.arial); worksheet.mergeCells('K10', 'M12'); // merge by start row, start column, end row, end column (equivalent to K10:M12) -worksheet.mergeCells(10,11,12,13); +worksheet.mergeCells(10, 11, 12, 13); ``` ## Insert Rows[⬆](#contents) ```javascript -insertRow(pos, value, style = 'n') -insertRows(pos, values, style = 'n') +insertRow(pos, value, (style = 'n')); +insertRows(pos, values, (style = 'n')); // Insert a couple of Rows by key-value, shifting down rows every time -worksheet.insertRow(1, {id: 1, name: 'John Doe', dob: new Date(1970,1,1)}); -worksheet.insertRow(1, {id: 2, name: 'Jane Doe', dob: new Date(1965,1,7)}); +worksheet.insertRow(1, {id: 1, name: 'John Doe', dob: new Date(1970, 1, 1)}); +worksheet.insertRow(1, {id: 2, name: 'Jane Doe', dob: new Date(1965, 1, 7)}); // Insert a row by contiguous Array (assign to columns A, B & C) worksheet.insertRow(1, [3, 'Sam', new Date()]); @@ -1027,8 +1035,8 @@ const insertedRowOriginal = worksheet.insertRow(1, rowValues, 'o'); // Insert an array of rows, in position 1, shifting down current position 1 and later rows by 2 rows var rows = [ - [5,'Bob',new Date()], // row by array - {id:6, name: 'Barbara', dob: new Date()} + [5, 'Bob', new Date()], // row by array + {id: 6, name: 'Barbara', dob: new Date()}, ]; // insert new rows and return them as array of row objects const insertedRows = worksheet.insertRows(1, rows); @@ -1041,13 +1049,13 @@ const insertedRowsInherited = worksheet.insertRows(1, rows, 'i'); // Insert an array of rows, keeping original style // These new rows will have same style as it was previously in 'pos' position const insertedRowsOriginal = worksheet.insertRows(1, rows, 'o'); - ``` -| Parameter | Description | Default Value | -| -------------- | ----------------- | -------- | -| pos | Row number where you want to insert, pushing down all rows from there | | -| value/s | The new row/s values | | -| style | 'i' for inherit from row above, , 'i+' to include empty cells, 'o' for original style, 'o+' to include empty cells, 'n' for none | *'n'* | + +| Parameter | Description | Default Value | +| --------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| pos | Row number where you want to insert, pushing down all rows from there | | +| value/s | The new row/s values | | +| style | 'i' for inherit from row above, , 'i+' to include empty cells, 'o' for original style, 'o+' to include empty cells, 'n' for none | _'n'_ | ## Splice[⬆](#contents) @@ -1069,16 +1077,17 @@ row.splice(3, 2); // remove one cell and insert two more (cells to the right of the cut cell will be shifted right) row.splice(4, 1, 'new value 1', 'new value 2'); ``` -| Parameter | Description | Default Value | -| -------------- | ----------------- | -------- | -| start | Starting point to splice from | | -| count | Number of rows/cells to remove | | -| ...inserts | New row/cell values to insert | | + +| Parameter | Description | Default Value | +| ---------- | ------------------------------ | ------------- | +| start | Starting point to splice from | | +| count | Number of rows/cells to remove | | +| ...inserts | New row/cell values to insert | | ## Duplicate a Row[⬆](#contents) ```javascript -duplicateRow(start, amount = 1, insert = true) +duplicateRow(start, (amount = 1), (insert = true)); const wb = new ExcelJS.Workbook(); const ws = wb.addWorksheet('duplicateTest'); @@ -1089,21 +1098,19 @@ ws.getCell('A4').value = 'Four'; // This line will duplicate the row 'One' twice but it will replace rows 'Two' and 'Three' // if third param was true so it would insert 2 new rows with the values and styles of row 'One' -ws.duplicateRow(1,2,false); +ws.duplicateRow(1, 2, false); ``` -| Parameter | Description | Default Value | -| -------------- | ----------------- | -------- | -| start | Row number you want to duplicate (first in excel is 1) | | -| amount | The times you want to duplicate the row | 1 | -| insert | *true* if you want to insert new rows for the duplicates, or *false* if you want to replace them | *true* | - - +| Parameter | Description | Default Value | +| --------- | ------------------------------------------------------------------------------------------------ | ------------- | +| start | Row number you want to duplicate (first in excel is 1) | | +| amount | The times you want to duplicate the row | 1 | +| insert | _true_ if you want to insert new rows for the duplicates, or _false_ if you want to replace them | _true_ | ## Defined Names[⬆](#contents) Individual cells (or multiple groups of cells) can have names assigned to them. - The names can be used in formulas and data validation (and probably more). +The names can be used in formulas and data validation (and probably more). ```javascript // assign (or get) a name for a cell (will overwrite any other names that cell had) @@ -1125,26 +1132,26 @@ Cells can define what values are valid or not and provide prompting to the user Validation types can be one of the following: -| Type | Description | -| ---------- | ----------- | +| Type | Description | +| ---------- | ------------------------------------------------------------------------------------------ | | list | Define a discrete set of valid values. Excel will offer these in a dropdown for easy entry | -| whole | The value must be a whole number | -| decimal | The value must be a decimal number | -| textLength | The value may be text but the length is controlled | -| custom | A custom formula controls the valid values | +| whole | The value must be a whole number | +| decimal | The value must be a decimal number | +| textLength | The value may be text but the length is controlled | +| custom | A custom formula controls the valid values | For types other than list or custom, the following operators affect the validation: -| Operator | Description | -| -------------------- | ----------- | -| between | Values must lie between formula results | -| notBetween | Values must not lie between formula results | -| equal | Value must equal formula result | -| notEqual | Value must not equal formula result | -| greaterThan | Value must be greater than formula result | -| lessThan | Value must be less than formula result | -| greaterThanOrEqual | Value must be greater than or equal to formula result | -| lessThanOrEqual | Value must be less than or equal to formula result | +| Operator | Description | +| ------------------ | ----------------------------------------------------- | +| between | Values must lie between formula results | +| notBetween | Values must not lie between formula results | +| equal | Value must equal formula result | +| notEqual | Value must not equal formula result | +| greaterThan | Value must be greater than formula result | +| lessThan | Value must be less than formula result | +| greaterThanOrEqual | Value must be greater than or equal to formula result | +| lessThanOrEqual | Value must be less than or equal to formula result | ```javascript // Specify list of valid values (One, Two, Three, Four). @@ -1152,7 +1159,7 @@ For types other than list or custom, the following operators affect the validati worksheet.getCell('A1').dataValidation = { type: 'list', allowBlank: true, - formulae: ['"One,Two,Three,Four"'] + formulae: ['"One,Two,Three,Four"'], }; // Specify list of valid values from a range. @@ -1160,7 +1167,7 @@ worksheet.getCell('A1').dataValidation = { worksheet.getCell('A1').dataValidation = { type: 'list', allowBlank: true, - formulae: ['$D$5:$F$5'] + formulae: ['$D$5:$F$5'], }; // Specify Cell must be a whole number that is not 5. @@ -1172,7 +1179,7 @@ worksheet.getCell('A1').dataValidation = { formulae: [5], errorStyle: 'error', errorTitle: 'Five', - error: 'The value must not be Five' + error: 'The value must not be Five', }; // Specify Cell must be a decimal number between 1.5 and 7. @@ -1184,7 +1191,7 @@ worksheet.getCell('A1').dataValidation = { showInputMessage: true, formulae: [1.5, 7], promptTitle: 'Decimal', - prompt: 'The value must between 1.5 and 7' + prompt: 'The value must between 1.5 and 7', }; // Specify Cell must be have a text length less than 15 @@ -1193,7 +1200,7 @@ worksheet.getCell('A1').dataValidation = { operator: 'lessThan', showErrorMessage: true, allowBlank: true, - formulae: [15] + formulae: [15], }; // Specify Cell must be have be a date before 1st Jan 2016 @@ -1202,7 +1209,7 @@ worksheet.getCell('A1').dataValidation = { operator: 'lessThan', showErrorMessage: true, allowBlank: true, - formulae: [new Date(2016,0,1)] + formulae: [new Date(2016, 0, 1)], }; ``` @@ -1217,26 +1224,44 @@ worksheet.getCell('A1').note = 'Hello, ExcelJS!'; // colourful formatted note ws.getCell('B1').note = { texts: [ - {'font': {'size': 12, 'color': {'theme': 0}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': 'This is '}, - {'font': {'italic': true, 'size': 12, 'color': {'theme': 0}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'a'}, - {'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' '}, - {'font': {'size': 12, 'color': {'argb': 'FFFF6600'}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'colorful'}, - {'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' text '}, - {'font': {'size': 12, 'color': {'argb': 'FFCCFFCC'}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'with'}, - {'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' in-cell '}, - {'font': {'bold': true, 'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': 'format'}, + { + font: {size: 12, color: {theme: 0}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: 'This is ', + }, + { + font: {italic: true, size: 12, color: {theme: 0}, name: 'Calibri', scheme: 'minor'}, + text: 'a', + }, + {font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, text: ' '}, + { + font: {size: 12, color: {argb: 'FFFF6600'}, name: 'Calibri', scheme: 'minor'}, + text: 'colorful', + }, + { + font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: ' text ', + }, + {font: {size: 12, color: {argb: 'FFCCFFCC'}, name: 'Calibri', scheme: 'minor'}, text: 'with'}, + { + font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: ' in-cell ', + }, + { + font: {bold: true, size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: 'format', + }, ], margins: { insetmode: 'custom', - inset: [0.25, 0.25, 0.35, 0.35] + inset: [0.25, 0.25, 0.35, 0.35], }, size: { - rows: 10, - cols: 4 + rows: 10, + cols: 4, }, protection: { locked: True, - lockText: False + lockText: False, }, editAs: 'twoCells', }; @@ -1246,13 +1271,14 @@ ws.getCell('B1').note = { The following table defines the properties supported by cell comments. -| Field | Required | Default Value | Description | -| -------- | -------- |---------------------|---------------------------------------------------------------------------------------------------------| -| texts | Y | | The text of the comment | -| margins | N | {} | Determines the value of margins for automatic or custom cell comments -| protection | N | {} | Specifying the lock status of objects and object text using protection attributes | -| editAs | N | 'absolute' | Use the 'editAs' attribute to specify how the annotation is anchored to the cell | -| size | N | {rows: 4, col*: 2} | Set size of note box in rows / columns. Rows defaults to length of `texts` if an array or 4 if a string | +| Field | Required | Default Value | Description | +| ---------- | -------- | ------------------- | ------------------------------------------------------------------------------------------------------- | +| texts | Y | | The text of the comment | +| margins | N | {} | Determines the value of margins for automatic or custom cell comments | +| protection | N | {} | Specifying the lock status of objects and object text using protection attributes | +| editAs | N | 'absolute' | Use the 'editAs' attribute to specify how the annotation is anchored to the cell | +| size | N | {rows: 4, col\*: 2} | Set size of note box in rows / columns. Rows defaults to length of `texts` if an array or 4 if a string | + ### Cell Comments Margins Determine the page margin setting mode of the cell annotation, automatic or custom mode. @@ -1260,18 +1286,18 @@ Determine the page margin setting mode of the cell annotation, automatic or cust ```javascript ws.getCell('B1').note.margins = { insetmode: 'custom', - inset: [0.25, 0.25, 0.35, 0.35] -} + inset: [0.25, 0.25, 0.35, 0.35], +}; ``` ### Supported Margins Properties[⬆](#contents) -| Property | Required | Default Value | Description | -| -------- | -------- | ------------- | ----------- | -| insetmode | N | 'auto' | Determines whether comment margins are set automatically and the value is 'auto' or 'custom' | -| inset | N | [0.13, 0.13, 0.25, 0.25] | Whitespace on the borders of the comment. Units are centimeter. Direction is left, top, right, bottom | +| Property | Required | Default Value | Description | +| --------- | -------- | ------------------------ | ----------------------------------------------------------------------------------------------------- | +| insetmode | N | 'auto' | Determines whether comment margins are set automatically and the value is 'auto' or 'custom' | +| inset | N | [0.13, 0.13, 0.25, 0.25] | Whitespace on the borders of the comment. Units are centimeter. Direction is left, top, right, bottom | -Note: This ```inset``` setting takes effect only when the value of ```insetmode``` is 'custom'. +Note: This `inset` setting takes effect only when the value of `insetmode` is 'custom'. ### Cell Comments Protection @@ -1286,10 +1312,10 @@ ws.getCell('B1').note.protection = { ### Supported Protection Properties[⬆](#contents) -| Property | Required | Default Value | Description | -| -------- | -------- | ------------- | ----------- | -| locked | N | 'True' | This element specifies that the object is locked when the sheet is protected | -| lockText | N | 'True' | This element specifies that the text of the object is locked | +| Property | Required | Default Value | Description | +| -------- | -------- | ------------- | ---------------------------------------------------------------------------- | +| locked | N | 'True' | This element specifies that the object is locked when the sheet is protected | +| lockText | N | 'True' | This element specifies that the text of the object is locked | Note: Locked objects are valid only when the worksheet is protected. @@ -1302,11 +1328,11 @@ It can have one of the following values: ws.getCell('B1').note.editAs = 'twoCells'; ``` -| Value | Description | -| --------- | ----------- | -| twoCells | It specifies that the size and position of the note varies with cells | -| oneCells | It specifies that the size of the note is fixed and the position changes with the cell | -| absolute | This is the default. Comments will not be moved or sized with cells | +| Value | Description | +| -------- | -------------------------------------------------------------------------------------- | +| twoCells | It specifies that the size and position of the note varies with cells | +| oneCells | It specifies that the size of the note is fixed and the position changes with the cell | +| absolute | This is the default. Comments will not be moved or sized with cells | ## Tables[⬆](#contents) @@ -1330,9 +1356,9 @@ ws.addTable({ {name: 'Amount', totalsRowFunction: 'sum', filterButton: false}, ], rows: [ - [new Date('2019-07-20'), 70.10], - [new Date('2019-07-21'), 70.60], - [new Date('2019-07-22'), 70.10], + [new Date('2019-07-20'), 70.1], + [new Date('2019-07-21'), 70.6], + [new Date('2019-07-22'), 70.1], ], }); ``` @@ -1346,42 +1372,42 @@ totals) will be overwritten. The following table defines the properties supported by tables. -| Table Property | Description | Required | Default Value | -| -------------- | ----------------- | -------- | ------------- | -| name | The name of the table | Y | | -| displayName | The display name of the table | N | name | -| ref | Top left cell of the table | Y | | -| headerRow | Show headers at top of table | N | true | -| totalsRow | Show totals at bottom of table | N | false | -| style | Extra style properties | N | {} | -| columns | Column definitions | Y | | -| rows | Rows of data | Y | | +| Table Property | Description | Required | Default Value | +| -------------- | ------------------------------ | -------- | ------------- | +| name | The name of the table | Y | | +| displayName | The display name of the table | N | name | +| ref | Top left cell of the table | Y | | +| headerRow | Show headers at top of table | N | true | +| totalsRow | Show totals at bottom of table | N | false | +| style | Extra style properties | N | {} | +| columns | Column definitions | Y | | +| rows | Rows of data | Y | | ### Table Style Properties[⬆](#contents) The following table defines the properties supported within the table style property. -| Style Property | Description | Required | Default Value | -| ------------------ | ----------------- | -------- | ------------- | -| theme | The colour theme of the table | N | 'TableStyleMedium2' | -| showFirstColumn | Highlight the first column (bold) | N | false | -| showLastColumn | Highlight the last column (bold) | N | false | -| showRowStripes | Alternate rows shown with background colour | N | false | -| showColumnStripes | Alternate rows shown with background colour | N | false | +| Style Property | Description | Required | Default Value | +| ----------------- | ------------------------------------------- | -------- | ------------------- | +| theme | The colour theme of the table | N | 'TableStyleMedium2' | +| showFirstColumn | Highlight the first column (bold) | N | false | +| showLastColumn | Highlight the last column (bold) | N | false | +| showRowStripes | Alternate rows shown with background colour | N | false | +| showColumnStripes | Alternate rows shown with background colour | N | false | ### Table Column Properties[⬆](#contents) The following table defines the properties supported within each table column. -| Column Property | Description | Required | Default Value | -| ------------------ | ----------------- | -------- | ------------- | -| name | The name of the column, also used in the header | Y | | -| filterButton | Switches the filter control in the header | N | false | -| totalsRowLabel | Label to describe the totals row (first column) | N | 'Total' | -| totalsRowFunction | Name of the totals function | N | 'none' | -| totalsRowFormula | Optional formula for custom functions | N | | +| Column Property | Description | Required | Default Value | +| ----------------- | ----------------------------------------------- | -------- | ------------- | +| name | The name of the column, also used in the header | Y | | +| filterButton | Switches the filter control in the header | N | false | +| totalsRowLabel | Label to describe the totals row (first column) | N | 'Total' | +| totalsRowFunction | Name of the totals function | N | 'none' | +| totalsRowFormula | Optional formula for custom functions | N | | ### Totals Functions[⬆](#contents) @@ -1390,30 +1416,30 @@ defined by columns. If any value other than 'custom' is used, it is not necessary to include the associated formula as this will be inserted by the table. -| Totals Functions | Description | -| ------------------ | ----------------- | -| none | No totals function for this column | -| average | Compute average for the column | -| countNums | Count the entries that are numbers | -| count | Count of entries | -| max | The maximum value in this column | -| min | The minimum value in this column | -| stdDev | The standard deviation for this column | -| var | The variance for this column | -| sum | The sum of entries for this column | -| custom | A custom formula. Requires an associated totalsRowFormula value. | +| Totals Functions | Description | +| ---------------- | ---------------------------------------------------------------- | +| none | No totals function for this column | +| average | Compute average for the column | +| countNums | Count the entries that are numbers | +| count | Count of entries | +| max | The maximum value in this column | +| min | The minimum value in this column | +| stdDev | The standard deviation for this column | +| var | The variance for this column | +| sum | The sum of entries for this column | +| custom | A custom formula. Requires an associated totalsRowFormula value. | ### Table Style Themes[⬆](#contents) Valid theme names follow the following pattern: -* "TableStyle[Shade][Number]" +- "TableStyle[Shade][Number]" Shades, Numbers can be one of: -* Light, 1-21 -* Medium, 1-28 -* Dark, 1-11 +- Light, 1-21 +- Medium, 1-28 +- Dark, 1-11 For no theme, use the value null. @@ -1484,7 +1510,13 @@ table.removeColumns(1, 1); // insert new column (with data) at index 1 table.addColumn( - {name: 'Letter', totalsRowFunction: 'custom', totalsRowFormula: 'ROW()', totalsRowResult: 6, filterButton: true}, + { + name: 'Letter', + totalsRowFunction: 'custom', + totalsRowFormula: 'ROW()', + totalsRowResult: 6, + filterButton: true, + }, ['a', 'b', 'c', 'd'], 2 ); @@ -1504,7 +1536,7 @@ const column = table.getColumn(1); // set some properties column.name = 'Code'; column.filterButton = true; -column.style = {font:{bold: true, name: 'Comic Sans MS'}}; +column.style = {font: {bold: true, name: 'Comic Sans MS'}}; column.totalsRowLabel = 'Totals'; column.totalsRowFunction = 'custom'; column.totalsRowFormula = 'ROW()'; @@ -1514,7 +1546,6 @@ column.totalsRowResult = 10; table.commit(); ``` - ## Pivot Tables[⬆](#contents) Pivot tables provide powerful data analysis capabilities by summarizing and reorganizing data from a source worksheet. @@ -1601,8 +1632,8 @@ pivotSheet.addPivotTable({ rows: ['Region'], columns: ['Quarter'], values: ['Sales'], - pages: ['latest'], // Add 'latest' as a page field - pageDefaults: { latest: 1 }, // Default to showing only latest=1 + pages: ['latest'], // Add 'latest' as a page field + pageDefaults: {latest: 1}, // Default to showing only latest=1 metric: 'sum', }); ``` @@ -1618,7 +1649,7 @@ pivotSheet.addPivotTable({ pages: ['latest', 'status'], pageDefaults: { latest: 1, - status: 'active' + status: 'active', }, metric: 'sum', }); @@ -1637,8 +1668,8 @@ const dataSheet = workbook.addWorksheet('Data'); const pivotSheet = workbook.addWorksheet('Report'); // Set custom column widths -pivotSheet.getColumn(1).width = 30; // Wide column for labels -pivotSheet.getColumn(2).width = 15; // Narrower for data +pivotSheet.getColumn(1).width = 30; // Wide column for labels +pivotSheet.getColumn(2).width = 15; // Narrower for data // Create pivot table that preserves these widths pivotSheet.addPivotTable({ @@ -1647,16 +1678,18 @@ pivotSheet.addPivotTable({ columns: ['Quarter'], values: ['Amount'], metric: 'sum', - applyWidthHeightFormats: '0', // Preserve worksheet column widths + applyWidthHeightFormats: '0', // Preserve worksheet column widths }); ``` **When to use `applyWidthHeightFormats: '0'`:** + - You need specific column widths for labels or data - You're generating reports with consistent formatting requirements - You want text wrapping to work with your custom widths **Default behavior (`applyWidthHeightFormats: '1'`):** + - Excel applies the pivot table style's auto-sizing - Column widths adjust based on content - Standard Excel pivot table behavior @@ -1665,29 +1698,32 @@ pivotSheet.addPivotTable({ The following properties are supported in the pivot table configuration: -| Property | Type | Required | Description | -| ------------------------- | ---------- | -------- | --------------------------------------------------------------------------- | -| sourceSheet | Worksheet | Y | The worksheet containing the source data. The entire sheet range is used. | -| rows | String[] | Y | Array of field names to use as row dimensions (must exist in first row) | -| columns | String[] | Y | Array of field names to use as column dimensions (must exist in first row) | -| values | String[] | Y | Array of field names to aggregate (currently only 1 value is supported) | -| pages | String[] | N | Array of field names to use as page fields / report filters (must exist in first row) | -| pageDefaults | Object | N | Default filter values for page fields. Keys are field names, values are the default selections | -| metric | String | N | Aggregation function (currently only 'sum' is supported). Default: 'sum' | -| applyWidthHeightFormats | String | N | Controls column width behavior: '1' = apply pivot table style (default), '0' = preserve worksheet column widths | +| Property | Type | Required | Description | +| ----------------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------- | +| sourceSheet | Worksheet | Y | The worksheet containing the source data. The entire sheet range is used. | +| rows | String[] | Y | Array of field names to use as row dimensions (must exist in first row) | +| columns | String[] | Y | Array of field names to use as column dimensions (must exist in first row) | +| values | String[] | Y | Array of field names to aggregate (currently only 1 value is supported) | +| pages | String[] | N | Array of field names to use as page fields / report filters (must exist in first row) | +| pageDefaults | Object | N | Default filter values for page fields. Keys are field names, values are the default selections | +| metric | String | N | Aggregation function (currently only 'sum' is supported). Default: 'sum' | +| applyWidthHeightFormats | String | N | Controls column width behavior: '1' = apply pivot table style (default), '0' = preserve worksheet column widths | ### Important Notes **Field Names:** + - Field names must match column headers in the first row of the source sheet exactly - Field names are case-sensitive **Source Data:** + - The pivot table uses the entire source worksheet data - The first row is treated as headers - All data rows below the header row will be included in the pivot table **Current Limitations:** + - **Streaming not supported:** Pivot tables are **not supported with the streaming API** (`WorkbookWriter`). Pivot tables require reading all source data to generate the pivot cache, which conflicts with streaming's one-pass write model. Excel requires complete pivot cache data (all unique values and all data rows) at file creation time. Use the standard (non-streaming) `Workbook` API for workbooks with pivot tables. - **Write-only:** Pivot tables can be created and written to XLSX files, but **reading pivot table definitions from existing files is not yet implemented**. When you read an Excel file containing pivot tables: - The pivot table data will be preserved if you write the file back out @@ -1706,6 +1742,7 @@ The following properties are supported in the pivot table configuration: ### Example Output When you open the generated Excel file, the pivot table will be interactive and fully functional in Excel, allowing you to: + - Expand/collapse row and column groups - Filter data using the pivot table controls - Refresh the pivot table if source data changes @@ -1725,18 +1762,17 @@ pivotTables.forEach(pt => { }); ``` - ## Styles[⬆](#contents) Cells, Rows and Columns each support a rich set of styles and formats that affect how the cells are displayed. Styles are set by assigning the following properties: -* numFmt -* font -* alignment -* border -* fill +- numFmt +- font +- alignment +- border +- fill ```javascript // assign a style to a cell @@ -1744,30 +1780,30 @@ ws.getCell('A1').numFmt = '0.00%'; // Apply styles to worksheet columns ws.columns = [ - { header: 'Id', key: 'id', width: 10 }, - { header: 'Name', key: 'name', width: 32, style: { font: { name: 'Arial Black' } } }, - { header: 'D.O.B.', key: 'DOB', width: 10, style: { numFmt: 'dd/mm/yyyy' } } + {header: 'Id', key: 'id', width: 10}, + {header: 'Name', key: 'name', width: 32, style: {font: {name: 'Arial Black'}}}, + {header: 'D.O.B.', key: 'DOB', width: 10, style: {numFmt: 'dd/mm/yyyy'}}, ]; // Set Column 3 to Currency Format ws.getColumn(3).numFmt = '"£"#,##0.00;[Red]\-"£"#,##0.00'; // Set Row 2 to Comic Sans. -ws.getRow(2).font = { name: 'Comic Sans MS', family: 4, size: 16, underline: 'double', bold: true }; +ws.getRow(2).font = {name: 'Comic Sans MS', family: 4, size: 16, underline: 'double', bold: true}; ``` When a style is applied to a row or column, it will be applied to all currently existing cells in that row or column. - Also, any new cell that is created will inherit its initial styles from the row and column it belongs to. +Also, any new cell that is created will inherit its initial styles from the row and column it belongs to. If a cell's row and column both define a specific style (e.g. font), the cell will use the row style over the column style. - However if the row and column define different styles (e.g. column.numFmt and row.font), the cell will inherit the font from the row and the numFmt from the column. +However if the row and column define different styles (e.g. column.numFmt and row.font), the cell will inherit the font from the row and the numFmt from the column. Caveat: All the above properties (with the exception of numFmt, which is a string), are JS object structures. - If the same style object is assigned to more than one spreadsheet entity, then each entity will share the same style object. - If the style object is later modified before the spreadsheet is serialized, then all entities referencing that style object will be modified too. - This behaviour is intended to prioritize performance by reducing the number of JS objects created. - If you want the style objects to be independent, you will need to clone them before assigning them. - Also, by default, when a document is read from file (or stream) if spreadsheet entities share similar styles, then they will reference the same style object too. +If the same style object is assigned to more than one spreadsheet entity, then each entity will share the same style object. +If the style object is later modified before the spreadsheet is serialized, then all entities referencing that style object will be modified too. +This behaviour is intended to prioritize performance by reducing the number of JS objects created. +If you want the style objects to be independent, you will need to clone them before assigning them. +Also, by default, when a document is read from file (or stream) if spreadsheet entities share similar styles, then they will reference the same style object too. ### Number Formats[⬆](#contents) @@ -1784,33 +1820,32 @@ ws.getCell('B1').numFmt = '0.00%'; ### Fonts[⬆](#contents) ```javascript - // for the wannabe graphic designers out there ws.getCell('A1').font = { name: 'Comic Sans MS', family: 4, size: 16, underline: true, - bold: true + bold: true, }; // for the graduate graphic designers... ws.getCell('A2').font = { name: 'Arial Black', - color: { argb: 'FF00FF00' }, + color: {argb: 'FF00FF00'}, family: 2, size: 14, - italic: true + italic: true, }; // for the vertical align ws.getCell('A3').font = { - vertAlign: 'superscript' + vertAlign: 'superscript', }; // note: the cell will store a reference to the font object assigned. // If the font object is changed afterwards, the cell font will change also... -const font = { name: 'Arial', size: 12 }; +const font = {name: 'Arial', size: 12}; ws.getCell('A3').font = font; font.size = 20; // Cell A3 now has font size 20! @@ -1818,39 +1853,39 @@ font.size = 20; // Cell A3 now has font size 20! // the workbook is read from file or stream ``` -| Font Property | Description | Example Value(s) | -| ------------- | ----------------- | ---------------- | -| name | Font name. | 'Arial', 'Calibri', etc. | -| family | Font family for fallback. An integer value. | 1 - Serif, 2 - Sans Serif, 3 - Mono, Others - unknown | -| scheme | Font scheme. | 'minor', 'major', 'none' | -| charset | Font charset. An integer value. | 1, 2, etc. | -| size | Font size. An integer value. | 9, 10, 12, 16, etc. | -| color | Colour description, an object containing an ARGB value. | { argb: 'FFFF0000'} | -| bold | Font **weight** | true, false | -| italic | Font *slope* | true, false | -| underline | Font underline style | true, false, 'none', 'single', 'double', 'singleAccounting', 'doubleAccounting' | -| strike | Font strikethrough | true, false | -| outline | Font outline | true, false | -| vertAlign | Vertical align | 'superscript', 'subscript' +| Font Property | Description | Example Value(s) | +| ------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------- | +| name | Font name. | 'Arial', 'Calibri', etc. | +| family | Font family for fallback. An integer value. | 1 - Serif, 2 - Sans Serif, 3 - Mono, Others - unknown | +| scheme | Font scheme. | 'minor', 'major', 'none' | +| charset | Font charset. An integer value. | 1, 2, etc. | +| size | Font size. An integer value. | 9, 10, 12, 16, etc. | +| color | Colour description, an object containing an ARGB value. | { argb: 'FFFF0000'} | +| bold | Font **weight** | true, false | +| italic | Font _slope_ | true, false | +| underline | Font underline style | true, false, 'none', 'single', 'double', 'singleAccounting', 'doubleAccounting' | +| strike | Font strikethrough | true, false | +| outline | Font outline | true, false | +| vertAlign | Vertical align | 'superscript', 'subscript' | ### Alignment[⬆](#contents) ```javascript // set cell alignment to top-left, middle-center, bottom-right -ws.getCell('A1').alignment = { vertical: 'top', horizontal: 'left' }; -ws.getCell('B1').alignment = { vertical: 'middle', horizontal: 'center' }; -ws.getCell('C1').alignment = { vertical: 'bottom', horizontal: 'right' }; +ws.getCell('A1').alignment = {vertical: 'top', horizontal: 'left'}; +ws.getCell('B1').alignment = {vertical: 'middle', horizontal: 'center'}; +ws.getCell('C1').alignment = {vertical: 'bottom', horizontal: 'right'}; // set cell to wrap-text -ws.getCell('D1').alignment = { wrapText: true }; +ws.getCell('D1').alignment = {wrapText: true}; // set cell indent to 1 -ws.getCell('E1').alignment = { indent: 1 }; +ws.getCell('E1').alignment = {indent: 1}; // set cell text rotation to 30deg upwards, 45deg downwards and vertical text -ws.getCell('F1').alignment = { textRotation: 30 }; -ws.getCell('G1').alignment = { textRotation: -45 }; -ws.getCell('H1').alignment = { textRotation: 'vertical' }; +ws.getCell('F1').alignment = {textRotation: 30}; +ws.getCell('G1').alignment = {textRotation: -45}; +ws.getCell('H1').alignment = {textRotation: 'vertical'}; ``` **Valid Alignment Property Values** @@ -1865,46 +1900,45 @@ ws.getCell('H1').alignment = { textRotation: 'vertical' }; | centerContinuous | | | | | | | | distributed | | | | | | | - ### Borders[⬆](#contents) ```javascript // set single thin border around A1 ws.getCell('A1').border = { - top: {style:'thin'}, - left: {style:'thin'}, - bottom: {style:'thin'}, - right: {style:'thin'} + top: {style: 'thin'}, + left: {style: 'thin'}, + bottom: {style: 'thin'}, + right: {style: 'thin'}, }; // set double thin green border around A3 ws.getCell('A3').border = { - top: {style:'double', color: {argb:'FF00FF00'}}, - left: {style:'double', color: {argb:'FF00FF00'}}, - bottom: {style:'double', color: {argb:'FF00FF00'}}, - right: {style:'double', color: {argb:'FF00FF00'}} + top: {style: 'double', color: {argb: 'FF00FF00'}}, + left: {style: 'double', color: {argb: 'FF00FF00'}}, + bottom: {style: 'double', color: {argb: 'FF00FF00'}}, + right: {style: 'double', color: {argb: 'FF00FF00'}}, }; // set thick red cross in A5 ws.getCell('A5').border = { - diagonal: {up: true, down: true, style:'thick', color: {argb:'FFFF0000'}} + diagonal: {up: true, down: true, style: 'thick', color: {argb: 'FFFF0000'}}, }; ``` **Valid Border Styles** -* thin -* dotted -* dashDot -* hair -* dashDotDot -* slantDashDot -* mediumDashed -* mediumDashDotDot -* mediumDashDot -* medium -* double -* thick +- thin +- dotted +- dashDot +- hair +- dashDotDot +- slantDashDot +- mediumDashed +- mediumDashDotDot +- mediumDashDot +- medium +- double +- thick ### Fills[⬆](#contents) @@ -1912,23 +1946,23 @@ ws.getCell('A5').border = { // fill A1 with red darkVertical stripes ws.getCell('A1').fill = { type: 'pattern', - pattern:'darkVertical', - fgColor:{argb:'FFFF0000'} + pattern: 'darkVertical', + fgColor: {argb: 'FFFF0000'}, }; // fill A2 with yellow dark trellis and blue behind ws.getCell('A2').fill = { type: 'pattern', - pattern:'darkTrellis', - fgColor:{argb:'FFFFFF00'}, - bgColor:{argb:'FF0000FF'} + pattern: 'darkTrellis', + fgColor: {argb: 'FFFFFF00'}, + bgColor: {argb: 'FF0000FF'}, }; // fill A3 with solid coral ws.getCell('A3').fill = { type: 'pattern', - pattern:'solid', - fgColor:{argb:'F08080'}, + pattern: 'solid', + fgColor: {argb: 'F08080'}, }; // fill A4 with blue-white-blue gradient from left to right @@ -1937,68 +1971,66 @@ ws.getCell('A4').fill = { gradient: 'angle', degree: 0, stops: [ - {position:0, color:{argb:'FF0000FF'}}, - {position:0.5, color:{argb:'FFFFFFFF'}}, - {position:1, color:{argb:'FF0000FF'}} - ] + {position: 0, color: {argb: 'FF0000FF'}}, + {position: 0.5, color: {argb: 'FFFFFFFF'}}, + {position: 1, color: {argb: 'FF0000FF'}}, + ], }; - // fill A5 with red-green gradient from center ws.getCell('A5').fill = { type: 'gradient', gradient: 'path', - center:{left:0.5,top:0.5}, + center: {left: 0.5, top: 0.5}, stops: [ - {position:0, color:{argb:'FFFF0000'}}, - {position:1, color:{argb:'FF00FF00'}} - ] + {position: 0, color: {argb: 'FFFF0000'}}, + {position: 1, color: {argb: 'FF00FF00'}}, + ], }; ``` #### Pattern Fills[⬆](#contents) -| Property | Required | Description | -| -------- | -------- | ----------- | -| type | Y | Value: 'pattern'
Specifies this fill uses patterns | +| Property | Required | Description | +| -------- | -------- | -------------------------------------------------------------------------------------------- | +| type | Y | Value: 'pattern'
Specifies this fill uses patterns | | pattern | Y | Specifies type of pattern (see Valid Pattern Types below) | -| fgColor | N | Specifies the pattern foreground color. Default is black. | -| bgColor | N | Specifies the pattern background color. Default is white. | +| fgColor | N | Specifies the pattern foreground color. Default is black. | +| bgColor | N | Specifies the pattern background color. Default is white. | Note: If you want to fill a cell using the `solid` pattern, then you don't need to specify `bgColor`. See example above for cell `A3` with a `solid` pattern and a coral `fgColor`. - **Valid Pattern Types** -* none -* solid -* darkGray -* mediumGray -* lightGray -* gray125 -* gray0625 -* darkHorizontal -* darkVertical -* darkDown -* darkUp -* darkGrid -* darkTrellis -* lightHorizontal -* lightVertical -* lightDown -* lightUp -* lightGrid -* lightTrellis +- none +- solid +- darkGray +- mediumGray +- lightGray +- gray125 +- gray0625 +- darkHorizontal +- darkVertical +- darkDown +- darkUp +- darkGrid +- darkTrellis +- lightHorizontal +- lightVertical +- lightDown +- lightUp +- lightGrid +- lightTrellis #### Gradient Fills[⬆](#contents) -| Property | Required | Description | -| -------- | -------- | ----------- | -| type | Y | Value: 'gradient'
Specifies this fill uses gradients | -| gradient | Y | Specifies gradient type. One of ['angle', 'path'] | -| degree | angle | For 'angle' gradient, specifies the direction of the gradient. 0 is from the left to the right. Values from 1 - 359 rotates the direction clockwise | -| center | path | For 'path' gradient. Specifies the relative coordinates for the start of the path. 'left' and 'top' values range from 0 to 1 | +| Property | Required | Description | +| -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| type | Y | Value: 'gradient'
Specifies this fill uses gradients | +| gradient | Y | Specifies gradient type. One of ['angle', 'path'] | +| degree | angle | For 'angle' gradient, specifies the direction of the gradient. 0 is from the left to the right. Values from 1 - 359 rotates the direction clockwise | +| center | path | For 'path' gradient. Specifies the relative coordinates for the start of the path. 'left' and 'top' values range from 0 to 1 | | stops | Y | Specifies the gradient colour sequence. Is an array of objects containing position and color starting with position 0 and ending with position 1. Intermediary positions may be used to specify other colours on the path. | **Caveats** @@ -2011,27 +2043,43 @@ Take care with this fill to be sure it is supported by the target XLSX viewers. ### Rich Text[⬆](#contents) Individual cells now support rich text or in-cell formatting. - Rich text values can control the font properties of any number of sub-strings within the text value. - See Fonts for a complete list of details on what font properties are supported. +Rich text values can control the font properties of any number of sub-strings within the text value. +See Fonts for a complete list of details on what font properties are supported. ```javascript - ws.getCell('A1').value = { - 'richText': [ - {'font': {'size': 12,'color': {'theme': 0},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': 'This is '}, - {'font': {'italic': true,'size': 12,'color': {'theme': 0},'name': 'Calibri','scheme': 'minor'},'text': 'a'}, - {'font': {'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': ' '}, - {'font': {'size': 12,'color': {'argb': 'FFFF6600'},'name': 'Calibri','scheme': 'minor'},'text': 'colorful'}, - {'font': {'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': ' text '}, - {'font': {'size': 12,'color': {'argb': 'FFCCFFCC'},'name': 'Calibri','scheme': 'minor'},'text': 'with'}, - {'font': {'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': ' in-cell '}, - {'font': {'bold': true,'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': 'format'} - ] + richText: [ + { + font: {size: 12, color: {theme: 0}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: 'This is ', + }, + { + font: {italic: true, size: 12, color: {theme: 0}, name: 'Calibri', scheme: 'minor'}, + text: 'a', + }, + {font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, text: ' '}, + { + font: {size: 12, color: {argb: 'FFFF6600'}, name: 'Calibri', scheme: 'minor'}, + text: 'colorful', + }, + { + font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: ' text ', + }, + {font: {size: 12, color: {argb: 'FFCCFFCC'}, name: 'Calibri', scheme: 'minor'}, text: 'with'}, + { + font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: ' in-cell ', + }, + { + font: {bold: true, size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: 'format', + }, + ], }; expect(ws.getCell('A1').text).to.equal('This is a colorful text with in-cell format'); expect(ws.getCell('A1').type).to.equal(Excel.ValueType.RichText); - ``` ### Cell Protection[⬆](#contents) @@ -2047,9 +2095,9 @@ ws.getCell('A1').protection = { **Supported Protection Properties** -| Property | Default | Description | -| -------- | ------- | ----------- | -| locked | true | Specifies whether a cell will be locked if the sheet is protected. | +| Property | Default | Description | +| -------- | ------- | ----------------------------------------------------------------------------- | +| locked | true | Specifies whether a cell will be locked if the sheet is protected. | | hidden | false | Specifies whether a cell's formula will be visible if the sheet is protected. | ## Conditional Formatting[⬆](#contents) @@ -2083,188 +2131,190 @@ worksheet.addConditionalFormatting({ type: 'expression', formulae: ['MOD(ROW()+COLUMN(),2)=0'], style: {fill: {type: 'pattern', pattern: 'solid', bgColor: {argb: 'FF00FF00'}}}, - } - ] -}) + }, + ], +}); ``` **Supported Conditional Formatting Rule Types** -| Type | Description | -| ------------ | ----------- | -| expression | Any custom function may be used to activate the rule. | -| cellIs | Compares cell value with supplied formula using specified operator | -| top10 | Applies formatting to cells with values in top (or bottom) ranges | -| aboveAverage | Applies formatting to cells with values above (or below) average | -| colorScale | Applies a coloured background to cells based on where their values lie in the range | -| iconSet | Adds one of a range of icons to cells based on value | -| containsText | Applies formatting based on whether cell a specific text | +| Type | Description | +| ------------ | ------------------------------------------------------------------------------------- | +| expression | Any custom function may be used to activate the rule. | +| cellIs | Compares cell value with supplied formula using specified operator | +| top10 | Applies formatting to cells with values in top (or bottom) ranges | +| aboveAverage | Applies formatting to cells with values above (or below) average | +| colorScale | Applies a coloured background to cells based on where their values lie in the range | +| iconSet | Adds one of a range of icons to cells based on value | +| containsText | Applies formatting based on whether cell a specific text | | timePeriod | Applies formatting based on whether cell datetime value lies within a specified range | ### Expression[⬆](#contents) -| Field | Optional | Default | Description | -| ---------- | -------- | ------- | ----------- | -| type | | | 'expression' | -| priority | Y | <auto> | determines priority ordering of styles | -| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | -| formulae | | | array of 1 formula string that returns a true/false value. To reference the cell value, use the top-left cell address | -| style | | | style structure to apply if the formula returns true | +| Field | Optional | Default | Description | +| ---------- | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------- | +| type | | | 'expression' | +| priority | Y | <auto> | determines priority ordering of styles | +| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | +| formulae | | | array of 1 formula string that returns a true/false value. To reference the cell value, use the top-left cell address | +| style | | | style structure to apply if the formula returns true | ### Cell Is[⬆](#contents) -| Field | Optional | Default | Description | -| ---------- | -------- | ------- | ----------- | -| type | | | 'cellIs' | -| priority | Y | <auto> | determines priority ordering of styles | -| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | -| operator | | | how to compare cell value with formula result | -| formulae | | | array of 1 formula string that returns the value to compare against each cell | -| style | | | style structure to apply if the comparison returns true | +| Field | Optional | Default | Description | +| ---------- | -------- | ------------ | ----------------------------------------------------------------------------- | +| type | | | 'cellIs' | +| priority | Y | <auto> | determines priority ordering of styles | +| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | +| operator | | | how to compare cell value with formula result | +| formulae | | | array of 1 formula string that returns the value to compare against each cell | +| style | | | style structure to apply if the comparison returns true | **Cell Is Operators** -| Operator | Description | -| -------------------- | ----------- | -| equal | Apply format if cell value equals formula value | -| notEqual | Apply format if cell value does not equal formula value | -| greaterThan | Apply format if cell value is greater than formula value | -| greaterThanOrEqual | Apply format if cell value is greater than or equal to formula value | -| lessThan | Apply format if cell value is less than formula value | -| lessThanOrEqual | Apply format if cell value is less than or equal to formula value | -| between | Apply format if cell value is between two formula values (inclusive) | -| notBetween | Apply format if cell value is not between two formula values | - +| Operator | Description | +| ------------------ | -------------------------------------------------------------------- | +| equal | Apply format if cell value equals formula value | +| notEqual | Apply format if cell value does not equal formula value | +| greaterThan | Apply format if cell value is greater than formula value | +| greaterThanOrEqual | Apply format if cell value is greater than or equal to formula value | +| lessThan | Apply format if cell value is less than formula value | +| lessThanOrEqual | Apply format if cell value is less than or equal to formula value | +| between | Apply format if cell value is between two formula values (inclusive) | +| notBetween | Apply format if cell value is not between two formula values | ### Top 10[⬆](#contents) -| Field | Optional | Default | Description | -| ---------- | -------- | ------- | ----------- | -| type | | | 'top10' | -| priority | Y | <auto> | determines priority ordering of styles | -| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | -| rank | Y | 10 | specifies how many top (or bottom) values are included in the formatting | -| percent | Y | false | if true, the rank field is a percentage, not an absolute | -| bottom | Y | false | if true, the bottom values are included instead of the top | -| style | | | style structure to apply if the comparison returns true | +| Field | Optional | Default | Description | +| ---------- | -------- | ------------ | ------------------------------------------------------------------------ | +| type | | | 'top10' | +| priority | Y | <auto> | determines priority ordering of styles | +| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | +| rank | Y | 10 | specifies how many top (or bottom) values are included in the formatting | +| percent | Y | false | if true, the rank field is a percentage, not an absolute | +| bottom | Y | false | if true, the bottom values are included instead of the top | +| style | | | style structure to apply if the comparison returns true | ### Above Average[⬆](#contents) -| Field | Optional | Default | Description | -| ------------- | -------- | ------- | ----------- | -| type | | | 'aboveAverage' | -| priority | Y | <auto> | determines priority ordering of styles | -| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | -| aboveAverage | Y | false | if true, the rank field is a percentage, not an absolute | -| style | | | style structure to apply if the comparison returns true | +| Field | Optional | Default | Description | +| ------------ | -------- | ------------ | ---------------------------------------------------------------------- | +| type | | | 'aboveAverage' | +| priority | Y | <auto> | determines priority ordering of styles | +| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | +| aboveAverage | Y | false | if true, the rank field is a percentage, not an absolute | +| style | | | style structure to apply if the comparison returns true | ### Color Scale[⬆](#contents) -| Field | Optional | Default | Description | -| ------------- | -------- | ------- | ----------- | -| type | | | 'colorScale' | -| priority | Y | <auto> | determines priority ordering of styles | -| cfvo | | | array of 2 to 5 Conditional Formatting Value Objects specifying way-points in the value range | -| color | | | corresponding array of colours to use at given way points | -| style | | | style structure to apply if the comparison returns true | +| Field | Optional | Default | Description | +| -------- | -------- | ------------ | --------------------------------------------------------------------------------------------- | +| type | | | 'colorScale' | +| priority | Y | <auto> | determines priority ordering of styles | +| cfvo | | | array of 2 to 5 Conditional Formatting Value Objects specifying way-points in the value range | +| color | | | corresponding array of colours to use at given way points | +| style | | | style structure to apply if the comparison returns true | ### Icon Set[⬆](#contents) -| Field | Optional | Default | Description | -| ------------- | -------- | ------- | ----------- | -| type | | | 'iconSet' | -| priority | Y | <auto> | determines priority ordering of styles | -| iconSet | Y | 3TrafficLights | name of icon set to use | -| showValue | | true | Specifies whether the cells in the applied range display the icon and cell value, or the icon only | -| reverse | | false | Specifies whether the icons in the icon set specified in iconSet are show in reserve order. If custom equals "true" this value must be ignored | -| custom | | false | Specifies whether a custom set of icons is used | -| cfvo | | | array of 2 to 5 Conditional Formatting Value Objects specifying way-points in the value range | -| style | | | style structure to apply if the comparison returns true | +| Field | Optional | Default | Description | +| --------- | -------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| type | | | 'iconSet' | +| priority | Y | <auto> | determines priority ordering of styles | +| iconSet | Y | 3TrafficLights | name of icon set to use | +| showValue | | true | Specifies whether the cells in the applied range display the icon and cell value, or the icon only | +| reverse | | false | Specifies whether the icons in the icon set specified in iconSet are show in reserve order. If custom equals "true" this value must be ignored | +| custom | | false | Specifies whether a custom set of icons is used | +| cfvo | | | array of 2 to 5 Conditional Formatting Value Objects specifying way-points in the value range | +| style | | | style structure to apply if the comparison returns true | ### Data Bar[⬆](#contents) -| Field | Optional | Default | Description | -| ---------- | -------- | ------- | ----------- | -| type | | | 'dataBar' | -| priority | Y | <auto> | determines priority ordering of styles | -| minLength | | 0 | Specifies the length of the shortest data bar in this conditional formatting range | -| maxLength | | 100 | Specifies the length of the longest data bar in this conditional formatting range | -| showValue | | true | Specifies whether the cells in the conditional formatting range display both the data bar and the numeric value or the data bar | -| gradient | | true | Specifies whether the data bar has a gradient fill | -| border | | true | Specifies whether the data bar has a border | -| negativeBarColorSameAsPositive | | true | Specifies whether the data bar has a negative bar color that is different from the positive bar color | -| negativeBarBorderColorSameAsPositive | | true | Specifies whether the data bar has a negative border color that is different from the positive border color | -| axisPosition | | 'auto' | Specifies the axis position for the data bar | -| direction | | 'leftToRight' | Specifies the direction of the data bar | -| cfvo | | | array of 2 to 5 Conditional Formatting Value Objects specifying way-points in the value range | -| style | | | style structure to apply if the comparison returns true | +| Field | Optional | Default | Description | +| ------------------------------------ | -------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| type | | | 'dataBar' | +| priority | Y | <auto> | determines priority ordering of styles | +| minLength | | 0 | Specifies the length of the shortest data bar in this conditional formatting range | +| maxLength | | 100 | Specifies the length of the longest data bar in this conditional formatting range | +| showValue | | true | Specifies whether the cells in the conditional formatting range display both the data bar and the numeric value or the data bar | +| gradient | | true | Specifies whether the data bar has a gradient fill | +| border | | true | Specifies whether the data bar has a border | +| negativeBarColorSameAsPositive | | true | Specifies whether the data bar has a negative bar color that is different from the positive bar color | +| negativeBarBorderColorSameAsPositive | | true | Specifies whether the data bar has a negative border color that is different from the positive border color | +| axisPosition | | 'auto' | Specifies the axis position for the data bar | +| direction | | 'leftToRight' | Specifies the direction of the data bar | +| cfvo | | | array of 2 to 5 Conditional Formatting Value Objects specifying way-points in the value range | +| style | | | style structure to apply if the comparison returns true | ### Contains Text[⬆](#contents) -| Field | Optional | Default | Description | -| ---------- | -------- | ------- | ----------- | -| type | | | 'containsText' | -| priority | Y | <auto> | determines priority ordering of styles | -| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | -| operator | | | type of text comparison | -| text | | | text to search for | -| style | | | style structure to apply if the comparison returns true | +| Field | Optional | Default | Description | +| ---------- | -------- | ------------ | ---------------------------------------------------------------------- | +| type | | | 'containsText' | +| priority | Y | <auto> | determines priority ordering of styles | +| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | +| operator | | | type of text comparison | +| text | | | text to search for | +| style | | | style structure to apply if the comparison returns true | **Contains Text Operators** -| Operator | Description | -| ----------------- | ----------- | +| Operator | Description | +| ----------------- | --------------------------------------------------------------------------- | | containsText | Apply format if cell value contains the value specified in the 'text' field | -| containsBlanks | Apply format if cell value contains blanks | -| notContainsBlanks | Apply format if cell value does not contain blanks | -| containsErrors | Apply format if cell value contains errors | -| notContainsErrors | Apply format if cell value does not contain errors | +| containsBlanks | Apply format if cell value contains blanks | +| notContainsBlanks | Apply format if cell value does not contain blanks | +| containsErrors | Apply format if cell value contains errors | +| notContainsErrors | Apply format if cell value does not contain errors | ### Time Period[⬆](#contents) -| Field | Optional | Default | Description | -| ---------- | -------- | ------- | ----------- | -| type | | | 'timePeriod' | -| priority | Y | <auto> | determines priority ordering of styles | -| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | -| timePeriod | | | what time period to compare cell value to | -| style | | | style structure to apply if the comparison returns true | +| Field | Optional | Default | Description | +| ---------- | -------- | ------------ | ---------------------------------------------------------------------- | +| type | | | 'timePeriod' | +| priority | Y | <auto> | determines priority ordering of styles | +| stopIfTrue | Y | false | if true, no rules with lower priority are applied if this rule is true | +| timePeriod | | | what time period to compare cell value to | +| style | | | style structure to apply if the comparison returns true | **Time Periods** -| Time Period | Description | -| ----------------- | ----------- | -| lastWeek | Apply format if cell value falls within the last week | -| thisWeek | Apply format if cell value falls in this week | -| nextWeek | Apply format if cell value falls in the next week | -| yesterday | Apply format if cell value is equal to yesterday | -| today | Apply format if cell value is equal to today | -| tomorrow | Apply format if cell value is equal to tomorrow | -| last7Days | Apply format if cell value falls within the last 7 days | -| lastMonth | Apply format if cell value falls in last month | -| thisMonth | Apply format if cell value falls in this month | -| nextMonth | Apply format if cell value falls in next month | +| Time Period | Description | +| ----------- | ------------------------------------------------------- | +| lastWeek | Apply format if cell value falls within the last week | +| thisWeek | Apply format if cell value falls in this week | +| nextWeek | Apply format if cell value falls in the next week | +| yesterday | Apply format if cell value is equal to yesterday | +| today | Apply format if cell value is equal to today | +| tomorrow | Apply format if cell value is equal to tomorrow | +| last7Days | Apply format if cell value falls within the last 7 days | +| lastMonth | Apply format if cell value falls in last month | +| thisMonth | Apply format if cell value falls in this month | +| nextMonth | Apply format if cell value falls in next month | ## Outline Levels[⬆](#contents) Excel supports outlining; where rows or columns can be expanded or collapsed depending on what level of detail the user wishes to view. Outline levels can be defined in column setup: + ```javascript worksheet.columns = [ - { header: 'Id', key: 'id', width: 10 }, - { header: 'Name', key: 'name', width: 32 }, - { header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1 } + {header: 'Id', key: 'id', width: 10}, + {header: 'Name', key: 'name', width: 32}, + {header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1}, ]; ``` Or directly on the row or column + ```javascript worksheet.getColumn(3).outlineLevel = 1; worksheet.getRow(3).outlineLevel = 1; ``` The sheet outline levels can be set on the worksheet + ```javascript // set column outline level worksheet.properties.outlineLevelCol = 1; @@ -2274,6 +2324,7 @@ worksheet.properties.outlineLevelRow = 1; ``` Note: adjusting outline levels on rows or columns or the outline levels on the worksheet will incur a side effect of also modifying the collapsed property of all rows or columns affected by the property change. E.g.: + ```javascript worksheet.properties.outlineLevelCol = 1; @@ -2321,7 +2372,7 @@ const imageId2 = workbook.addImage({ }); // add image to workbook by base64 -const myBase64Image = "data:image/png;base64,iVBORw0KG..."; +const myBase64Image = 'data:image/png;base64,iVBORw0KG...'; const imageId2 = workbook.addImage({ base64: myBase64Image, extension: 'png', @@ -2355,25 +2406,25 @@ Fractions of cells can be specified by using floating point numbers, e.g. the mi ```javascript // insert an image over part of B2:D6 worksheet.addImage(imageId2, { - tl: new Anchor(worksheet, { col: 1.5, row: 1.5 }), - br: new Anchor(worksheet, { col: 3.5, row: 5.5 }), + tl: new Anchor(worksheet, {col: 1.5, row: 1.5}), + br: new Anchor(worksheet, {col: 3.5, row: 5.5}), }); ``` The cell range can also have the property 'editAs' which will control how the image is anchored to the cell(s) It can have one of the following values: -| Value | Description | -| -------- | ----------- | -| twoCell | It specifies the image will be moved and sized with cells | +| Value | Description | +| -------- | ----------------------------------------------------------------- | +| twoCell | It specifies the image will be moved and sized with cells | | oneCell | This is the default. Image will be moved with cells but not sized | -| absolute | Image will not be moved or sized with cells | +| absolute | Image will not be moved or sized with cells | ```javascript ws.addImage(imageId, { - tl: new Anchor(worksheet, { col: 0.1125, row: 0.4 }), - br: new Anchor(worksheet, { col: 2.101046875, row: 3.4 }), - editAs: 'oneCell' + tl: new Anchor(worksheet, {col: 0.1125, row: 0.4}), + br: new Anchor(worksheet, {col: 2.101046875, row: 3.4}), + editAs: 'oneCell', }); ``` @@ -2383,8 +2434,8 @@ You can add an image to a cell and then define its width and height in pixels at ```javascript worksheet.addImage(imageId2, { - tl: { col: 0, row: 0 }, - ext: { width: 500, height: 200 } + tl: {col: 0, row: 0}, + ext: {width: 500, height: 200}, }); ``` @@ -2394,12 +2445,12 @@ You can add an image with hyperlinks to a cell, and defines the hyperlinks in im ```javascript worksheet.addImage(imageId2, { - tl: { col: 0, row: 0 }, - ext: { width: 500, height: 200 }, + tl: {col: 0, row: 0}, + ext: {width: 500, height: 200}, hyperlinks: { hyperlink: 'http://www.somewhere.com', - tooltip: 'http://www.somewhere.com' - } + tooltip: 'http://www.somewhere.com', + }, }); ``` @@ -2417,7 +2468,6 @@ Worksheet protection can also be removed: worksheet.unprotect(); ``` - See Cell Protection for details on how to modify individual cell protection. @@ -2429,25 +2479,23 @@ faster or more resilient. ### Sheet Protection Options[⬆](#contents) -| Field | Default | Description | -| ------------------- | ------- | ----------- | -| selectLockedCells | true | Lets the user select locked cells | -| selectUnlockedCells | true | Lets the user select unlocked cells | -| formatCells | false | Lets the user format cells | -| formatColumns | false | Lets the user format columns | -| formatRows | false | Lets the user format rows | -| insertRows | false | Lets the user insert rows | -| insertColumns | false | Lets the user insert columns | -| insertHyperlinks | false | Lets the user insert hyperlinks | -| deleteRows | false | Lets the user delete rows | -| deleteColumns | false | Lets the user delete columns | -| sort | false | Lets the user sort data | -| autoFilter | false | Lets the user filter data in tables | -| pivotTables | false | Lets the user use pivot tables | +| Field | Default | Description | +| ------------------- | ------- | ----------------------------------------------------------------------- | +| selectLockedCells | true | Lets the user select locked cells | +| selectUnlockedCells | true | Lets the user select unlocked cells | +| formatCells | false | Lets the user format cells | +| formatColumns | false | Lets the user format columns | +| formatRows | false | Lets the user format rows | +| insertRows | false | Lets the user insert rows | +| insertColumns | false | Lets the user insert columns | +| insertHyperlinks | false | Lets the user insert hyperlinks | +| deleteRows | false | Lets the user delete rows | +| deleteColumns | false | Lets the user delete columns | +| sort | false | Lets the user sort data | +| autoFilter | false | Lets the user filter data in tables | +| pivotTables | false | Lets the user use pivot tables | | spinCount | 100000 | The number of hash iterations performed when protecting or unprotecting | - - ## File I/O[⬆](#contents) ### XLSX[⬆](#contents) @@ -2456,9 +2504,9 @@ faster or more resilient. Options supported when reading XLSX files. -| Field | Required | Type |Description | -| ---------------- | ----------- | ----------- | ----------- | -| ignoreNodes | N | Array | A list of node names to ignore while loading the XLSX document. Improves performance in some situations.
Available: `sheetPr`, `dimension`, `sheetViews `, `sheetFormatPr`, `cols `, `sheetData`, `autoFilter `, `mergeCells `, `rowBreaks`, `hyperlinks `, `pageMargins`, `dataValidations`, `pageSetup`, `headerFooter `, `printOptions `, `picture`, `drawing`, `sheetProtection`, `tableParts `, `conditionalFormatting`, `extLst`,| +| Field | Required | Type | Description | +| ----------- | -------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ignoreNodes | N | Array | A list of node names to ignore while loading the XLSX document. Improves performance in some situations.
Available: `sheetPr`, `dimension`, `sheetViews `, `sheetFormatPr`, `cols `, `sheetData`, `autoFilter `, `mergeCells `, `rowBreaks`, `hyperlinks `, `pageMargins`, `dataValidations`, `pageSetup`, `headerFooter `, `printOptions `, `picture`, `drawing`, `sheetProtection`, `tableParts `, `conditionalFormatting`, `extLst`, | ```javascript // read from a file @@ -2466,24 +2514,21 @@ const workbook = new Excel.Workbook(); await workbook.xlsx.readFile(filename); // ... use workbook - // read from a stream const workbook = new Excel.Workbook(); await workbook.xlsx.read(stream); // ... use workbook - // load from buffer const workbook = new Excel.Workbook(); await workbook.xlsx.load(data); // ... use workbook - // using additional options const workbook = new Excel.Workbook(); await workbook.xlsx.load(data, { ignoreNodes: [ - 'dataValidations' // ignores the workbook's Data Validations + 'dataValidations', // ignores the workbook's Data Validations ], }); // ... use workbook @@ -2509,12 +2554,12 @@ const buffer = await workbook.xlsx.writeBuffer(); Options supported when reading CSV files. -| Field | Required | Type |Description | -| ---------------- | ----------- | ----------- | ----------- | -| dateFormats | N | Array | Specify the date encoding format of dayjs. | -| map | N | Function | Custom Array.prototype.map() callback function for processing data. | -| sheetName | N | String | Specify worksheet name. | -| parserOptions | N | Object | [parseOptions options](https://c2fo.github.io/fast-csv/docs/parsing/options) @fast-csv/format module to write csv data. | +| Field | Required | Type | Description | +| ------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------- | +| dateFormats | N | Array | Specify the date encoding format of dayjs. | +| map | N | Function | Custom Array.prototype.map() callback function for processing data. | +| sheetName | N | String | Specify worksheet name. | +| parserOptions | N | Object | [parseOptions options](https://c2fo.github.io/fast-csv/docs/parsing/options) @fast-csv/format module to write csv data. | ```javascript // read from a file @@ -2522,27 +2567,24 @@ const workbook = new Excel.Workbook(); const worksheet = await workbook.csv.readFile(filename); // ... use workbook or worksheet - // read from a stream const workbook = new Excel.Workbook(); const worksheet = await workbook.csv.read(stream); // ... use workbook or worksheet - // read from a file with European Dates const workbook = new Excel.Workbook(); const options = { - dateFormats: ['DD/MM/YYYY'] + dateFormats: ['DD/MM/YYYY'], }; const worksheet = await workbook.csv.readFile(filename, options); // ... use workbook or worksheet - // read from a file with custom value parsing const workbook = new Excel.Workbook(); const options = { map(value, index) { - switch(index) { + switch (index) { case 0: // column 1 is string return value; @@ -2569,14 +2611,14 @@ const worksheet = await workbook.csv.readFile(filename, options); The CSV parser uses [fast-csv](https://www.npmjs.com/package/fast-csv) to read the CSV file. The formatterOptions in the options passed to the above write function will be passed to the @fast-csv/format module to write csv data. - Please refer to the fast-csv README.md for details. +Please refer to the fast-csv README.md for details. Dates are parsed using the npm module [dayjs](https://www.npmjs.com/package/dayjs). - If a dateFormats array is not supplied, the following dateFormats are used: +If a dateFormats array is not supplied, the following dateFormats are used: -* 'YYYY-MM-DD\[T\]HH:mm:ss' -* 'MM-DD-YYYY' -* 'YYYY-MM-DD' +- 'YYYY-MM-DD\[T\]HH:mm:ss' +- 'MM-DD-YYYY' +- 'YYYY-MM-DD' Please refer to the [dayjs CustomParseFormat plugin](https://github.com/iamkun/dayjs/blob/HEAD/docs/en/Plugin.md#customparseformat) for details on how to structure a dateFormat. @@ -2584,19 +2626,18 @@ Please refer to the [dayjs CustomParseFormat plugin](https://github.com/iamkun/d Options supported when writing to a CSV file. -| Field | Required | Type | Description | -| ---------------- | ----------- | ----------- | ----------- | -| dateFormat | N | String | Specify the date encoding format of dayjs. | -| dateUTC | N | Boolean | Specify whether ExcelJS uses `dayjs.utc ()` to convert time zone for parsing dates. | -| encoding | N | String | Specify file encoding format. (Only applies to `.writeFile`.) | -| includeEmptyRows | N | Boolean | Specifies whether empty rows can be written. | -| map | N | Function | Custom Array.prototype.map() callback function for processing row values. | -| sheetName | N | String | Specify worksheet name. | -| sheetId | N | Number | Specify worksheet ID. | -| formatterOptions | N | Object | [formatterOptions options](https://c2fo.github.io/fast-csv/docs/formatting/options/) @fast-csv/format module to write csv data. | +| Field | Required | Type | Description | +| ---------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- | +| dateFormat | N | String | Specify the date encoding format of dayjs. | +| dateUTC | N | Boolean | Specify whether ExcelJS uses `dayjs.utc ()` to convert time zone for parsing dates. | +| encoding | N | String | Specify file encoding format. (Only applies to `.writeFile`.) | +| includeEmptyRows | N | Boolean | Specifies whether empty rows can be written. | +| map | N | Function | Custom Array.prototype.map() callback function for processing row values. | +| sheetName | N | String | Specify worksheet name. | +| sheetId | N | Number | Specify worksheet ID. | +| formatterOptions | N | Object | [formatterOptions options](https://c2fo.github.io/fast-csv/docs/formatting/options/) @fast-csv/format module to write csv data. | ```javascript - // write to a file const workbook = new Excel.Workbook(); await workbook.csv.writeFile(filename); @@ -2604,7 +2645,7 @@ await workbook.csv.writeFile(filename); // write to a stream // Be careful that you need to provide sheetName or // sheetId for correct import to csv. -await workbook.csv.write(stream, { sheetName: 'Page name' }); +await workbook.csv.write(stream, {sheetName: 'Page name'}); // write to a file with European Date-Times const workbook = new Excel.Workbook(); @@ -2614,12 +2655,11 @@ const options = { }; await workbook.csv.writeFile(filename, options); - // write to a file with custom value formatting const workbook = new Excel.Workbook(); const options = { map(value, index) { - switch(index) { + switch (index) { case 0: // column 1 is string return value; @@ -2647,33 +2687,33 @@ const buffer = await workbook.csv.writeBuffer(); ``` The CSV parser uses [fast-csv](https://www.npmjs.com/package/fast-csv) to write the CSV file. - The formatterOptions in the options passed to the above write function will be passed to the @fast-csv/format module to write csv data. - Please refer to the fast-csv README.md for details. +The formatterOptions in the options passed to the above write function will be passed to the @fast-csv/format module to write csv data. +Please refer to the fast-csv README.md for details. Dates are formatted using the npm module [dayjs](https://www.npmjs.com/package/dayjs). - If no dateFormat is supplied, dayjs.ISO_8601 is used. - When writing a CSV you can supply the boolean dateUTC as true to have ExcelJS parse the date without automatically - converting the timezone using `dayjs.utc()`. +If no dateFormat is supplied, dayjs.ISO_8601 is used. +When writing a CSV you can supply the boolean dateUTC as true to have ExcelJS parse the date without automatically +converting the timezone using `dayjs.utc()`. ### Streaming I/O[⬆](#contents) The File I/O documented above requires that an entire workbook is built up in memory before the file can be written. - While convenient, it can limit the size of the document due to the amount of memory required. +While convenient, it can limit the size of the document due to the amount of memory required. A streaming writer (or reader) processes the workbook or worksheet data as it is generated, - converting it into file form as it goes. Typically this is much more efficient on memory as the final - memory footprint and even intermediate memory footprints are much more compact than with the document version, - especially when you consider that the row and cell objects are disposed once they are committed. +converting it into file form as it goes. Typically this is much more efficient on memory as the final +memory footprint and even intermediate memory footprints are much more compact than with the document version, +especially when you consider that the row and cell objects are disposed once they are committed. The interface to the streaming workbook and worksheet is almost the same as the document versions with a few minor practical differences: -* Once a worksheet is added to a workbook, it cannot be removed. -* Once a row is committed, it is no longer accessible since it will have been dropped from the worksheet. -* unMergeCells() is not supported. +- Once a worksheet is added to a workbook, it cannot be removed. +- Once a row is committed, it is no longer accessible since it will have been dropped from the worksheet. +- unMergeCells() is not supported. Note that it is possible to build the entire workbook without committing any rows. - When the workbook is committed, all added worksheets (including all uncommitted rows) will be automatically committed. - However in this case, little will have been gained over the Document version. +When the workbook is committed, all added worksheets (including all uncommitted rows) will be automatically committed. +However in this case, little will have been gained over the Document version. #### Streaming XLSX[⬆](#contents) @@ -2683,31 +2723,31 @@ The streaming XLSX workbook writer is available in the ExcelJS.stream.xlsx names The constructor takes an optional options object with the following fields: -| Field | Description | -| ---------------- | ----------- | -| stream | Specifies a writable stream to write the XLSX workbook to. | -| filename | If stream not specified, this field specifies the path to a file to write the XLSX workbook to. | -| useSharedStrings | Specifies whether to use shared strings in the workbook. Default is `false`. | -| useStyles | Specifies whether to add style information to the workbook. Styles can add some performance overhead. Default is `false`. | +| Field | Description | +| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| stream | Specifies a writable stream to write the XLSX workbook to. | +| filename | If stream not specified, this field specifies the path to a file to write the XLSX workbook to. | +| useSharedStrings | Specifies whether to use shared strings in the workbook. Default is `false`. | +| useStyles | Specifies whether to add style information to the workbook. Styles can add some performance overhead. Default is `false`. | | zip | [Zip options](https://www.archiverjs.com/global.html#ZipOptions) that ExcelJS internally passes to [Archiver](https://github.com/archiverjs/node-archiver). Default is `undefined`. | If neither stream nor filename is specified in the options, the workbook writer will create a StreamBuf object - that will store the contents of the XLSX workbook in memory. - This StreamBuf object, which can be accessed via the property workbook.stream, can be used to either - access the bytes directly by stream.read() or to pipe the contents to another stream. +that will store the contents of the XLSX workbook in memory. +This StreamBuf object, which can be accessed via the property workbook.stream, can be used to either +access the bytes directly by stream.read() or to pipe the contents to another stream. ```javascript // construct a streaming XLSX workbook writer with styles and shared strings const options = { filename: './streamed-workbook.xlsx', useStyles: true, - useSharedStrings: true + useSharedStrings: true, }; const workbook = new Excel.stream.xlsx.WorkbookWriter(options); ``` In general, the interface to the streaming XLSX writer is the same as the Document workbook (and worksheets) - described above, in fact the row, cell and style objects are the same. +described above, in fact the row, cell and style objects are the same. However there are some differences... @@ -2718,14 +2758,16 @@ As seen above, the WorkbookWriter will typically require the output stream or fi **Committing Data** When a worksheet row is ready, it should be committed so that the row object and contents can be freed. - Typically this would be done as each row is added... +Typically this would be done as each row is added... ```javascript -worksheet.addRow({ - id: i, - name: theName, - etc: someOtherDetail -}).commit(); +worksheet + .addRow({ + id: i, + name: theName, + etc: someOtherDetail, + }) + .commit(); ``` The reason the WorksheetWriter does not commit rows as they are added is to allow cells to be merged across rows: @@ -2746,7 +2788,7 @@ worksheet.commit(); ``` To complete the XLSX document, the workbook must be committed. If any worksheet in a workbook are uncommitted, - they will be committed automatically as part of the workbook commit. +they will be committed automatically as part of the workbook commit. ```javascript // Finished the workbook. @@ -2760,15 +2802,15 @@ The streaming XLSX workbook reader is available in the ExcelJS.stream.xlsx names The constructor takes a required input argument and an optional options argument: -| Argument | Description | -| --------------------- | ----------- | -| input (required) | Specifies the name of the file or the readable stream from which to read the XLSX workbook. | -| options (optional) | Specifies how to handle the event types occuring during the read parsing. | -| options.entries | Specifies whether to emit entries (`'emit'`) or not (`'ignore'`). Default is `'emit'`. | +| Argument | Description | +| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| input (required) | Specifies the name of the file or the readable stream from which to read the XLSX workbook. | +| options (optional) | Specifies how to handle the event types occuring during the read parsing. | +| options.entries | Specifies whether to emit entries (`'emit'`) or not (`'ignore'`). Default is `'emit'`. | | options.sharedStrings | Specifies whether to cache shared strings (`'cache'`), which inserts them into the respective cell values, or whether to emit them (`'emit'`) or ignore them (`'ignore'`), in both of which case the cell value will be a reference to the shared string's index. Default is `'cache'`. | -| options.hyperlinks | Specifies whether to cache hyperlinks (`'cache'`), which inserts them into their respective cells, whether to emit them (`'emit'`) or whether to ignore them (`'ignore'`). Default is `'cache'`. | -| options.styles | Specifies whether to cache styles (`'cache'`), which inserts them into their respective rows and cells, or whether to ignore them (`'ignore'`). Default is `'cache'`. | -| options.worksheets | Specifies whether to emit worksheets (`'emit'`) or not (`'ignore'`). Default is `'emit'`. | +| options.hyperlinks | Specifies whether to cache hyperlinks (`'cache'`), which inserts them into their respective cells, whether to emit them (`'emit'`) or whether to ignore them (`'ignore'`). Default is `'cache'`. | +| options.styles | Specifies whether to cache styles (`'cache'`), which inserts them into their respective rows and cells, or whether to ignore them (`'ignore'`). Default is `'cache'`. | +| options.worksheets | Specifies whether to emit worksheets (`'emit'`) or not (`'ignore'`). Default is `'emit'`. | ```js const workbookReader = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx'); @@ -2795,11 +2837,11 @@ const workbook = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx', options); for await (const {eventType, value} of workbook.parse()) { switch (eventType) { case 'shared-strings': - // value is the shared string + // value is the shared string case 'worksheet': - // value is the worksheetReader + // value is the worksheetReader case 'hyperlinks': - // value is the hyperlinksReader + // value is the hyperlinksReader } } ``` @@ -2818,8 +2860,7 @@ const workbookReader = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx', opt workbookReader.read(); workbookReader.on('worksheet', worksheet => { - worksheet.on('row', row => { - }); + worksheet.on('row', row => {}); }); workbookReader.on('shared-strings', sharedString => { @@ -2833,7 +2874,7 @@ workbookReader.on('hyperlinks', hyperlinksReader => { workbookReader.on('end', () => { // ... }); -workbookReader.on('error', (err) => { +workbookReader.on('error', err => { // ... }); ``` @@ -2851,8 +2892,8 @@ For example code using ExcelJS in the browser take a look at the @@ -2939,8 +2981,8 @@ worksheet.getCell('A1').value = { text: 'Sheet2', hyperlink: '#\'Sheet2\'!A1' }; Enum: Excel.ValueType.Formula An Excel formula for calculating values on the fly. - Note that while the cell type will be Formula, the cell may have an effectiveType value that will - be derived from the result value. +Note that while the cell type will be Formula, the cell may have an effectiveType value that will +be derived from the result value. Note that ExcelJS cannot process the formula to generate a result, it must be supplied. @@ -2949,8 +2991,8 @@ Note that function semantic names must be in English and the separator must be a E.g. ```javascript -worksheet.getCell('A3').value = { formula: 'A1+A2', result: 7 }; -worksheet.getCell('A3').value = { formula: 'SUM(A1,A2)', result: 7 }; +worksheet.getCell('A3').value = {formula: 'A1+A2', result: 7}; +worksheet.getCell('A3').value = {formula: 'SUM(A1,A2)', result: 7}; ``` Cells also support convenience getters to access the formula and result: @@ -2981,14 +3023,14 @@ worksheet.getCell('A2').value = { formula: 'A1', result: 10, shareType: 'shared', - ref: 'A2:B3' + ref: 'A2:B3', }; ``` A shared formula can be assigned to a cell using a new value form: ```javascript -worksheet.getCell('B2').value = { sharedFormula: 'A2', result: 10 }; +worksheet.getCell('B2').value = {sharedFormula: 'A2', result: 10}; ``` This specifies that the cell B2 is a formula that will be derived from the formula in @@ -3007,7 +3049,7 @@ Shared formulae can be assigned into a sheet using the 'fillFormula' function: worksheet.getCell('A1').value = 1; // fill A2 to A10 with ascending count starting from A1 -worksheet.fillFormula('A2:A10', 'A1+1', [2,3,4,5,6,7,8,9,10]); +worksheet.fillFormula('A2:A10', 'A1+1', [2, 3, 4, 5, 6, 7, 8, 9, 10]); ``` fillFormula can also use a callback function to calculate the value at each cell @@ -3028,11 +3070,11 @@ worksheet.getCell('B3').formulaType === Enums.FormulaType.Shared; Formula type has the following values: -| Name | Value | -| -------------------------- | ------- | -| Enums.FormulaType.None | 0 | -| Enums.FormulaType.Master | 1 | -| Enums.FormulaType.Shared | 2 | +| Name | Value | +| ------------------------ | ----- | +| Enums.FormulaType.None | 0 | +| Enums.FormulaType.Master | 1 | +| Enums.FormulaType.Shared | 2 | ### Array Formula[⬆](#contents) @@ -3045,13 +3087,14 @@ Note: array formulae are not translated in the way shared formulae are. So if master cell A2 refers to A1, then slave cell B2 will also refer to A1. E.g. + ```javascript // assign array formula to A2:B3 worksheet.getCell('A2').value = { formula: 'A1', result: 10, shareType: 'array', - ref: 'A2:B3' + ref: 'A2:B3', }; // it may not be necessary to fill the rest of the values in the sheet @@ -3061,10 +3104,9 @@ The fillFormula function can also be used to fill an array formula ```javascript // fill A2:B3 with array formula "A1" -worksheet.fillFormula('A2:B3', 'A1', [1,1,1,1], 'array'); +worksheet.fillFormula('A2:B3', 'A1', [1, 1, 1, 1], 'array'); ``` - ## Rich Text Value[⬆](#contents) Enum: Excel.ValueType.RichText @@ -3072,12 +3114,10 @@ Enum: Excel.ValueType.RichText Rich, styled text. E.g. + ```javascript worksheet.getCell('A1').value = { - richText: [ - { text: 'This is '}, - {font: {italic: true}, text: 'italic'}, - ] + richText: [{text: 'This is '}, {font: {italic: true}, text: 'italic'}], }; ``` @@ -3099,21 +3139,21 @@ Enum: Excel.ValueType.Error E.g. ```javascript -worksheet.getCell('A1').value = { error: '#N/A' }; -worksheet.getCell('A2').value = { error: '#VALUE!' }; +worksheet.getCell('A1').value = {error: '#N/A'}; +worksheet.getCell('A2').value = {error: '#VALUE!'}; ``` The current valid Error text values are: -| Name | Value | -| ------------------------------ | ----------- | -| Excel.ErrorValue.NotApplicable | #N/A | -| Excel.ErrorValue.Ref | #REF! | -| Excel.ErrorValue.Name | #NAME? | -| Excel.ErrorValue.DivZero | #DIV/0! | -| Excel.ErrorValue.Null | #NULL! | -| Excel.ErrorValue.Value | #VALUE! | -| Excel.ErrorValue.Num | #NUM! | +| Name | Value | +| ------------------------------ | ------- | +| Excel.ErrorValue.NotApplicable | #N/A | +| Excel.ErrorValue.Ref | #REF! | +| Excel.ErrorValue.Name | #NAME? | +| Excel.ErrorValue.DivZero | #DIV/0! | +| Excel.ErrorValue.Null | #NULL! | +| Excel.ErrorValue.Value | #VALUE! | +| Excel.ErrorValue.Num | #NUM! | # Interface Changes[⬆](#contents) @@ -3123,7 +3163,7 @@ Every effort is made to make a good consistent interface that doesn't break thro ### Worksheet.eachRow[⬆](#contents) -The arguments in the callback function to Worksheet.eachRow have been swapped and changed; it was function(rowNumber,rowValues), now it is function(row, rowNumber) which gives it a look and feel more like the underscore (_.each) function and priorities the row object over the row number. +The arguments in the callback function to Worksheet.eachRow have been swapped and changed; it was function(rowNumber,rowValues), now it is function(row, rowNumber) which gives it a look and feel more like the underscore (\_.each) function and priorities the row object over the row number. ### Worksheet.getRow[⬆](#contents) @@ -3140,24 +3180,24 @@ cell.styles renamed to cell.style ## 0.2.44[⬆](#contents) Promises returned from functions switched from Bluebird to native node Promise which can break calling code - if they rely on Bluebird's extra features. +if they rely on Bluebird's extra features. To mitigate this the following two changes were added to 0.3.0: -* A more fully featured and still browser compatible promise lib is used by default. This lib supports many of the features of Bluebird but with a much lower footprint. -* An option to inject a different Promise implementation. See Config section for more details. +- A more fully featured and still browser compatible promise lib is used by default. This lib supports many of the features of Bluebird but with a much lower footprint. +- An option to inject a different Promise implementation. See Config section for more details. # Config[⬆](#contents) ExcelJS now supports dependency injection for the promise library. - You can restore Bluebird promises by including the following code in your module... +You can restore Bluebird promises by including the following code in your module... ```javascript ExcelJS.config.setValue('promise', require('bluebird')); ``` Please note: I have tested ExcelJS with bluebird specifically (since up until recently this was the library it used). - From the tests I have done it will not work with Q. +From the tests I have done it will not work with Q. # Caveats[⬆](#contents) @@ -3169,7 +3209,6 @@ This README identifies two files - a browserified bundle and minified version. No other contents of the dist/ folder are guaranteed in any way other than the file specified as "main" in the package.json - # Known Issues[⬆](#contents) ## Testing with Puppeteer[⬆](#contents) @@ -3183,6 +3222,7 @@ sudo apt-get install libfontconfig ``` Browser tests can be disabled by creating: + ```bash touch .disable-test-browser ``` @@ -3201,148 +3241,148 @@ For @protobi/exceljs release history, see [FORK.md Release History](FORK.md#fork The table below shows upstream exceljs release history: -| Version | Changes | -|---------| ------- | -| 0.0.9 | | -| 0.1.0 | | -| 0.1.1 | | -| 0.1.2 | | -| 0.1.3 | | -| 0.1.5 | | -| 0.1.6 | | -| 0.1.8 | | -| 0.1.9 | | -| 0.1.10 | | -| 0.1.11 | | -| 0.2.0 | | -| 0.2.2 | | -| 0.2.3 | | -| 0.2.4 | | -| 0.2.6 | | -| 0.2.7 | | -| 0.2.8 | | -| 0.2.9 | | -| 0.2.10 | | -| 0.2.11 | | -| 0.2.12 | | -| 0.2.13 | | -| 0.2.14 | | -| 0.2.15 | | -| 0.2.16 | | -| 0.2.17 | | -| 0.2.18 | | -| 0.2.19 | | -| 0.2.20 | | -| 0.2.21 | | -| 0.2.22 | | -| 0.2.23 | | -| 0.2.24 | | -| 0.2.25 | | -| 0.2.26 | | -| 0.2.27 | | -| 0.2.28 | | -| 0.2.29 | | -| 0.2.30 | | -| 0.2.31 | | -| 0.2.32 | | -| 0.2.33 | | -| 0.2.34 | | -| 0.2.35 | | -| 0.2.36 | | -| 0.2.37 | | -| 0.2.38 | | -| 0.2.39 | | -| 0.2.42 | | -| 0.2.43 | | -| 0.2.44 | | -| 0.2.45 | | -| 0.2.46 | | -| 0.3.0 | | -| 0.3.1 | | -| 0.4.0 | | -| 0.4.1 | | -| 0.4.2 | | -| 0.4.3 | | -| 0.4.4 | | -| 0.4.6 | | -| 0.4.9 | | -| 0.4.10 | | -| 0.4.11 | | -| 0.4.12 | | -| 0.4.13 | | -| 0.4.14 | | -| 0.5.0 | | -| 0.5.1 | -| 0.6.0 | | -| 0.6.1 | | -| 0.6.2 | | -| 0.7.0 | | -| 0.7.1 | -| 0.8.0 | | -| 0.8.1 | | -| 0.8.2 | | -| 0.8.3 | | -| 0.8.4 | | -| 0.8.5 | | -| 0.9.0 | | -| 0.9.1 | | -| 1.0.0 | | -| 1.0.1 | | -| 1.0.2 | | -| 1.1.0 | | -| 1.1.1 | | -| 1.1.2 | | -| 1.1.3 | | -| 1.2.0 | | -| 1.2.1 | | -| 1.3.0 | | -| 1.4.2 | | -| 1.4.3 | | -| 1.4.5 | | -| 1.4.6 | | -| 1.4.7 | | -| 1.4.8 | | -| 1.4.9 | | -| 1.4.10 | | -| 1.4.12 | | -| 1.4.13 | | -| 1.5.0 | | -| 1.5.1 | | -| 1.6.0 | | -| 1.6.1 | | -| 1.6.2 | | -| 1.6.3 | | -| 1.7.0 | | -| 1.8.0 | | -| 1.9.0 | | -| 1.9.1 | | -| 1.10.0 | | -| 1.11.0 | | -| 1.12.0 | | -| 1.12.1 | | -| 1.12.2 | | -| 1.13.0 | | -| 1.14.0 | | -| 1.15.0 | | -| 2.0.1 |

Major Version Change

Introducing async/await to ExcelJS!

The new async and await features of JavaScript can help a lot to make code more readable and maintainable. To avoid confusion, particularly with returned promises from async functions, we have had to remove the Promise class configuration option and from v2 onwards ExcelJS will use native Promises. Since this is potentially a breaking change we're bumping the major version for this release.

Changes

| -| 3.0.0 |

Another Major Version Change

Javascript has changed a lot over the years, and so have the modules and technologies surrounding it. To this end, this major version of ExcelJS changes the structure of the publish artefacts:

Main Export is now the Original Javascript Source

Prior to this release, the transpiled ES5 code was exported as the package main. From now on, the package main comes directly from the lib/ folder. This means a number of dependencies have been removed, including the polyfills.

ES5 and Browserify are Still Included

In order to support those that still require ES5 ready code (e.g. as dependencies in web apps) the source code will still be transpiled and available in dist/es5.

The ES5 code is also browserified and available as dist/exceljs.js or dist/exceljs.min.js

See the section Importing for details

| -| 3.1.0 | | -| 3.2.0 | | -| 3.3.0 | | -| 3.3.1 | | -| 3.4.0 | | -| 3.5.0 | | -| 3.6.0 | | -| 3.6.1 | | -| 3.7.0 | | -| 3.8.0 | | -| 3.8.1 | | -| 3.8.2 | | -| 3.9.0 | | -| 3.10.0 | | -| 4.0.1 | | -| 4.1.0 | | -| 4.1.1 | | -| 4.2.0 | | -| 4.2.1 | | -| 4.3.0 | | +| Version | Changes | +| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 0.0.9 | | +| 0.1.0 | | +| 0.1.1 | | +| 0.1.2 | | +| 0.1.3 | | +| 0.1.5 | | +| 0.1.6 | | +| 0.1.8 | | +| 0.1.9 | | +| 0.1.10 | | +| 0.1.11 | | +| 0.2.0 | | +| 0.2.2 | | +| 0.2.3 | | +| 0.2.4 | | +| 0.2.6 | | +| 0.2.7 | | +| 0.2.8 | | +| 0.2.9 | | +| 0.2.10 | | +| 0.2.11 | | +| 0.2.12 | | +| 0.2.13 | | +| 0.2.14 | | +| 0.2.15 | | +| 0.2.16 | | +| 0.2.17 | | +| 0.2.18 | | +| 0.2.19 | | +| 0.2.20 | | +| 0.2.21 | | +| 0.2.22 | | +| 0.2.23 | | +| 0.2.24 | | +| 0.2.25 | | +| 0.2.26 | | +| 0.2.27 | | +| 0.2.28 | | +| 0.2.29 | | +| 0.2.30 | | +| 0.2.31 | | +| 0.2.32 | | +| 0.2.33 | | +| 0.2.34 | | +| 0.2.35 | | +| 0.2.36 | | +| 0.2.37 | | +| 0.2.38 | | +| 0.2.39 | | +| 0.2.42 | | +| 0.2.43 | | +| 0.2.44 | | +| 0.2.45 | | +| 0.2.46 | | +| 0.3.0 | | +| 0.3.1 | | +| 0.4.0 | | +| 0.4.1 | | +| 0.4.2 | | +| 0.4.3 | | +| 0.4.4 | | +| 0.4.6 | | +| 0.4.9 | | +| 0.4.10 | | +| 0.4.11 | | +| 0.4.12 | | +| 0.4.13 | | +| 0.4.14 | | +| 0.5.0 | | +| 0.5.1 | | +| 0.6.0 | | +| 0.6.1 | | +| 0.6.2 | | +| 0.7.0 | | +| 0.7.1 | | +| 0.8.0 | | +| 0.8.1 | | +| 0.8.2 | | +| 0.8.3 | | +| 0.8.4 | | +| 0.8.5 | | +| 0.9.0 | | +| 0.9.1 | | +| 1.0.0 | | +| 1.0.1 | | +| 1.0.2 | | +| 1.1.0 | | +| 1.1.1 | | +| 1.1.2 | | +| 1.1.3 | | +| 1.2.0 | | +| 1.2.1 | | +| 1.3.0 | | +| 1.4.2 | | +| 1.4.3 | | +| 1.4.5 | | +| 1.4.6 | | +| 1.4.7 | | +| 1.4.8 | | +| 1.4.9 | | +| 1.4.10 | | +| 1.4.12 | | +| 1.4.13 | | +| 1.5.0 | | +| 1.5.1 | | +| 1.6.0 | | +| 1.6.1 | | +| 1.6.2 | | +| 1.6.3 | | +| 1.7.0 | | +| 1.8.0 | | +| 1.9.0 | | +| 1.9.1 | | +| 1.10.0 | | +| 1.11.0 | | +| 1.12.0 | | +| 1.12.1 | | +| 1.12.2 | | +| 1.13.0 | | +| 1.14.0 | | +| 1.15.0 | | +| 2.0.1 |

Major Version Change

Introducing async/await to ExcelJS!

The new async and await features of JavaScript can help a lot to make code more readable and maintainable. To avoid confusion, particularly with returned promises from async functions, we have had to remove the Promise class configuration option and from v2 onwards ExcelJS will use native Promises. Since this is potentially a breaking change we're bumping the major version for this release.

Changes

| +| 3.0.0 |

Another Major Version Change

Javascript has changed a lot over the years, and so have the modules and technologies surrounding it. To this end, this major version of ExcelJS changes the structure of the publish artefacts:

Main Export is now the Original Javascript Source

Prior to this release, the transpiled ES5 code was exported as the package main. From now on, the package main comes directly from the lib/ folder. This means a number of dependencies have been removed, including the polyfills.

ES5 and Browserify are Still Included

In order to support those that still require ES5 ready code (e.g. as dependencies in web apps) the source code will still be transpiled and available in dist/es5.

The ES5 code is also browserified and available as dist/exceljs.js or dist/exceljs.min.js

See the section Importing for details

| +| 3.1.0 | | +| 3.2.0 | | +| 3.3.0 | | +| 3.3.1 | | +| 3.4.0 | | +| 3.5.0 | | +| 3.6.0 | | +| 3.6.1 | | +| 3.7.0 | | +| 3.8.0 | | +| 3.8.1 | | +| 3.8.2 | | +| 3.9.0 | | +| 3.10.0 | | +| 4.0.1 | | +| 4.1.0 | | +| 4.1.1 | | +| 4.2.0 | | +| 4.2.1 | | +| 4.3.0 | | diff --git a/README_zh.md b/README_zh.md index 56e543da6..c744507db 100644 --- a/README_zh.md +++ b/README_zh.md @@ -16,46 +16,46 @@ npm install exceljs # 新的功能! -* Merged [fix: styles rendering in case when "numFmt" is present in conditional formatting rules (resolves #1814) #1815](https://github.com/exceljs/exceljs/pull/1815).
Many thanks to [@andreykrupskii](https://github.com/andreykrupskii) for this contribution! -* Merged [inlineStr cell type support #1575 #1576](https://github.com/exceljs/exceljs/pull/1576).
Many thanks to [@drdmitry](https://github.com/drdmitry) for this contribution! -* Merged [Fix parsing of boolean attributes #1849](https://github.com/exceljs/exceljs/pull/1849).
Many thanks to [@bno1](https://github.com/bno1) for this contribution! -* Merged [add optional custom auto-filter to table #1670](https://github.com/exceljs/exceljs/pull/1670).
Many thanks to [@thambley](https://github.com/thambley) for this contribution! -* Merged [Deep copy inherited style #1850](https://github.com/exceljs/exceljs/pull/1850).
Many thanks to [@ikzhr](https://github.com/ikzhr) for this contribution! -* Merged [Upgrade actions/cache and actions/setup-node #1846](https://github.com/exceljs/exceljs/pull/1846).
Many thanks to [@cclauss](https://github.com/cclauss) for this contribution! -* Merged [Check object keys in isEqual #1831](https://github.com/exceljs/exceljs/pull/1831).
Many thanks to [@bno1](https://github.com/bno1) for this contribution! -* Merged [Add v17 to testing workflow #1856](https://github.com/exceljs/exceljs/pull/1856).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! -* Merged [Upgrade jszip to its latest version to date. This version does not have any vulnerability found by Snyk so far #1895](https://github.com/exceljs/exceljs/pull/1895).
Many thanks to [@ValerioSevilla](https://github.com/ValerioSevilla) for this contribution! -* Merged [Update README.md #1677](https://github.com/exceljs/exceljs/pull/1677).
Many thanks to [@xjrcode](https://github.com/xjrcode) for this contribution! -* Merged [(docs): set prototype of RegExp correctly. #1700](https://github.com/exceljs/exceljs/pull/1700).
Many thanks to [@joeldenning](https://github.com/joeldenning) for this contribution! -* Merged [Added timeouts to github actions #1733](https://github.com/exceljs/exceljs/pull/1733).
Many thanks to [@alexbjorlig](https://github.com/alexbjorlig) for this contribution! -* Merged [fix issue 1676 #1701](https://github.com/exceljs/exceljs/pull/1701).
Many thanks to [@skypesky](https://github.com/skypesky) for this contribution! -* Merged [ExcelJS/ExcelJS#2237 : Update CI Tests, Drop support for Node v8 #2242](https://github.com/exceljs/exceljs/pull/2242).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! -* Merged [Fix types for getWorksheet() #2223](https://github.com/exceljs/exceljs/pull/2223).
Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution! -* Merged [add characters cannot be used for worksheet name #2126](https://github.com/exceljs/exceljs/pull/2126).
Many thanks to [@tkm-kj](https://github.com/tkm-kj) for this contribution! -* Merged [Fix issue #1753 Reject promise when workbook reader is writing to temporary file stream and error occurs #1756](https://github.com/exceljs/exceljs/pull/1756).
Many thanks to [@pauliusg](https://github.com/pauliusg) for this contribution! -* Merged [README.md to have correct link for Streaming XLSX #2186](https://github.com/exceljs/exceljs/pull/2186).
Many thanks to [@wulfsolter](https://github.com/wulfsolter) for this contribution! -* Merged [Added a polyfill of promise.finally to support lower versions of Firefox. #1982](https://github.com/exceljs/exceljs/pull/1982).
Many thanks to [@DemoJj](https://github.com/DemoJj) for this contribution! -* Merged [Fix read this.worksheet before assign it #1934](https://github.com/exceljs/exceljs/pull/1934).
Many thanks to [@ZyqGitHub1](https://github.com/ZyqGitHub1) for this contribution! -* Merged [chore: upgrade jszip to ^3.10.1 #2211](https://github.com/exceljs/exceljs/pull/2211).
Many thanks to [@jarrod-cocoon](https://github.com/jarrod-cocoon) for this contribution! -* Merged [fixed spelling error in README.md file #2208](https://github.com/exceljs/exceljs/pull/2208).
Many thanks to [@HugoP27](https://github.com/HugoP27) for this contribution! -* Merged [fix: Fix xlsx.writeFile() not catching error when error occurs #2244](https://github.com/exceljs/exceljs/pull/2244).
Many thanks to [@zurmokeeper](https://github.com/zurmokeeper) for this contribution! -* Merged [Improve worksheets' naming validation logic. #2257](https://github.com/exceljs/exceljs/pull/2257).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! -* Merged [fix issue 2125 - spliceRows remove last row #2140](https://github.com/exceljs/exceljs/pull/2140).
Many thanks to [@babu-ch](https://github.com/babu-ch) for this contribution! -* Merged [fix: fix the loss of column attributes due to incorrect column order #2222](https://github.com/exceljs/exceljs/pull/2222).
Many thanks to [@cpaiyueyue](https://github.com/cpaiyueyue) for this contribution! -* Merged [Fix: Sheet Properties Types #2327](https://github.com/exceljs/exceljs/pull/2327).
Many thanks to [@albeniraouf](https://github.com/albeniraouf) for this contribution! -* Merged [Use node 18 LTS for tsc, and benchmark. Add node 20. to test matrix. … #2354](https://github.com/exceljs/exceljs/pull/2354).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! -* Merged [Add missing tooltip attribute to CellHyperlinkValue index.d.ts #2350](https://github.com/exceljs/exceljs/pull/2350).
Many thanks to [@NiklasPor](https://github.com/NiklasPor) for this contribution! -* Merged [Increase resilience to generating large workbooks #2320](https://github.com/exceljs/exceljs/pull/2320).
Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution! -* Merged [repair all 'c2fo.io' links ('c2fo.github.io') #2324](https://github.com/exceljs/exceljs/pull/2324).
Many thanks to [@justintunev7](https://github.com/justintunev7) for this contribution! -* Merged [fix: fix type definitions about last column, formula values and protection #2309](https://github.com/exceljs/exceljs/pull/2309).
Many thanks to [@gltjk](https://github.com/gltjk) for this contribution! -* Merged [fix: add spinCount field for WorksheetProtection type #2284](https://github.com/exceljs/exceljs/pull/2284).
Many thanks to [@damingerdai](https://github.com/damingerdai) for this contribution! -* Merged [Add type definition for WorksheetModel.merges #2281](https://github.com/exceljs/exceljs/pull/2281).
Many thanks to [@ytjmt](https://github.com/ytjmt) for this contribution! +- Merged [fix: styles rendering in case when "numFmt" is present in conditional formatting rules (resolves #1814) #1815](https://github.com/exceljs/exceljs/pull/1815).
Many thanks to [@andreykrupskii](https://github.com/andreykrupskii) for this contribution! +- Merged [inlineStr cell type support #1575 #1576](https://github.com/exceljs/exceljs/pull/1576).
Many thanks to [@drdmitry](https://github.com/drdmitry) for this contribution! +- Merged [Fix parsing of boolean attributes #1849](https://github.com/exceljs/exceljs/pull/1849).
Many thanks to [@bno1](https://github.com/bno1) for this contribution! +- Merged [add optional custom auto-filter to table #1670](https://github.com/exceljs/exceljs/pull/1670).
Many thanks to [@thambley](https://github.com/thambley) for this contribution! +- Merged [Deep copy inherited style #1850](https://github.com/exceljs/exceljs/pull/1850).
Many thanks to [@ikzhr](https://github.com/ikzhr) for this contribution! +- Merged [Upgrade actions/cache and actions/setup-node #1846](https://github.com/exceljs/exceljs/pull/1846).
Many thanks to [@cclauss](https://github.com/cclauss) for this contribution! +- Merged [Check object keys in isEqual #1831](https://github.com/exceljs/exceljs/pull/1831).
Many thanks to [@bno1](https://github.com/bno1) for this contribution! +- Merged [Add v17 to testing workflow #1856](https://github.com/exceljs/exceljs/pull/1856).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! +- Merged [Upgrade jszip to its latest version to date. This version does not have any vulnerability found by Snyk so far #1895](https://github.com/exceljs/exceljs/pull/1895).
Many thanks to [@ValerioSevilla](https://github.com/ValerioSevilla) for this contribution! +- Merged [Update README.md #1677](https://github.com/exceljs/exceljs/pull/1677).
Many thanks to [@xjrcode](https://github.com/xjrcode) for this contribution! +- Merged [(docs): set prototype of RegExp correctly. #1700](https://github.com/exceljs/exceljs/pull/1700).
Many thanks to [@joeldenning](https://github.com/joeldenning) for this contribution! +- Merged [Added timeouts to github actions #1733](https://github.com/exceljs/exceljs/pull/1733).
Many thanks to [@alexbjorlig](https://github.com/alexbjorlig) for this contribution! +- Merged [fix issue 1676 #1701](https://github.com/exceljs/exceljs/pull/1701).
Many thanks to [@skypesky](https://github.com/skypesky) for this contribution! +- Merged [ExcelJS/ExcelJS#2237 : Update CI Tests, Drop support for Node v8 #2242](https://github.com/exceljs/exceljs/pull/2242).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! +- Merged [Fix types for getWorksheet() #2223](https://github.com/exceljs/exceljs/pull/2223).
Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution! +- Merged [add characters cannot be used for worksheet name #2126](https://github.com/exceljs/exceljs/pull/2126).
Many thanks to [@tkm-kj](https://github.com/tkm-kj) for this contribution! +- Merged [Fix issue #1753 Reject promise when workbook reader is writing to temporary file stream and error occurs #1756](https://github.com/exceljs/exceljs/pull/1756).
Many thanks to [@pauliusg](https://github.com/pauliusg) for this contribution! +- Merged [README.md to have correct link for Streaming XLSX #2186](https://github.com/exceljs/exceljs/pull/2186).
Many thanks to [@wulfsolter](https://github.com/wulfsolter) for this contribution! +- Merged [Added a polyfill of promise.finally to support lower versions of Firefox. #1982](https://github.com/exceljs/exceljs/pull/1982).
Many thanks to [@DemoJj](https://github.com/DemoJj) for this contribution! +- Merged [Fix read this.worksheet before assign it #1934](https://github.com/exceljs/exceljs/pull/1934).
Many thanks to [@ZyqGitHub1](https://github.com/ZyqGitHub1) for this contribution! +- Merged [chore: upgrade jszip to ^3.10.1 #2211](https://github.com/exceljs/exceljs/pull/2211).
Many thanks to [@jarrod-cocoon](https://github.com/jarrod-cocoon) for this contribution! +- Merged [fixed spelling error in README.md file #2208](https://github.com/exceljs/exceljs/pull/2208).
Many thanks to [@HugoP27](https://github.com/HugoP27) for this contribution! +- Merged [fix: Fix xlsx.writeFile() not catching error when error occurs #2244](https://github.com/exceljs/exceljs/pull/2244).
Many thanks to [@zurmokeeper](https://github.com/zurmokeeper) for this contribution! +- Merged [Improve worksheets' naming validation logic. #2257](https://github.com/exceljs/exceljs/pull/2257).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! +- Merged [fix issue 2125 - spliceRows remove last row #2140](https://github.com/exceljs/exceljs/pull/2140).
Many thanks to [@babu-ch](https://github.com/babu-ch) for this contribution! +- Merged [fix: fix the loss of column attributes due to incorrect column order #2222](https://github.com/exceljs/exceljs/pull/2222).
Many thanks to [@cpaiyueyue](https://github.com/cpaiyueyue) for this contribution! +- Merged [Fix: Sheet Properties Types #2327](https://github.com/exceljs/exceljs/pull/2327).
Many thanks to [@albeniraouf](https://github.com/albeniraouf) for this contribution! +- Merged [Use node 18 LTS for tsc, and benchmark. Add node 20. to test matrix. … #2354](https://github.com/exceljs/exceljs/pull/2354).
Many thanks to [@Siemienik](https://github.com/Siemienik) for this contribution! +- Merged [Add missing tooltip attribute to CellHyperlinkValue index.d.ts #2350](https://github.com/exceljs/exceljs/pull/2350).
Many thanks to [@NiklasPor](https://github.com/NiklasPor) for this contribution! +- Merged [Increase resilience to generating large workbooks #2320](https://github.com/exceljs/exceljs/pull/2320).
Many thanks to [@hfhchan-plb](https://github.com/hfhchan-plb) for this contribution! +- Merged [repair all 'c2fo.io' links ('c2fo.github.io') #2324](https://github.com/exceljs/exceljs/pull/2324).
Many thanks to [@justintunev7](https://github.com/justintunev7) for this contribution! +- Merged [fix: fix type definitions about last column, formula values and protection #2309](https://github.com/exceljs/exceljs/pull/2309).
Many thanks to [@gltjk](https://github.com/gltjk) for this contribution! +- Merged [fix: add spinCount field for WorksheetProtection type #2284](https://github.com/exceljs/exceljs/pull/2284).
Many thanks to [@damingerdai](https://github.com/damingerdai) for this contribution! +- Merged [Add type definition for WorksheetModel.merges #2281](https://github.com/exceljs/exceljs/pull/2281).
Many thanks to [@ytjmt](https://github.com/ytjmt) for this contribution! # 贡献 欢迎贡献!这可以帮助我了解大家需要一些什么功能,或者哪些 bugs 造成了极大的麻烦。 -我只有一个请求;如果您提交对错误修复的请求(PR),请添加一个能够解决问题的单元测试或集成测试(在 *spec* 文件夹中)。 +我只有一个请求;如果您提交对错误修复的请求(PR),请添加一个能够解决问题的单元测试或集成测试(在 _spec_ 文件夹中)。 即使只是测试失败的请求(PR)也可以 - 我可以分析测试的过程并以此修复代码。 注意:请尽可能避免在请求(PR)中修改软件包版本。 @@ -168,8 +168,6 @@ npm install exceljs
  • 发布历史
  • - - # 导入[⬆](#目录) ```javascript @@ -178,7 +176,7 @@ const ExcelJS = require('exceljs'); ## ES5 导入[⬆](#目录) -要使用 ES5 编译代码,请使用 *dist/es5* 路径。 +要使用 ES5 编译代码,请使用 _dist/es5_ 路径。 ```javascript const ExcelJS = require('exceljs/dist/es5'); @@ -210,7 +208,7 @@ const {RegExp} = global; try { new RegExp('a', 'u'); } catch (err) { - global.RegExp = function(pattern, flags) { + global.RegExp = function (pattern, flags) { if (flags && flags.includes('u')) { return new RegExp(rewritePattern(pattern, flags, generateRegexpuOptions({flags, pattern}))); } @@ -222,21 +220,22 @@ try { ## 浏览器端[⬆](#目录) -ExcelJS 在 *dist/* 文件夹内发布了两个支持浏览器的包: +ExcelJS 在 _dist/_ 文件夹内发布了两个支持浏览器的包: 一个是隐式依赖 `core-js` polyfills 的... + ```html ``` 另一个则没有... + ```html ``` - # 接口[⬆](#目录) ## 创建工作簿[⬆](#目录) @@ -274,10 +273,15 @@ workbook.calcProperties.fullCalcOnLoad = true; ```javascript workbook.views = [ { - x: 0, y: 0, width: 10000, height: 20000, - firstSheet: 0, activeTab: 1, visibility: 'visible' - } -] + x: 0, + y: 0, + width: 10000, + height: 20000, + firstSheet: 0, + activeTab: 1, + visibility: 'visible', + }, +]; ``` ## 添加工作表[⬆](#目录) @@ -292,32 +296,31 @@ const sheet = workbook.addWorksheet('My Sheet'); ```javascript // 创建带有红色标签颜色的工作表 -const sheet = workbook.addWorksheet('My Sheet', {properties:{tabColor:{argb:'FFC0000'}}}); +const sheet = workbook.addWorksheet('My Sheet', {properties: {tabColor: {argb: 'FFC0000'}}}); // 创建一个隐藏了网格线的工作表 const sheet = workbook.addWorksheet('My Sheet', {views: [{showGridLines: false}]}); // 创建一个第一行和列冻结的工作表 -const sheet = workbook.addWorksheet('My Sheet', {views:[{xSplit: 1, ySplit:1}]}); +const sheet = workbook.addWorksheet('My Sheet', {views: [{xSplit: 1, ySplit: 1}]}); // 使用A4设置的页面设置设置创建新工作表 - 横向 -const worksheet = workbook.addWorksheet('My Sheet', { - pageSetup:{paperSize: 9, orientation:'landscape'} +const worksheet = workbook.addWorksheet('My Sheet', { + pageSetup: {paperSize: 9, orientation: 'landscape'}, }); // 创建一个具有页眉页脚的工作表 const sheet = workbook.addWorksheet('My Sheet', { - headerFooter:{firstHeader: "Hello Exceljs", firstFooter: "Hello World"} + headerFooter: {firstHeader: 'Hello Exceljs', firstFooter: 'Hello World'}, }); // 创建一个冻结了第一行和第一列的工作表 -const sheet = workbook.addWorksheet('My Sheet', {views:[{state: 'frozen', xSplit: 1, ySplit:1}]}); - +const sheet = workbook.addWorksheet('My Sheet', {views: [{state: 'frozen', xSplit: 1, ySplit: 1}]}); ``` ## 删除工作表[⬆](#目录) -使用工作表的 `id` 从工作簿中删除工作表。 +使用工作表的 `id` 从工作簿中删除工作表。 示例: @@ -326,14 +329,15 @@ const sheet = workbook.addWorksheet('My Sheet', {views:[{state: 'frozen', xSplit const sheet = workbook.addWorksheet('My Sheet'); // 使用工作表 id 删除工作表 -workbook.removeWorksheet(sheet.id) +workbook.removeWorksheet(sheet.id); ``` ## 访问工作表[⬆](#目录) + ```javascript // 遍历所有工作表 // 注意: workbook.worksheets.forEach 仍然是可以正常运行的, 但是以下的方式更好 -workbook.eachSheet(function(worksheet, sheetId) { +workbook.eachSheet(function (worksheet, sheetId) { // ... }); @@ -363,10 +367,10 @@ worksheet.state = 'veryHidden'; ```javascript // 创建具有属性的新工作表 -const worksheet = workbook.addWorksheet('sheet', {properties:{tabColor:{argb:'FF00FF00'}}}); +const worksheet = workbook.addWorksheet('sheet', {properties: {tabColor: {argb: 'FF00FF00'}}}); // 创建一个具有属性的可写的新工作表 -const worksheetWriter = workbookWriter.addWorksheet('sheet', {properties:{outlineLevelCol:1}}); +const worksheetWriter = workbookWriter.addWorksheet('sheet', {properties: {outlineLevelCol: 1}}); // 之后调整属性(工作表读写器不支持该操作) worksheet.properties.outlineLevelCol = 2; @@ -375,26 +379,25 @@ worksheet.properties.defaultRowHeight = 15; **支持的属性** -| 属性名 | 默认值 | 描述 | -| ---------------- | ---------- | ----------- | -| tabColor | `undefined` | 标签的颜色 | -| outlineLevelCol | 0 | 工作表列大纲级别 | -| outlineLevelRow | 0 | 工作表行大纲级别 | -| defaultRowHeight | 15 | 默认行高 | -| defaultColWidth | (optional) | 默认列宽 | -| dyDescent | 55 | TBD | +| 属性名 | 默认值 | 描述 | +| ---------------- | ----------- | ---------------- | +| tabColor | `undefined` | 标签的颜色 | +| outlineLevelCol | 0 | 工作表列大纲级别 | +| outlineLevelRow | 0 | 工作表行大纲级别 | +| defaultRowHeight | 15 | 默认行高 | +| defaultColWidth | (optional) | 默认列宽 | +| dyDescent | 55 | TBD | ### 工作表尺寸[⬆](#目录) 一些新的尺寸属性已添加到工作表中... -| 属性名 | 描述 | -| ----------------- | ------------------------------------------------------------ | -| rowCount | 文档的总行数。 等于具有值的最后一行的行号。 | +| 属性名 | 描述 | +| ----------------- | ----------------------------------------------------------------- | +| rowCount | 文档的总行数。 等于具有值的最后一行的行号。 | | actualRowCount | 具有值的行数的计数。 如果中间文档行为空,则该行将不包括在计数中。 | -| columnCount | 文档的总列数。 等于所有行的最大单元数。 | -| actualColumnCount | 具有值的列数的计数。 | - +| columnCount | 文档的总列数。 等于所有行的最大单元数。 | +| actualColumnCount | 具有值的列数的计数。 | ## 页面设置[⬆](#目录) @@ -402,20 +405,23 @@ worksheet.properties.defaultRowHeight = 15; ```javascript // 使用 A4 横向的页面设置创建新工作表 -const worksheet = workbook.addWorksheet('sheet', { - pageSetup:{paperSize: 9, orientation:'landscape'} +const worksheet = workbook.addWorksheet('sheet', { + pageSetup: {paperSize: 9, orientation: 'landscape'}, }); // 使用适合页面的pageSetup设置创建一个新的工作表编写器 const worksheetWriter = workbookWriter.addWorksheet('sheet', { - pageSetup:{fitToPage: true, fitToHeight: 5, fitToWidth: 7} + pageSetup: {fitToPage: true, fitToHeight: 5, fitToWidth: 7}, }); // 之后调整页面设置配置 worksheet.pageSetup.margins = { - left: 0.7, right: 0.7, - top: 0.75, bottom: 0.75, - header: 0.3, footer: 0.3 + left: 0.7, + right: 0.7, + top: 0.75, + bottom: 0.75, + header: 0.3, + footer: 0.3, }; // 设置工作表的打印区域 @@ -433,31 +439,31 @@ worksheet.pageSetup.printTitlesColumn = 'A:C'; **支持的页面设置配置项** -| 属性名 | 默认值 | 描述 | -| --------------------- | ------------- | ----------- | -| margins | | 页面上的空白边距。 单位为英寸。 | -| orientation | `'portrait'` | 页面方向 - 即较高 (`'portrait'`) 或者较宽 (`'landscape'`) | -| horizontalDpi | 4294967295 | 水平方向上的 DPI。默认值为 `-1` | -| verticalDpi | 4294967295 | 垂直方向上的 DPI。默认值为 `-1` | -| fitToPage | | 是否使用 `fitToWidth` 和 `fitToHeight` 或 `scale` 设置。默认基于存在于 `pageSetup` 对象中的设置-如果两者都存在,则 `scale` 优先级高(默认值为 `false`)。 | -| pageOrder | `'downThenOver'` | 打印页面的顺序-`['downThenOver', 'overThenDown']` 之一 | -| blackAndWhite | `false` | 无色打印 | -| draft | `false` | 打印质量较低(墨水) | -| cellComments | `'None'` | 在何处放置批注-`['atEnd','asDisplayed','None']`中的一个 | -| errors | `'displayed'` | 哪里显示错误 -`['dash', 'blank', 'NA', 'displayed']` 之一 | -| scale | 100 | 增加或减小打印尺寸的百分比值。 当 `fitToPage` 为 `false` 时激活 | -| fitToWidth | 1 | 纸张应打印多少页宽。 当 `fitToPage` 为 `true` 时激活 | -| fitToHeight | 1 | 纸张应打印多少页高。 当 `fitToPage` 为 `true` 时激活 | -| paperSize | | 使用哪种纸张尺寸(见下文) | -| showRowColHeaders | false | 是否显示行号和列字母 | -| showGridLines | false | 是否显示网格线 | -| firstPageNumber | | 第一页使用哪个页码 | -| horizontalCentered | false | 是否将工作表数据水平居中 | -| verticalCentered | false | 是否将工作表数据垂直居中 | +| 属性名 | 默认值 | 描述 | +| ------------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| margins | | 页面上的空白边距。 单位为英寸。 | +| orientation | `'portrait'` | 页面方向 - 即较高 (`'portrait'`) 或者较宽 (`'landscape'`) | +| horizontalDpi | 4294967295 | 水平方向上的 DPI。默认值为 `-1` | +| verticalDpi | 4294967295 | 垂直方向上的 DPI。默认值为 `-1` | +| fitToPage | | 是否使用 `fitToWidth` 和 `fitToHeight` 或 `scale` 设置。默认基于存在于 `pageSetup` 对象中的设置-如果两者都存在,则 `scale` 优先级高(默认值为 `false`)。 | +| pageOrder | `'downThenOver'` | 打印页面的顺序-`['downThenOver', 'overThenDown']` 之一 | +| blackAndWhite | `false` | 无色打印 | +| draft | `false` | 打印质量较低(墨水) | +| cellComments | `'None'` | 在何处放置批注-`['atEnd','asDisplayed','None']`中的一个 | +| errors | `'displayed'` | 哪里显示错误 -`['dash', 'blank', 'NA', 'displayed']` 之一 | +| scale | 100 | 增加或减小打印尺寸的百分比值。 当 `fitToPage` 为 `false` 时激活 | +| fitToWidth | 1 | 纸张应打印多少页宽。 当 `fitToPage` 为 `true` 时激活 | +| fitToHeight | 1 | 纸张应打印多少页高。 当 `fitToPage` 为 `true` 时激活 | +| paperSize | | 使用哪种纸张尺寸(见下文) | +| showRowColHeaders | false | 是否显示行号和列字母 | +| showGridLines | false | 是否显示网格线 | +| firstPageNumber | | 第一页使用哪个页码 | +| horizontalCentered | false | 是否将工作表数据水平居中 | +| verticalCentered | false | 是否将工作表数据垂直居中 | **示例纸张尺寸** -| 属性名 | 值 | +| 属性名 | 值 | | ----------------------------- | ----------- | | Letter | `undefined` | | Legal | 5 | @@ -485,120 +491,118 @@ worksheet.pageSetup.printTitlesColumn = 'A:C'; ```javascript // 创建一个带有页眉和页脚的工作表 var sheet = workbook.addWorksheet('My Sheet', { - headerFooter:{firstHeader: "Hello Exceljs", firstFooter: "Hello World"} + headerFooter: {firstHeader: 'Hello Exceljs', firstFooter: 'Hello World'}, }); // 创建一个带有页眉和页脚可写的工作表 var worksheetWriter = workbookWriter.addWorksheet('sheet', { - headerFooter:{firstHeader: "Hello Exceljs", firstFooter: "Hello World"} + headerFooter: {firstHeader: 'Hello Exceljs', firstFooter: 'Hello World'}, }); // 代码中出现的&开头字符对应变量,相关信息可查阅下文的变量表 // 设置页脚(默认居中),结果:“第 2 页,共 16 页” -worksheet.headerFooter.oddFooter = "第 &P 页,共 &N 页"; +worksheet.headerFooter.oddFooter = '第 &P 页,共 &N 页'; // 将页脚(默认居中)设置为粗体,结果是:“第2页,共16页” -worksheet.headerFooter.oddFooter = "Page &P of &N"; +worksheet.headerFooter.oddFooter = 'Page &P of &N'; // 将左页脚设置为 18px 并以斜体显示。 结果:“第2页,共16页” -worksheet.headerFooter.oddFooter = "&LPage &P of &N"; +worksheet.headerFooter.oddFooter = '&LPage &P of &N'; // 将中间标题设置为灰色Aril,结果为:“ 52 exceljs” -worksheet.headerFooter.oddHeader = "&C&KCCCCCC&\"Aril\"52 exceljs"; +worksheet.headerFooter.oddHeader = '&C&KCCCCCC&"Aril"52 exceljs'; // 设置页脚的左,中和右文本。 结果:页脚左侧为“ Exceljs”。 页脚中心的“ demo.xlsx”。 页脚右侧的“第2页” -worksheet.headerFooter.oddFooter = "&Lexceljs&C&F&RPage &P"; +worksheet.headerFooter.oddFooter = '&Lexceljs&C&F&RPage &P'; // 在首页添加不同的页眉和页脚 worksheet.headerFooter.differentFirst = true; -worksheet.headerFooter.firstHeader = "Hello Exceljs"; -worksheet.headerFooter.firstFooter = "Hello World" +worksheet.headerFooter.firstHeader = 'Hello Exceljs'; +worksheet.headerFooter.firstFooter = 'Hello World'; ``` **支持的 headerFooter 设置** -| 属性名 | 默认值 | 描述 | -| ---------------- | ------- | ------------------------------------------------------------ | +| 属性名 | 默认值 | 描述 | +| ---------------- | ------- | -------------------------------------------------------------------------- | | differentFirst | `false` | 将 `differentFirst` 的值设置为 `true`,这表示第一页的页眉/页脚与其他页不同 | | differentOddEven | `false` | 将 `differentOddEven` 的值设置为 `true`,表示奇数页和偶数页的页眉/页脚不同 | -| oddHeader | `null` | 设置奇数(默认)页面的标题字符串,可以设置格式化字符串 | -| oddFooter | `null` | 设置奇数(默认)页面的页脚字符串,可以设置格式化字符串 | -| evenHeader | `null` | 设置偶数页的标题字符串,可以设置格式化字符串 | -| evenFooter | `null` | 为偶数页设置页脚字符串,可以设置格式化字符串 | -| firstHeader | `null` | 设置首页的标题字符串,可以设置格式化字符串 | -| firstFooter | `null` | 设置首页的页脚字符串,可以设置格式化字符串 | +| oddHeader | `null` | 设置奇数(默认)页面的标题字符串,可以设置格式化字符串 | +| oddFooter | `null` | 设置奇数(默认)页面的页脚字符串,可以设置格式化字符串 | +| evenHeader | `null` | 设置偶数页的标题字符串,可以设置格式化字符串 | +| evenFooter | `null` | 为偶数页设置页脚字符串,可以设置格式化字符串 | +| firstHeader | `null` | 设置首页的标题字符串,可以设置格式化字符串 | +| firstFooter | `null` | 设置首页的页脚字符串,可以设置格式化字符串 | **脚本命令** -| 命令 | 描述 | -| ------------ | ----------- | -| &L | 将位置设定在左侧 | -| &C | 将位置设置在中心 | -| &R | 将位置设定在右边 | -| &P | 当前页码 | -| &N | 总页数 | -| &D | 当前日期 | -| &T | 当前时间 | -| &G | 照片 | -| &A | 工作表名称 | -| &F | 文件名称 | -| &B | 加粗文本 | +| 命令 | 描述 | +| ------------ | ----------------------- | +| &L | 将位置设定在左侧 | +| &C | 将位置设置在中心 | +| &R | 将位置设定在右边 | +| &P | 当前页码 | +| &N | 总页数 | +| &D | 当前日期 | +| &T | 当前时间 | +| &G | 照片 | +| &A | 工作表名称 | +| &F | 文件名称 | +| &B | 加粗文本 | | &I | 斜体文本 | -| &U | 文本下划线 | +| &U | 文本下划线 | | &"font name" | 字体名称,例如&“ Aril” | -| &font size | 字体大小,例如12 | +| &font size | 字体大小,例如12 | | &KHEXCode | 字体颜色,例如 &KCCCCCC | ## 工作表视图[⬆](#目录) 现在,工作表支持视图列表,这些视图控制Excel如何显示工作表: -* `frozen` - 顶部和左侧的许多行和列被冻结在适当的位置。 仅右下部分会滚动 -* `split` - 该视图分为4个部分,每个部分可半独立滚动。 +- `frozen` - 顶部和左侧的许多行和列被冻结在适当的位置。 仅右下部分会滚动 +- `split` - 该视图分为4个部分,每个部分可半独立滚动。 每个视图还支持各种属性: -| 属性名 | 默认值 | 描述 | -| ----------------- | --------- | ----------- | -| state | `'normal'` | 控制视图状态 - `'normal'`, `'frozen'` 或者 `'split'` 之一 | -| rightToLeft | `false` | 将工作表视图的方向设置为从右到左 | -| activeCell | `undefined` | 当前选择的单元格 | -| showRuler | `true` | 在页面布局中显示或隐藏标尺 | -| showRowColHeaders | `true` | 显示或隐藏行标题和列标题(例如,顶部的 A1,B1 和左侧的1,2,3) | -| showGridLines | `true` | 显示或隐藏网格线(针对未定义边框的单元格显示) | -| zoomScale | 100 | 用于视图的缩放比例 | -| zoomScaleNormal | 100 | 正常缩放视图 | +| 属性名 | 默认值 | 描述 | +| ----------------- | ----------- | ---------------------------------------------------------------------------------------- | +| state | `'normal'` | 控制视图状态 - `'normal'`, `'frozen'` 或者 `'split'` 之一 | +| rightToLeft | `false` | 将工作表视图的方向设置为从右到左 | +| activeCell | `undefined` | 当前选择的单元格 | +| showRuler | `true` | 在页面布局中显示或隐藏标尺 | +| showRowColHeaders | `true` | 显示或隐藏行标题和列标题(例如,顶部的 A1,B1 和左侧的1,2,3) | +| showGridLines | `true` | 显示或隐藏网格线(针对未定义边框的单元格显示) | +| zoomScale | 100 | 用于视图的缩放比例 | +| zoomScaleNormal | 100 | 正常缩放视图 | | style | `undefined` | 演示样式- `pageBreakPreview` 或 `pageLayout` 之一。 注意:页面布局与 `frozen` 视图不兼容 | ### 冻结视图[⬆](#目录) 冻结视图支持以下额外属性: -| 属性名 | 默认值 | 描述 | -| ----------------- | --------- | ----------- | -| xSplit | 0 | 冻结多少列。要仅冻结行,请将其设置为 `0` 或 `undefined` | -| ySplit | 0 | 冻结多少行。要仅冻结列,请将其设置为 `0` 或 `undefined` | -| topLeftCell | special | 哪个单元格将在右下窗格中的左上角。注意:不能是冻结单元格。默认为第一个未冻结的单元格 | +| 属性名 | 默认值 | 描述 | +| ----------- | ------- | ------------------------------------------------------------------------------------ | +| xSplit | 0 | 冻结多少列。要仅冻结行,请将其设置为 `0` 或 `undefined` | +| ySplit | 0 | 冻结多少行。要仅冻结列,请将其设置为 `0` 或 `undefined` | +| topLeftCell | special | 哪个单元格将在右下窗格中的左上角。注意:不能是冻结单元格。默认为第一个未冻结的单元格 | ```javascript -worksheet.views = [ - {state: 'frozen', xSplit: 2, ySplit: 3, topLeftCell: 'G10', activeCell: 'A1'} -]; +worksheet.views = [{state: 'frozen', xSplit: 2, ySplit: 3, topLeftCell: 'G10', activeCell: 'A1'}]; ``` ### 拆分视图[⬆](#目录) 拆分视图支持以下额外属性: -| 属性名 | 默认值 | 描述 | -| ----------------- | --------- | ----------- | -| xSplit | 0 | 从左侧多少个点起,以放置拆分器。要垂直拆分,请将其设置为 `0` 或 `undefined` | -| ySplit | 0 | 从顶部多少个点起,放置拆分器。要水平拆分,请将其设置为 `0` 或 `undefined` | -| topLeftCell | `undefined` | 哪个单元格将在右下窗格中的左上角。 | -| activePane | `undefined` | 哪个窗格将处于活动状态-`topLeft`,`topRight`,`bottomLeft` 和 `bottomRight` 中的一个 | +| 属性名 | 默认值 | 描述 | +| ----------- | ----------- | ------------------------------------------------------------------------------------ | +| xSplit | 0 | 从左侧多少个点起,以放置拆分器。要垂直拆分,请将其设置为 `0` 或 `undefined` | +| ySplit | 0 | 从顶部多少个点起,放置拆分器。要水平拆分,请将其设置为 `0` 或 `undefined` | +| topLeftCell | `undefined` | 哪个单元格将在右下窗格中的左上角。 | +| activePane | `undefined` | 哪个窗格将处于活动状态-`topLeft`,`topRight`,`bottomLeft` 和 `bottomRight` 中的一个 | ```javascript worksheet.views = [ - {state: 'split', xSplit: 2000, ySplit: 3000, topLeftCell: 'G10', activeCell: 'A1'} + {state: 'split', xSplit: 2000, ySplit: 3000, topLeftCell: 'G10', activeCell: 'A1'}, ]; ``` @@ -617,28 +621,28 @@ worksheet.autoFilter = 'A1:C1'; worksheet.autoFilter = { from: 'A1', to: 'C1', -} +}; // 将自动筛选器设置为从第3行第1列的单元格到第5行第12列的单元格 worksheet.autoFilter = { from: { row: 3, - column: 1 + column: 1, }, to: { row: 5, - column: 12 - } -} + column: 12, + }, +}; // 将自动筛选器设置为从D3到第7行第5列中的单元格 worksheet.autoFilter = { from: 'D3', to: { row: 7, - column: 5 - } -} + column: 5, + }, +}; ``` ## 列[⬆](#目录) @@ -647,9 +651,9 @@ worksheet.autoFilter = { // 添加列标题并定义列键和宽度 // 注意:这些列结构仅是构建工作簿的方便之处,除了列宽之外,它们不会完全保留。 worksheet.columns = [ - { header: 'Id', key: 'id', width: 10 }, - { header: 'Name', key: 'name', width: 32 }, - { header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1 } + {header: 'Id', key: 'id', width: 10}, + {header: 'Name', key: 'name', width: 32}, + {header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1}, ]; // 通过键,字母和基于1的列号访问单个列 @@ -682,33 +686,32 @@ expect(worksheet.getColumn(4).collapsed).to.equal(false); expect(worksheet.getColumn(5).collapsed).to.equal(true); // 遍历此列中的所有当前单元格 -dobCol.eachCell(function(cell, rowNumber) { +dobCol.eachCell(function (cell, rowNumber) { // ... }); // 遍历此列中的所有当前单元格,包括空单元格 -dobCol.eachCell({ includeEmpty: true }, function(cell, rowNumber) { +dobCol.eachCell({includeEmpty: true}, function (cell, rowNumber) { // ... }); // 添加一列新值 -worksheet.getColumn(6).values = [1,2,3,4,5]; +worksheet.getColumn(6).values = [1, 2, 3, 4, 5]; // 添加稀疏列值 -worksheet.getColumn(7).values = [,,2,3,,5,,7,,,,11]; +worksheet.getColumn(7).values = [, , 2, 3, , 5, , 7, , , , 11]; // 剪切一列或多列(右边的列向左移动) // 如果定义了列属性,则会相应地对其进行切割或移动 // 已知问题:如果拼接导致任何合并的单元格移动,结果可能是不可预测的 -worksheet.spliceColumns(3,2); +worksheet.spliceColumns(3, 2); // 删除一列,再插入两列。 // 注意:第4列及以上的列将右移1列。 // 另外:如果工作表中的行数多于列插入项中的值,则行将仍然被插入,就好像值存在一样。 -const newCol3Values = [1,2,3,4,5]; +const newCol3Values = [1, 2, 3, 4, 5]; const newCol4Values = ['one', 'two', 'three', 'four', 'five']; worksheet.spliceColumns(3, 1, newCol3Values, newCol4Values); - ``` ## 行[⬆](#目录) @@ -737,7 +740,6 @@ worksheet.getRow(5).outlineLevel = 1; expect(worksheet.getRow(4).collapsed).to.equal(false); expect(worksheet.getRow(5).collapsed).to.equal(true); - row.getCell(1).value = 5; // A5 的值设置为5 row.getCell('name').value = 'Zeb'; // B5 的值设置为 “Zeb” - 假设第2列仍按名称键入 row.getCell('C').value = new Date(); // C5 的值设置为当前时间 @@ -748,13 +750,13 @@ row = worksheet.getRow(4).values; expect(row[5]).toEqual('Kyle'); // 通过连续数组分配行值(其中数组元素 0 具有值) -row.values = [1,2,3]; +row.values = [1, 2, 3]; expect(row.getCell(1).value).toEqual(1); expect(row.getCell(2).value).toEqual(2); expect(row.getCell(3).value).toEqual(3); // 通过稀疏数组分配行值(其中数组元素 0 为 `undefined`) -const values = [] +const values = []; values[5] = 7; values[10] = 'Hello, World!'; row.values = values; @@ -766,29 +768,29 @@ expect(row.getCell(10).value).toEqual('Hello, World!'); row.values = { id: 13, name: 'Thing 1', - dob: new Date() + dob: new Date(), }; // 在该行下方插入一个分页符 row.addPageBreak(); // 遍历工作表中具有值的所有行 -worksheet.eachRow(function(row, rowNumber) { +worksheet.eachRow(function (row, rowNumber) { console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values)); }); // 遍历工作表中的所有行(包括空行) -worksheet.eachRow({ includeEmpty: true }, function(row, rowNumber) { +worksheet.eachRow({includeEmpty: true}, function (row, rowNumber) { console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values)); }); // 连续遍历所有非空单元格 -row.eachCell(function(cell, colNumber) { +row.eachCell(function (cell, colNumber) { console.log('Cell ' + colNumber + ' = ' + cell.value); }); // 遍历一行中的所有单元格(包括空单元格) -row.eachCell({ includeEmpty: true }, function(cell, colNumber) { +row.eachCell({includeEmpty: true}, function (cell, colNumber) { console.log('Cell ' + colNumber + ' = ' + cell.value); }); @@ -804,8 +806,8 @@ const numValues = row.actualCellCount; ```javascript // Add a couple of Rows by key-value, after the last current row, using the column keys -worksheet.addRow({id: 1, name: 'John Doe', dob: new Date(1970,1,1)}); -worksheet.addRow({id: 2, name: 'Jane Doe', dob: new Date(1965,1,7)}); +worksheet.addRow({id: 1, name: 'John Doe', dob: new Date(1970, 1, 1)}); +worksheet.addRow({id: 2, name: 'Jane Doe', dob: new Date(1965, 1, 7)}); // Add a row by contiguous Array (assign to columns A, B & C) worksheet.addRow([3, 'Sam', new Date()]); @@ -824,8 +826,8 @@ const newRow = worksheet.addRow(rowValues, 'i'); // Add an array of rows const rows = [ - [5,'Bob',new Date()], // row by array - {id:6, name: 'Barbara', dob: new Date()} + [5, 'Bob', new Date()], // row by array + {id: 6, name: 'Barbara', dob: new Date()}, ]; // add new rows and return them as array of row objects const newRows = worksheet.addRows(rows); @@ -835,10 +837,11 @@ const newRows = worksheet.addRows(rows); // and return them as array of row objects const newRowsStyled = worksheet.addRows(rows, 'i'); ``` -| Parameter | Description | Default Value | -| -------------- | ----------------- | -------- | -| value/s | The new row/s values | | -| style | 'i' for inherit from row above, 'i+' to include empty cells, 'n' for none | *'n'* | + +| Parameter | Description | Default Value | +| --------- | ------------------------------------------------------------------------- | ------------- | +| value/s | The new row/s values | | +| style | 'i' for inherit from row above, 'i+' to include empty cells, 'n' for none | _'n'_ | ## 处理单个单元格[⬆](#目录) @@ -856,7 +859,6 @@ myInput.value = cell.text; // 使用 html 安全的字符串进行渲染... const html = '
    ' + cell.html + '
    '; - ``` ## 合并单元格[⬆](#目录) @@ -884,18 +886,18 @@ expect(worksheet.getCell('B5').style.font).not.toBe(myFonts.arial); worksheet.mergeCells('K10', 'M12'); // 按开始行,开始列,结束行,结束列合并(相当于 K10:M12) -worksheet.mergeCells(10,11,12,13); +worksheet.mergeCells(10, 11, 12, 13); ``` ## Insert Rows[⬆](#目录) ```javascript -insertRow(pos, value, style = 'n') -insertRows(pos, values, style = 'n') +insertRow(pos, value, (style = 'n')); +insertRows(pos, values, (style = 'n')); // Insert a couple of Rows by key-value, shifting down rows every time -worksheet.insertRow(1, {id: 1, name: 'John Doe', dob: new Date(1970,1,1)}); -worksheet.insertRow(1, {id: 2, name: 'Jane Doe', dob: new Date(1965,1,7)}); +worksheet.insertRow(1, {id: 1, name: 'John Doe', dob: new Date(1970, 1, 1)}); +worksheet.insertRow(1, {id: 2, name: 'Jane Doe', dob: new Date(1965, 1, 7)}); // Insert a row by contiguous Array (assign to columns A, B & C) worksheet.insertRow(1, [3, 'Sam', new Date()]); @@ -920,8 +922,8 @@ const insertedRowOriginal = worksheet.insertRow(1, rowValues, 'o'); // Insert an array of rows, in position 1, shifting down current position 1 and later rows by 2 rows var rows = [ - [5,'Bob',new Date()], // row by array - {id:6, name: 'Barbara', dob: new Date()} + [5, 'Bob', new Date()], // row by array + {id: 6, name: 'Barbara', dob: new Date()}, ]; // insert new rows and return them as array of row objects const insertedRows = worksheet.insertRows(1, rows); @@ -934,13 +936,13 @@ const insertedRowsInherited = worksheet.insertRows(1, rows, 'i'); // Insert an array of rows, keeping original style // These new rows will have same style as it was previously in 'pos' position const insertedRowsOriginal = worksheet.insertRows(1, rows, 'o'); - ``` -| Parameter | Description | Default Value | -| -------------- | ----------------- | -------- | -| pos | Row number where you want to insert, pushing down all rows from there | | -| value/s | The new row/s values | | -| style | 'i' for inherit from row above, , 'i+' to include empty cells, 'o' for original style, 'o+' to include empty cells, 'n' for none | *'n'* | + +| Parameter | Description | Default Value | +| --------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| pos | Row number where you want to insert, pushing down all rows from there | | +| value/s | The new row/s values | | +| style | 'i' for inherit from row above, , 'i+' to include empty cells, 'o' for original style, 'o+' to include empty cells, 'n' for none | _'n'_ | ## Splice[⬆](#contents) @@ -962,16 +964,17 @@ row.splice(3, 2); // remove one cell and insert two more (cells to the right of the cut cell will be shifted right) row.splice(4, 1, 'new value 1', 'new value 2'); ``` -| Parameter | Description | Default Value | -| -------------- | ----------------- | -------- | -| start | Starting point to splice from | | -| count | Number of rows/cells to remove | | -| ...inserts | New row/cell values to insert | | + +| Parameter | Description | Default Value | +| ---------- | ------------------------------ | ------------- | +| start | Starting point to splice from | | +| count | Number of rows/cells to remove | | +| ...inserts | New row/cell values to insert | | ## 重复行[⬆](#目录) ```javascript -duplicateRow(start, amount = 1, insert = true) +duplicateRow(start, (amount = 1), (insert = true)); const wb = new ExcelJS.Workbook(); const ws = wb.addWorksheet('duplicateTest'); @@ -982,16 +985,14 @@ ws.getCell('A4').value = 'Four'; // 该行将重复复制第一行两次,但将替换第二行和第三行 // 如果第三个参数为 true,则它将插入2个新行,其中包含行 “One” 的值和样式 -ws.duplicateRow(1,2,false); +ws.duplicateRow(1, 2, false); ``` -| 参数 | 描述 | 默认值 | -| -------------- | ----------------- | -------- | -| start | 要复制的行号(Excel中的第一个是1) | | -| amount | 您要复制行的次数 | 1 | -| insert | 如果要为重复项插入新行,则为 `true`,否则为 `false` 将替换已有行 | `true` | - - +| 参数 | 描述 | 默认值 | +| ------ | ---------------------------------------------------------------- | ------ | +| start | 要复制的行号(Excel中的第一个是1) | | +| amount | 您要复制行的次数 | 1 | +| insert | 如果要为重复项插入新行,则为 `true`,否则为 `false` 将替换已有行 | `true` | ## 定义名称[⬆](#目录) @@ -1017,26 +1018,26 @@ expect(worksheet.getCell('A1').names).to.have.members(['thing2']); 验证类型可以是以下之一: -| 类型 | 描述 | -| ---------- | ----------- | +| 类型 | 描述 | +| ---------- | ------------------------------------------------------------------ | | list | 定义一组离散的有效值。Excel 将在下拉菜单中提供这些内容,以便于输入 | -| whole | 该值必须是整数 | -| decimal | 该值必须是十进制数 | -| textLength | 该值可以是文本,但长度是受控的 | -| custom | 自定义公式控制有效值 | +| whole | 该值必须是整数 | +| decimal | 该值必须是十进制数 | +| textLength | 该值可以是文本,但长度是受控的 | +| custom | 自定义公式控制有效值 | 对于 `list` 或 `custom` 以外的其他类型,以下运算符会影响验证: -| 运算符 | 描述 | -| -------------------- | ----------- | -| between | 值必须介于公式结果之间 | -| notBetween | 值不能介于公式结果之间 | -| equal | 值必须等于公式结果 | -| notEqual | 值不能等于公式结果 | -| greaterThan | 值必须大于公式结果 | -| lessThan | 值必须小于公式结果 | -| greaterThanOrEqual | 值必须大于或等于公式结果 | -| lessThanOrEqual | 值必须小于或等于公式结果 | +| 运算符 | 描述 | +| ------------------ | ------------------------ | +| between | 值必须介于公式结果之间 | +| notBetween | 值不能介于公式结果之间 | +| equal | 值必须等于公式结果 | +| notEqual | 值不能等于公式结果 | +| greaterThan | 值必须大于公式结果 | +| lessThan | 值必须小于公式结果 | +| greaterThanOrEqual | 值必须大于或等于公式结果 | +| lessThanOrEqual | 值必须小于或等于公式结果 | ```javascript // 指定有效值的列表(One,Two,Three,Four)。 @@ -1044,7 +1045,7 @@ expect(worksheet.getCell('A1').names).to.have.members(['thing2']); worksheet.getCell('A1').dataValidation = { type: 'list', allowBlank: true, - formulae: ['"One,Two,Three,Four"'] + formulae: ['"One,Two,Three,Four"'], }; // 指定范围内的有效值列表。 @@ -1052,7 +1053,7 @@ worksheet.getCell('A1').dataValidation = { worksheet.getCell('A1').dataValidation = { type: 'list', allowBlank: true, - formulae: ['$D$5:$F$5'] + formulae: ['$D$5:$F$5'], }; // 指定单元格必须为非5的整数。 @@ -1064,7 +1065,7 @@ worksheet.getCell('A1').dataValidation = { formulae: [5], errorStyle: 'error', errorTitle: 'Five', - error: 'The value must not be Five' + error: 'The value must not be Five', }; // 指定单元格必须为1.5到7之间的十进制数字。 @@ -1076,7 +1077,7 @@ worksheet.getCell('A1').dataValidation = { showInputMessage: true, formulae: [1.5, 7], promptTitle: 'Decimal', - prompt: 'The value must between 1.5 and 7' + prompt: 'The value must between 1.5 and 7', }; // 指定单元格的文本长度必须小于15 @@ -1085,7 +1086,7 @@ worksheet.getCell('A1').dataValidation = { operator: 'lessThan', showErrorMessage: true, allowBlank: true, - formulae: [15] + formulae: [15], }; // 指定单元格必须是2016年1月1日之前的日期 @@ -1094,7 +1095,7 @@ worksheet.getCell('A1').dataValidation = { operator: 'lessThan', showErrorMessage: true, allowBlank: true, - formulae: [new Date(2016,0,1)] + formulae: [new Date(2016, 0, 1)], }; ``` @@ -1109,24 +1110,42 @@ worksheet.getCell('A1').note = 'Hello, ExcelJS!'; // 彩色格式化的笔记 ws.getCell('B1').note = { texts: [ - {'font': {'size': 12, 'color': {'theme': 0}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': 'This is '}, - {'font': {'italic': true, 'size': 12, 'color': {'theme': 0}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'a'}, - {'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' '}, - {'font': {'size': 12, 'color': {'argb': 'FFFF6600'}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'colorful'}, - {'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' text '}, - {'font': {'size': 12, 'color': {'argb': 'FFCCFFCC'}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'with'}, - {'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' in-cell '}, - {'font': {'bold': true, 'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': 'format'}, + { + font: {size: 12, color: {theme: 0}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: 'This is ', + }, + { + font: {italic: true, size: 12, color: {theme: 0}, name: 'Calibri', scheme: 'minor'}, + text: 'a', + }, + {font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, text: ' '}, + { + font: {size: 12, color: {argb: 'FFFF6600'}, name: 'Calibri', scheme: 'minor'}, + text: 'colorful', + }, + { + font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: ' text ', + }, + {font: {size: 12, color: {argb: 'FFCCFFCC'}, name: 'Calibri', scheme: 'minor'}, text: 'with'}, + { + font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: ' in-cell ', + }, + { + font: {bold: true, size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: 'format', + }, ], margins: { insetmode: 'custom', - inset: [0.25, 0.25, 0.35, 0.35] + inset: [0.25, 0.25, 0.35, 0.35], }, protection: { locked: True, - lockText: False + lockText: False, }, - editAs: 'twoCells' + editAs: 'twoCells', }; ``` @@ -1134,12 +1153,12 @@ ws.getCell('B1').note = { 下表定义了单元格注释已支持的属性。 -| Field | Required | Default Value | Description | -| -------- | -------- | ------------- | ----------- | -| texts | Y | | 评论文字 | -| margins | N | {} | 确定自动或自定义设置单元格注释的边距值 | -| protection | N | {} | 可以使用保护属性来指定对象和对象文本的锁定状态 | -| editAs | N | 'absolute' | 可以使用'editAs'属性来指定注释如何锚定到单元格 | +| Field | Required | Default Value | Description | +| ---------- | -------- | ------------- | ---------------------------------------------- | +| texts | Y | | 评论文字 | +| margins | N | {} | 确定自动或自定义设置单元格注释的边距值 | +| protection | N | {} | 可以使用保护属性来指定对象和对象文本的锁定状态 | +| editAs | N | 'absolute' | 可以使用'editAs'属性来指定注释如何锚定到单元格 | ### 单元格批注页边距[⬆](#目录) @@ -1148,18 +1167,18 @@ ws.getCell('B1').note = { ```javascript ws.getCell('B1').note.margins = { insetmode: 'custom', - inset: [0.25, 0.25, 0.35, 0.35] -} + inset: [0.25, 0.25, 0.35, 0.35], +}; ``` ### 已支持的页边距属性[⬆](#目录) -| Property | Required | Default Value | Description | -| -------- | -------- | ------------- | ----------- | -| insetmode | N | 'auto' | 确定是否自动设置注释边距,并且值是'auto' 或者 'custom' | -| inset | N | [0.13, 0.13, 0.25, 0.25] | 批注页边距的值,单位是厘米, 方向是左-上-右-下 | +| Property | Required | Default Value | Description | +| --------- | -------- | ------------------------ | ------------------------------------------------------ | +| insetmode | N | 'auto' | 确定是否自动设置注释边距,并且值是'auto' 或者 'custom' | +| inset | N | [0.13, 0.13, 0.25, 0.25] | 批注页边距的值,单位是厘米, 方向是左-上-右-下 | -注意:只有当 ```insetmode```的值设置为'custom'时,```inset```的设置才生效。 +注意:只有当 `insetmode`的值设置为'custom'时,`inset`的设置才生效。 ### 单元格批注保护[⬆](#目录) @@ -1174,11 +1193,10 @@ ws.getCell('B1').note.protection = { ### 已支持的保护属性[⬆](#目录) -| Property | Required | Default Value | Description | -| -------- | -------- | ------------- | ----------- | -| locked | N | 'True' | 此元素指定在保护工作表时对象已锁定 | -| lockText | N | 'True' | 该元素指定对象的文本已锁定 | - +| Property | Required | Default Value | Description | +| -------- | -------- | ------------- | ---------------------------------- | +| locked | N | 'True' | 此元素指定在保护工作表时对象已锁定 | +| lockText | N | 'True' | 该元素指定对象的文本已锁定 | ### 单元格批注对象位置属性[⬆](#目录) @@ -1186,14 +1204,14 @@ ws.getCell('B1').note.protection = { 它可以具有以下值之一: ```javascript -ws.getCell('B1').note.editAs = 'twoCell' +ws.getCell('B1').note.editAs = 'twoCell'; ``` -| Value | Description | -| --------- | ----------- | -| twoCell | 它指定注释的大小、位置随单元格而变 | -| oneCell | 这是默认值,它指定注释的大小固定,位置随单元格而变 | -| absolute | 它指定注释的大小、位置均固定 | +| Value | Description | +| -------- | -------------------------------------------------- | +| twoCell | 它指定注释的大小、位置随单元格而变 | +| oneCell | 这是默认值,它指定注释的大小固定,位置随单元格而变 | +| absolute | 它指定注释的大小、位置均固定 | ## 表格[⬆](#目录) @@ -1217,9 +1235,9 @@ ws.addTable({ {name: 'Amount', totalsRowFunction: 'sum', filterButton: false}, ], rows: [ - [new Date('2019-07-20'), 70.10], - [new Date('2019-07-21'), 70.60], - [new Date('2019-07-22'), 70.10], + [new Date('2019-07-20'), 70.1], + [new Date('2019-07-21'), 70.6], + [new Date('2019-07-22'), 70.1], ], }); ``` @@ -1229,72 +1247,71 @@ ws.addTable({ ### 表格属性[⬆](#目录) - 下表定义了表格支持的属性。 -| 表属性 | 描述 | 是否需要 | 默认值 | -| -------------- | ----------------- | -------- | ------------- | -| name | 表格名称 | Y | | -| displayName | 表格的显示名称 | N | `name` | -| ref | 表格的左上方单元格 | Y | | -| headerRow | 在表格顶部显示标题 | N | true | -| totalsRow | 在表格底部显示总计 | N | `false` | -| style | 额外的样式属性 | N | {} | -| columns | 列定义 | Y | | -| rows | 数据行 | Y | | +| 表属性 | 描述 | 是否需要 | 默认值 | +| ----------- | ------------------ | -------- | ------- | +| name | 表格名称 | Y | | +| displayName | 表格的显示名称 | N | `name` | +| ref | 表格的左上方单元格 | Y | | +| headerRow | 在表格顶部显示标题 | N | true | +| totalsRow | 在表格底部显示总计 | N | `false` | +| style | 额外的样式属性 | N | {} | +| columns | 列定义 | Y | | +| rows | 数据行 | Y | | ### 表格样式属性[⬆](#目录) 下表定义了表格中支持的属性样式属性。 -| 样式属性 | 描述 | 是否需要 | 默认值 | -| ------------------ | ----------------- | -------- | ------------- | -| theme | 桌子的颜色主题 | N | `'TableStyleMedium2'` | -| showFirstColumn | 突出显示第一列(粗体) | N | `false` | -| showLastColumn | 突出显示最后一列(粗体) | N | `false` | -| showRowStripes | 用交替的背景色显示行 | N | `false` | -| showColumnStripes | 用交替的背景色显示列 | N | `false` | +| 样式属性 | 描述 | 是否需要 | 默认值 | +| ----------------- | ------------------------ | -------- | --------------------- | +| theme | 桌子的颜色主题 | N | `'TableStyleMedium2'` | +| showFirstColumn | 突出显示第一列(粗体) | N | `false` | +| showLastColumn | 突出显示最后一列(粗体) | N | `false` | +| showRowStripes | 用交替的背景色显示行 | N | `false` | +| showColumnStripes | 用交替的背景色显示列 | N | `false` | ### 表格列属性[⬆](#目录) 下表定义了每个表格列中支持的属性。 -| 列属性 | 描述 | 是否需要 | 默认值 | -| ------------------ | ----------------- | -------- | ------------- | -| name | 列名,也用在标题中 | Y | | -| filterButton | 切换标题中的过滤器控件 | N | false | -| totalsRowLabel | 用于描述统计行的标签(第一列) | N | `'Total'` | -| totalsRowFunction | 统计函数名称 | N | `'none'` | -| totalsRowFormula | 自定义函数的可选公式 | N | | +| 列属性 | 描述 | 是否需要 | 默认值 | +| ----------------- | ------------------------------ | -------- | --------- | +| name | 列名,也用在标题中 | Y | | +| filterButton | 切换标题中的过滤器控件 | N | false | +| totalsRowLabel | 用于描述统计行的标签(第一列) | N | `'Total'` | +| totalsRowFunction | 统计函数名称 | N | `'none'` | +| totalsRowFormula | 自定义函数的可选公式 | N | | ### 统计函数[⬆](#目录) 下表列出了由列定义的 `totalsRowFunction` 属性的有效值。如果使用 `'custom'` 以外的任何值,则无需包括关联的公式,因为该公式将被表格插入。 -| 统计函数 | 描述 | -| ------------------ | ----------------- | -| none | 此列没有统计函数 | -| average | 计算列的平均值 | -| countNums | 统计数字条目数 | -| count | 条目数 | -| max | 此列中的最大值 | -| min | 此列中的最小值 | -| stdDev | 该列的标准偏差 | -| var | 此列的方差 | -| sum | 此列的条目总数 | -| custom | 自定义公式。 需要关联的 `totalsRowFormula` 值。 | +| 统计函数 | 描述 | +| --------- | ----------------------------------------------- | +| none | 此列没有统计函数 | +| average | 计算列的平均值 | +| countNums | 统计数字条目数 | +| count | 条目数 | +| max | 此列中的最大值 | +| min | 此列中的最小值 | +| stdDev | 该列的标准偏差 | +| var | 此列的方差 | +| sum | 此列的条目总数 | +| custom | 自定义公式。 需要关联的 `totalsRowFormula` 值。 | ### 表格样式主题[⬆](#目录) 有效的主题名称遵循以下模式: -* "TableStyle[Shade][Number]" +- "TableStyle[Shade][Number]" Shades(阴影),Number(数字)可以是以下之一: -* Light, 1-21 -* Medium, 1-28 -* Dark, 1-11 +- Light, 1-21 +- Medium, 1-28 +- Dark, 1-11 对于无主题,请使用值 `null`。 @@ -1361,7 +1378,13 @@ table.removeColumns(1, 1); // 在索引 1 处插入新列(包含数据) table.addColumn( - {name: 'Letter', totalsRowFunction: 'custom', totalsRowFormula: 'ROW()', totalsRowResult: 6, filterButton: true}, + { + name: 'Letter', + totalsRowFunction: 'custom', + totalsRowFormula: 'ROW()', + totalsRowResult: 6, + filterButton: true, + }, ['a', 'b', 'c', 'd'], 2 ); @@ -1381,7 +1404,7 @@ const column = table.getColumn(1); // 设置一些属性 column.name = 'Code'; column.filterButton = true; -column.style = {font:{bold: true, name: 'Comic Sans MS'}}; +column.style = {font: {bold: true, name: 'Comic Sans MS'}}; column.totalsRowLabel = 'Totals'; column.totalsRowFunction = 'custom'; column.totalsRowFormula = 'ROW()'; @@ -1391,18 +1414,17 @@ column.totalsRowResult = 10; table.commit(); ``` - ## 样式[⬆](#目录) 单元格,行和列均支持一组丰富的样式和格式,这些样式和格式会影响单元格的显示方式。 通过分配以下属性来设置样式: -* numFmt -* font -* alignment -* border -* fill +- numFmt +- font +- alignment +- border +- fill ```javascript // 为单元格分配样式 @@ -1410,23 +1432,22 @@ ws.getCell('A1').numFmt = '0.00%'; // 将样式应用于工作表列 ws.columns = [ - { header: 'Id', key: 'id', width: 10 }, - { header: 'Name', key: 'name', width: 32, style: { font: { name: 'Arial Black' } } }, - { header: 'D.O.B.', key: 'DOB', width: 10, style: { numFmt: 'dd/mm/yyyy' } } + {header: 'Id', key: 'id', width: 10}, + {header: 'Name', key: 'name', width: 32, style: {font: {name: 'Arial Black'}}}, + {header: 'D.O.B.', key: 'DOB', width: 10, style: {numFmt: 'dd/mm/yyyy'}}, ]; // 将第3列设置为“货币格式” ws.getColumn(3).numFmt = '"£"#,##0.00;[Red]\-"£"#,##0.00'; // 将第2行设置为 Comic Sans。 -ws.getRow(2).font = { name: 'Comic Sans MS', family: 4, size: 16, underline: 'double', bold: true }; +ws.getRow(2).font = {name: 'Comic Sans MS', family: 4, size: 16, underline: 'double', bold: true}; ``` 将样式应用于行或列时,它将应用于该行或列中所有当前存在的单元格。另外,创建的任何新单元格都将从其所属的行和列继承其初始样式。 如果单元格的行和列都定义了特定的样式(例如,字体),则该单元格所在行样式比列样式具有更高优先级。但是,如果行和列定义了不同的样式(例如 `column.numFmt` 和 `row.font`),则单元格将继承行的字体和列的 `numFmt`。 - 注意:以上所有属性(`numFmt`(字符串)除外)都是 JS 对象结构。如果将同一样式对象分配给多个电子表格实体,则每个实体将共享同一样式对象。如果样式对象后来在电子表格序列化之前被修改,则所有引用该样式对象的实体也将被修改。此行为旨在通过减少创建的JS对象的数量来优先考虑性能。如果希望样式对象是独立的,则需要先对其进行克隆,然后再分配它们。同样,默认情况下,如果电子表格实体共享相似的样式,则从文件(或流)中读取文档时,它们也将引用相同的样式对象。 ### 数字格式[⬆](#目录) @@ -1444,126 +1465,124 @@ ws.getCell('B1').numFmt = '0.00%'; ### 字体 ```javascript - // for the wannabe graphic designers out there ws.getCell('A1').font = { name: 'Comic Sans MS', family: 4, size: 16, underline: true, - bold: true + bold: true, }; // for the graduate graphic designers... ws.getCell('A2').font = { name: 'Arial Black', - color: { argb: 'FF00FF00' }, + color: {argb: 'FF00FF00'}, family: 2, size: 14, - italic: true + italic: true, }; // 垂直对齐 ws.getCell('A3').font = { - vertAlign: 'superscript' + vertAlign: 'superscript', }; // 注意:该单元格将存储对分配的字体对象的引用。 // 如果之后更改了字体对象,则单元字体也将更改。 -const font = { name: 'Arial', size: 12 }; +const font = {name: 'Arial', size: 12}; ws.getCell('A3').font = font; font.size = 20; // 单元格 A3 现在具有20号字体! // 从文件或流中读取工作簿后,共享相似字体的单元格可能引用相同的字体对象 ``` -| 字体属性 | 描述 | 示例值 | -| ------------- | ----------------- | ---------------- | -| name | 字体名称。 | 'Arial', 'Calibri', etc. | -| family | 备用字体家族。整数值。 | 1 - Serif, 2 - Sans Serif, 3 - Mono, Others - unknown | -| scheme | 字体方案。 | 'minor', 'major', 'none' | -| charset | 字体字符集。整数值。 | 1, 2, etc. | -| size | 字体大小。整数值。 | 9, 10, 12, 16, etc. | -| color | 颜色描述,一个包含 ARGB 值的对象。 | { argb: 'FFFF0000'} | -| bold | 字体 **粗细** | true, false | -| italic | 字体 *倾斜* | true, false | -| underline | 字体 下划线 样式 | true, false, 'none', 'single', 'double', 'singleAccounting', 'doubleAccounting' | -| strike | 字体 删除线 | true, false | -| outline | 字体轮廓 | true, false | -| vertAlign | 垂直对齐 | 'superscript', 'subscript' +| 字体属性 | 描述 | 示例值 | +| --------- | ---------------------------------- | ------------------------------------------------------------------------------- | +| name | 字体名称。 | 'Arial', 'Calibri', etc. | +| family | 备用字体家族。整数值。 | 1 - Serif, 2 - Sans Serif, 3 - Mono, Others - unknown | +| scheme | 字体方案。 | 'minor', 'major', 'none' | +| charset | 字体字符集。整数值。 | 1, 2, etc. | +| size | 字体大小。整数值。 | 9, 10, 12, 16, etc. | +| color | 颜色描述,一个包含 ARGB 值的对象。 | { argb: 'FFFF0000'} | +| bold | 字体 **粗细** | true, false | +| italic | 字体 _倾斜_ | true, false | +| underline | 字体 下划线 样式 | true, false, 'none', 'single', 'double', 'singleAccounting', 'doubleAccounting' | +| strike | 字体 删除线 | true, false | +| outline | 字体轮廓 | true, false | +| vertAlign | 垂直对齐 | 'superscript', 'subscript' | ### 对齐[⬆](#目录) ```javascript // 将单元格对齐方式设置为左上,中间居中,右下 -ws.getCell('A1').alignment = { vertical: 'top', horizontal: 'left' }; -ws.getCell('B1').alignment = { vertical: 'middle', horizontal: 'center' }; -ws.getCell('C1').alignment = { vertical: 'bottom', horizontal: 'right' }; +ws.getCell('A1').alignment = {vertical: 'top', horizontal: 'left'}; +ws.getCell('B1').alignment = {vertical: 'middle', horizontal: 'center'}; +ws.getCell('C1').alignment = {vertical: 'bottom', horizontal: 'right'}; // 将单元格设置为自动换行 -ws.getCell('D1').alignment = { wrapText: true }; +ws.getCell('D1').alignment = {wrapText: true}; // 将单元格缩进设置为1 -ws.getCell('E1').alignment = { indent: 1 }; +ws.getCell('E1').alignment = {indent: 1}; // 将单元格文本旋转设置为向上30deg,向下45deg和垂直文本 -ws.getCell('F1').alignment = { textRotation: 30 }; -ws.getCell('G1').alignment = { textRotation: -45 }; -ws.getCell('H1').alignment = { textRotation: 'vertical' }; +ws.getCell('F1').alignment = {textRotation: 30}; +ws.getCell('G1').alignment = {textRotation: -45}; +ws.getCell('H1').alignment = {textRotation: 'vertical'}; ``` **有效的对齐属性值** -| 水平的 | 垂直 | 文本换行 | 自适应 | 缩进 | 阅读顺序 | 文本旋转 | -| ---------------- | ----------- | -------- | ----------- | ------- | ------------ | ------------ | -| left | top | true | true | integer | rtl | 0 to 90 | -| center | middle | false | false | | ltr | -1 to -90 | -| right | bottom | | | | | vertical | -| fill | distributed | | | | | | -| justify | justify | | | | | | -| centerContinuous | | | | | | | -| distributed | | | | | | | - +| 水平的 | 垂直 | 文本换行 | 自适应 | 缩进 | 阅读顺序 | 文本旋转 | +| ---------------- | ----------- | -------- | ------ | ------- | -------- | --------- | +| left | top | true | true | integer | rtl | 0 to 90 | +| center | middle | false | false | | ltr | -1 to -90 | +| right | bottom | | | | | vertical | +| fill | distributed | | | | | | +| justify | justify | | | | | | +| centerContinuous | | | | | | | +| distributed | | | | | | | ### 边框[⬆](#目录) ```javascript // 在A1周围设置单个细边框 ws.getCell('A1').border = { - top: {style:'thin'}, - left: {style:'thin'}, - bottom: {style:'thin'}, - right: {style:'thin'} + top: {style: 'thin'}, + left: {style: 'thin'}, + bottom: {style: 'thin'}, + right: {style: 'thin'}, }; // 在A3周围设置双细绿色边框 ws.getCell('A3').border = { - top: {style:'double', color: {argb:'FF00FF00'}}, - left: {style:'double', color: {argb:'FF00FF00'}}, - bottom: {style:'double', color: {argb:'FF00FF00'}}, - right: {style:'double', color: {argb:'FF00FF00'}} + top: {style: 'double', color: {argb: 'FF00FF00'}}, + left: {style: 'double', color: {argb: 'FF00FF00'}}, + bottom: {style: 'double', color: {argb: 'FF00FF00'}}, + right: {style: 'double', color: {argb: 'FF00FF00'}}, }; // 在A5中设置厚红十字边框 ws.getCell('A5').border = { - diagonal: {up: true, down: true, style:'thick', color: {argb:'FFFF0000'}} + diagonal: {up: true, down: true, style: 'thick', color: {argb: 'FFFF0000'}}, }; ``` **有效边框样式** -* thin -* dotted -* dashDot -* hair -* dashDotDot -* slantDashDot -* mediumDashed -* mediumDashDotDot -* mediumDashDot -* medium -* double -* thick +- thin +- dotted +- dashDot +- hair +- dashDotDot +- slantDashDot +- mediumDashed +- mediumDashDotDot +- mediumDashDot +- medium +- double +- thick ### 填充[⬆](#目录) @@ -1571,16 +1590,16 @@ ws.getCell('A5').border = { // 用红色深色垂直条纹填充A1 ws.getCell('A1').fill = { type: 'pattern', - pattern:'darkVertical', - fgColor:{argb:'FFFF0000'} + pattern: 'darkVertical', + fgColor: {argb: 'FFFF0000'}, }; // 在A2中填充深黄色格子和蓝色背景 ws.getCell('A2').fill = { type: 'pattern', - pattern:'darkTrellis', - fgColor:{argb:'FFFFFF00'}, - bgColor:{argb:'FF0000FF'} + pattern: 'darkTrellis', + fgColor: {argb: 'FFFFFF00'}, + bgColor: {argb: 'FF0000FF'}, }; // 从左到右用蓝白蓝渐变填充A3 @@ -1589,64 +1608,63 @@ ws.getCell('A3').fill = { gradient: 'angle', degree: 0, stops: [ - {position:0, color:{argb:'FF0000FF'}}, - {position:0.5, color:{argb:'FFFFFFFF'}}, - {position:1, color:{argb:'FF0000FF'}} - ] + {position: 0, color: {argb: 'FF0000FF'}}, + {position: 0.5, color: {argb: 'FFFFFFFF'}}, + {position: 1, color: {argb: 'FF0000FF'}}, + ], }; - // 从中心开始用红绿色渐变填充A4 ws.getCell('A4').fill = { type: 'gradient', gradient: 'path', - center:{left:0.5,top:0.5}, + center: {left: 0.5, top: 0.5}, stops: [ - {position:0, color:{argb:'FFFF0000'}}, - {position:1, color:{argb:'FF00FF00'}} - ] + {position: 0, color: {argb: 'FFFF0000'}}, + {position: 1, color: {argb: 'FF00FF00'}}, + ], }; ``` #### 填充模式[⬆](#目录) -| 属性 | 是否需要 | 描述 | -| -------- | -------- | ----------- | -| type | Y | 值: `'pattern'`
    指定此填充使用模式 | -| pattern | Y | 指定模式类型 (查看下面 有效模式类型 ) | -| fgColor | N | 指定图案前景色。默认为黑色。 | -| bgColor | N | 指定图案背景色。默认为白色。 | +| 属性 | 是否需要 | 描述 | +| ------- | -------- | ----------------------------------------------------------------- | +| type | Y | 值: `'pattern'`
    指定此填充使用模式 | +| pattern | Y | 指定模式类型 (查看下面 有效模式类型 ) | +| fgColor | N | 指定图案前景色。默认为黑色。 | +| bgColor | N | 指定图案背景色。默认为白色。 | **有效模式类型** -* none -* solid -* darkGray -* mediumGray -* lightGray -* gray125 -* gray0625 -* darkHorizontal -* darkVertical -* darkDown -* darkUp -* darkGrid -* darkTrellis -* lightHorizontal -* lightVertical -* lightDown -* lightUp -* lightGrid -* lightTrellis +- none +- solid +- darkGray +- mediumGray +- lightGray +- gray125 +- gray0625 +- darkHorizontal +- darkVertical +- darkDown +- darkUp +- darkGrid +- darkTrellis +- lightHorizontal +- lightVertical +- lightDown +- lightUp +- lightGrid +- lightTrellis #### 渐变填充[⬆](#目录) -| 属性 | 是否需要 | 描述 | -| -------- | -------- | ----------- | -| type | Y | 值: `'gradient'`
    指定此填充使用渐变 | -| gradient | Y | 指定渐变类型。`['angle','path']` 之一 | -| degree | angle | 对于“角度”渐变,指定渐变的方向。`0` 是从左到右。值从 1-359 顺时针旋转方向 | -| center | path | 对于“路径”渐变。指定路径起点的相对坐标。“左”和“顶”值的范围是 0 到 1 | +| 属性 | 是否需要 | 描述 | +| -------- | -------- | ------------------------------------------------------------------------------------------------------------------ | +| type | Y | 值: `'gradient'`
    指定此填充使用渐变 | +| gradient | Y | 指定渐变类型。`['angle','path']` 之一 | +| degree | angle | 对于“角度”渐变,指定渐变的方向。`0` 是从左到右。值从 1-359 顺时针旋转方向 | +| center | path | 对于“路径”渐变。指定路径起点的相对坐标。“左”和“顶”值的范围是 0 到 1 | | stops | Y | 指定渐变颜色序列。是包含位置和颜色(从位置 0 开始到位置 1 结束)的对象的数组。中间位置可用于指定路径上的其他颜色。 | **注意事项** @@ -1658,23 +1676,39 @@ ws.getCell('A4').fill = { 现在,单个单元格支持RTF文本或单元格格式化。富文本值可以控制文本值内任意数量的子字符串的字体属性。有关支持哪些字体属性的详细信息,请参见字体。 ```javascript - ws.getCell('A1').value = { - 'richText': [ - {'font': {'size': 12,'color': {'theme': 0},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': 'This is '}, - {'font': {'italic': true,'size': 12,'color': {'theme': 0},'name': 'Calibri','scheme': 'minor'},'text': 'a'}, - {'font': {'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': ' '}, - {'font': {'size': 12,'color': {'argb': 'FFFF6600'},'name': 'Calibri','scheme': 'minor'},'text': 'colorful'}, - {'font': {'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': ' text '}, - {'font': {'size': 12,'color': {'argb': 'FFCCFFCC'},'name': 'Calibri','scheme': 'minor'},'text': 'with'}, - {'font': {'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': ' in-cell '}, - {'font': {'bold': true,'size': 12,'color': {'theme': 1},'name': 'Calibri','family': 2,'scheme': 'minor'},'text': 'format'} - ] + richText: [ + { + font: {size: 12, color: {theme: 0}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: 'This is ', + }, + { + font: {italic: true, size: 12, color: {theme: 0}, name: 'Calibri', scheme: 'minor'}, + text: 'a', + }, + {font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, text: ' '}, + { + font: {size: 12, color: {argb: 'FFFF6600'}, name: 'Calibri', scheme: 'minor'}, + text: 'colorful', + }, + { + font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: ' text ', + }, + {font: {size: 12, color: {argb: 'FFCCFFCC'}, name: 'Calibri', scheme: 'minor'}, text: 'with'}, + { + font: {size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: ' in-cell ', + }, + { + font: {bold: true, size: 12, color: {theme: 1}, name: 'Calibri', family: 2, scheme: 'minor'}, + text: 'format', + }, + ], }; expect(ws.getCell('A1').text).to.equal('This is a colorful text with in-cell format'); expect(ws.getCell('A1').type).to.equal(Excel.ValueType.RichText); - ``` ### 单元格保护[⬆](#目录) @@ -1690,10 +1724,10 @@ ws.getCell('A1').protection = { **支持的保护属性** -| 属性 | 默认值 | 描述 | -| -------- | ------- | ----------- | -| locked | `true` | 指定在工作表受保护的情况下是否将单元格锁定。 | -| hidden | `false` | 指定如果工作表受保护,则单元格的公式是否可见。 | +| 属性 | 默认值 | 描述 | +| ------ | ------- | ---------------------------------------------- | +| locked | `true` | 指定在工作表受保护的情况下是否将单元格锁定。 | +| hidden | `false` | 指定如果工作表受保护,则单元格的公式是否可见。 | ## 条件格式化[⬆](#目录) @@ -1716,179 +1750,180 @@ worksheet.addConditionalFormatting({ type: 'expression', formulae: ['MOD(ROW()+COLUMN(),2)=0'], style: {fill: {type: 'pattern', pattern: 'solid', bgColor: {argb: 'FF00FF00'}}}, - } - ] -}) + }, + ], +}); ``` **支持的条件格式设置规则类型** -| 类型 | 描述 | -| ------------ | ----------- | -| expression | 任何自定义功能均可用于激活规则。 | +| 类型 | 描述 | +| ------------ | ---------------------------------------------- | +| expression | 任何自定义功能均可用于激活规则。 | | cellIs | 使用指定的运算符将单元格值与提供的公式进行比较 | | top10 | 将格式化应用于值在顶部(或底部)范围内的单元格 | -| aboveAverage | 将格式化应用于值高于(或低于)平均值的单元格 | -| colorScale | 根据其值在范围内的位置将彩色背景应用于单元格 | -| iconSet | 根据值将一系列图标之一添加到单元格 | -| containsText | 根据单元格是否为特定文本来应用格式 | -| timePeriod | 根据单元格日期时间值是否在指定范围内应用格式 | +| aboveAverage | 将格式化应用于值高于(或低于)平均值的单元格 | +| colorScale | 根据其值在范围内的位置将彩色背景应用于单元格 | +| iconSet | 根据值将一系列图标之一添加到单元格 | +| containsText | 根据单元格是否为特定文本来应用格式 | +| timePeriod | 根据单元格日期时间值是否在指定范围内应用格式 | ### 表达式[⬆](#目录) -| 属性 | 可选 | 默认值 | 描述 | -| -------- | -------- | ------- | ----------- | -| type | | | `'expression'` | -| priority | Y | <auto> | 确定样式的优先顺序 | -| formulae | | | 1个包含真/假值的公式字符串数组。要引用单元格值,请使用左上角的单元格地址 | -| style | | | 公式返回 `true` 时要应用的样式结构 | +| 属性 | 可选 | 默认值 | 描述 | +| -------- | ---- | ------------ | ------------------------------------------------------------------------ | +| type | | | `'expression'` | +| priority | Y | <auto> | 确定样式的优先顺序 | +| formulae | | | 1个包含真/假值的公式字符串数组。要引用单元格值,请使用左上角的单元格地址 | +| style | | | 公式返回 `true` 时要应用的样式结构 | ### Cell Is[⬆](#目录) -| 属性 | 可选 | 默认值 | 描述 | -| -------- | -------- | ------- | ----------- | -| type | | | `'cellIs'` | -| priority | Y | <auto> | 确定样式的优先顺序 | -| operator | | | 如何将单元格值与公式结果进行比较 | -| formulae | | | 1个公式字符串数组,返回要与每个单元格进行比较的值 | -| style | | | 如果比较返回 `true`,则应用样式结构 | +| 属性 | 可选 | 默认值 | 描述 | +| -------- | ---- | ------------ | ------------------------------------------------- | +| type | | | `'cellIs'` | +| priority | Y | <auto> | 确定样式的优先顺序 | +| operator | | | 如何将单元格值与公式结果进行比较 | +| formulae | | | 1个公式字符串数组,返回要与每个单元格进行比较的值 | +| style | | | 如果比较返回 `true`,则应用样式结构 | **Cell Is 运算符** -| 运算 | 描述 | -| ----------- | ----------- | -| equal | 如果单元格值等于公式值,则应用格式 | -| greaterThan | 如果单元格值大于公式值,则应用格式 | -| lessThan | 如果单元格值小于公式值,则应用格式 | +| 运算 | 描述 | +| ----------- | ------------------------------------------------------ | +| equal | 如果单元格值等于公式值,则应用格式 | +| greaterThan | 如果单元格值大于公式值,则应用格式 | +| lessThan | 如果单元格值小于公式值,则应用格式 | | between | 如果单元格值在两个公式值之间(包括两个值),则应用格式 | - ### Top 10[⬆](#目录) -| 属性 | 可选 | 默认值 | 描述 | -| -------- | -------- | ------- | ----------- | -| type | | | `'top10'` | -| priority | Y | <auto> | 确定样式的优先顺序 | -| rank | Y | 10 | 指定格式中包含多少个顶部(或底部)值 | -| percent | Y | `false` | 如果为 true,则等级字段为百分比,而不是绝对值 | -| bottom | Y | `false` | 如果为 true,则包含最低值而不是最高值 | -| style | | | 如果比较返回 true,则应用样式结构 | +| 属性 | 可选 | 默认值 | 描述 | +| -------- | ---- | ------------ | --------------------------------------------- | +| type | | | `'top10'` | +| priority | Y | <auto> | 确定样式的优先顺序 | +| rank | Y | 10 | 指定格式中包含多少个顶部(或底部)值 | +| percent | Y | `false` | 如果为 true,则等级字段为百分比,而不是绝对值 | +| bottom | Y | `false` | 如果为 true,则包含最低值而不是最高值 | +| style | | | 如果比较返回 true,则应用样式结构 | ### 高于平均值[⬆](#目录) -| 属性 | 可选 | 默认值 | 描述 | -| ------------- | -------- | ------- | ----------- | -| type | | | `'aboveAverage'` | -| priority | Y | <auto> | 确定样式的优先顺序 | -| aboveAverage | Y | `false` | 如果为 true,则等级字段为百分比,而不是绝对值 | -| style | | | 如果比较返回 true,则应用样式结构 | +| 属性 | 可选 | 默认值 | 描述 | +| ------------ | ---- | ------------ | --------------------------------------------- | +| type | | | `'aboveAverage'` | +| priority | Y | <auto> | 确定样式的优先顺序 | +| aboveAverage | Y | `false` | 如果为 true,则等级字段为百分比,而不是绝对值 | +| style | | | 如果比较返回 true,则应用样式结构 | ### 色阶[⬆](#目录) -| 属性 | 可选 | 默认值 | 描述 | -| ------------- | -------- | ------- | ----------- | -| type | | | `'colorScale'` | -| priority | Y | <auto> | 确定样式的优先顺序 | -| cfvo | | | 2到5个条件格式化值对象的数组,指定值范围内的航路点 | -| color | | | 在给定的航路点使用的相应颜色数组 | -| style | | | 如果比较返回 true,则应用样式结构 | +| 属性 | 可选 | 默认值 | 描述 | +| -------- | ---- | ------------ | -------------------------------------------------- | +| type | | | `'colorScale'` | +| priority | Y | <auto> | 确定样式的优先顺序 | +| cfvo | | | 2到5个条件格式化值对象的数组,指定值范围内的航路点 | +| color | | | 在给定的航路点使用的相应颜色数组 | +| style | | | 如果比较返回 true,则应用样式结构 | ### 图标集[⬆](#目录) -| 属性 | 可选 | 默认值 | 描述 | -| ------------- | -------- | ------- | ----------- | -| type | | | `'iconSet'` | -| priority | Y | <auto> | 确定样式的优先顺序 | -| iconSet | Y | 3TrafficLights | 设置使用的图标名称 | -| showValue | | true | 指定应用范围内的单元格是显示图标和单元格值,还是仅显示图标 | -| reverse | | false | 指定是否以保留顺序显示 `iconSet` 中指定的图标集中的图标。 如果 `custom` 等于 `true`,则必须忽略此值 | -| custom | | false | 指定是否使用自定义图标集 | -| cfvo | | | 2到5个条件格式化值对象的数组,指定值范围内的航路点 | -| style | | | 如果比较返回 true,则应用样式结构 | +| 属性 | 可选 | 默认值 | 描述 | +| --------- | ---- | -------------- | --------------------------------------------------------------------------------------------------- | +| type | | | `'iconSet'` | +| priority | Y | <auto> | 确定样式的优先顺序 | +| iconSet | Y | 3TrafficLights | 设置使用的图标名称 | +| showValue | | true | 指定应用范围内的单元格是显示图标和单元格值,还是仅显示图标 | +| reverse | | false | 指定是否以保留顺序显示 `iconSet` 中指定的图标集中的图标。 如果 `custom` 等于 `true`,则必须忽略此值 | +| custom | | false | 指定是否使用自定义图标集 | +| cfvo | | | 2到5个条件格式化值对象的数组,指定值范围内的航路点 | +| style | | | 如果比较返回 true,则应用样式结构 | ### 数据条[⬆](#目录) -| 字段 | 可选 | 默认值 | 描述 | -| ---------- | -------- | ------- | ----------- | -| type | | | `'dataBar'` | -| priority | Y | <auto> | 确定样式的优先顺序 | -| minLength | | 0 | 指定此条件格式范围内最短数据条的长度 | -| maxLength | | 100 | 指定此条件格式范围内最长数据条的长度 | -| showValue | | true | 指定条件格式范围内的单元格是否同时显示数据条和数值或数据条 | -| gradient | | true | 指定数据条是否具有渐变填充 | -| border | | true | 指定数据条是否有边框 | -| negativeBarColorSameAsPositive | | true | 指定数据条是否具有与正条颜色不同的负条颜色 | -| negativeBarBorderColorSameAsPositive | | true | 指定数据条的负边框颜色是否不同于正边框颜色 | -| axisPosition | | 'auto' | 指定数据条的轴位置 | -| direction | | 'leftToRight' | 指定数据条的方向 | -| cfvo | | | 2 到 5 个条件格式化值对象的数组,指定值范围内的航路点 | -| style | | | 如果比较返回 true,则应用样式结构 | +| 字段 | 可选 | 默认值 | 描述 | +| ------------------------------------ | ---- | ------------- | ---------------------------------------------------------- | +| type | | | `'dataBar'` | +| priority | Y | <auto> | 确定样式的优先顺序 | +| minLength | | 0 | 指定此条件格式范围内最短数据条的长度 | +| maxLength | | 100 | 指定此条件格式范围内最长数据条的长度 | +| showValue | | true | 指定条件格式范围内的单元格是否同时显示数据条和数值或数据条 | +| gradient | | true | 指定数据条是否具有渐变填充 | +| border | | true | 指定数据条是否有边框 | +| negativeBarColorSameAsPositive | | true | 指定数据条是否具有与正条颜色不同的负条颜色 | +| negativeBarBorderColorSameAsPositive | | true | 指定数据条的负边框颜色是否不同于正边框颜色 | +| axisPosition | | 'auto' | 指定数据条的轴位置 | +| direction | | 'leftToRight' | 指定数据条的方向 | +| cfvo | | | 2 到 5 个条件格式化值对象的数组,指定值范围内的航路点 | +| style | | | 如果比较返回 true,则应用样式结构 | ### 包含文字[⬆](#目录) -| 属性 | 可选 | 默认值 | 描述 | -| -------- | -------- | ------- | ----------- | -| type | | | `'containsText'` | -| priority | Y | <auto> | 确定样式的优先顺序 | -| operator | | | 文本比较类型 | -| text | | | 要搜索的文本 | -| style | | | 如果比较返回 true,则应用样式结构 | +| 属性 | 可选 | 默认值 | 描述 | +| -------- | ---- | ------------ | --------------------------------- | +| type | | | `'containsText'` | +| priority | Y | <auto> | 确定样式的优先顺序 | +| operator | | | 文本比较类型 | +| text | | | 要搜索的文本 | +| style | | | 如果比较返回 true,则应用样式结构 | **包含文本运算符** -| 运算符 | 描述 | -| ----------------- | ----------- | +| 运算符 | 描述 | +| ----------------- | ---------------------------------------------------- | | containsText | 如果单元格值包含在 `text` 字段中指定的值,则应用格式 | -| containsBlanks | 如果单元格值包含空格,则应用格式 | -| notContainsBlanks | 如果单元格值不包含空格,则应用格式 | -| containsErrors | 如果单元格值包含错误,则应用格式 | -| notContainsErrors | 如果单元格值不包含错误,则应用格式 | +| containsBlanks | 如果单元格值包含空格,则应用格式 | +| notContainsBlanks | 如果单元格值不包含空格,则应用格式 | +| containsErrors | 如果单元格值包含错误,则应用格式 | +| notContainsErrors | 如果单元格值不包含错误,则应用格式 | ### 时间段[⬆](#目录) -| 属性 | 可选 | 默认值 | 描述 | -| ---------- | -------- | ------- | ----------- | -| type | | | `'timePeriod'` | -| priority | Y | <auto> | 确定样式的优先顺序 | -| timePeriod | | | 比较单元格值的时间段 | -| style | | | 如果比较返回 true,则应用样式结构 | +| 属性 | 可选 | 默认值 | 描述 | +| ---------- | ---- | ------------ | --------------------------------- | +| type | | | `'timePeriod'` | +| priority | Y | <auto> | 确定样式的优先顺序 | +| timePeriod | | | 比较单元格值的时间段 | +| style | | | 如果比较返回 true,则应用样式结构 | **时间段** -| 时间段 | 描述 | -| ----------------- | ----------- | -| lastWeek | 如果单元格值落在最后一周内,则应用格式 | -| thisWeek | 如果单元格值在本周下降,则应用格式 | -| nextWeek | 如果单元格值在下一周下降,则应用格式 | -| yesterday | 如果单元格值等于昨天,则应用格式 | -| today | 如果单元格值等于今天,则应用格式 | -| tomorrow | 如果单元格值等于明天,则应用格式 | -| last7Days | 如果单元格值在过去7天之内,则应用格式 | -| lastMonth | 如果单元格值属于上个月,则应用格式 | -| thisMonth | 如果单元格值在本月下降,则应用格式 | -| nextMonth | 如果单元格值在下个月下降,则应用格式 | - +| 时间段 | 描述 | +| --------- | -------------------------------------- | +| lastWeek | 如果单元格值落在最后一周内,则应用格式 | +| thisWeek | 如果单元格值在本周下降,则应用格式 | +| nextWeek | 如果单元格值在下一周下降,则应用格式 | +| yesterday | 如果单元格值等于昨天,则应用格式 | +| today | 如果单元格值等于今天,则应用格式 | +| tomorrow | 如果单元格值等于明天,则应用格式 | +| last7Days | 如果单元格值在过去7天之内,则应用格式 | +| lastMonth | 如果单元格值属于上个月,则应用格式 | +| thisMonth | 如果单元格值在本月下降,则应用格式 | +| nextMonth | 如果单元格值在下个月下降,则应用格式 | ## 大纲级别[⬆](#目录) Excel 支持大纲;行或列可以根据用户希望查看的详细程度展开或折叠。 大纲级别可以在列设置中定义: + ```javascript worksheet.columns = [ - { header: 'Id', key: 'id', width: 10 }, - { header: 'Name', key: 'name', width: 32 }, - { header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1 } + {header: 'Id', key: 'id', width: 10}, + {header: 'Name', key: 'name', width: 32}, + {header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1}, ]; ``` 或直接在行或列上 + ```javascript worksheet.getColumn(3).outlineLevel = 1; worksheet.getRow(3).outlineLevel = 1; ``` 工作表大纲级别可以在工作表上设置 + ```javascript // 设置列大纲级别 worksheet.properties.outlineLevelCol = 1; @@ -1898,6 +1933,7 @@ worksheet.properties.outlineLevelRow = 1; ``` 注意:调整行或列上的大纲级别或工作表上的大纲级别将产生副作用,即还修改受属性更改影响的所有行或列的折叠属性。 例如。: + ```javascript worksheet.properties.outlineLevelCol = 1; @@ -1941,7 +1977,7 @@ const imageId2 = workbook.addImage({ }); // 通过 base64 将图像添加到工作簿 -const myBase64Image = "data:image/png;base64,iVBORw0KG..."; +const myBase64Image = 'data:image/png;base64,iVBORw0KG...'; const imageId2 = workbook.addImage({ base64: myBase64Image, extension: 'png', @@ -1973,24 +2009,24 @@ worksheet.addImage(imageId2, 'B2:D6'); ```javascript // 在 B2:D6 的一部分上插入图像 worksheet.addImage(imageId2, { - tl: new Anchor(worksheet, { col: 1.5, row: 1.5 }), - br: new Anchor(worksheet, { col: 3.5, row: 5.5 }), + tl: new Anchor(worksheet, {col: 1.5, row: 1.5}), + br: new Anchor(worksheet, {col: 3.5, row: 5.5}), }); ``` 单元格区域还可以具有属性 `"editAs"`,该属性将控制将图像锚定到单元格的方式。它可以具有以下值之一: -| 值 | 描述 | -| --------- | ----------- | -| `undefined` | 它指定使图像将根据单元格移动和调整其大小 | +| 值 | 描述 | +| ----------- | ------------------------------------------------ | +| `undefined` | 它指定使图像将根据单元格移动和调整其大小 | | `oneCell` | 这是默认值。图像将与单元格一起移动,但大小不变动 | -| `absolute` | 图像将不会随着单元格移动或调整大小 | +| `absolute` | 图像将不会随着单元格移动或调整大小 | ```javascript ws.addImage(imageId, { - tl: new Anchor(worksheet, { col: 0.1125, row: 0.4 }), - br: new Anchor(worksheet, { col: 2.101046875, row: 3.4 }), - editAs: 'oneCell' + tl: new Anchor(worksheet, {col: 0.1125, row: 0.4}), + br: new Anchor(worksheet, {col: 2.101046875, row: 3.4}), + editAs: 'oneCell', }); ``` @@ -2000,8 +2036,8 @@ ws.addImage(imageId, { ```javascript worksheet.addImage(imageId2, { - tl: { col: 0, row: 0 }, - ext: { width: 500, height: 200 } + tl: {col: 0, row: 0}, + ext: {width: 500, height: 200}, }); ``` @@ -2011,12 +2047,12 @@ worksheet.addImage(imageId2, { ```javascript worksheet.addImage(imageId2, { - tl: { col: 0, row: 0 }, - ext: { width: 500, height: 200 }, + tl: {col: 0, row: 0}, + ext: {width: 500, height: 200}, hyperlinks: { hyperlink: 'http://www.somewhere.com', - tooltip: 'http://www.somewhere.com' - } + tooltip: 'http://www.somewhere.com', + }, }); ``` @@ -2034,31 +2070,29 @@ await worksheet.protect('the-password', options); worksheet.unprotect(); ``` - 有关如何修改单个单元格保护的详细信息请查看 单元格保护。 **注意:** 当 `protect()` 函数返回一个 Promise 代表它是异步的,当前的实现在主线程上运行,并且在 CPU 上将使用平均大约 600 毫秒。可以通过设置 `spinCount` 进行调整,该值可用于使过程更快或更有弹性。 ### 工作表保护选项[⬆](#目录) -| 属性 | 默认值 | 描述 | -| ------------------- | ------- | ----------- | -| selectLockedCells | `true` | 允许用户选择锁定的单元格 | -| selectUnlockedCells | `true` | 允许用户选择未锁定的单元格 | -| formatCells | `false` | 允许用户格式化单元格 | -| formatColumns | `false` | 允许用户格式化列 | -| formatRows | `false` | 允许用户格式化行 | -| insertRows | `false` | 允许用户插入行 | -| insertColumns | `false` | 允许用户插入列 | -| insertHyperlinks | `false` | 允许用户插入超链接 | -| deleteRows | `false` | 允许用户删除行 | -| deleteColumns | `false` | 允许用户删除列 | -| sort | `false` | 允许用户对数据进行排序 | -| autoFilter | `false` | 允许用户过滤表中的数据 | -| pivotTables | `false` | 允许用户使用数据透视表 | +| 属性 | 默认值 | 描述 | +| ------------------- | ------- | ---------------------------------- | +| selectLockedCells | `true` | 允许用户选择锁定的单元格 | +| selectUnlockedCells | `true` | 允许用户选择未锁定的单元格 | +| formatCells | `false` | 允许用户格式化单元格 | +| formatColumns | `false` | 允许用户格式化列 | +| formatRows | `false` | 允许用户格式化行 | +| insertRows | `false` | 允许用户插入行 | +| insertColumns | `false` | 允许用户插入列 | +| insertHyperlinks | `false` | 允许用户插入超链接 | +| deleteRows | `false` | 允许用户删除行 | +| deleteColumns | `false` | 允许用户删除列 | +| sort | `false` | 允许用户对数据进行排序 | +| autoFilter | `false` | 允许用户过滤表中的数据 | +| pivotTables | `false` | 允许用户使用数据透视表 | | spinCount | 100000 | 保护或取消保护时执行的哈希迭代次数 | - ## 文件 I/O[⬆](#目录) ### XLSX[⬆](#目录) @@ -2071,13 +2105,11 @@ const workbook = new Excel.Workbook(); await workbook.xlsx.readFile(filename); // ... 使用 workbook - // 从流读取 const workbook = new Excel.Workbook(); await workbook.xlsx.read(stream); // ... 使用 workbook - // 从 buffer 加载 const workbook = new Excel.Workbook(); await workbook.xlsx.load(data); @@ -2104,12 +2136,12 @@ const buffer = await workbook.xlsx.writeBuffer(); 读取 CSV 文件时支持的选项。 -| 属性 | 是否需要 | 类型 | 描述 | -| ---------------- | ----------- | ----------- | ----------- | -| dateFormats | N | Array | 指定 dayjs 的日期编码格式。 | -| map | N | Function | 自定义`Array.prototype.map()` 回调函数,用于处理数据。 | -| sheetName | N | String | 指定工作表名称。 | -| parserOptions | N | Object | [parseOptions 选项](https://c2fo.github.io/fast-csv/docs/parsing/options) @fast-csv/format 模块以写入 csv 数据。 | +| 属性 | 是否需要 | 类型 | 描述 | +| ------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------- | +| dateFormats | N | Array | 指定 dayjs 的日期编码格式。 | +| map | N | Function | 自定义`Array.prototype.map()` 回调函数,用于处理数据。 | +| sheetName | N | String | 指定工作表名称。 | +| parserOptions | N | Object | [parseOptions 选项](https://c2fo.github.io/fast-csv/docs/parsing/options) @fast-csv/format 模块以写入 csv 数据。 | ```javascript // 从文件读取 @@ -2117,27 +2149,24 @@ const workbook = new Excel.Workbook(); const worksheet = await workbook.csv.readFile(filename); // ... 使用 workbook 或 worksheet - // 从流中读取 const workbook = new Excel.Workbook(); const worksheet = await workbook.csv.read(stream); // ... 使用 workbook 或 worksheet - // 从带有欧洲日期的文件中读取 const workbook = new Excel.Workbook(); const options = { - dateFormats: ['DD/MM/YYYY'] + dateFormats: ['DD/MM/YYYY'], }; const worksheet = await workbook.csv.readFile(filename, options); // ... 使用 workbook 或 worksheet - // 从具有自定义值解析的文件中读取 const workbook = new Excel.Workbook(); const options = { map(value, index) { - switch(index) { + switch (index) { case 0: // 第1列是字符串 return value; @@ -2166,9 +2195,9 @@ CSV 解析器使用 [fast-csv](https://www.npmjs.com/package/fast-csv) 读取CSV 使用 npm 模块 [dayjs](https://www.npmjs.com/package/dayjs) 解析日期。如果未提供 `dateFormats` 数组,则使用以下 dateFormats: -* 'YYYY-MM-DD\[T\]HH:mm:ss' -* 'MM-DD-YYYY' -* 'YYYY-MM-DD' +- 'YYYY-MM-DD\[T\]HH:mm:ss' +- 'MM-DD-YYYY' +- 'YYYY-MM-DD' 请参阅 [dayjs CustomParseFormat 插件](https://github.com/iamkun/dayjs/blob/HEAD/docs/en/Plugin.md#customparseformat),以获取有关如何构造 `dateFormat` 的详细信息。 @@ -2176,26 +2205,25 @@ CSV 解析器使用 [fast-csv](https://www.npmjs.com/package/fast-csv) 读取CSV 写入 CSV 文件时支持的选项。 -| 属性 | 是否需要 | 类型 | 描述 | -| ---------------- | ----------- | ----------- | ----------- | -| dateFormat | N | String | 指定 dayjs 的日期编码格式。 | -| dateUTC | N | Boolean | 指定 ExcelJS 是否使用`dayjs.utc()`转换时区以解析日期。 | -| encoding | N | String | 指定文件编码格式。 | -| includeEmptyRows | N | Boolean | 指定是否可以写入空行。 | -| map | N | Function | 自定义`Array.prototype.map()` 回调函数,用于处理行值。 | -| sheetName | N | String | 指定工作表名称。 | -| sheetId | N | Number | 指定工作表 ID。 | -| formatterOptions | N | Object | [formatterOptions 选项](https://c2fo.github.io/fast-csv/docs/formatting/options/) @fast-csv/format 模块写入csv 数据。 | +| 属性 | 是否需要 | 类型 | 描述 | +| ---------------- | -------- | -------- | --------------------------------------------------------------------------------------------------------------------- | +| dateFormat | N | String | 指定 dayjs 的日期编码格式。 | +| dateUTC | N | Boolean | 指定 ExcelJS 是否使用`dayjs.utc()`转换时区以解析日期。 | +| encoding | N | String | 指定文件编码格式。 | +| includeEmptyRows | N | Boolean | 指定是否可以写入空行。 | +| map | N | Function | 自定义`Array.prototype.map()` 回调函数,用于处理行值。 | +| sheetName | N | String | 指定工作表名称。 | +| sheetId | N | Number | 指定工作表 ID。 | +| formatterOptions | N | Object | [formatterOptions 选项](https://c2fo.github.io/fast-csv/docs/formatting/options/) @fast-csv/format 模块写入csv 数据。 | ```javascript - // 写入文件 const workbook = new Excel.Workbook(); await workbook.csv.writeFile(filename); // 写入流 // 请注意,您需要提供 sheetName 或 sheetId 以正确导入到 csv -await workbook.csv.write(stream, { sheetName: 'Page name' }); +await workbook.csv.write(stream, {sheetName: 'Page name'}); // 使用欧洲日期时间写入文件 const workbook = new Excel.Workbook(); @@ -2205,12 +2233,11 @@ const options = { }; await workbook.csv.writeFile(filename, options); - // 使用自定义值格式写入文件 const workbook = new Excel.Workbook(); const options = { map(value, index) { - switch(index) { + switch (index) { case 0: // 第1列是字符串 return value; @@ -2249,9 +2276,9 @@ CSV 解析器使用 [fast-csv](https://www.npmjs.com/package/fast-csv) 编写 CS 流式工作簿和工作表的接口几乎与文档版本相同,但实际存在一些细微差别: -* 将工作表添加到工作簿后,将无法将其删除。 -* 提交行后,将无法再访问该行,因为该行将从工作表中删除。 -* 不支持 `unMergeCells()`。 +- 将工作表添加到工作簿后,将无法将其删除。 +- 提交行后,将无法再访问该行,因为该行将从工作表中删除。 +- 不支持 `unMergeCells()`。 请注意,可以在不提交任何行的情况下构建整个工作簿。提交工作簿后,所有添加的工作表(包括所有未提交的行)将自动提交。但是,在这种情况下,与文档版本相比收效甚微。 @@ -2263,12 +2290,12 @@ CSV 解析器使用 [fast-csv](https://www.npmjs.com/package/fast-csv) 编写 CS 构造函数采用带有以下字段的可选 `options` 对象: -| 字段 | 描述 | -| ---------------- | ----------- | -| stream | 指定要写入 XLSX 工作簿的可写流。 | -| filename | 如果未指定流,则此字段指定要写入 XLSX 工作簿的文件的路径。 | -| useSharedStrings | 指定是否在工作簿中使用共享字符串。默认为 `false` | -| useStyles | 指定是否将样式信息添加到工作簿。样式会增加一些性能开销。默认为 `false` | +| 字段 | 描述 | +| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| stream | 指定要写入 XLSX 工作簿的可写流。 | +| filename | 如果未指定流,则此字段指定要写入 XLSX 工作簿的文件的路径。 | +| useSharedStrings | 指定是否在工作簿中使用共享字符串。默认为 `false` | +| useStyles | 指定是否将样式信息添加到工作簿。样式会增加一些性能开销。默认为 `false` | | zip | ExcelJS 内部传递给 [Archiver](https://github.com/archiverjs/node-archiver) 的 [Zip选项](https://www.archiverjs.com/global.html#ZipOptions)。默认值为 `undefined` | 如果在选项中未指定 `stream` 或 `filename`,则工作簿编写器将创建一个 StreamBuf 对象,该对象将 XLSX 工作簿的内容存储在内存中。可以通过属性 `workbook.stream` 访问此 StreamBuf 对象,该对象可用于通过 `stream.read()` 直接访问字节,或将内容通过管道传输到另一个流。 @@ -2278,7 +2305,7 @@ CSV 解析器使用 [fast-csv](https://www.npmjs.com/package/fast-csv) 编写 CS const options = { filename: './streamed-workbook.xlsx', useStyles: true, - useSharedStrings: true + useSharedStrings: true, }; const workbook = new Excel.stream.xlsx.WorkbookWriter(options); ``` @@ -2296,14 +2323,17 @@ const workbook = new Excel.stream.xlsx.WorkbookWriter(options); 当工作表行准备就绪时,应将其提交,以便可以释放行对象和内容。通常,这将在添加每一行时完成... ```javascript -worksheet.addRow({ - id: i, - name: theName, - etc: someOtherDetail -}).commit(); +worksheet + .addRow({ + id: i, + name: theName, + etc: someOtherDetail, + }) + .commit(); ``` WorksheetWriter 在添加行时不提交行的原因是允许单元格跨行合并: + ```javascript worksheet.mergeCells('A1:B2'); worksheet.getCell('A1').value = 'I am merged'; @@ -2333,15 +2363,15 @@ await workbook.commit(); 构造函数包含必需的输入参数和可选的options参数: -| Argument | Description | -| --------------------- | ----------- | -| input (必需的) | 指定从中读取XLSX工作簿的文件或可读流的名称| -| options (可选的) | 指定如何处理读取解析期间发生的事件类型 | -| options.entries | 指定是否去触发事件(`'emit'`)或者不发出事件(`'ignore'`),默认值是`'emit'` | +| Argument | Description | +| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| input (必需的) | 指定从中读取XLSX工作簿的文件或可读流的名称 | +| options (可选的) | 指定如何处理读取解析期间发生的事件类型 | +| options.entries | 指定是否去触发事件(`'emit'`)或者不发出事件(`'ignore'`),默认值是`'emit'` | | options.sharedStrings | 指定是否去缓存(`'cache'`)共享字符串,将其插入到相应的单元格值中,或者是否去触发(`'emit'`)或忽略(`'ignore'`)它们,在这两种情况下,单元格值都将是对共享字符串索引的引用。默认值是`'cache'` | -| options.hyperlinks | 指定是否去缓存超链接(`'cache'`),将其插入到相应的单元格值中,是否去触发(`'emit'`)或忽略(`'ignore'`)它们。默认值是`'cache'` | -| options.styles | 指定是否去缓存样式(`'cache'`),将其插入到相应的行或单元格值中,或是否忽略(`'忽略'`)它们。默认值是`'cache'` | -| options.worksheets |指定是否去触发(`'emit'`)或忽略(`'ignore'`)工作表。默认值是`'emit'` | +| options.hyperlinks | 指定是否去缓存超链接(`'cache'`),将其插入到相应的单元格值中,是否去触发(`'emit'`)或忽略(`'ignore'`)它们。默认值是`'cache'` | +| options.styles | 指定是否去缓存样式(`'cache'`),将其插入到相应的行或单元格值中,或是否忽略(`'忽略'`)它们。默认值是`'cache'` | +| options.worksheets | 指定是否去触发(`'emit'`)或忽略(`'ignore'`)工作表。默认值是`'emit'` | ```js const workbookReader = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx'); @@ -2368,11 +2398,11 @@ const workbook = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx', options); for await (const {eventType, value} of workbook.parse()) { switch (eventType) { case 'shared-strings': - // 值是共享字符串 + // 值是共享字符串 case 'worksheet': - // 值是worksheetReader + // 值是worksheetReader case 'hyperlinks': - // 值是hyperlinksReader + // 值是hyperlinksReader } } ``` @@ -2391,8 +2421,7 @@ const workbookReader = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx', opt workbookReader.read(); workbookReader.on('worksheet', worksheet => { - worksheet.on('row', row => { - }); + worksheet.on('row', row => {}); }); workbookReader.on('shared-strings', sharedString => { @@ -2406,7 +2435,7 @@ workbookReader.on('hyperlinks', hyperlinksReader => { workbookReader.on('end', () => { // ... }); -workbookReader.on('error', (err) => { +workbookReader.on('error', err => { // ... }); ``` @@ -2421,10 +2450,10 @@ workbookReader.on('error', (err) => { ## 预捆绑[⬆](#目录) -以下文件已预先捆绑在一起,并包含在 *dist* 文件夹中。 +以下文件已预先捆绑在一起,并包含在 _dist_ 文件夹中。 -* exceljs.js -* exceljs.min.js +- exceljs.js +- exceljs.min.js # 值类型[⬆](#目录) @@ -2490,16 +2519,17 @@ Enum: `Excel.ValueType.Hyperlink` 具有文本和链接值的 URL。 例如: + ```javascript // 链接到网络 worksheet.getCell('A1').value = { text: 'www.mylink.com', hyperlink: 'http://www.mylink.com', - tooltip: 'www.mylink.com' + tooltip: 'www.mylink.com', }; // 内部链接 -worksheet.getCell('A1').value = { text: 'Sheet2', hyperlink: '#\'Sheet2\'!A1' }; +worksheet.getCell('A1').value = {text: 'Sheet2', hyperlink: "#'Sheet2'!A1"}; ``` ## 公式值[⬆](#目录) @@ -2513,7 +2543,7 @@ Enum: `Excel.ValueType.Formula` 例如: ```javascript -worksheet.getCell('A3').value = { formula: 'A1+A2', result: 7 }; +worksheet.getCell('A3').value = {formula: 'A1+A2', result: 7}; ``` 单元格还支持便捷的获取器,以访问公式和结果: @@ -2534,14 +2564,14 @@ worksheet.getCell('A2').value = { formula: 'A1', result: 10, shareType: 'shared', - ref: 'A2:B3' + ref: 'A2:B3', }; ``` 可以使用新的值形式将共享公式分配给单元格: ```javascript -worksheet.getCell('B2').value = { sharedFormula: 'A2', result: 10 }; +worksheet.getCell('B2').value = {sharedFormula: 'A2', result: 10}; ``` 这指定单元格B2是将从A2中的公式派生的公式,其结果为10。 @@ -2559,7 +2589,7 @@ expect(worksheet.getCell('B2').formula).to.equal('B1'); worksheet.getCell('A1').value = 1; // 从 A1 开始以递增计数将 A2 填充到 A10 -worksheet.fillFormula('A2:A10', 'A1+1', [2,3,4,5,6,7,8,9,10]); +worksheet.fillFormula('A2:A10', 'A1+1', [2, 3, 4, 5, 6, 7, 8, 9, 10]); ``` `fillFormula` 也可以使用回调函数来计算每个单元格的值 @@ -2580,11 +2610,11 @@ worksheet.getCell('B3').formulaType === Enums.FormulaType.Shared; 公式类型具有以下值: -| 名称 | 值 | -| -------------------------- | ------- | -| Enums.FormulaType.None | 0 | -| Enums.FormulaType.Master | 1 | -| Enums.FormulaType.Shared | 2 | +| 名称 | 值 | +| ------------------------ | --- | +| Enums.FormulaType.None | 0 | +| Enums.FormulaType.Master | 1 | +| Enums.FormulaType.Shared | 2 | ### 数组公式[⬆](#目录) @@ -2593,13 +2623,14 @@ worksheet.getCell('B3').formulaType === Enums.FormulaType.Shared; 注意:数组公式不会以共享公式的方式转换。因此,如果主单元A2引用A1,则从单元B2也将引用A1。 例如: + ```javascript // 将数组公式分配给 A2:B3 worksheet.getCell('A2').value = { formula: 'A1', result: 10, shareType: 'array', - ref: 'A2:B3' + ref: 'A2:B3', }; // 可能没有必要填写工作表中的其余值 @@ -2609,10 +2640,9 @@ worksheet.getCell('A2').value = { ```javascript // 用数组公式 "A1" 填充 A2:B3 -worksheet.fillFormula('A2:B3', 'A1', [1,1,1,1], 'array'); +worksheet.fillFormula('A2:B3', 'A1', [1, 1, 1, 1], 'array'); ``` - ## 富文本值[⬆](#目录) Enum: `Excel.ValueType.RichText` @@ -2620,12 +2650,10 @@ Enum: `Excel.ValueType.RichText` 样式丰富的文本。 例如: + ```javascript worksheet.getCell('A1').value = { - richText: [ - { text: 'This is '}, - {font: {italic: true}, text: 'italic'}, - ] + richText: [{text: 'This is '}, {font: {italic: true}, text: 'italic'}], }; ``` @@ -2647,21 +2675,21 @@ Enum: `Excel.ValueType.Error` 例如: ```javascript -worksheet.getCell('A1').value = { error: '#N/A' }; -worksheet.getCell('A2').value = { error: '#VALUE!' }; +worksheet.getCell('A1').value = {error: '#N/A'}; +worksheet.getCell('A2').value = {error: '#VALUE!'}; ``` 当前有效的错误文本值为: -| 名称 | 值 | -| ------------------------------ | ----------- | -| Excel.ErrorValue.NotApplicable | #N/A | -| Excel.ErrorValue.Ref | #REF! | -| Excel.ErrorValue.Name | #NAME? | -| Excel.ErrorValue.DivZero | #DIV/0! | -| Excel.ErrorValue.Null | #NULL! | -| Excel.ErrorValue.Value | #VALUE! | -| Excel.ErrorValue.Num | #NUM! | +| 名称 | 值 | +| ------------------------------ | ------- | +| Excel.ErrorValue.NotApplicable | #N/A | +| Excel.ErrorValue.Ref | #REF! | +| Excel.ErrorValue.Name | #NAME? | +| Excel.ErrorValue.DivZero | #DIV/0! | +| Excel.ErrorValue.Null | #NULL! | +| Excel.ErrorValue.Value | #VALUE! | +| Excel.ErrorValue.Num | #NUM! | # 接口变化[⬆](#目录) @@ -2671,7 +2699,7 @@ worksheet.getCell('A2').value = { error: '#VALUE!' }; ### Worksheet.eachRow[⬆](#目录) -在 `Worksheet.eachRow` 的回调函数中的参数已被交换和更改;它是 `function(rowNumber,rowValues)`,现在是 `function(row,rowNumber)`,使它的外观更像 *underscore(`_.each`)方法,并且行对象优先于行号。* +在 `Worksheet.eachRow` 的回调函数中的参数已被交换和更改;它是 `function(rowNumber,rowValues)`,现在是 `function(row,rowNumber)`,使它的外观更像 _underscore(`_.each`)方法,并且行对象优先于行号。\_ ### Worksheet.getRow[⬆](#目录) @@ -2691,10 +2719,8 @@ worksheet.getCell('A2').value = { error: '#VALUE!' }; 为了减少这种情况的出现,在0.3.0中添加了以下两个更改: -* 默认情况下使用功能更全且仍与浏览器兼容的 promise lib。 该库支持 Bluebird 的许多功能,但占用空间少得多。 -* 注入其他 Promise 实现的选项。有关更多详细信息,请参见配置部分。 - - +- 默认情况下使用功能更全且仍与浏览器兼容的 promise lib。 该库支持 Bluebird 的许多功能,但占用空间少得多。 +- 注入其他 Promise 实现的选项。有关更多详细信息,请参见配置部分。 # 配置[⬆](#目录) @@ -2710,8 +2736,7 @@ ExcelJS.config.setValue('promise', require('bluebird')); ## Dist 文件夹[⬆](#目录) -在发布此模块之前,先对源代码进行编译和其他处理,然后再将它们放置在 *dist/* 文件夹中。该自述文件标识两个文件-浏览器捆绑和压缩版本。除了在 package.json 中指定为 `"main"` 的文件外,不能保证 *dist/* 文件夹的其他内容。 - +在发布此模块之前,先对源代码进行编译和其他处理,然后再将它们放置在 _dist/_ 文件夹中。该自述文件标识两个文件-浏览器捆绑和压缩版本。除了在 package.json 中指定为 `"main"` 的文件外,不能保证 _dist/_ 文件夹的其他内容。 # 已知的问题[⬆](#目录) @@ -2719,7 +2744,7 @@ ExcelJS.config.setValue('promise', require('bluebird')); 该 lib 中包含的测试套件包括一个在无头浏览器中执行的小脚本,以验证捆绑的软件包。 在撰写本文时,其表现出该测试在 Windows Linux 子系统中不能很好地进行。 -因此,可以通过存在名为 *.disable-test-browser* 的文件来禁用浏览器测试。 +因此,可以通过存在名为 _.disable-test-browser_ 的文件来禁用浏览器测试。 ```bash sudo apt-get install libfontconfig @@ -2731,148 +2756,148 @@ sudo apt-get install libfontconfig # 发布历史[⬆](#目录) -| Version | Changes | -|---------| ------- | -| 0.0.9 | | -| 0.1.0 | | -| 0.1.1 | | -| 0.1.2 | | -| 0.1.3 | | -| 0.1.5 | | -| 0.1.6 | | -| 0.1.8 | | -| 0.1.9 | | -| 0.1.10 | | -| 0.1.11 | | -| 0.2.0 | | -| 0.2.2 | | -| 0.2.3 | | -| 0.2.4 | | -| 0.2.6 | | -| 0.2.7 | | -| 0.2.8 | | -| 0.2.9 | | -| 0.2.10 | | -| 0.2.11 | | -| 0.2.12 | | -| 0.2.13 | | -| 0.2.14 | | -| 0.2.15 | | -| 0.2.16 | | -| 0.2.17 | | -| 0.2.18 | | -| 0.2.19 | | -| 0.2.20 | | -| 0.2.21 | | -| 0.2.22 | | -| 0.2.23 | | -| 0.2.24 | | -| 0.2.25 | | -| 0.2.26 | | -| 0.2.27 | | -| 0.2.28 | | -| 0.2.29 | | -| 0.2.30 | | -| 0.2.31 | | -| 0.2.32 | | -| 0.2.33 | | -| 0.2.34 | | -| 0.2.35 | | -| 0.2.36 | | -| 0.2.37 | | -| 0.2.38 | | -| 0.2.39 | | -| 0.2.42 | | -| 0.2.43 | | -| 0.2.44 | | -| 0.2.45 | | -| 0.2.46 | | -| 0.3.0 | | -| 0.3.1 | | -| 0.4.0 | | -| 0.4.1 | | -| 0.4.2 | | -| 0.4.3 | | -| 0.4.4 | | -| 0.4.6 | | -| 0.4.9 | | -| 0.4.10 | | -| 0.4.11 | | -| 0.4.12 | | -| 0.4.13 | | -| 0.4.14 | | -| 0.5.0 | | -| 0.5.1 | -| 0.6.0 | | -| 0.6.1 | | -| 0.6.2 | | -| 0.7.0 | | -| 0.7.1 | -| 0.8.0 | | -| 0.8.1 | | -| 0.8.2 | | -| 0.8.3 | | -| 0.8.4 | | -| 0.8.5 | | -| 0.9.0 | | -| 0.9.1 | | -| 1.0.0 | | -| 1.0.1 | | -| 1.0.2 | | -| 1.1.0 | | -| 1.1.1 | | -| 1.1.2 | | -| 1.1.3 | | -| 1.2.0 | | -| 1.2.1 | | -| 1.3.0 | | -| 1.4.2 | | -| 1.4.3 | | -| 1.4.5 | | -| 1.4.6 | | -| 1.4.7 | | -| 1.4.8 | | -| 1.4.9 | | -| 1.4.10 | | -| 1.4.12 | | -| 1.4.13 | | -| 1.5.0 | | -| 1.5.1 | | -| 1.6.0 | | -| 1.6.1 | | -| 1.6.2 | | -| 1.6.3 | | -| 1.7.0 | | -| 1.8.0 | | -| 1.9.0 | | -| 1.9.1 | | -| 1.10.0 | | -| 1.11.0 | | -| 1.12.0 | | -| 1.12.1 | | -| 1.12.2 | | -| 1.13.0 | | -| 1.14.0 | | -| 1.15.0 | | -| 2.0.1 |

    Major Version Change

    Introducing async/await to ExcelJS!

    The new async and await features of JavaScript can help a lot to make code more readable and maintainable. To avoid confusion, particularly with returned promises from async functions, we have had to remove the Promise class configuration option and from v2 onwards ExcelJS will use native Promises. Since this is potentially a breaking change we're bumping the major version for this release.

    Changes

    | -| 3.0.0 |

    Another Major Version Change

    Javascript has changed a lot over the years, and so have the modules and technologies surrounding it. To this end, this major version of ExcelJS changes the structure of the publish artefacts:

    Main Export is now the Original Javascript Source

    Prior to this release, the transpiled ES5 code was exported as the package main. From now on, the package main comes directly from the lib/ folder. This means a number of dependencies have been removed, including the polyfills.

    ES5 and Browserify are Still Included

    In order to support those that still require ES5 ready code (e.g. as dependencies in web apps) the source code will still be transpiled and available in dist/es5.

    The ES5 code is also browserified and available as dist/exceljs.js or dist/exceljs.min.js

    See the section Importing for details

    | -| 3.1.0 | | -| 3.2.0 | | -| 3.3.0 | | -| 3.3.1 | | -| 3.4.0 | | -| 3.5.0 | | -| 3.6.0 | | -| 3.6.1 | | -| 3.7.0 | | -| 3.8.0 | | -| 3.8.1 | | -| 3.8.2 | | -| 3.9.0 | | -| 3.10.0 | | -| 4.0.1 | | -| 4.1.0 | | -| 4.1.1 | | -| 4.2.0 | | -| 4.2.1 | | -| 4.3.0 | | +| Version | Changes | +| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 0.0.9 | | +| 0.1.0 | | +| 0.1.1 | | +| 0.1.2 | | +| 0.1.3 | | +| 0.1.5 | | +| 0.1.6 | | +| 0.1.8 | | +| 0.1.9 | | +| 0.1.10 | | +| 0.1.11 | | +| 0.2.0 | | +| 0.2.2 | | +| 0.2.3 | | +| 0.2.4 | | +| 0.2.6 | | +| 0.2.7 | | +| 0.2.8 | | +| 0.2.9 | | +| 0.2.10 | | +| 0.2.11 | | +| 0.2.12 | | +| 0.2.13 | | +| 0.2.14 | | +| 0.2.15 | | +| 0.2.16 | | +| 0.2.17 | | +| 0.2.18 | | +| 0.2.19 | | +| 0.2.20 | | +| 0.2.21 | | +| 0.2.22 | | +| 0.2.23 | | +| 0.2.24 | | +| 0.2.25 | | +| 0.2.26 | | +| 0.2.27 | | +| 0.2.28 | | +| 0.2.29 | | +| 0.2.30 | | +| 0.2.31 | | +| 0.2.32 | | +| 0.2.33 | | +| 0.2.34 | | +| 0.2.35 | | +| 0.2.36 | | +| 0.2.37 | | +| 0.2.38 | | +| 0.2.39 | | +| 0.2.42 | | +| 0.2.43 | | +| 0.2.44 | | +| 0.2.45 | | +| 0.2.46 | | +| 0.3.0 | | +| 0.3.1 | | +| 0.4.0 | | +| 0.4.1 | | +| 0.4.2 | | +| 0.4.3 | | +| 0.4.4 | | +| 0.4.6 | | +| 0.4.9 | | +| 0.4.10 | | +| 0.4.11 | | +| 0.4.12 | | +| 0.4.13 | | +| 0.4.14 | | +| 0.5.0 | | +| 0.5.1 | | +| 0.6.0 | | +| 0.6.1 | | +| 0.6.2 | | +| 0.7.0 | | +| 0.7.1 | | +| 0.8.0 | | +| 0.8.1 | | +| 0.8.2 | | +| 0.8.3 | | +| 0.8.4 | | +| 0.8.5 | | +| 0.9.0 | | +| 0.9.1 | | +| 1.0.0 | | +| 1.0.1 | | +| 1.0.2 | | +| 1.1.0 | | +| 1.1.1 | | +| 1.1.2 | | +| 1.1.3 | | +| 1.2.0 | | +| 1.2.1 | | +| 1.3.0 | | +| 1.4.2 | | +| 1.4.3 | | +| 1.4.5 | | +| 1.4.6 | | +| 1.4.7 | | +| 1.4.8 | | +| 1.4.9 | | +| 1.4.10 | | +| 1.4.12 | | +| 1.4.13 | | +| 1.5.0 | | +| 1.5.1 | | +| 1.6.0 | | +| 1.6.1 | | +| 1.6.2 | | +| 1.6.3 | | +| 1.7.0 | | +| 1.8.0 | | +| 1.9.0 | | +| 1.9.1 | | +| 1.10.0 | | +| 1.11.0 | | +| 1.12.0 | | +| 1.12.1 | | +| 1.12.2 | | +| 1.13.0 | | +| 1.14.0 | | +| 1.15.0 | | +| 2.0.1 |

    Major Version Change

    Introducing async/await to ExcelJS!

    The new async and await features of JavaScript can help a lot to make code more readable and maintainable. To avoid confusion, particularly with returned promises from async functions, we have had to remove the Promise class configuration option and from v2 onwards ExcelJS will use native Promises. Since this is potentially a breaking change we're bumping the major version for this release.

    Changes

    | +| 3.0.0 |

    Another Major Version Change

    Javascript has changed a lot over the years, and so have the modules and technologies surrounding it. To this end, this major version of ExcelJS changes the structure of the publish artefacts:

    Main Export is now the Original Javascript Source

    Prior to this release, the transpiled ES5 code was exported as the package main. From now on, the package main comes directly from the lib/ folder. This means a number of dependencies have been removed, including the polyfills.

    ES5 and Browserify are Still Included

    In order to support those that still require ES5 ready code (e.g. as dependencies in web apps) the source code will still be transpiled and available in dist/es5.

    The ES5 code is also browserified and available as dist/exceljs.js or dist/exceljs.min.js

    See the section Importing for details

    | +| 3.1.0 | | +| 3.2.0 | | +| 3.3.0 | | +| 3.3.1 | | +| 3.4.0 | | +| 3.5.0 | | +| 3.6.0 | | +| 3.6.1 | | +| 3.7.0 | | +| 3.8.0 | | +| 3.8.1 | | +| 3.8.2 | | +| 3.9.0 | | +| 3.10.0 | | +| 4.0.1 | | +| 4.1.0 | | +| 4.1.1 | | +| 4.2.0 | | +| 4.2.1 | | +| 4.3.0 | | diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index 4f544748b..bc4631edf 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -2,11 +2,10 @@ ## `wb.createInputStream()` deprecation -| ExcelJS V3.9.* | ExcelJS v4 | -|---------------------------------------------------------------------|------------------------------------| -|`stream.pipe(workbook.xlsx.createInputStream());` | `await workbook.xlsx.read(stream)` | -| | | - +| ExcelJS V3.9.\* | ExcelJS v4 | +| ------------------------------------------------- | ---------------------------------- | +| `stream.pipe(workbook.xlsx.createInputStream());` | `await workbook.xlsx.read(stream)` | +| | | ## Stream Reading @@ -16,12 +15,11 @@ While upgrading to version 4 you get more ways to stream reading file. We strongly recommend using this way, because it's 20% faster than any other and you get flow control -``` js +```js const workbook = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx'); for await (const worksheetReader of workbookReader) { for await (const row of worksheetReader) { // ... - // continue, break, return } } @@ -39,11 +37,11 @@ const workbook = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx', options); for await (const {eventType, value} of workbook.parse()) { switch (eventType) { case 'shared-strings': - // value is the shared string + // value is the shared string case 'worksheet': - // value is the worksheetReader + // value is the worksheetReader case 'hyperlinks': - // value is the hyperlinksReader + // value is the hyperlinksReader } } ``` @@ -59,8 +57,7 @@ const options = { const workbookReader = new ExcelJS.stream.xlsx.WorkbookReader('./file.xlsx', options); workbookReader.read(); workbookReader.on('worksheet', worksheet => { - worksheet.on('row', row => { - }); + worksheet.on('row', row => {}); }); workbookReader.on('shared-strings', sharedString => { // ... @@ -71,7 +68,7 @@ workbookReader.on('hyperlinks', hyperlinksReader => { workbookReader.on('end', () => { // ... }); -workbookReader.on('error', (err) => { +workbookReader.on('error', err => { // ... }); ``` diff --git a/gruntfile.js b/gruntfile.js index 384b04500..52b0aaf75 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -1,6 +1,6 @@ 'use strict'; -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.loadNpmTasks('grunt-babel'); grunt.loadNpmTasks('grunt-browserify'); grunt.loadNpmTasks('grunt-terser'); diff --git a/index.d.ts b/index.d.ts index cae3394bd..f9f8cdd16 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,1509 +1,1622 @@ -declare interface Buffer extends ArrayBuffer { } +declare interface Buffer extends ArrayBuffer {} export declare enum RelationshipType { - None = 0, - OfficeDocument = 1, - Worksheet = 2, - CalcChain = 3, - SharedStrings = 4, - Styles = 5, - Theme = 6, - Hyperlink = 7 + None = 0, + OfficeDocument = 1, + Worksheet = 2, + CalcChain = 3, + SharedStrings = 4, + Styles = 5, + Theme = 6, + Hyperlink = 7, } export declare enum DocumentType { - Xlsx = 1 + Xlsx = 1, } export const enum PaperSize { - Legal = 5, - Executive = 7, - A4 = 9, - A5 = 11, - B5 = 13, - Envelope_10 = 20, - Envelope_DL = 27, - Envelope_C5 = 28, - Envelope_B5 = 34, - Envelope_Monarch = 37, - Double_Japan_Postcard_Rotated = 82, - K16_197x273_mm = 119, + Legal = 5, + Executive = 7, + A4 = 9, + A5 = 11, + B5 = 13, + Envelope_10 = 20, + Envelope_DL = 27, + Envelope_C5 = 28, + Envelope_B5 = 34, + Envelope_Monarch = 37, + Double_Japan_Postcard_Rotated = 82, + K16_197x273_mm = 119, } export interface WorksheetViewCommon { - /** - * Sets the worksheet view's orientation to right-to-left, `false` by default - */ - rightToLeft: boolean; - - /** - * The currently selected cell - */ - activeCell: string; - - /** - * Shows or hides the ruler in Page Layout, `true` by default - */ - showRuler: boolean; - - /** - * Shows or hides the row and column headers (e.g. A1, B1 at the top and 1,2,3 on the left, - * `true` by default - */ - showRowColHeaders: boolean; - - /** - * Shows or hides the gridlines (shown for cells where borders have not been defined), - * `true` by default - */ - showGridLines: boolean; - - /** - * Percentage zoom to use for the view, `100` by default - */ - zoomScale: number; - - /** - * Normal zoom for the view, `100` by default - */ - zoomScaleNormal: number; + /** + * Sets the worksheet view's orientation to right-to-left, `false` by default + */ + rightToLeft: boolean; + + /** + * The currently selected cell + */ + activeCell: string; + + /** + * Shows or hides the ruler in Page Layout, `true` by default + */ + showRuler: boolean; + + /** + * Shows or hides the row and column headers (e.g. A1, B1 at the top and 1,2,3 on the left, + * `true` by default + */ + showRowColHeaders: boolean; + + /** + * Shows or hides the gridlines (shown for cells where borders have not been defined), + * `true` by default + */ + showGridLines: boolean; + + /** + * Percentage zoom to use for the view, `100` by default + */ + zoomScale: number; + + /** + * Normal zoom for the view, `100` by default + */ + zoomScaleNormal: number; } export interface WorksheetViewNormal { - /** - * Controls the view state - */ - state: 'normal'; + /** + * Controls the view state + */ + state: 'normal'; - /** - * Presentation style - */ - style: 'pageBreakPreview' | 'pageLayout'; + /** + * Presentation style + */ + style: 'pageBreakPreview' | 'pageLayout'; } export interface WorksheetViewFrozen { - /** - * Where a number of rows and columns to the top and left are frozen in place. - * Only the bottom left section will scroll - */ - state: 'frozen'; - - /** - * Presentation style - */ - style?: 'pageBreakPreview'; - - /** - * How many columns to freeze. To freeze rows only, set this to 0 or undefined - */ - xSplit?: number; - - /** - * How many rows to freeze. To freeze columns only, set this to 0 or undefined - */ - ySplit?: number; - - /** - * Which cell will be top-left in the bottom-right pane. Note: cannot be a frozen cell. - * Defaults to first unfrozen cell - */ - topLeftCell?: string; + /** + * Where a number of rows and columns to the top and left are frozen in place. + * Only the bottom left section will scroll + */ + state: 'frozen'; + + /** + * Presentation style + */ + style?: 'pageBreakPreview'; + + /** + * How many columns to freeze. To freeze rows only, set this to 0 or undefined + */ + xSplit?: number; + + /** + * How many rows to freeze. To freeze columns only, set this to 0 or undefined + */ + ySplit?: number; + + /** + * Which cell will be top-left in the bottom-right pane. Note: cannot be a frozen cell. + * Defaults to first unfrozen cell + */ + topLeftCell?: string; } export interface WorksheetViewSplit { - /** - * Where the view is split into 4 sections, each semi-independently scrollable. - */ - state: 'split'; - - /** - * Presentation style - */ - style?: 'pageBreakPreview' | 'pageLayout'; - - /** - * How many points from the left to place the splitter. - * To split vertically, set this to 0 or undefined - */ - xSplit?: number; - - /** - * How many points from the top to place the splitter. - * To split horizontally, set this to 0 or undefined - */ - ySplit?: number; - - /** - * Which cell will be top-left in the bottom-right pane - */ - topLeftCell?: string; - - /** - * Which pane will be active - */ - activePane?: 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'; -} - -export type WorksheetView = - & WorksheetViewCommon - & (WorksheetViewNormal | WorksheetViewFrozen | WorksheetViewSplit); + /** + * Where the view is split into 4 sections, each semi-independently scrollable. + */ + state: 'split'; + + /** + * Presentation style + */ + style?: 'pageBreakPreview' | 'pageLayout'; + + /** + * How many points from the left to place the splitter. + * To split vertically, set this to 0 or undefined + */ + xSplit?: number; + + /** + * How many points from the top to place the splitter. + * To split horizontally, set this to 0 or undefined + */ + ySplit?: number; + + /** + * Which cell will be top-left in the bottom-right pane + */ + topLeftCell?: string; + + /** + * Which pane will be active + */ + activePane?: 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'; +} + +export type WorksheetView = WorksheetViewCommon & + (WorksheetViewNormal | WorksheetViewFrozen | WorksheetViewSplit); export interface WorkbookView { - x: number; - y: number; - width: number; - height: number; - firstSheet: number; - activeTab: number; - visibility: string; + x: number; + y: number; + width: number; + height: number; + firstSheet: number; + activeTab: number; + visibility: string; } export type FillPatterns = - | 'none' | 'solid' - | 'darkVertical' | 'darkHorizontal' | 'darkGrid' | 'darkTrellis' | 'darkDown' | 'darkUp' - | 'lightVertical' | 'lightHorizontal' | 'lightGrid' | 'lightTrellis' | 'lightDown' | 'lightUp' - | 'darkGray' | 'mediumGray' | 'lightGray' | 'gray125' | 'gray0625'; + | 'none' + | 'solid' + | 'darkVertical' + | 'darkHorizontal' + | 'darkGrid' + | 'darkTrellis' + | 'darkDown' + | 'darkUp' + | 'lightVertical' + | 'lightHorizontal' + | 'lightGrid' + | 'lightTrellis' + | 'lightDown' + | 'lightUp' + | 'darkGray' + | 'mediumGray' + | 'lightGray' + | 'gray125' + | 'gray0625'; export interface FillPattern { - type: 'pattern'; - pattern: FillPatterns; - fgColor?: Partial; - bgColor?: Partial; + type: 'pattern'; + pattern: FillPatterns; + fgColor?: Partial; + bgColor?: Partial; } export interface GradientStop { - position: number; - color: Partial; + position: number; + color: Partial; } export interface FillGradientAngle { - type: 'gradient'; - gradient: 'angle'; + type: 'gradient'; + gradient: 'angle'; - /** - * For 'angle' gradient, specifies the direction of the gradient. 0 is from the left to the right. - * Values from 1 - 359 rotates the direction clockwise - */ - degree: number; + /** + * For 'angle' gradient, specifies the direction of the gradient. 0 is from the left to the right. + * Values from 1 - 359 rotates the direction clockwise + */ + degree: number; - /** - * Specifies the gradient colour sequence. Is an array of objects containing position and - * color starting with position 0 and ending with position 1. - * Intermediary positions may be used to specify other colours on the path. - */ - stops: GradientStop[]; + /** + * Specifies the gradient colour sequence. Is an array of objects containing position and + * color starting with position 0 and ending with position 1. + * Intermediary positions may be used to specify other colours on the path. + */ + stops: GradientStop[]; } export interface FillGradientPath { - type: 'gradient'; - gradient: 'path'; + type: 'gradient'; + gradient: 'path'; - /** - * For 'path' gradient. Specifies the relative coordinates for the start of the path. - * 'left' and 'top' values range from 0 to 1 - */ - center: { left: number; top: number }; + /** + * For 'path' gradient. Specifies the relative coordinates for the start of the path. + * 'left' and 'top' values range from 0 to 1 + */ + center: {left: number; top: number}; - /** - * Specifies the gradient colour sequence. Is an array of objects containing position and - * color starting with position 0 and ending with position 1. - * Intermediary positions may be used to specify other colours on the path. - */ - stops: GradientStop[]; + /** + * Specifies the gradient colour sequence. Is an array of objects containing position and + * color starting with position 0 and ending with position 1. + * Intermediary positions may be used to specify other colours on the path. + */ + stops: GradientStop[]; } export type Fill = FillPattern | FillGradientAngle | FillGradientPath; export interface Font { - name: string; - size: number; - family: number; - scheme: 'minor' | 'major' | 'none'; - charset: number; - color: Partial; - bold: boolean; - italic: boolean; - underline: boolean | 'none' | 'single' | 'double' | 'singleAccounting' | 'doubleAccounting'; - vertAlign: 'superscript' | 'subscript'; - strike: boolean; - outline: boolean; + name: string; + size: number; + family: number; + scheme: 'minor' | 'major' | 'none'; + charset: number; + color: Partial; + bold: boolean; + italic: boolean; + underline: boolean | 'none' | 'single' | 'double' | 'singleAccounting' | 'doubleAccounting'; + vertAlign: 'superscript' | 'subscript'; + strike: boolean; + outline: boolean; } export type BorderStyle = - | 'thin' | 'dotted' | 'hair' | 'medium' | 'double' | 'thick' | 'dashed' | 'dashDot' - | 'dashDotDot' | 'slantDashDot' | 'mediumDashed' | 'mediumDashDotDot' | 'mediumDashDot'; + | 'thin' + | 'dotted' + | 'hair' + | 'medium' + | 'double' + | 'thick' + | 'dashed' + | 'dashDot' + | 'dashDotDot' + | 'slantDashDot' + | 'mediumDashed' + | 'mediumDashDotDot' + | 'mediumDashDot'; export interface Color { - /** - * Hex string for alpha-red-green-blue e.g. FF00FF00 - */ - argb: string; + /** + * Hex string for alpha-red-green-blue e.g. FF00FF00 + */ + argb: string; - /** - * Choose a theme by index - */ - theme: number; + /** + * Choose a theme by index + */ + theme: number; } export interface Border { - style: BorderStyle; - color: Partial; + style: BorderStyle; + color: Partial; } export interface BorderDiagonal extends Border { - up: boolean; - down: boolean; + up: boolean; + down: boolean; } export interface Borders { - top: Partial; - left: Partial; - bottom: Partial; - right: Partial; - diagonal: Partial; + top: Partial; + left: Partial; + bottom: Partial; + right: Partial; + diagonal: Partial; } export interface Margins { - top: number; - left: number; - bottom: number; - right: number; - header: number; - footer: number; + top: number; + left: number; + bottom: number; + right: number; + header: number; + footer: number; } export declare enum ReadingOrder { - LeftToRight = 1, - RightToLeft = 2, + LeftToRight = 1, + RightToLeft = 2, } export interface Alignment { - horizontal: 'left' | 'center' | 'right' | 'fill' | 'justify' | 'centerContinuous' | 'distributed'; - vertical: 'top' | 'middle' | 'bottom' | 'distributed' | 'justify'; - wrapText: boolean; - shrinkToFit: boolean; - indent: number; - readingOrder: 'rtl' | 'ltr'; - textRotation: number | 'vertical'; + horizontal: 'left' | 'center' | 'right' | 'fill' | 'justify' | 'centerContinuous' | 'distributed'; + vertical: 'top' | 'middle' | 'bottom' | 'distributed' | 'justify'; + wrapText: boolean; + shrinkToFit: boolean; + indent: number; + readingOrder: 'rtl' | 'ltr'; + textRotation: number | 'vertical'; } export interface Protection { - locked: boolean; - hidden: boolean; + locked: boolean; + hidden: boolean; } export interface Style { - numFmt: string; - font: Partial; - alignment: Partial; - protection: Partial; - border: Partial; - fill: Fill; + numFmt: string; + font: Partial; + alignment: Partial; + protection: Partial; + border: Partial; + fill: Fill; } export type DataValidationOperator = - | 'between' | 'notBetween' | 'equal' | 'notEqual' | 'greaterThan' | 'lessThan' - | 'greaterThanOrEqual' | 'lessThanOrEqual'; + | 'between' + | 'notBetween' + | 'equal' + | 'notEqual' + | 'greaterThan' + | 'lessThan' + | 'greaterThanOrEqual' + | 'lessThanOrEqual'; export interface DataValidation { - type: 'list' | 'whole' | 'decimal' | 'date' | 'textLength' | 'custom'; - formulae: any[]; - allowBlank?: boolean; - operator?: DataValidationOperator; - error?: string; - errorTitle?: string; - errorStyle?: string; - prompt?: string; - promptTitle?: string; - showErrorMessage?: boolean; - showInputMessage?: boolean; + type: 'list' | 'whole' | 'decimal' | 'date' | 'textLength' | 'custom'; + formulae: any[]; + allowBlank?: boolean; + operator?: DataValidationOperator; + error?: string; + errorTitle?: string; + errorStyle?: string; + prompt?: string; + promptTitle?: string; + showErrorMessage?: boolean; + showInputMessage?: boolean; } export declare enum ErrorValue { - NotApplicable = '#N/A', - Ref = '#REF!', - Name = '#NAME?', - DivZero = '#DIV/0!', - Null = '#NULL!', - Value = '#VALUE!', - Num = '#NUM!', + NotApplicable = '#N/A', + Ref = '#REF!', + Name = '#NAME?', + DivZero = '#DIV/0!', + Null = '#NULL!', + Value = '#VALUE!', + Num = '#NUM!', } export interface CellErrorValue { - error: '#N/A' | '#REF!' | '#NAME?' | '#DIV/0!' | '#NULL!' | '#VALUE!' | '#NUM!'; + error: '#N/A' | '#REF!' | '#NAME?' | '#DIV/0!' | '#NULL!' | '#VALUE!' | '#NUM!'; } export interface RichText { - text: string; - font?: Partial; + text: string; + font?: Partial; } export interface CellRichTextValue { - richText: RichText[]; + richText: RichText[]; } export interface CellHyperlinkValue { - text: string; - hyperlink: string; - tooltip?: string; + text: string; + hyperlink: string; + tooltip?: string; } export interface CellFormulaValue { - formula: string; - result?: number | string | boolean | Date | CellErrorValue; - date1904?: boolean; + formula: string; + result?: number | string | boolean | Date | CellErrorValue; + date1904?: boolean; } export interface CellSharedFormulaValue { - sharedFormula: string; - readonly formula?: string; - result?: number | string | boolean | Date | CellErrorValue; - date1904?: boolean; + sharedFormula: string; + readonly formula?: string; + result?: number | string | boolean | Date | CellErrorValue; + date1904?: boolean; } export declare enum ValueType { - Null = 0, - Merge = 1, - Number = 2, - String = 3, - Date = 4, - Hyperlink = 5, - Formula = 6, - SharedString = 7, - RichText = 8, - Boolean = 9, - Error = 10 + Null = 0, + Merge = 1, + Number = 2, + String = 3, + Date = 4, + Hyperlink = 5, + Formula = 6, + SharedString = 7, + RichText = 8, + Boolean = 9, + Error = 10, } export declare enum FormulaType { - None = 0, - Master = 1, - Shared = 2 + None = 0, + Master = 1, + Shared = 2, } export type CellValue = - | null | number | string | boolean | Date | undefined - | CellErrorValue - | CellRichTextValue | CellHyperlinkValue - | CellFormulaValue | CellSharedFormulaValue; + | null + | number + | string + | boolean + | Date + | undefined + | CellErrorValue + | CellRichTextValue + | CellHyperlinkValue + | CellFormulaValue + | CellSharedFormulaValue; +export interface CommentMargins { + insetmode: 'auto' | 'custom'; + inset: Number[]; +} - export interface CommentMargins { - insetmode: 'auto' | 'custom'; - inset: Number[]; - } - - export interface CommentProtection { - locked: 'True' | 'False'; - lockText: 'True' | 'False'; - } +export interface CommentProtection { + locked: 'True' | 'False'; + lockText: 'True' | 'False'; +} - export type CommentEditAs = 'twoCells' | 'oneCells' | 'absolute'; +export type CommentEditAs = 'twoCells' | 'oneCells' | 'absolute'; - export interface Comment { - texts?: RichText[]; - margins?: Partial; - protection?: Partial; - editAs?: CommentEditAs; - } +export interface Comment { + texts?: RichText[]; + margins?: Partial; + protection?: Partial; + editAs?: CommentEditAs; +} export interface CellModel { - address: Address; - style: Style; - type: ValueType; - text?: string; - hyperlink?: string; - value?: CellValue; - master: string; - formula?: string; - sharedFormula?: string; - result?: string | number | any; - comment: Comment; + address: Address; + style: Style; + type: ValueType; + text?: string; + hyperlink?: string; + value?: CellValue; + master: string; + formula?: string; + sharedFormula?: string; + result?: string | number | any; + comment: Comment; } export interface Cell extends Style, Address { - readonly worksheet: Worksheet; - readonly workbook: Workbook; - - readonly effectiveType: ValueType; - readonly isMerged: boolean; - readonly master: Cell; - readonly isHyperlink: boolean; - readonly hyperlink: string; // todo - readonly text: string; - readonly fullAddress: { - sheetName: string; - address: string; - row: number; - col: number; - }; - model: CellModel; - /** - * Assign (or get) a name for a cell (will overwrite any other names that cell had) - */ - name: string; - - /** - * Assign (or get) an array of names for a cell (cells can have more than one name) - */ - names: string[]; - - /** - * Cells can define what values are valid or not and provide - * prompting to the user to help guide them. - */ - dataValidation: DataValidation; - - /** - * Value of the cell - */ - value: CellValue; - - /** - * comment of the cell - */ - note: string | Comment; - - /** - * convenience getter to access the formula - */ - readonly formula: string; - - /** - * convenience getter to access the formula result - */ - readonly result: number | string | Date; - - /** - * The type of the cell's value - */ - readonly type: ValueType; - - /** - * The type of the cell's formula - */ - readonly formulaType: FormulaType; - - /** - * The styles of the cell - */ - style: Partial