@trebco/treb 37.0.0 → 37.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/package.json +119 -0
- package/build/treb-base-types/src/api_types.d.ts +11 -0
- package/build/treb-base-types/src/api_types.js +22 -0
- package/build/treb-base-types/src/api_types.js.map +1 -0
- package/build/treb-base-types/src/area-utils.d.ts +9 -0
- package/build/treb-base-types/src/area-utils.js +50 -0
- package/build/treb-base-types/src/area-utils.js.map +1 -0
- package/build/treb-base-types/src/area.d.ts +182 -0
- package/build/treb-base-types/src/area.js +715 -0
- package/build/treb-base-types/src/area.js.map +1 -0
- package/build/treb-base-types/src/basic_types.d.ts +20 -0
- package/build/treb-base-types/src/basic_types.js +22 -0
- package/build/treb-base-types/src/basic_types.js.map +1 -0
- package/build/treb-base-types/src/cell.d.ts +167 -0
- package/build/treb-base-types/src/cell.js +432 -0
- package/build/treb-base-types/src/cell.js.map +1 -0
- package/build/treb-base-types/src/cells.d.ts +251 -0
- package/build/treb-base-types/src/cells.js +1136 -0
- package/build/treb-base-types/src/cells.js.map +1 -0
- package/build/treb-base-types/src/color.d.ts +35 -0
- package/build/treb-base-types/src/color.js +162 -0
- package/build/treb-base-types/src/color.js.map +1 -0
- package/build/treb-base-types/src/dom-utilities.d.ts +70 -0
- package/build/treb-base-types/src/dom-utilities.js +144 -0
- package/build/treb-base-types/src/dom-utilities.js.map +1 -0
- package/build/treb-base-types/src/evaluate-options.d.ts +35 -0
- package/build/treb-base-types/src/evaluate-options.js +22 -0
- package/build/treb-base-types/src/evaluate-options.js.map +1 -0
- package/build/treb-base-types/src/font-stack.d.ts +37 -0
- package/build/treb-base-types/src/font-stack.js +93 -0
- package/build/treb-base-types/src/font-stack.js.map +1 -0
- package/build/treb-base-types/src/gradient.d.ts +18 -0
- package/build/treb-base-types/src/gradient.js +86 -0
- package/build/treb-base-types/src/gradient.js.map +1 -0
- package/build/treb-base-types/src/import.d.ts +48 -0
- package/build/treb-base-types/src/import.js +22 -0
- package/build/treb-base-types/src/import.js.map +1 -0
- package/build/treb-base-types/src/index-standalone.d.ts +6 -0
- package/build/treb-base-types/src/index-standalone.js +27 -0
- package/build/treb-base-types/src/index-standalone.js.map +1 -0
- package/build/treb-base-types/src/index.d.ts +22 -0
- package/build/treb-base-types/src/index.js +45 -0
- package/build/treb-base-types/src/index.js.map +1 -0
- package/build/treb-base-types/src/layout.d.ts +22 -0
- package/build/treb-base-types/src/layout.js +22 -0
- package/build/treb-base-types/src/layout.js.map +1 -0
- package/build/treb-base-types/src/localization.d.ts +37 -0
- package/build/treb-base-types/src/localization.js +157 -0
- package/build/treb-base-types/src/localization.js.map +1 -0
- package/build/treb-base-types/src/rectangle.d.ts +51 -0
- package/build/treb-base-types/src/rectangle.js +123 -0
- package/build/treb-base-types/src/rectangle.js.map +1 -0
- package/build/treb-base-types/src/render_text.d.ts +34 -0
- package/build/treb-base-types/src/render_text.js +22 -0
- package/build/treb-base-types/src/render_text.js.map +1 -0
- package/build/treb-base-types/src/style.d.ts +214 -0
- package/build/treb-base-types/src/style.js +373 -0
- package/build/treb-base-types/src/style.js.map +1 -0
- package/build/treb-base-types/src/table.d.ts +58 -0
- package/build/treb-base-types/src/table.js +27 -0
- package/build/treb-base-types/src/table.js.map +1 -0
- package/build/treb-base-types/src/text_part.d.ts +26 -0
- package/build/treb-base-types/src/text_part.js +47 -0
- package/build/treb-base-types/src/text_part.js.map +1 -0
- package/build/treb-base-types/src/theme.d.ts +120 -0
- package/build/treb-base-types/src/theme.js +460 -0
- package/build/treb-base-types/src/theme.js.map +1 -0
- package/build/treb-base-types/src/union.d.ts +73 -0
- package/build/treb-base-types/src/union.js +61 -0
- package/build/treb-base-types/src/union.js.map +1 -0
- package/build/treb-base-types/src/value-type.d.ts +86 -0
- package/build/treb-base-types/src/value-type.js +168 -0
- package/build/treb-base-types/src/value-type.js.map +1 -0
- package/build/treb-base-types/src/worker-proxy.d.ts +95 -0
- package/build/treb-base-types/src/worker-proxy.js +221 -0
- package/build/treb-base-types/src/worker-proxy.js.map +1 -0
- package/build/treb-calculator/src/calculator.d.ts +249 -0
- package/build/treb-calculator/src/calculator.js +2755 -0
- package/build/treb-calculator/src/calculator.js.map +1 -0
- package/build/treb-calculator/src/complex-math.d.ts +75 -0
- package/build/treb-calculator/src/complex-math.js +559 -0
- package/build/treb-calculator/src/complex-math.js.map +1 -0
- package/build/treb-calculator/src/dag/array-vertex.d.ts +71 -0
- package/build/treb-calculator/src/dag/array-vertex.js +156 -0
- package/build/treb-calculator/src/dag/array-vertex.js.map +1 -0
- package/build/treb-calculator/src/dag/calculation_leaf_vertex.d.ts +48 -0
- package/build/treb-calculator/src/dag/calculation_leaf_vertex.js +84 -0
- package/build/treb-calculator/src/dag/calculation_leaf_vertex.js.map +1 -0
- package/build/treb-calculator/src/dag/graph.d.ts +134 -0
- package/build/treb-calculator/src/dag/graph.js +842 -0
- package/build/treb-calculator/src/dag/graph.js.map +1 -0
- package/build/treb-calculator/src/dag/spreadsheet_vertex.d.ts +58 -0
- package/build/treb-calculator/src/dag/spreadsheet_vertex.js +232 -0
- package/build/treb-calculator/src/dag/spreadsheet_vertex.js.map +1 -0
- package/build/treb-calculator/src/dag/spreadsheet_vertex_base.d.ts +20 -0
- package/build/treb-calculator/src/dag/spreadsheet_vertex_base.js +25 -0
- package/build/treb-calculator/src/dag/spreadsheet_vertex_base.js.map +1 -0
- package/build/treb-calculator/src/dag/state_leaf_vertex.d.ts +43 -0
- package/build/treb-calculator/src/dag/state_leaf_vertex.js +81 -0
- package/build/treb-calculator/src/dag/state_leaf_vertex.js.map +1 -0
- package/build/treb-calculator/src/dag/vertex.d.ts +71 -0
- package/build/treb-calculator/src/dag/vertex.js +274 -0
- package/build/treb-calculator/src/dag/vertex.js.map +1 -0
- package/build/treb-calculator/src/descriptors.d.ts +189 -0
- package/build/treb-calculator/src/descriptors.js +22 -0
- package/build/treb-calculator/src/descriptors.js.map +1 -0
- package/build/treb-calculator/src/expression-calculator.d.ts +127 -0
- package/build/treb-calculator/src/expression-calculator.js +1033 -0
- package/build/treb-calculator/src/expression-calculator.js.map +1 -0
- package/build/treb-calculator/src/function-error.d.ts +35 -0
- package/build/treb-calculator/src/function-error.js +85 -0
- package/build/treb-calculator/src/function-error.js.map +1 -0
- package/build/treb-calculator/src/function-library.d.ts +22 -0
- package/build/treb-calculator/src/function-library.js +96 -0
- package/build/treb-calculator/src/function-library.js.map +1 -0
- package/build/treb-calculator/src/functions/base-functions.d.ts +7 -0
- package/build/treb-calculator/src/functions/base-functions.js +2611 -0
- package/build/treb-calculator/src/functions/base-functions.js.map +1 -0
- package/build/treb-calculator/src/functions/beta.d.ts +17 -0
- package/build/treb-calculator/src/functions/beta.js +201 -0
- package/build/treb-calculator/src/functions/beta.js.map +1 -0
- package/build/treb-calculator/src/functions/checkbox.d.ts +3 -0
- package/build/treb-calculator/src/functions/checkbox.js +128 -0
- package/build/treb-calculator/src/functions/checkbox.js.map +1 -0
- package/build/treb-calculator/src/functions/complex-functions.d.ts +2 -0
- package/build/treb-calculator/src/functions/complex-functions.js +217 -0
- package/build/treb-calculator/src/functions/complex-functions.js.map +1 -0
- package/build/treb-calculator/src/functions/date-utils.d.ts +3 -0
- package/build/treb-calculator/src/functions/date-utils.js +59 -0
- package/build/treb-calculator/src/functions/date-utils.js.map +1 -0
- package/build/treb-calculator/src/functions/finance-functions.d.ts +2 -0
- package/build/treb-calculator/src/functions/finance-functions.js +547 -0
- package/build/treb-calculator/src/functions/finance-functions.js.map +1 -0
- package/build/treb-calculator/src/functions/fp.d.ts +2 -0
- package/build/treb-calculator/src/functions/fp.js +463 -0
- package/build/treb-calculator/src/functions/fp.js.map +1 -0
- package/build/treb-calculator/src/functions/function-utilities.d.ts +2 -0
- package/build/treb-calculator/src/functions/function-utilities.js +36 -0
- package/build/treb-calculator/src/functions/function-utilities.js.map +1 -0
- package/build/treb-calculator/src/functions/gamma.d.ts +20 -0
- package/build/treb-calculator/src/functions/gamma.js +142 -0
- package/build/treb-calculator/src/functions/gamma.js.map +1 -0
- package/build/treb-calculator/src/functions/information-functions.d.ts +2 -0
- package/build/treb-calculator/src/functions/information-functions.js +71 -0
- package/build/treb-calculator/src/functions/information-functions.js.map +1 -0
- package/build/treb-calculator/src/functions/lambda-functions.d.ts +2 -0
- package/build/treb-calculator/src/functions/lambda-functions.js +85 -0
- package/build/treb-calculator/src/functions/lambda-functions.js.map +1 -0
- package/build/treb-calculator/src/functions/matrix-functions.d.ts +2 -0
- package/build/treb-calculator/src/functions/matrix-functions.js +144 -0
- package/build/treb-calculator/src/functions/matrix-functions.js.map +1 -0
- package/build/treb-calculator/src/functions/normal.d.ts +2 -0
- package/build/treb-calculator/src/functions/normal.js +32 -0
- package/build/treb-calculator/src/functions/normal.js.map +1 -0
- package/build/treb-calculator/src/functions/regex-functions.d.ts +2 -0
- package/build/treb-calculator/src/functions/regex-functions.js +188 -0
- package/build/treb-calculator/src/functions/regex-functions.js.map +1 -0
- package/build/treb-calculator/src/functions/sparkline.d.ts +37 -0
- package/build/treb-calculator/src/functions/sparkline.js +264 -0
- package/build/treb-calculator/src/functions/sparkline.js.map +1 -0
- package/build/treb-calculator/src/functions/statistics-functions.d.ts +6 -0
- package/build/treb-calculator/src/functions/statistics-functions.js +989 -0
- package/build/treb-calculator/src/functions/statistics-functions.js.map +1 -0
- package/build/treb-calculator/src/functions/students-t.d.ts +3 -0
- package/build/treb-calculator/src/functions/students-t.js +64 -0
- package/build/treb-calculator/src/functions/students-t.js.map +1 -0
- package/build/treb-calculator/src/functions/text-functions.d.ts +3 -0
- package/build/treb-calculator/src/functions/text-functions.js +320 -0
- package/build/treb-calculator/src/functions/text-functions.js.map +1 -0
- package/build/treb-calculator/src/index.d.ts +2 -0
- package/build/treb-calculator/src/index.js +22 -0
- package/build/treb-calculator/src/index.js.map +1 -0
- package/build/treb-calculator/src/notifier-types.d.ts +26 -0
- package/build/treb-calculator/src/notifier-types.js +22 -0
- package/build/treb-calculator/src/notifier-types.js.map +1 -0
- package/build/treb-calculator/src/primitives.d.ts +15 -0
- package/build/treb-calculator/src/primitives.js +398 -0
- package/build/treb-calculator/src/primitives.js.map +1 -0
- package/build/treb-calculator/src/utilities.d.ts +68 -0
- package/build/treb-calculator/src/utilities.js +324 -0
- package/build/treb-calculator/src/utilities.js.map +1 -0
- package/build/treb-charts/src/chart-functions.d.ts +8 -0
- package/build/treb-charts/src/chart-functions.js +209 -0
- package/build/treb-charts/src/chart-functions.js.map +1 -0
- package/build/treb-charts/src/chart-types.d.ts +233 -0
- package/build/treb-charts/src/chart-types.js +57 -0
- package/build/treb-charts/src/chart-types.js.map +1 -0
- package/build/treb-charts/src/chart-utils.d.ts +106 -0
- package/build/treb-charts/src/chart-utils.js +1060 -0
- package/build/treb-charts/src/chart-utils.js.map +1 -0
- package/build/treb-charts/src/chart.d.ts +23 -0
- package/build/treb-charts/src/chart.js +94 -0
- package/build/treb-charts/src/chart.js.map +1 -0
- package/build/treb-charts/src/default-chart-renderer.d.ts +16 -0
- package/build/treb-charts/src/default-chart-renderer.js +533 -0
- package/build/treb-charts/src/default-chart-renderer.js.map +1 -0
- package/build/treb-charts/src/index.d.ts +5 -0
- package/build/treb-charts/src/index.js +24 -0
- package/build/treb-charts/src/index.js.map +1 -0
- package/build/treb-charts/src/main.d.ts +1 -0
- package/build/treb-charts/src/main.js +34 -0
- package/build/treb-charts/src/main.js.map +1 -0
- package/build/treb-charts/src/quicksort.d.ts +1 -0
- package/build/treb-charts/src/quicksort.js +49 -0
- package/build/treb-charts/src/quicksort.js.map +1 -0
- package/build/treb-charts/src/rectangle.d.ts +18 -0
- package/build/treb-charts/src/rectangle.js +41 -0
- package/build/treb-charts/src/rectangle.js.map +1 -0
- package/build/treb-charts/src/renderer-type.d.ts +24 -0
- package/build/treb-charts/src/renderer-type.js +22 -0
- package/build/treb-charts/src/renderer-type.js.map +1 -0
- package/build/treb-charts/src/renderer.d.ts +127 -0
- package/build/treb-charts/src/renderer.js +1518 -0
- package/build/treb-charts/src/renderer.js.map +1 -0
- package/build/treb-charts/src/util.d.ts +18 -0
- package/build/treb-charts/src/util.js +71 -0
- package/build/treb-charts/src/util.js.map +1 -0
- package/build/treb-data-model/src/annotation.d.ts +167 -0
- package/build/treb-data-model/src/annotation.js +120 -0
- package/build/treb-data-model/src/annotation.js.map +1 -0
- package/build/treb-data-model/src/conditional_format.d.ts +155 -0
- package/build/treb-data-model/src/conditional_format.js +62 -0
- package/build/treb-data-model/src/conditional_format.js.map +1 -0
- package/build/treb-data-model/src/data-validation.d.ts +28 -0
- package/build/treb-data-model/src/data-validation.js +22 -0
- package/build/treb-data-model/src/data-validation.js.map +1 -0
- package/build/treb-data-model/src/data_model.d.ts +173 -0
- package/build/treb-data-model/src/data_model.js +637 -0
- package/build/treb-data-model/src/data_model.js.map +1 -0
- package/build/treb-data-model/src/index.d.ts +13 -0
- package/build/treb-data-model/src/index.js +28 -0
- package/build/treb-data-model/src/index.js.map +1 -0
- package/build/treb-data-model/src/language-model.d.ts +22 -0
- package/build/treb-data-model/src/language-model.js +22 -0
- package/build/treb-data-model/src/language-model.js.map +1 -0
- package/build/treb-data-model/src/named.d.ts +124 -0
- package/build/treb-data-model/src/named.js +372 -0
- package/build/treb-data-model/src/named.js.map +1 -0
- package/build/treb-data-model/src/serialize_options.d.ts +49 -0
- package/build/treb-data-model/src/serialize_options.js +22 -0
- package/build/treb-data-model/src/serialize_options.js.map +1 -0
- package/build/treb-data-model/src/sheet.d.ts +499 -0
- package/build/treb-data-model/src/sheet.js +2904 -0
- package/build/treb-data-model/src/sheet.js.map +1 -0
- package/build/treb-data-model/src/sheet_collection.d.ts +58 -0
- package/build/treb-data-model/src/sheet_collection.js +112 -0
- package/build/treb-data-model/src/sheet_collection.js.map +1 -0
- package/build/treb-data-model/src/sheet_selection.d.ts +42 -0
- package/build/treb-data-model/src/sheet_selection.js +39 -0
- package/build/treb-data-model/src/sheet_selection.js.map +1 -0
- package/build/treb-data-model/src/sheet_types.d.ts +104 -0
- package/build/treb-data-model/src/sheet_types.js +22 -0
- package/build/treb-data-model/src/sheet_types.js.map +1 -0
- package/build/treb-data-model/src/types.d.ts +59 -0
- package/build/treb-data-model/src/types.js +22 -0
- package/build/treb-data-model/src/types.js.map +1 -0
- package/build/treb-embed/src/custom-element/spreadsheet-constructor.d.ts +75 -0
- package/build/treb-embed/src/custom-element/spreadsheet-constructor.js +1144 -0
- package/build/treb-embed/src/custom-element/spreadsheet-constructor.js.map +1 -0
- package/build/treb-embed/src/custom-element/treb-global.d.ts +36 -0
- package/build/treb-embed/src/custom-element/treb-global.js +64 -0
- package/build/treb-embed/src/custom-element/treb-global.js.map +1 -0
- package/build/treb-embed/src/custom-element/treb-spreadsheet-element.d.ts +1 -0
- package/build/treb-embed/src/custom-element/treb-spreadsheet-element.js +61 -0
- package/build/treb-embed/src/custom-element/treb-spreadsheet-element.js.map +1 -0
- package/build/treb-embed/src/embedded-spreadsheet.d.ts +1358 -0
- package/build/treb-embed/src/embedded-spreadsheet.js +5205 -0
- package/build/treb-embed/src/embedded-spreadsheet.js.map +1 -0
- package/build/treb-embed/src/index.d.ts +12 -0
- package/build/treb-embed/src/index.js +34 -0
- package/build/treb-embed/src/index.js.map +1 -0
- package/build/treb-embed/src/options.d.ts +266 -0
- package/build/treb-embed/src/options.js +56 -0
- package/build/treb-embed/src/options.js.map +1 -0
- package/build/treb-embed/src/plugin.d.ts +9 -0
- package/build/treb-embed/src/plugin.js +22 -0
- package/build/treb-embed/src/plugin.js.map +1 -0
- package/build/treb-embed/src/progress-dialog.d.ts +49 -0
- package/build/treb-embed/src/progress-dialog.js +178 -0
- package/build/treb-embed/src/progress-dialog.js.map +1 -0
- package/build/treb-embed/src/selection-state.d.ts +15 -0
- package/build/treb-embed/src/selection-state.js +22 -0
- package/build/treb-embed/src/selection-state.js.map +1 -0
- package/build/treb-embed/src/spinner.d.ts +8 -0
- package/build/treb-embed/src/spinner.js +40 -0
- package/build/treb-embed/src/spinner.js.map +1 -0
- package/build/treb-embed/src/toolbar-message.d.ts +72 -0
- package/build/treb-embed/src/toolbar-message.js +22 -0
- package/build/treb-embed/src/toolbar-message.js.map +1 -0
- package/build/treb-embed/src/types.d.ts +185 -0
- package/build/treb-embed/src/types.js +45 -0
- package/build/treb-embed/src/types.js.map +1 -0
- package/build/treb-embed/tsconfig.tsbuildinfo +1 -0
- package/build/treb-export/src/address-type.d.ts +34 -0
- package/build/treb-export/src/address-type.js +53 -0
- package/build/treb-export/src/address-type.js.map +1 -0
- package/build/treb-export/src/base-template.d.ts +1 -0
- package/build/treb-export/src/base-template.js +22 -0
- package/build/treb-export/src/base-template.js.map +1 -0
- package/build/treb-export/src/column-width.d.ts +2 -0
- package/build/treb-export/src/column-width.js +80 -0
- package/build/treb-export/src/column-width.js.map +1 -0
- package/build/treb-export/src/drawing/bubble-chart-template.d.ts +514 -0
- package/build/treb-export/src/drawing/bubble-chart-template.js +544 -0
- package/build/treb-export/src/drawing/bubble-chart-template.js.map +1 -0
- package/build/treb-export/src/drawing/chart-template-components2.d.ts +365 -0
- package/build/treb-export/src/drawing/chart-template-components2.js +386 -0
- package/build/treb-export/src/drawing/chart-template-components2.js.map +1 -0
- package/build/treb-export/src/drawing/chart.d.ts +26 -0
- package/build/treb-export/src/drawing/chart.js +247 -0
- package/build/treb-export/src/drawing/chart.js.map +1 -0
- package/build/treb-export/src/drawing/column-chart-template2.d.ts +490 -0
- package/build/treb-export/src/drawing/column-chart-template2.js +518 -0
- package/build/treb-export/src/drawing/column-chart-template2.js.map +1 -0
- package/build/treb-export/src/drawing/donut-chart-template2.d.ts +272 -0
- package/build/treb-export/src/drawing/donut-chart-template2.js +293 -0
- package/build/treb-export/src/drawing/donut-chart-template2.js.map +1 -0
- package/build/treb-export/src/drawing/drawing.d.ts +49 -0
- package/build/treb-export/src/drawing/drawing.js +193 -0
- package/build/treb-export/src/drawing/drawing.js.map +1 -0
- package/build/treb-export/src/drawing/embedded-image.d.ts +12 -0
- package/build/treb-export/src/drawing/embedded-image.js +54 -0
- package/build/treb-export/src/drawing/embedded-image.js.map +1 -0
- package/build/treb-export/src/drawing/scatter-chart-template2.d.ts +520 -0
- package/build/treb-export/src/drawing/scatter-chart-template2.js +551 -0
- package/build/treb-export/src/drawing/scatter-chart-template2.js.map +1 -0
- package/build/treb-export/src/export.d.ts +72 -0
- package/build/treb-export/src/export.js +2039 -0
- package/build/treb-export/src/export.js.map +1 -0
- package/build/treb-export/src/import-export-messages.d.ts +31 -0
- package/build/treb-export/src/import-export-messages.js +22 -0
- package/build/treb-export/src/import-export-messages.js.map +1 -0
- package/build/treb-export/src/import.d.ts +33 -0
- package/build/treb-export/src/import.js +1258 -0
- package/build/treb-export/src/import.js.map +1 -0
- package/build/treb-export/src/index.worker.d.ts +1 -0
- package/build/treb-export/src/index.worker.js +93 -0
- package/build/treb-export/src/index.worker.js.map +1 -0
- package/build/treb-export/src/metadata.d.ts +51 -0
- package/build/treb-export/src/metadata.js +153 -0
- package/build/treb-export/src/metadata.js.map +1 -0
- package/build/treb-export/src/ooxml.d.ts +7 -0
- package/build/treb-export/src/ooxml.js +41 -0
- package/build/treb-export/src/ooxml.js.map +1 -0
- package/build/treb-export/src/relationship.d.ts +8 -0
- package/build/treb-export/src/relationship.js +27 -0
- package/build/treb-export/src/relationship.js.map +1 -0
- package/build/treb-export/src/shared-strings.d.ts +11 -0
- package/build/treb-export/src/shared-strings.js +105 -0
- package/build/treb-export/src/shared-strings.js.map +1 -0
- package/build/treb-export/src/template-2.d.ts +1 -0
- package/build/treb-export/src/template-2.js +22 -0
- package/build/treb-export/src/template-2.js.map +1 -0
- package/build/treb-export/src/unescape_xml.d.ts +1 -0
- package/build/treb-export/src/unescape_xml.js +61 -0
- package/build/treb-export/src/unescape_xml.js.map +1 -0
- package/build/treb-export/src/workbook-sheet.d.ts +75 -0
- package/build/treb-export/src/workbook-sheet.js +128 -0
- package/build/treb-export/src/workbook-sheet.js.map +1 -0
- package/build/treb-export/src/workbook-style.d.ts +110 -0
- package/build/treb-export/src/workbook-style.js +1134 -0
- package/build/treb-export/src/workbook-style.js.map +1 -0
- package/build/treb-export/src/workbook-theme.d.ts +13 -0
- package/build/treb-export/src/workbook-theme.js +85 -0
- package/build/treb-export/src/workbook-theme.js.map +1 -0
- package/build/treb-export/src/workbook.d.ts +123 -0
- package/build/treb-export/src/workbook.js +644 -0
- package/build/treb-export/src/workbook.js.map +1 -0
- package/build/treb-export/src/xml-test.d.ts +9 -0
- package/build/treb-export/src/xml-test.js +52 -0
- package/build/treb-export/src/xml-test.js.map +1 -0
- package/build/treb-export/src/xml-utils.d.ts +76 -0
- package/build/treb-export/src/xml-utils.js +223 -0
- package/build/treb-export/src/xml-utils.js.map +1 -0
- package/build/treb-export/src/zip-wrapper.d.ts +22 -0
- package/build/treb-export/src/zip-wrapper.js +93 -0
- package/build/treb-export/src/zip-wrapper.js.map +1 -0
- package/build/treb-format/src/format.d.ts +130 -0
- package/build/treb-format/src/format.js +805 -0
- package/build/treb-format/src/format.js.map +1 -0
- package/build/treb-format/src/format_cache.d.ts +55 -0
- package/build/treb-format/src/format_cache.js +166 -0
- package/build/treb-format/src/format_cache.js.map +1 -0
- package/build/treb-format/src/format_parser.d.ts +70 -0
- package/build/treb-format/src/format_parser.js +618 -0
- package/build/treb-format/src/format_parser.js.map +1 -0
- package/build/treb-format/src/index.d.ts +4 -0
- package/build/treb-format/src/index.js +25 -0
- package/build/treb-format/src/index.js.map +1 -0
- package/build/treb-format/src/number_format_section.d.ts +58 -0
- package/build/treb-format/src/number_format_section.js +78 -0
- package/build/treb-format/src/number_format_section.js.map +1 -0
- package/build/treb-format/src/value_parser.d.ts +48 -0
- package/build/treb-format/src/value_parser.js +244 -0
- package/build/treb-format/src/value_parser.js.map +1 -0
- package/build/treb-grid/src/editors/autocomplete.d.ts +39 -0
- package/build/treb-grid/src/editors/autocomplete.js +316 -0
- package/build/treb-grid/src/editors/autocomplete.js.map +1 -0
- package/build/treb-grid/src/editors/autocomplete_matcher.d.ts +74 -0
- package/build/treb-grid/src/editors/autocomplete_matcher.js +212 -0
- package/build/treb-grid/src/editors/autocomplete_matcher.js.map +1 -0
- package/build/treb-grid/src/editors/editor.d.ts +214 -0
- package/build/treb-grid/src/editors/editor.js +879 -0
- package/build/treb-grid/src/editors/editor.js.map +1 -0
- package/build/treb-grid/src/editors/external_editor.d.ts +11 -0
- package/build/treb-grid/src/editors/external_editor.js +118 -0
- package/build/treb-grid/src/editors/external_editor.js.map +1 -0
- package/build/treb-grid/src/editors/formula_bar.d.ts +85 -0
- package/build/treb-grid/src/editors/formula_bar.js +444 -0
- package/build/treb-grid/src/editors/formula_bar.js.map +1 -0
- package/build/treb-grid/src/editors/overlay_editor.d.ts +85 -0
- package/build/treb-grid/src/editors/overlay_editor.js +353 -0
- package/build/treb-grid/src/editors/overlay_editor.js.map +1 -0
- package/build/treb-grid/src/index.d.ts +12 -0
- package/build/treb-grid/src/index.js +28 -0
- package/build/treb-grid/src/index.js.map +1 -0
- package/build/treb-grid/src/layout/base_layout.d.ts +346 -0
- package/build/treb-grid/src/layout/base_layout.js +2050 -0
- package/build/treb-grid/src/layout/base_layout.js.map +1 -0
- package/build/treb-grid/src/layout/grid_layout.d.ts +19 -0
- package/build/treb-grid/src/layout/grid_layout.js +235 -0
- package/build/treb-grid/src/layout/grid_layout.js.map +1 -0
- package/build/treb-grid/src/layout/mock-layout.d.ts +10 -0
- package/build/treb-grid/src/layout/mock-layout.js +37 -0
- package/build/treb-grid/src/layout/mock-layout.js.map +1 -0
- package/build/treb-grid/src/render/selection-renderer.d.ts +97 -0
- package/build/treb-grid/src/render/selection-renderer.js +315 -0
- package/build/treb-grid/src/render/selection-renderer.js.map +1 -0
- package/build/treb-grid/src/render/svg_header_overlay.d.ts +20 -0
- package/build/treb-grid/src/render/svg_header_overlay.js +76 -0
- package/build/treb-grid/src/render/svg_header_overlay.js.map +1 -0
- package/build/treb-grid/src/render/svg_selection_block.d.ts +27 -0
- package/build/treb-grid/src/render/svg_selection_block.js +106 -0
- package/build/treb-grid/src/render/svg_selection_block.js.map +1 -0
- package/build/treb-grid/src/render/tile_renderer.d.ts +121 -0
- package/build/treb-grid/src/render/tile_renderer.js +1609 -0
- package/build/treb-grid/src/render/tile_renderer.js.map +1 -0
- package/build/treb-grid/src/types/border_constants.d.ts +9 -0
- package/build/treb-grid/src/types/border_constants.js +34 -0
- package/build/treb-grid/src/types/border_constants.js.map +1 -0
- package/build/treb-grid/src/types/clipboard_data.d.ts +11 -0
- package/build/treb-grid/src/types/clipboard_data.js +22 -0
- package/build/treb-grid/src/types/clipboard_data.js.map +1 -0
- package/build/treb-grid/src/types/clipboard_data2.d.ts +46 -0
- package/build/treb-grid/src/types/clipboard_data2.js +22 -0
- package/build/treb-grid/src/types/clipboard_data2.js.map +1 -0
- package/build/treb-grid/src/types/drag_mask.d.ts +10 -0
- package/build/treb-grid/src/types/drag_mask.js +78 -0
- package/build/treb-grid/src/types/drag_mask.js.map +1 -0
- package/build/treb-grid/src/types/external_editor_config.d.ts +33 -0
- package/build/treb-grid/src/types/external_editor_config.js +22 -0
- package/build/treb-grid/src/types/external_editor_config.js.map +1 -0
- package/build/treb-grid/src/types/grid.d.ts +806 -0
- package/build/treb-grid/src/types/grid.js +6410 -0
- package/build/treb-grid/src/types/grid.js.map +1 -0
- package/build/treb-grid/src/types/grid_base.d.ts +442 -0
- package/build/treb-grid/src/types/grid_base.js +3523 -0
- package/build/treb-grid/src/types/grid_base.js.map +1 -0
- package/build/treb-grid/src/types/grid_command.d.ts +408 -0
- package/build/treb-grid/src/types/grid_command.js +75 -0
- package/build/treb-grid/src/types/grid_command.js.map +1 -0
- package/build/treb-grid/src/types/grid_events.d.ts +93 -0
- package/build/treb-grid/src/types/grid_events.js +36 -0
- package/build/treb-grid/src/types/grid_events.js.map +1 -0
- package/build/treb-grid/src/types/grid_options.d.ts +50 -0
- package/build/treb-grid/src/types/grid_options.js +34 -0
- package/build/treb-grid/src/types/grid_options.js.map +1 -0
- package/build/treb-grid/src/types/scale-control.d.ts +21 -0
- package/build/treb-grid/src/types/scale-control.js +148 -0
- package/build/treb-grid/src/types/scale-control.js.map +1 -0
- package/build/treb-grid/src/types/set_range_options.d.ts +24 -0
- package/build/treb-grid/src/types/set_range_options.js +22 -0
- package/build/treb-grid/src/types/set_range_options.js.map +1 -0
- package/build/treb-grid/src/types/tab_bar.d.ts +84 -0
- package/build/treb-grid/src/types/tab_bar.js +426 -0
- package/build/treb-grid/src/types/tab_bar.js.map +1 -0
- package/build/treb-grid/src/types/tile.d.ts +29 -0
- package/build/treb-grid/src/types/tile.js +22 -0
- package/build/treb-grid/src/types/tile.js.map +1 -0
- package/build/treb-grid/src/types/update_flags.d.ts +48 -0
- package/build/treb-grid/src/types/update_flags.js +22 -0
- package/build/treb-grid/src/types/update_flags.js.map +1 -0
- package/build/treb-grid/src/util/fontmetrics.d.ts +21 -0
- package/build/treb-grid/src/util/fontmetrics.js +82 -0
- package/build/treb-grid/src/util/fontmetrics.js.map +1 -0
- package/build/treb-grid/src/util/ua.d.ts +33 -0
- package/build/treb-grid/src/util/ua.js +86 -0
- package/build/treb-grid/src/util/ua.js.map +1 -0
- package/build/treb-parser/src/csv-parser.d.ts +13 -0
- package/build/treb-parser/src/csv-parser.js +107 -0
- package/build/treb-parser/src/csv-parser.js.map +1 -0
- package/build/treb-parser/src/index.d.ts +4 -0
- package/build/treb-parser/src/index.js +25 -0
- package/build/treb-parser/src/index.js.map +1 -0
- package/build/treb-parser/src/md-parser.d.ts +97 -0
- package/build/treb-parser/src/md-parser.js +403 -0
- package/build/treb-parser/src/md-parser.js.map +1 -0
- package/build/treb-parser/src/parser-types.d.ts +345 -0
- package/build/treb-parser/src/parser-types.js +53 -0
- package/build/treb-parser/src/parser-types.js.map +1 -0
- package/build/treb-parser/src/parser.d.ts +422 -0
- package/build/treb-parser/src/parser.js +2418 -0
- package/build/treb-parser/src/parser.js.map +1 -0
- package/build/treb-utils/src/event_source.d.ts +34 -0
- package/build/treb-utils/src/event_source.js +110 -0
- package/build/treb-utils/src/event_source.js.map +1 -0
- package/build/treb-utils/src/ievent_source.d.ts +9 -0
- package/build/treb-utils/src/ievent_source.js +22 -0
- package/build/treb-utils/src/ievent_source.js.map +1 -0
- package/build/treb-utils/src/index.d.ts +6 -0
- package/build/treb-utils/src/index.js +30 -0
- package/build/treb-utils/src/index.js.map +1 -0
- package/build/treb-utils/src/measurement.d.ts +42 -0
- package/build/treb-utils/src/measurement.js +145 -0
- package/build/treb-utils/src/measurement.js.map +1 -0
- package/build/treb-utils/src/scale.d.ts +16 -0
- package/build/treb-utils/src/scale.js +106 -0
- package/build/treb-utils/src/scale.js.map +1 -0
- package/build/treb-utils/src/serialize_html.d.ts +5 -0
- package/build/treb-utils/src/serialize_html.js +128 -0
- package/build/treb-utils/src/serialize_html.js.map +1 -0
- package/build/treb-utils/src/validate_uri.d.ts +20 -0
- package/build/treb-utils/src/validate_uri.js +55 -0
- package/build/treb-utils/src/validate_uri.js.map +1 -0
- package/dist/{chunk-XD5PEZBZ.mjs → chunk-E35ONJUS.mjs} +1 -1
- package/dist/treb-export-worker.mjs +2 -2
- package/dist/treb-spreadsheet.mjs +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,2039 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of TREB.
|
|
3
|
+
*
|
|
4
|
+
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
+
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
+
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
+
* later version.
|
|
8
|
+
*
|
|
9
|
+
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
+
* details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License along
|
|
15
|
+
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
* Copyright 2022-2026 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* rewrite of export. we'll still use a template, but do more direct
|
|
23
|
+
* writing and less DOM manipulation. this should be cleaner in the long
|
|
24
|
+
* run, but it will take a bit more work.
|
|
25
|
+
*/
|
|
26
|
+
// import JSZip from 'jszip';
|
|
27
|
+
import * as Base64JS from 'base64-js';
|
|
28
|
+
import { PixelsToColumnWidth } from './column-width';
|
|
29
|
+
const XMLDeclaration = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n`;
|
|
30
|
+
import { template } from './template-2';
|
|
31
|
+
import { Area, Cells, ValueType, Style, IsHTMLColor, IsThemeColor, ThemeColorIndex } from 'treb-base-types';
|
|
32
|
+
import { SharedStrings } from './shared-strings';
|
|
33
|
+
import { StyleCache } from './workbook-style';
|
|
34
|
+
import { Theme } from './workbook-theme';
|
|
35
|
+
import { AddRel } from './relationship';
|
|
36
|
+
import { PatchXMLBuilder } from './xml-utils';
|
|
37
|
+
import { Parser } from 'treb-parser';
|
|
38
|
+
import { Chart } from './drawing/chart';
|
|
39
|
+
import { Drawing } from './drawing/drawing';
|
|
40
|
+
import { ConditionalFormatOperators } from './workbook';
|
|
41
|
+
import { ZipWrapper } from './zip-wrapper';
|
|
42
|
+
import { ooxml_parser } from './ooxml';
|
|
43
|
+
/*
|
|
44
|
+
interface NestedDOMType {
|
|
45
|
+
[index: string]: string|number|NestedDOMType|NestedDOMType[];
|
|
46
|
+
}
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* utility function. given a Color object (our Color, from Style) returns
|
|
50
|
+
* an XML structure like
|
|
51
|
+
*
|
|
52
|
+
* { a$: { rgb: '123456 }}
|
|
53
|
+
*
|
|
54
|
+
* or
|
|
55
|
+
*
|
|
56
|
+
* { a$: { theme: 1, tint: .5 }}
|
|
57
|
+
*
|
|
58
|
+
*/
|
|
59
|
+
const ColorAttrs = (color) => {
|
|
60
|
+
if (IsHTMLColor(color)) {
|
|
61
|
+
return {
|
|
62
|
+
a$: {
|
|
63
|
+
rgb: `FF` + color.text.substring(1),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (IsThemeColor(color)) {
|
|
68
|
+
return {
|
|
69
|
+
a$: {
|
|
70
|
+
theme: ThemeColorIndex(color),
|
|
71
|
+
tint: color.tint,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
};
|
|
77
|
+
export class Exporter {
|
|
78
|
+
// public zip?: JSZip;
|
|
79
|
+
zip;
|
|
80
|
+
xmloptions = {
|
|
81
|
+
format: true,
|
|
82
|
+
attributesGroupName: 'a$',
|
|
83
|
+
textNodeName: 't$',
|
|
84
|
+
ignoreAttributes: false,
|
|
85
|
+
suppressEmptyNode: true,
|
|
86
|
+
// OK so now I am turning this off altogether. not sure why we
|
|
87
|
+
// were using it in the first place -- which is a problem, since
|
|
88
|
+
// there's probably something I don't know.
|
|
89
|
+
/*
|
|
90
|
+
tagValueProcessor: (name: string, a: string) => {
|
|
91
|
+
|
|
92
|
+
// we were including unsafe symbols here, but that was
|
|
93
|
+
// resulting in double-encoding. not sure why this is
|
|
94
|
+
// here at all, unless we need it for unicode? in any
|
|
95
|
+
// event (atm) allowing unsafe symbols is sufficient
|
|
96
|
+
|
|
97
|
+
return a; // ?
|
|
98
|
+
|
|
99
|
+
return (typeof a === 'string') ? he.encode(a, { useNamedReferences: true, allowUnsafeSymbols: true }) : a;
|
|
100
|
+
},
|
|
101
|
+
*/
|
|
102
|
+
// there's a "isAttributeValue" for decode, but no option for encode?
|
|
103
|
+
// we only want to encode ' and "
|
|
104
|
+
// attrValueProcessor: a => (typeof a === 'string') ? he.encode(a, { useNamedReferences: true }) : a,
|
|
105
|
+
// why is this double-encoding? is there arlready implicit encoding? (...)
|
|
106
|
+
// there must have been a reason we used it in the first place... but I don't know what that was.
|
|
107
|
+
// do we need to encode apostrophes?
|
|
108
|
+
// attributeValueProcessor: (name: string, a: string) => (typeof a === 'string') ?
|
|
109
|
+
// a.replace(/"/g, '"').replace(/'/g, ''') : a,
|
|
110
|
+
};
|
|
111
|
+
// public xmlparser = new xmlparser.j2xParser(this.xmloptions);
|
|
112
|
+
xmlbuilder1 = PatchXMLBuilder(this.xmloptions);
|
|
113
|
+
// public xmlparser2 = new XMLParser(XMLOptions2);
|
|
114
|
+
// FIXME: need a way to share/pass parser flags
|
|
115
|
+
parser = new Parser();
|
|
116
|
+
decorated_functions = {};
|
|
117
|
+
/*
|
|
118
|
+
constructor() {
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
*/
|
|
122
|
+
/**
|
|
123
|
+
* init used to load the template file. we added a parameter to
|
|
124
|
+
* pass in the list of functions that need decoration (_xlfn).
|
|
125
|
+
*
|
|
126
|
+
* @param decorated_functions
|
|
127
|
+
*/
|
|
128
|
+
Init(decorated_functions = {}) {
|
|
129
|
+
for (const key of Object.keys(decorated_functions)) {
|
|
130
|
+
this.decorated_functions[key.toLowerCase()] = decorated_functions[key]; // normalized
|
|
131
|
+
}
|
|
132
|
+
const parsed = Base64JS.toByteArray(template);
|
|
133
|
+
this.zip = new ZipWrapper(parsed.buffer);
|
|
134
|
+
}
|
|
135
|
+
WriteRels(rels, path, dump = false) {
|
|
136
|
+
if (!this.zip) {
|
|
137
|
+
throw new Error('missing zip');
|
|
138
|
+
}
|
|
139
|
+
const keys = Object.keys(rels);
|
|
140
|
+
const dom = {
|
|
141
|
+
Relationships: {
|
|
142
|
+
a$: {
|
|
143
|
+
xmlns: 'http://schemas.openxmlformats.org/package/2006/relationships',
|
|
144
|
+
},
|
|
145
|
+
Relationship: keys.map(key => {
|
|
146
|
+
const rel = rels[key];
|
|
147
|
+
const a$ = {
|
|
148
|
+
Id: rel.id,
|
|
149
|
+
Target: rel.target,
|
|
150
|
+
Type: rel.type,
|
|
151
|
+
};
|
|
152
|
+
if (rel.mode) {
|
|
153
|
+
a$.TargetMode = rel.mode;
|
|
154
|
+
}
|
|
155
|
+
return { a$ };
|
|
156
|
+
}),
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
const xml = XMLDeclaration + this.xmlbuilder1.build(dom);
|
|
160
|
+
// console.info({dom, xml});
|
|
161
|
+
if (dump) {
|
|
162
|
+
console.info(xml);
|
|
163
|
+
}
|
|
164
|
+
this.zip.Set(path, xml);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* format and write styles
|
|
168
|
+
*/
|
|
169
|
+
WriteStyleCache(style_cache) {
|
|
170
|
+
if (!this.zip) {
|
|
171
|
+
throw new Error('missing zip');
|
|
172
|
+
}
|
|
173
|
+
const ColorAttributes = (color) => {
|
|
174
|
+
// we could just pass through except that we have argb and excel has rgb
|
|
175
|
+
const attrs = {};
|
|
176
|
+
if (color.indexed !== undefined) {
|
|
177
|
+
attrs.indexed = color.indexed;
|
|
178
|
+
}
|
|
179
|
+
if (color.theme !== undefined) {
|
|
180
|
+
attrs.theme = color.theme;
|
|
181
|
+
}
|
|
182
|
+
if (color.tint !== undefined) {
|
|
183
|
+
attrs.tint = color.tint;
|
|
184
|
+
}
|
|
185
|
+
if (color.argb !== undefined) {
|
|
186
|
+
attrs.rgb = color.argb;
|
|
187
|
+
}
|
|
188
|
+
return attrs;
|
|
189
|
+
};
|
|
190
|
+
const xfs = style_cache.cell_xfs.map(xf => {
|
|
191
|
+
const block = {
|
|
192
|
+
a$: {
|
|
193
|
+
numFmtId: xf.number_format,
|
|
194
|
+
fontId: xf.font,
|
|
195
|
+
fillId: xf.fill,
|
|
196
|
+
borderId: xf.border,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
if (xf.horizontal_alignment || xf.vertical_alignment || xf.wrap_text || xf.indent) {
|
|
200
|
+
const attrs = {};
|
|
201
|
+
if (xf.horizontal_alignment) {
|
|
202
|
+
attrs.horizontal = xf.horizontal_alignment;
|
|
203
|
+
}
|
|
204
|
+
if (xf.vertical_alignment) {
|
|
205
|
+
attrs.vertical = xf.vertical_alignment;
|
|
206
|
+
}
|
|
207
|
+
if (xf.wrap_text) {
|
|
208
|
+
attrs.wrapText = 1;
|
|
209
|
+
}
|
|
210
|
+
if (xf.indent && xf.horizontal_alignment !== 'center') {
|
|
211
|
+
attrs.indent = xf.indent;
|
|
212
|
+
}
|
|
213
|
+
block.alignment = { a$: attrs };
|
|
214
|
+
}
|
|
215
|
+
return block;
|
|
216
|
+
});
|
|
217
|
+
const BorderColorAttributes = (edge) => {
|
|
218
|
+
if (edge.color) {
|
|
219
|
+
return { indexed: edge.color };
|
|
220
|
+
}
|
|
221
|
+
if (edge.rgba) {
|
|
222
|
+
return { rgb: edge.rgba };
|
|
223
|
+
}
|
|
224
|
+
if (typeof edge.theme !== 'undefined') {
|
|
225
|
+
return {
|
|
226
|
+
theme: edge.theme,
|
|
227
|
+
tint: edge.tint,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return undefined;
|
|
231
|
+
};
|
|
232
|
+
const borders = style_cache.borders.map(border => {
|
|
233
|
+
const top = {};
|
|
234
|
+
const left = {};
|
|
235
|
+
const right = {};
|
|
236
|
+
const bottom = {};
|
|
237
|
+
const diagonal = {};
|
|
238
|
+
if (border.top.style) {
|
|
239
|
+
top.a$ = {
|
|
240
|
+
style: border.top.style,
|
|
241
|
+
};
|
|
242
|
+
const attrs = BorderColorAttributes(border.top);
|
|
243
|
+
if (attrs) {
|
|
244
|
+
top.color = { a$: attrs };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (border.left.style) {
|
|
248
|
+
left.a$ = {
|
|
249
|
+
style: border.left.style,
|
|
250
|
+
};
|
|
251
|
+
const attrs = BorderColorAttributes(border.left);
|
|
252
|
+
if (attrs) {
|
|
253
|
+
left.color = { a$: attrs };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (border.bottom.style) {
|
|
257
|
+
bottom.a$ = {
|
|
258
|
+
style: border.bottom.style,
|
|
259
|
+
};
|
|
260
|
+
const attrs = BorderColorAttributes(border.bottom);
|
|
261
|
+
if (attrs) {
|
|
262
|
+
bottom.color = { a$: attrs };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (border.right.style) {
|
|
266
|
+
right.a$ = {
|
|
267
|
+
style: border.right.style,
|
|
268
|
+
};
|
|
269
|
+
const attrs = BorderColorAttributes(border.right);
|
|
270
|
+
if (attrs) {
|
|
271
|
+
right.color = { a$: attrs };
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (border.diagonal.style) {
|
|
275
|
+
diagonal.a$ = {
|
|
276
|
+
style: border.diagonal.style,
|
|
277
|
+
};
|
|
278
|
+
const attrs = BorderColorAttributes(border.diagonal);
|
|
279
|
+
if (attrs) {
|
|
280
|
+
diagonal.color = { a$: attrs };
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
left,
|
|
285
|
+
right,
|
|
286
|
+
top,
|
|
287
|
+
bottom,
|
|
288
|
+
diagonal,
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
const fills = style_cache.fills.map(fill => ({
|
|
292
|
+
patternFill: {
|
|
293
|
+
a$: {
|
|
294
|
+
patternType: (fill.pattern_gray !== undefined) ? `gray${fill.pattern_gray}` : fill.pattern_type,
|
|
295
|
+
},
|
|
296
|
+
bgColor: fill.bg_color ? {
|
|
297
|
+
a$: ColorAttributes(fill.bg_color),
|
|
298
|
+
} : undefined,
|
|
299
|
+
fgColor: fill.fg_color ? {
|
|
300
|
+
a$: ColorAttributes(fill.fg_color),
|
|
301
|
+
} : undefined,
|
|
302
|
+
},
|
|
303
|
+
}));
|
|
304
|
+
const ValProp = (prop) => {
|
|
305
|
+
if (typeof prop === 'undefined') {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
a$: {
|
|
310
|
+
val: prop,
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
};
|
|
314
|
+
// console.info({style_cache});
|
|
315
|
+
const fonts = style_cache.fonts.map(font => {
|
|
316
|
+
return {
|
|
317
|
+
// flags
|
|
318
|
+
b: font.bold ? '' : undefined,
|
|
319
|
+
i: font.italic ? '' : undefined,
|
|
320
|
+
u: font.underline ? '' : undefined,
|
|
321
|
+
strike: font.strike ? '' : undefined,
|
|
322
|
+
// 'val' props
|
|
323
|
+
sz: ValProp(font.size),
|
|
324
|
+
family: ValProp(font.family),
|
|
325
|
+
name: ValProp(font.name),
|
|
326
|
+
scheme: ValProp(font.scheme),
|
|
327
|
+
color: font.color_argb ? {
|
|
328
|
+
a$: { rgb: font.color_argb },
|
|
329
|
+
} : (typeof font.color_theme !== 'undefined') ? {
|
|
330
|
+
a$: {
|
|
331
|
+
theme: font.color_theme,
|
|
332
|
+
tint: font.color_tint,
|
|
333
|
+
},
|
|
334
|
+
} : undefined,
|
|
335
|
+
};
|
|
336
|
+
});
|
|
337
|
+
const WithCount = (key, source) => {
|
|
338
|
+
if (source.length) {
|
|
339
|
+
return {
|
|
340
|
+
a$: { count: source.length },
|
|
341
|
+
[key]: source,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
return undefined;
|
|
345
|
+
};
|
|
346
|
+
const dxf = style_cache.dxf_styles.map(style => {
|
|
347
|
+
const entry = {};
|
|
348
|
+
if (style.text || style.bold || style.italic || style.underline) {
|
|
349
|
+
entry.font = {
|
|
350
|
+
b: style.bold ? {} : undefined,
|
|
351
|
+
i: style.italic ? {} : undefined,
|
|
352
|
+
u: style.underline ? {} : undefined,
|
|
353
|
+
strike: style.strike ? {} : undefined,
|
|
354
|
+
color: ColorAttrs(style.text),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
if (style.fill) {
|
|
358
|
+
entry.fill = {
|
|
359
|
+
patternFill: {
|
|
360
|
+
bgColor: ColorAttrs(style.fill),
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
;
|
|
365
|
+
return entry;
|
|
366
|
+
});
|
|
367
|
+
// console.info({dxf});
|
|
368
|
+
const dom = {
|
|
369
|
+
styleSheet: {
|
|
370
|
+
a$: {
|
|
371
|
+
'xmlns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
|
|
372
|
+
'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',
|
|
373
|
+
'mc:Ignorable': 'x14ac x16r2 xr',
|
|
374
|
+
'xmlns:x14ac': 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac',
|
|
375
|
+
'xmlns:x16r2': 'http://schemas.microsoft.com/office/spreadsheetml/2015/02/main',
|
|
376
|
+
'xmlns:xr': 'http://schemas.microsoft.com/office/spreadsheetml/2014/revision',
|
|
377
|
+
},
|
|
378
|
+
// we're only adding elements here if they are not empty, but in
|
|
379
|
+
// practice only numFmts can be empty (because there are implicit
|
|
380
|
+
// formats); everything else has a default 0 entry
|
|
381
|
+
numFmts: style_cache.number_formats.length ? {
|
|
382
|
+
a$: { count: style_cache.number_formats.length },
|
|
383
|
+
numFmt: style_cache.number_formats.map(format => {
|
|
384
|
+
return {
|
|
385
|
+
a$: {
|
|
386
|
+
numFmtId: format.id,
|
|
387
|
+
formatCode: format.format,
|
|
388
|
+
},
|
|
389
|
+
};
|
|
390
|
+
}),
|
|
391
|
+
} : undefined,
|
|
392
|
+
fonts: WithCount('font', fonts),
|
|
393
|
+
fills: WithCount('fill', fills),
|
|
394
|
+
borders: WithCount('border', borders),
|
|
395
|
+
cellXfs: WithCount('xf', xfs),
|
|
396
|
+
dxfs: WithCount('dxf', dxf),
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
const xml = XMLDeclaration + this.xmlbuilder1.build(dom);
|
|
400
|
+
// console.info(xml);
|
|
401
|
+
this.zip?.Set('xl/styles.xml', xml);
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* format and write shared strings file to the zip archive. this will
|
|
405
|
+
* replace any existing shared strings file.
|
|
406
|
+
*/
|
|
407
|
+
WriteSharedStrings(shared_strings) {
|
|
408
|
+
// console.info({shared_strings});
|
|
409
|
+
if (!this.zip) {
|
|
410
|
+
throw new Error('missing zip');
|
|
411
|
+
}
|
|
412
|
+
const dom = {
|
|
413
|
+
sst: {
|
|
414
|
+
a$: {
|
|
415
|
+
'xmlns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
|
|
416
|
+
count: shared_strings.strings.length,
|
|
417
|
+
uniqueCount: shared_strings.strings.length,
|
|
418
|
+
},
|
|
419
|
+
si: [
|
|
420
|
+
...shared_strings.strings.map(t => { return { t }; }),
|
|
421
|
+
],
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
const xml = XMLDeclaration + this.xmlbuilder1.build(dom);
|
|
425
|
+
// console.info(xml);
|
|
426
|
+
this.zip.Set('xl/sharedStrings.xml', xml);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* FIXME: we might not always need this.
|
|
430
|
+
*/
|
|
431
|
+
SheetStyle(sheet, style_cache) {
|
|
432
|
+
if (!sheet.sheet_style) {
|
|
433
|
+
return 0;
|
|
434
|
+
}
|
|
435
|
+
const options = style_cache.StyleOptionsFromProperties(sheet.sheet_style);
|
|
436
|
+
return style_cache.EnsureStyle(options);
|
|
437
|
+
}
|
|
438
|
+
RowStyle(sheet, style_cache, row) {
|
|
439
|
+
const cell_style_refs = sheet.styles || sheet.cell_style_refs || [];
|
|
440
|
+
const list = [sheet.sheet_style];
|
|
441
|
+
if (sheet.row_style) {
|
|
442
|
+
let style = sheet.row_style[row];
|
|
443
|
+
if (typeof style === 'number') {
|
|
444
|
+
style = cell_style_refs[style];
|
|
445
|
+
if (style) {
|
|
446
|
+
list.push(style);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
else if (style) {
|
|
450
|
+
list.push(style);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
const options = style_cache.StyleOptionsFromProperties(Style.Composite(list));
|
|
454
|
+
return style_cache.EnsureStyle(options);
|
|
455
|
+
}
|
|
456
|
+
ColumnStyle(sheet, style_cache, column) {
|
|
457
|
+
const cell_style_refs = sheet.styles || sheet.cell_style_refs || [];
|
|
458
|
+
const list = [sheet.sheet_style];
|
|
459
|
+
if (sheet.column_style) {
|
|
460
|
+
let style = sheet.column_style[column];
|
|
461
|
+
if (typeof style === 'number') {
|
|
462
|
+
style = cell_style_refs[style];
|
|
463
|
+
if (style) {
|
|
464
|
+
list.push(style);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
else if (style) {
|
|
468
|
+
list.push(style);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
const options = style_cache.StyleOptionsFromProperties(Style.Composite(list));
|
|
472
|
+
return style_cache.EnsureStyle(options);
|
|
473
|
+
}
|
|
474
|
+
StyleFromCell(sheet, style_cache, row, column, style = {}) {
|
|
475
|
+
//if (row === 2 && column === 5)
|
|
476
|
+
// console.info("SFC", JSON.stringify(style, undefined, 2));
|
|
477
|
+
const cell_style_refs = sheet.styles || sheet.cell_style_refs || [];
|
|
478
|
+
const list = [sheet.sheet_style];
|
|
479
|
+
/*
|
|
480
|
+
// should apply to rows, not cells
|
|
481
|
+
|
|
482
|
+
if (sheet.row_pattern && sheet.row_pattern.length) {
|
|
483
|
+
list.push(sheet.row_pattern[row % sheet.row_pattern.length]);
|
|
484
|
+
}
|
|
485
|
+
*/
|
|
486
|
+
// is this backwards, vis a vis our rendering? I think it might be...
|
|
487
|
+
// YES: should be row pattern -> row -> column -> cell [corrected]
|
|
488
|
+
// FIXME: can't we just ask the sheet? (A: no, because we don't have
|
|
489
|
+
// an actual sheet, although we could?)
|
|
490
|
+
// if (sheet.row_style && sheet.row_style[row]) {
|
|
491
|
+
// list.push(sheet.row_style[row]);
|
|
492
|
+
// }
|
|
493
|
+
if (sheet.row_style) {
|
|
494
|
+
let style = sheet.row_style[row];
|
|
495
|
+
if (typeof style === 'number') {
|
|
496
|
+
style = cell_style_refs[style];
|
|
497
|
+
if (style) {
|
|
498
|
+
list.push(style);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
else if (style) {
|
|
502
|
+
list.push(style);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
// this can now be a number, and possibly 0 (?)
|
|
506
|
+
// actually 0 is by default a null style, although that's more of
|
|
507
|
+
// a convention than a hard rule, not sure we should rely on it
|
|
508
|
+
if (sheet.column_style) {
|
|
509
|
+
let style = sheet.column_style[column];
|
|
510
|
+
if (typeof style === 'number') {
|
|
511
|
+
style = cell_style_refs[style];
|
|
512
|
+
if (style) {
|
|
513
|
+
list.push(style);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
else if (style) {
|
|
517
|
+
list.push(style);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
//if (sheet.column_style && sheet.column_style[column]) {
|
|
521
|
+
// list.push(sheet.column_style[column]);
|
|
522
|
+
//}
|
|
523
|
+
/*
|
|
524
|
+
if (cell.ref) {
|
|
525
|
+
list.push(sheet_source.cell_style_refs[cell.ref]);
|
|
526
|
+
}
|
|
527
|
+
else if (cell.style_ref) {
|
|
528
|
+
list.push(sheet_source.cell_style_refs[cell.style_ref]);
|
|
529
|
+
}
|
|
530
|
+
else if (style_map[cell.column] && style_map[cell.column][cell.row]) {
|
|
531
|
+
list.push(style_map[cell.column][cell.row]);
|
|
532
|
+
}
|
|
533
|
+
*/
|
|
534
|
+
list.push(style);
|
|
535
|
+
const options = style_cache.StyleOptionsFromProperties(Style.Composite(list));
|
|
536
|
+
return style_cache.EnsureStyle(options);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* for charts we need addresses to be absolute ($) and ensure there's
|
|
540
|
+
* a sheet name -- use the active sheet if it's not explicitly referenced
|
|
541
|
+
*/
|
|
542
|
+
NormalizeAddress(unit, sheet) {
|
|
543
|
+
const addresses = (unit.type === 'address') ? [unit] : [unit.start, unit.end];
|
|
544
|
+
for (const address of addresses) {
|
|
545
|
+
address.absolute_row = true;
|
|
546
|
+
address.absolute_column = true;
|
|
547
|
+
if (!address.sheet) {
|
|
548
|
+
address.sheet = sheet.name;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
if (unit.type === 'range') {
|
|
552
|
+
unit.end.sheet = undefined;
|
|
553
|
+
}
|
|
554
|
+
unit.label = this.parser.Render(unit);
|
|
555
|
+
return unit; // fluent
|
|
556
|
+
}
|
|
557
|
+
EnsureRange(unit) {
|
|
558
|
+
if (unit.type === 'range') {
|
|
559
|
+
return unit;
|
|
560
|
+
}
|
|
561
|
+
return {
|
|
562
|
+
type: 'range',
|
|
563
|
+
start: unit,
|
|
564
|
+
end: unit,
|
|
565
|
+
label: unit.label,
|
|
566
|
+
id: unit.id,
|
|
567
|
+
position: unit.position,
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* new-style annotation layout (kind of a two-cell anchor) to two-cell anchor
|
|
572
|
+
*/
|
|
573
|
+
AnnotationLayoutToAnchor(layout, sheet) {
|
|
574
|
+
// our offsets are % of cell. their offsets are in excel units,
|
|
575
|
+
// but when the chart is added our method will convert from pixels.
|
|
576
|
+
const address_to_anchor = (corner) => {
|
|
577
|
+
const width = (sheet.column_width && sheet.column_width[corner.address.column]) ?
|
|
578
|
+
sheet.column_width[corner.address.column] : (sheet.default_column_width || 100);
|
|
579
|
+
const height = (sheet.row_height && sheet.row_height[corner.address.row]) ?
|
|
580
|
+
sheet.row_height[corner.address.row] : (sheet.default_row_height || 20);
|
|
581
|
+
return {
|
|
582
|
+
...corner.address,
|
|
583
|
+
row_offset: Math.round(corner.offset.y * height),
|
|
584
|
+
column_offset: Math.round(corner.offset.x * width),
|
|
585
|
+
};
|
|
586
|
+
};
|
|
587
|
+
return {
|
|
588
|
+
from: address_to_anchor(layout.tl),
|
|
589
|
+
to: address_to_anchor(layout.br),
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* convert a rectangle (pixels) to a two-cell anchor. note that
|
|
594
|
+
* our offsets are in pixels, they'll need to be changed to whatever
|
|
595
|
+
* the target units are.
|
|
596
|
+
*/
|
|
597
|
+
AnnotationRectToAnchor(src_rect, sheet) {
|
|
598
|
+
const anchor = {
|
|
599
|
+
from: { row: -1, column: -1 },
|
|
600
|
+
to: { row: -1, column: -1 },
|
|
601
|
+
};
|
|
602
|
+
const annotation_rect = {
|
|
603
|
+
top: 0, left: 0, width: 301, height: 301,
|
|
604
|
+
...src_rect,
|
|
605
|
+
};
|
|
606
|
+
const rect = {
|
|
607
|
+
...annotation_rect, // {top, left, width, height}
|
|
608
|
+
right: annotation_rect.left + annotation_rect.width,
|
|
609
|
+
bottom: annotation_rect.top + annotation_rect.height,
|
|
610
|
+
};
|
|
611
|
+
for (let x = 0, column = 0; column < 1000; column++) {
|
|
612
|
+
const width = (sheet.column_width && sheet.column_width[column]) ? sheet.column_width[column] : (sheet.default_column_width || 100);
|
|
613
|
+
if (anchor.from.column < 0 && rect.left <= x + width) {
|
|
614
|
+
anchor.from.column = column;
|
|
615
|
+
anchor.from.column_offset = (rect.left - x);
|
|
616
|
+
}
|
|
617
|
+
if (anchor.to.column < 0 && rect.right <= x + width) {
|
|
618
|
+
anchor.to.column = column;
|
|
619
|
+
anchor.to.column_offset = (rect.right - x);
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
x += width;
|
|
623
|
+
}
|
|
624
|
+
for (let y = 0, row = 0; row < 1000; row++) {
|
|
625
|
+
const height = (sheet.row_height && sheet.row_height[row]) ? sheet.row_height[row] : (sheet.default_row_height || 20);
|
|
626
|
+
if (anchor.from.row < 0 && rect.top <= y + height) {
|
|
627
|
+
anchor.from.row = row;
|
|
628
|
+
anchor.from.row_offset = (rect.top - y);
|
|
629
|
+
}
|
|
630
|
+
if (anchor.to.row < 0 && rect.bottom <= y + height) {
|
|
631
|
+
anchor.to.row = row;
|
|
632
|
+
anchor.to.row_offset = (rect.bottom - y);
|
|
633
|
+
break;
|
|
634
|
+
}
|
|
635
|
+
y += height;
|
|
636
|
+
}
|
|
637
|
+
return anchor;
|
|
638
|
+
}
|
|
639
|
+
ParseImages(sheet_source) {
|
|
640
|
+
const images = [];
|
|
641
|
+
for (const annotation of sheet_source.annotations || []) {
|
|
642
|
+
if (annotation.type === 'image' && annotation.data?.src) {
|
|
643
|
+
// this is (should be) a data URI in base64. at least (atm)
|
|
644
|
+
// that's all we support for exporting.
|
|
645
|
+
const src = annotation.data.src;
|
|
646
|
+
const match = src.match(/^data:image\/([^;]*?);base64,/);
|
|
647
|
+
if (match) {
|
|
648
|
+
const data = src.substr(match[0].length);
|
|
649
|
+
const mimetype = match[1];
|
|
650
|
+
const options = {
|
|
651
|
+
data,
|
|
652
|
+
mimetype,
|
|
653
|
+
encoding: 'base64',
|
|
654
|
+
};
|
|
655
|
+
switch (mimetype) {
|
|
656
|
+
case 'svg+xml':
|
|
657
|
+
case 'webp':
|
|
658
|
+
case 'jpeg':
|
|
659
|
+
case 'jpg':
|
|
660
|
+
case 'image/png':
|
|
661
|
+
case 'png':
|
|
662
|
+
case 'gif':
|
|
663
|
+
if (annotation.layout) {
|
|
664
|
+
images.push({
|
|
665
|
+
anchor: this.AnnotationLayoutToAnchor(annotation.layout, sheet_source), options
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
else if (annotation.rect) {
|
|
669
|
+
images.push({
|
|
670
|
+
anchor: this.AnnotationRectToAnchor(annotation.rect, sheet_source), options
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
else {
|
|
674
|
+
console.warn('annotation missing layout');
|
|
675
|
+
}
|
|
676
|
+
break;
|
|
677
|
+
default:
|
|
678
|
+
console.info('unhandled image type', mimetype);
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return images;
|
|
685
|
+
}
|
|
686
|
+
ParseCharts(sheet_source) {
|
|
687
|
+
const charts = [];
|
|
688
|
+
const parse_series = (arg, options, ref) => {
|
|
689
|
+
if (arg.type === 'range') {
|
|
690
|
+
options.data.push(this.NormalizeAddress(arg, sheet_source));
|
|
691
|
+
}
|
|
692
|
+
else if (arg.type === 'call') {
|
|
693
|
+
if (/group/i.test(arg.name)) {
|
|
694
|
+
// recurse
|
|
695
|
+
for (const value of (arg.args || [])) {
|
|
696
|
+
parse_series(value, options, ref ? ref + ` (recurse)` : undefined);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
else if (/series/i.test(arg.name)) {
|
|
700
|
+
const [label, x, y, z] = arg.args; // y is required
|
|
701
|
+
// FIXME: could be address also [x, y]
|
|
702
|
+
if (y && (y.type === 'range' || y.type === 'address')) {
|
|
703
|
+
options.data.push(this.EnsureRange(this.NormalizeAddress(y, sheet_source)));
|
|
704
|
+
if (label) {
|
|
705
|
+
if (!options.names) {
|
|
706
|
+
options.names = [];
|
|
707
|
+
}
|
|
708
|
+
if (label.type === 'address') {
|
|
709
|
+
this.NormalizeAddress(label, sheet_source);
|
|
710
|
+
}
|
|
711
|
+
if (label.type === 'range') {
|
|
712
|
+
this.NormalizeAddress(label.start, sheet_source);
|
|
713
|
+
options.names[options.data.length - 1] = label.start;
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
options.names[options.data.length - 1] = label;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
if (!options.labels2) {
|
|
720
|
+
options.labels2 = [];
|
|
721
|
+
}
|
|
722
|
+
if (x && (x.type === 'range' || x.type === 'address')) {
|
|
723
|
+
options.labels2[options.data.length - 1] = this.EnsureRange(this.NormalizeAddress(x, sheet_source));
|
|
724
|
+
}
|
|
725
|
+
if (z && (z.type === 'range' || z.type === 'address')) {
|
|
726
|
+
if (!options.labels3) {
|
|
727
|
+
options.labels3 = [];
|
|
728
|
+
}
|
|
729
|
+
options.labels3[options.data.length - 1] = this.EnsureRange(this.NormalizeAddress(z, sheet_source));
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
console.info('invalid series missing Y', { y, arg, ref });
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
for (const annotation of sheet_source.annotations || []) {
|
|
739
|
+
const parse_result = this.parser.Parse(annotation.formula || '');
|
|
740
|
+
if (parse_result.expression && parse_result.expression.type === 'call') {
|
|
741
|
+
let type = ''; // FIXME
|
|
742
|
+
switch (parse_result.expression.name.toLowerCase()) {
|
|
743
|
+
case 'line.chart':
|
|
744
|
+
type = 'scatter';
|
|
745
|
+
break;
|
|
746
|
+
case 'bubble.chart':
|
|
747
|
+
type = 'bubble';
|
|
748
|
+
break;
|
|
749
|
+
case 'scatter.line':
|
|
750
|
+
type = 'scatter2';
|
|
751
|
+
break;
|
|
752
|
+
case 'donut.chart':
|
|
753
|
+
type = 'donut';
|
|
754
|
+
break;
|
|
755
|
+
case 'bar.chart':
|
|
756
|
+
type = 'bar';
|
|
757
|
+
break;
|
|
758
|
+
case 'column.chart':
|
|
759
|
+
type = 'column';
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
if (type === 'column' || type === 'donut' || type === 'bar' || type === 'scatter' || type === 'scatter2' || type === 'bubble') {
|
|
763
|
+
const options = { type, data: [] };
|
|
764
|
+
const title_index = (type === 'scatter2' || type === 'bubble') ? 1 : 2;
|
|
765
|
+
const title_arg = parse_result.expression.args[title_index];
|
|
766
|
+
if (title_arg && title_arg.type === 'literal') {
|
|
767
|
+
options.title = title_arg;
|
|
768
|
+
}
|
|
769
|
+
else if (title_arg && title_arg.type === 'address') {
|
|
770
|
+
options.title = this.NormalizeAddress(title_arg, sheet_source);
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
// FIXME: formula here will not work. we need to bring
|
|
774
|
+
// a calculator into this class? (!) or somehow cache the value...
|
|
775
|
+
// console.info('chart title arg', title_arg)
|
|
776
|
+
}
|
|
777
|
+
// we changed our Series() to Group(), and then added a new Series()
|
|
778
|
+
// function which adds data labels and per-series X values... will
|
|
779
|
+
// need to incorporate somehow. for now, just s/series/group to get
|
|
780
|
+
// the data in the chart
|
|
781
|
+
// oh we already did that... duh
|
|
782
|
+
if (parse_result.expression.args[0]) {
|
|
783
|
+
const arg0 = parse_result.expression.args[0];
|
|
784
|
+
if (type === 'scatter2' || type === 'bar' || type === 'column' || type === 'scatter' || type === 'bubble') {
|
|
785
|
+
parse_series(arg0, options, sheet_source.name);
|
|
786
|
+
}
|
|
787
|
+
else if (arg0.type === 'range') {
|
|
788
|
+
options.data.push(this.NormalizeAddress(arg0, sheet_source));
|
|
789
|
+
}
|
|
790
|
+
// so the next cases cannot happen? (...) donut? (...)
|
|
791
|
+
else if (arg0.type === 'call' && /group/i.test(arg0.name)) {
|
|
792
|
+
for (const series of arg0.args) {
|
|
793
|
+
// in group, could be a range or a Series()
|
|
794
|
+
if (series.type === 'range') {
|
|
795
|
+
options.data.push(this.NormalizeAddress(series, sheet_source));
|
|
796
|
+
}
|
|
797
|
+
else if (series.type === 'call' && /series/i.test(series.name)) {
|
|
798
|
+
// in Series(), args are (name, X, range of data)
|
|
799
|
+
if (series.args[2] && series.args[2].type === 'range') {
|
|
800
|
+
options.data.push(this.NormalizeAddress(series.args[2], sheet_source));
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
else if (arg0.type === 'call' && /series/i.test(arg0.name)) {
|
|
806
|
+
// another case, single Series()
|
|
807
|
+
if (arg0.args[2] && arg0.args[2].type === 'range') {
|
|
808
|
+
options.data.push(this.NormalizeAddress(arg0.args[2], sheet_source));
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
/*
|
|
812
|
+
else if (arg0.type === 'call' && /series/i.test(arg0.name)) {
|
|
813
|
+
for (const series of arg0.args) {
|
|
814
|
+
if (series.type === 'range') {
|
|
815
|
+
options.data.push(this.NormalizeAddress(series, sheet_source));
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
*/
|
|
820
|
+
}
|
|
821
|
+
if (type !== 'scatter2' && type !== 'bubble') {
|
|
822
|
+
if (parse_result.expression.args[1] && parse_result.expression.args[1].type === 'range') {
|
|
823
|
+
options.labels = this.NormalizeAddress(parse_result.expression.args[1], sheet_source);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (type === 'scatter'
|
|
827
|
+
&& parse_result.expression.args[4]
|
|
828
|
+
&& parse_result.expression.args[4].type === 'literal'
|
|
829
|
+
&& parse_result.expression.args[4].value.toString().toLowerCase() === 'smooth') {
|
|
830
|
+
options.smooth = true;
|
|
831
|
+
}
|
|
832
|
+
else if (type === 'scatter2' && parse_result.expression.args[2]) {
|
|
833
|
+
if (parse_result.expression.args[2].type === 'literal'
|
|
834
|
+
&& /smooth/i.test(parse_result.expression.args[2].value.toString())) {
|
|
835
|
+
options.smooth = true;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
else if (type === 'bubble') {
|
|
839
|
+
// ...
|
|
840
|
+
// console.info({parse_result});
|
|
841
|
+
}
|
|
842
|
+
// FIXME: fix this type (this happened when we switched from annotation
|
|
843
|
+
// class to a data interface)
|
|
844
|
+
const rect = annotation.rect;
|
|
845
|
+
if (annotation.layout) {
|
|
846
|
+
charts.push({
|
|
847
|
+
anchor: this.AnnotationLayoutToAnchor(annotation.layout, sheet_source), options
|
|
848
|
+
});
|
|
849
|
+
// sheet.AddChart(this.AnnotationLayoutToAnchor(annotation.layout, sheet_source), options);
|
|
850
|
+
}
|
|
851
|
+
else if (rect) {
|
|
852
|
+
charts.push({
|
|
853
|
+
anchor: this.AnnotationRectToAnchor(rect, sheet_source), options
|
|
854
|
+
});
|
|
855
|
+
// sheet.AddChart(this.AnnotationRectToAnchor(annotation.rect, sheet_source), options);
|
|
856
|
+
}
|
|
857
|
+
else {
|
|
858
|
+
console.warn('annotation missing layout');
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
return charts;
|
|
864
|
+
}
|
|
865
|
+
FormulaText(text, context) {
|
|
866
|
+
// let mared = false;
|
|
867
|
+
if (text[0] !== '=') {
|
|
868
|
+
return text;
|
|
869
|
+
}
|
|
870
|
+
const parse_result = this.parser.Parse(text);
|
|
871
|
+
if (!parse_result.expression) {
|
|
872
|
+
console.warn('parsing function failed');
|
|
873
|
+
console.warn(text);
|
|
874
|
+
return text.substring(1);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
// if (this.decorated_functions.length) {
|
|
878
|
+
{
|
|
879
|
+
this.parser.Walk(parse_result.expression, (unit) => {
|
|
880
|
+
if (unit.type === 'call') {
|
|
881
|
+
// unit.name = unit.name.toUpperCase();
|
|
882
|
+
const lc = unit.name.toLowerCase();
|
|
883
|
+
/*
|
|
884
|
+
for (const test of this.decorated_functions) {
|
|
885
|
+
if (test === lc) {
|
|
886
|
+
unit.name = '_xlfn.' + unit.name;
|
|
887
|
+
break;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
*/
|
|
891
|
+
if (this.decorated_functions[lc]) {
|
|
892
|
+
// mared = true;
|
|
893
|
+
unit.name = this.decorated_functions[lc] + '.' + unit.name;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return true;
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
//if (mared) {
|
|
900
|
+
// console.info("MARED", this.parser.Render(parse_result.expression, undefined, ''));
|
|
901
|
+
//}
|
|
902
|
+
// const x = this.parser.Render(parse_result.expression, undefined, '');
|
|
903
|
+
// console.info("T", text, x);
|
|
904
|
+
const table_name = context.table?.name || '';
|
|
905
|
+
/*
|
|
906
|
+
console.info('tn', table_name);
|
|
907
|
+
const temp = this.parser.Render(parse_result.expression, undefined, '', undefined, undefined, undefined, true, table_name);
|
|
908
|
+
console.info({temp});
|
|
909
|
+
*/
|
|
910
|
+
return this.parser.Render(parse_result.expression, {
|
|
911
|
+
missing: '',
|
|
912
|
+
long_structured_references: true,
|
|
913
|
+
table_name
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
Export(source) {
|
|
918
|
+
// --- create a map --------------------------------------------------------
|
|
919
|
+
// active_sheet, in source, is a sheet ID. we need to map
|
|
920
|
+
// that to an index. luckily we preserve index order. we can
|
|
921
|
+
// do that as a side effect of creating the map, although we
|
|
922
|
+
// will need a loop index.
|
|
923
|
+
let active_sheet = 0;
|
|
924
|
+
const sheet_name_map = [];
|
|
925
|
+
for (let index = 0; index < source.sheet_data.length; index++) {
|
|
926
|
+
const sheet = source.sheet_data[index];
|
|
927
|
+
const id = sheet.id || 0;
|
|
928
|
+
if (id) {
|
|
929
|
+
sheet_name_map[id] = sheet.name || '';
|
|
930
|
+
}
|
|
931
|
+
if (id === source.active_sheet) {
|
|
932
|
+
active_sheet = index;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
// console.info("active sheet", source.active_sheet, active_sheet);
|
|
936
|
+
// --- init workbook globals -----------------------------------------------
|
|
937
|
+
// shared strings, start empty
|
|
938
|
+
const shared_strings = new SharedStrings();
|
|
939
|
+
// style and theme: use the template so we have the base values
|
|
940
|
+
const style_cache = new StyleCache();
|
|
941
|
+
const theme = new Theme();
|
|
942
|
+
let data = this.zip?.Get('xl/theme/theme1.xml');
|
|
943
|
+
theme.FromXML(ooxml_parser.parse(data || '')?.theme);
|
|
944
|
+
// theme.FromXML(this.xmlparser2.parse(data || ''));
|
|
945
|
+
// console.info({data, xml: this.xmlparser2.parse(data)})
|
|
946
|
+
data = this.zip?.Get('xl/styles.xml');
|
|
947
|
+
//style_cache.FromXML(this.xmlparser2.parse(data || ''), theme);
|
|
948
|
+
style_cache.FromXML(ooxml_parser.parse(data || '')?.styleSheet, theme);
|
|
949
|
+
// new flag: we need metadata for dynamic arrays
|
|
950
|
+
let dynamic_array_metadata = false;
|
|
951
|
+
// reset counters
|
|
952
|
+
Drawing.next_drawing_index = 1;
|
|
953
|
+
Chart.next_chart_index = 1;
|
|
954
|
+
const drawings = [];
|
|
955
|
+
// we need to keep track of tables in all sheets
|
|
956
|
+
const global_tables = [];
|
|
957
|
+
// --- now sheets ----------------------------------------------------------
|
|
958
|
+
for (let sheet_index = 0; sheet_index < source.sheet_data.length; sheet_index++) {
|
|
959
|
+
const sheet = source.sheet_data[sheet_index];
|
|
960
|
+
const sheet_rels = {};
|
|
961
|
+
// FIXME: we could, in theory, type this thing...
|
|
962
|
+
const sheet_attributes = {
|
|
963
|
+
'xmlns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
|
|
964
|
+
'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
|
|
965
|
+
'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',
|
|
966
|
+
'mc:Ignorable': 'x14ac xr xr2 xr3',
|
|
967
|
+
'xmlns:x14ac': 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac',
|
|
968
|
+
'xmlns:xr': 'http://schemas.microsoft.com/office/spreadsheetml/2014/revision',
|
|
969
|
+
'xmlns:xr2': 'http://schemas.microsoft.com/office/spreadsheetml/2015/revision2',
|
|
970
|
+
'xmlns:xr3': 'http://schemas.microsoft.com/office/spreadsheetml/2016/revision3',
|
|
971
|
+
'xr:uid': '{D37933E2-499F-4789-8D13-194E11B743FC}',
|
|
972
|
+
};
|
|
973
|
+
const default_row_height = sheet.default_row_height ? (sheet.default_row_height / 20 * 15) : 15;
|
|
974
|
+
// data has different representations. it is either blocked into rows or
|
|
975
|
+
// columns, or a set of individual cells. we could theoretically guarantee
|
|
976
|
+
// a particular encoding if we wanted to (by row would be optimal for excel).
|
|
977
|
+
// but we don't do that at the moment, so let's just unwind it using the
|
|
978
|
+
// standard class (adding support for cell styles)
|
|
979
|
+
const cell_style_refs = sheet.styles || sheet.cell_style_refs || [];
|
|
980
|
+
const cells = new Cells();
|
|
981
|
+
cells.FromJSON(sheet.data, cell_style_refs);
|
|
982
|
+
// console.info({ss: sheet.sheet_style, sheet});
|
|
983
|
+
// these are cells with style but no contents
|
|
984
|
+
for (const entry of sheet.cell_styles) {
|
|
985
|
+
const cell = cells.EnsureCell(entry); // cheating
|
|
986
|
+
if (!cell.style) {
|
|
987
|
+
cell.style = cell_style_refs[entry.ref];
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
// start with an extent from (0, 0). we can shift this as necessary.
|
|
991
|
+
const extent = {
|
|
992
|
+
start: { row: cells.rows + 1, column: cells.columns + 1, },
|
|
993
|
+
end: { row: cells.rows + 1, column: cells.columns + 1, }
|
|
994
|
+
};
|
|
995
|
+
// const FormulaText = (text: string) => (text[0] === '=') ? TranslateFormula(text.substr(1)) : text;
|
|
996
|
+
// cells data is row-major, and sparse.
|
|
997
|
+
// const sheet_data: any = { row: [] };
|
|
998
|
+
const sheet_rows = [];
|
|
999
|
+
const hyperlinks = [];
|
|
1000
|
+
const sparklines = [];
|
|
1001
|
+
const merges = [];
|
|
1002
|
+
const tables = [];
|
|
1003
|
+
// --
|
|
1004
|
+
//
|
|
1005
|
+
// this is a map of column number -> column style. we need this
|
|
1006
|
+
// for two things: (1) so we can skip cells that are empty, but
|
|
1007
|
+
// have a style from the column; and (2) so we can create the list
|
|
1008
|
+
// of columns, including styles.
|
|
1009
|
+
//
|
|
1010
|
+
const column_style_map = [];
|
|
1011
|
+
const sheet_style = this.SheetStyle(sheet, style_cache);
|
|
1012
|
+
for (let r = 0; r < cells.data.length; r++) {
|
|
1013
|
+
const row_style = this.RowStyle(sheet, style_cache, r);
|
|
1014
|
+
if (cells.data[r] && cells.data[r].length) {
|
|
1015
|
+
// push out the extent (reversed)
|
|
1016
|
+
if (r < extent.start.row) {
|
|
1017
|
+
extent.start.row = r;
|
|
1018
|
+
}
|
|
1019
|
+
// row span
|
|
1020
|
+
const span = { start: -1, end: -1 };
|
|
1021
|
+
const row = [];
|
|
1022
|
+
for (let c = 0; c < cells.data[r].length; c++) {
|
|
1023
|
+
if (!column_style_map[c]) {
|
|
1024
|
+
column_style_map[c] = this.ColumnStyle(sheet, style_cache, c);
|
|
1025
|
+
}
|
|
1026
|
+
const cell = cells.data[r][c];
|
|
1027
|
+
if (cell) {
|
|
1028
|
+
// create a table reference at the table head, we can ignore the rest
|
|
1029
|
+
if (cell.table &&
|
|
1030
|
+
cell.table.area.start.row === r &&
|
|
1031
|
+
cell.table.area.start.column === c) {
|
|
1032
|
+
const area = new Area(cell.table.area.start, cell.table.area.end);
|
|
1033
|
+
const global_count = global_tables.length + 1;
|
|
1034
|
+
const path = `../tables/table${global_count}.xml`;
|
|
1035
|
+
// column names must match the text in the column. AND, they
|
|
1036
|
+
// have to be unique. case-insensitive unique! we are not (atm)
|
|
1037
|
+
// enforcing those rules, so we need to enforce them on export.
|
|
1038
|
+
// also, values (and column headers) MUST BE STRINGS.
|
|
1039
|
+
const columns = [];
|
|
1040
|
+
for (let i = 0; i < area.columns; i++) {
|
|
1041
|
+
const header = cells.data[r][c + i];
|
|
1042
|
+
let value = '';
|
|
1043
|
+
if (header.type !== ValueType.string) {
|
|
1044
|
+
if (typeof header.calculated !== 'undefined') {
|
|
1045
|
+
value = (header.calculated).toString();
|
|
1046
|
+
}
|
|
1047
|
+
else if (typeof header.value !== 'undefined') {
|
|
1048
|
+
value = (header.value).toString();
|
|
1049
|
+
}
|
|
1050
|
+
header.type = ValueType.string;
|
|
1051
|
+
header.value = value;
|
|
1052
|
+
}
|
|
1053
|
+
else {
|
|
1054
|
+
value = header.value || '';
|
|
1055
|
+
}
|
|
1056
|
+
if (!value) {
|
|
1057
|
+
value = `Column${i + 1}`;
|
|
1058
|
+
}
|
|
1059
|
+
let proposed = value;
|
|
1060
|
+
let success = false;
|
|
1061
|
+
let index = 1;
|
|
1062
|
+
while (!success) {
|
|
1063
|
+
success = true;
|
|
1064
|
+
inner_loop: for (const check of columns) {
|
|
1065
|
+
if (check.toLowerCase() === proposed.toLowerCase()) {
|
|
1066
|
+
success = false;
|
|
1067
|
+
proposed = `${value}${++index}`;
|
|
1068
|
+
break inner_loop;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
header.value = proposed;
|
|
1073
|
+
columns.push(proposed);
|
|
1074
|
+
}
|
|
1075
|
+
let footers = undefined;
|
|
1076
|
+
if (cell.table.totals_row) {
|
|
1077
|
+
footers = [];
|
|
1078
|
+
for (let i = 0; i < area.columns; i++) {
|
|
1079
|
+
const footer = cells.data[area.end.row][area.start.column + i];
|
|
1080
|
+
if (footer.type) {
|
|
1081
|
+
if (footer.type === ValueType.formula) {
|
|
1082
|
+
footers[i] = {
|
|
1083
|
+
type: 'formula',
|
|
1084
|
+
value: (footer.value || '').toString().substring(1),
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
else {
|
|
1088
|
+
if (footer.type !== ValueType.string) {
|
|
1089
|
+
footer.type = ValueType.string;
|
|
1090
|
+
footer.value = footer.value?.toString() || '';
|
|
1091
|
+
}
|
|
1092
|
+
footers[i] = {
|
|
1093
|
+
type: 'label',
|
|
1094
|
+
value: footer.value,
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
// console.info({footer});
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
// console.info({columns});
|
|
1102
|
+
const description = {
|
|
1103
|
+
rel: AddRel(sheet_rels, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/table', path),
|
|
1104
|
+
index: global_count,
|
|
1105
|
+
ref: area.spreadsheet_label,
|
|
1106
|
+
name: `Table${global_count}`,
|
|
1107
|
+
display_name: `Table${global_count}`,
|
|
1108
|
+
totals_row_shown: 0,
|
|
1109
|
+
totals_row_count: cell.table?.totals_row ? 1 : 0,
|
|
1110
|
+
columns,
|
|
1111
|
+
footers,
|
|
1112
|
+
};
|
|
1113
|
+
if (cell.table.totals_row) {
|
|
1114
|
+
const filter_area = new Area(area.start, {
|
|
1115
|
+
row: area.end.row - 1,
|
|
1116
|
+
column: area.end.column,
|
|
1117
|
+
});
|
|
1118
|
+
description.filterRef = filter_area.spreadsheet_label;
|
|
1119
|
+
}
|
|
1120
|
+
// console.info({description});
|
|
1121
|
+
// this list is used to add tables on this sheet
|
|
1122
|
+
tables.push(description);
|
|
1123
|
+
// but we also need global references to create the files
|
|
1124
|
+
global_tables.push(description);
|
|
1125
|
+
}
|
|
1126
|
+
// merges
|
|
1127
|
+
if (cell.merge_area &&
|
|
1128
|
+
cell.merge_area.start.row === r &&
|
|
1129
|
+
cell.merge_area.start.column === c) {
|
|
1130
|
+
merges.push(new Area(cell.merge_area.start, cell.merge_area.end));
|
|
1131
|
+
}
|
|
1132
|
+
// links
|
|
1133
|
+
if (cell.hyperlink) {
|
|
1134
|
+
const rel = AddRel(sheet_rels, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', cell.hyperlink, 'External');
|
|
1135
|
+
hyperlinks.push({
|
|
1136
|
+
rel, target: cell.hyperlink, address: { row: r, column: c },
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
// short-circuit here
|
|
1140
|
+
if (cell.type === ValueType.formula && /^=?sparkline\./i.test(cell.value)) {
|
|
1141
|
+
sparklines.push({
|
|
1142
|
+
address: { row: r, column: c },
|
|
1143
|
+
formula: cell.value,
|
|
1144
|
+
style: cell.style,
|
|
1145
|
+
});
|
|
1146
|
+
continue;
|
|
1147
|
+
}
|
|
1148
|
+
// push out the extent (reversed)
|
|
1149
|
+
if (c < extent.start.column) {
|
|
1150
|
+
extent.start.column = c;
|
|
1151
|
+
}
|
|
1152
|
+
// update span: end is implicit
|
|
1153
|
+
if (span.start < 0) {
|
|
1154
|
+
span.start = c;
|
|
1155
|
+
}
|
|
1156
|
+
span.end = c;
|
|
1157
|
+
// we have to stack the styles? what if there's no cell style?
|
|
1158
|
+
// there are definitely column styles...
|
|
1159
|
+
// s is style, index into the style table
|
|
1160
|
+
const s = this.StyleFromCell(sheet, style_cache, r, c, cell.style);
|
|
1161
|
+
if (cell.type === ValueType.undefined) {
|
|
1162
|
+
// you can skip if (1) there's a row style, and style === row style;
|
|
1163
|
+
// (2) there's a column style, no row style, and style === column style
|
|
1164
|
+
if ((row_style && s === row_style) ||
|
|
1165
|
+
(!row_style && (column_style_map[c] && s === column_style_map[c]))) {
|
|
1166
|
+
continue; // can skip
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
// v (child element) is the value
|
|
1170
|
+
let v;
|
|
1171
|
+
let t;
|
|
1172
|
+
let f; // string|undefined;
|
|
1173
|
+
switch (cell.type) {
|
|
1174
|
+
case ValueType.formula:
|
|
1175
|
+
f = this.FormulaText(cell.value, cell);
|
|
1176
|
+
switch (cell.calculated_type) {
|
|
1177
|
+
case ValueType.string:
|
|
1178
|
+
v = cell.calculated;
|
|
1179
|
+
t = 'str';
|
|
1180
|
+
break;
|
|
1181
|
+
case ValueType.number:
|
|
1182
|
+
v = cell.calculated;
|
|
1183
|
+
break;
|
|
1184
|
+
case ValueType.boolean:
|
|
1185
|
+
v = (cell.calculated ? 1 : 0);
|
|
1186
|
+
t = 'b';
|
|
1187
|
+
break;
|
|
1188
|
+
}
|
|
1189
|
+
break;
|
|
1190
|
+
case ValueType.string:
|
|
1191
|
+
v = shared_strings.Ensure(cell.value);
|
|
1192
|
+
t = 's'; // shared string
|
|
1193
|
+
break;
|
|
1194
|
+
case ValueType.number:
|
|
1195
|
+
v = cell.value;
|
|
1196
|
+
break;
|
|
1197
|
+
case ValueType.boolean:
|
|
1198
|
+
v = (cell.value ? 1 : 0);
|
|
1199
|
+
t = 'b';
|
|
1200
|
+
break;
|
|
1201
|
+
//default:
|
|
1202
|
+
// v = 0;
|
|
1203
|
+
}
|
|
1204
|
+
if (cell.area && cell.area.start.row === r && cell.area.start.column === c) {
|
|
1205
|
+
if (typeof f === 'string') {
|
|
1206
|
+
f = {
|
|
1207
|
+
t$: f,
|
|
1208
|
+
a$: {
|
|
1209
|
+
t: 'array',
|
|
1210
|
+
ref: cell.area.spreadsheet_label,
|
|
1211
|
+
},
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
let cm = undefined;
|
|
1216
|
+
if (cell.spill && cell.spill.start.row === r && cell.spill.start.column === c) {
|
|
1217
|
+
cm = 1;
|
|
1218
|
+
dynamic_array_metadata = true;
|
|
1219
|
+
if (typeof f === 'string') {
|
|
1220
|
+
f = {
|
|
1221
|
+
t$: f,
|
|
1222
|
+
a$: {
|
|
1223
|
+
t: 'array',
|
|
1224
|
+
ref: cell.spill.spreadsheet_label,
|
|
1225
|
+
},
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
row.push({
|
|
1230
|
+
a$: {
|
|
1231
|
+
r: Area.CellAddressToLabel({ row: r, column: c }),
|
|
1232
|
+
t,
|
|
1233
|
+
// old comment regarding `s`:
|
|
1234
|
+
// we could skip this if it's equal to row style,
|
|
1235
|
+
// or there is no row style and it's equal to column style
|
|
1236
|
+
// or there is no column style and it's equal to sheet style
|
|
1237
|
+
s,
|
|
1238
|
+
cm,
|
|
1239
|
+
},
|
|
1240
|
+
f,
|
|
1241
|
+
v,
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
if (row.length || (row_style && row_style !== sheet_style)) {
|
|
1246
|
+
let customHeight = undefined;
|
|
1247
|
+
let ht = undefined;
|
|
1248
|
+
let s = undefined;
|
|
1249
|
+
let customFormat = undefined;
|
|
1250
|
+
if (sheet.row_height
|
|
1251
|
+
&& (typeof sheet.row_height[r] === 'number')
|
|
1252
|
+
&& sheet.row_height[r] !== sheet.default_row_height) {
|
|
1253
|
+
customHeight = 1;
|
|
1254
|
+
ht = sheet.row_height[r] * 3 / 4;
|
|
1255
|
+
}
|
|
1256
|
+
if (row_style && row_style !== sheet_style) {
|
|
1257
|
+
s = row_style;
|
|
1258
|
+
customFormat = 1;
|
|
1259
|
+
}
|
|
1260
|
+
// sheet_data.row.
|
|
1261
|
+
sheet_rows.push({
|
|
1262
|
+
a$: {
|
|
1263
|
+
r: r + 1,
|
|
1264
|
+
spans: `${span.start + 1}:${span.end + 1}`, // this works out to 0:0 for an empty row, will that work?
|
|
1265
|
+
customHeight,
|
|
1266
|
+
ht,
|
|
1267
|
+
s,
|
|
1268
|
+
customFormat,
|
|
1269
|
+
},
|
|
1270
|
+
c: row,
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
// --- cols ----------------------------------------------------------------
|
|
1276
|
+
// the "cols" element represents column styles and nonstandard column
|
|
1277
|
+
// widths. FIXME: should we put sheet style in here as well? I think so...
|
|
1278
|
+
const column_entries = [];
|
|
1279
|
+
// we only need to include column style if it's !== sheet style,
|
|
1280
|
+
// because we'll have a default entry for columns that have the
|
|
1281
|
+
// sheet style. this is only for columns that are different.
|
|
1282
|
+
for (let c = 0; c < sheet.columns; c++) {
|
|
1283
|
+
const entry = { index: c };
|
|
1284
|
+
if (sheet.column_width
|
|
1285
|
+
&& sheet.default_column_width
|
|
1286
|
+
&& (typeof sheet.column_width[c] === 'number')
|
|
1287
|
+
&& sheet.column_width[c] !== sheet.default_column_width) {
|
|
1288
|
+
entry.width = PixelsToColumnWidth(sheet.column_width[c]);
|
|
1289
|
+
}
|
|
1290
|
+
const style = column_style_map[c];
|
|
1291
|
+
if (style && style !== sheet_style) {
|
|
1292
|
+
entry.style = style;
|
|
1293
|
+
}
|
|
1294
|
+
if (entry.style !== undefined || entry.width !== undefined) {
|
|
1295
|
+
column_entries[c] = entry;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
// we're short-cutting here, these should be arranged in blocks if
|
|
1299
|
+
// there's overlap. not sure how much of an issue that is though.
|
|
1300
|
+
let dom_cols;
|
|
1301
|
+
if (column_entries.length || sheet_style) {
|
|
1302
|
+
const filled = [];
|
|
1303
|
+
const default_column_width = PixelsToColumnWidth(sheet.default_column_width || 90);
|
|
1304
|
+
// FIXME: can merge these two branches
|
|
1305
|
+
{ // if (sheet_style) {
|
|
1306
|
+
let start_index = 0;
|
|
1307
|
+
for (const entry of column_entries) {
|
|
1308
|
+
if (!entry) {
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1311
|
+
// fill with defaults
|
|
1312
|
+
if (sheet_style && (entry.index > start_index + 1)) {
|
|
1313
|
+
filled.push({
|
|
1314
|
+
a$: {
|
|
1315
|
+
min: start_index + 1,
|
|
1316
|
+
max: entry.index,
|
|
1317
|
+
style: sheet_style,
|
|
1318
|
+
width: default_column_width,
|
|
1319
|
+
},
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
filled.push({ a$: {
|
|
1323
|
+
min: entry.index + 1,
|
|
1324
|
+
max: entry.index + 1,
|
|
1325
|
+
style: entry.style === undefined ? sheet_style : entry.style,
|
|
1326
|
+
width: entry.width === undefined ? default_column_width : entry.width,
|
|
1327
|
+
customWidth: entry.width === undefined ? undefined : 1,
|
|
1328
|
+
} });
|
|
1329
|
+
start_index = entry.index;
|
|
1330
|
+
}
|
|
1331
|
+
if (sheet_style && (start_index < 16384)) { // OK, sure why not
|
|
1332
|
+
filled.push({
|
|
1333
|
+
a$: {
|
|
1334
|
+
min: start_index + 1,
|
|
1335
|
+
max: 16384,
|
|
1336
|
+
style: sheet_style,
|
|
1337
|
+
width: default_column_width,
|
|
1338
|
+
},
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
dom_cols = { col: filled };
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
// --- validation ----------------------------------------------------------
|
|
1345
|
+
let dataValidations;
|
|
1346
|
+
if (sheet.data_validations?.length) {
|
|
1347
|
+
dataValidations = {
|
|
1348
|
+
a$: { count: sheet.data_validations.length },
|
|
1349
|
+
dataValidation: sheet.data_validations.map(validation => {
|
|
1350
|
+
const sqref = validation.target.map(target => {
|
|
1351
|
+
return new Area(target.start, target.end).spreadsheet_label;
|
|
1352
|
+
}).join(' ');
|
|
1353
|
+
let formula1 = undefined;
|
|
1354
|
+
if (validation.type === 'range') {
|
|
1355
|
+
const range = {
|
|
1356
|
+
id: 0,
|
|
1357
|
+
type: 'range',
|
|
1358
|
+
label: '', position: 0,
|
|
1359
|
+
start: { ...validation.area.start, absolute_column: true, absolute_row: true, id: 0, label: '', position: 0, type: 'address', },
|
|
1360
|
+
end: { ...validation.area.end, absolute_column: true, absolute_row: true, id: 0, label: '', position: 0, type: 'address', },
|
|
1361
|
+
};
|
|
1362
|
+
if (typeof validation.area.start.sheet_id !== 'undefined') {
|
|
1363
|
+
range.start.sheet = sheet_name_map[validation.area.start.sheet_id];
|
|
1364
|
+
}
|
|
1365
|
+
formula1 = this.parser.Render(range);
|
|
1366
|
+
}
|
|
1367
|
+
else if (validation.type === 'list') {
|
|
1368
|
+
formula1 = `"${validation.list.join(',')}"`;
|
|
1369
|
+
}
|
|
1370
|
+
return {
|
|
1371
|
+
a$: {
|
|
1372
|
+
type: 'list',
|
|
1373
|
+
allowBlank: 1,
|
|
1374
|
+
showInputMessage: 1,
|
|
1375
|
+
showErrorMessage: 1,
|
|
1376
|
+
sqref, // : new Area(validation.address).spreadsheet_label,
|
|
1377
|
+
},
|
|
1378
|
+
formula1,
|
|
1379
|
+
};
|
|
1380
|
+
}),
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
// --- tables ------------------------------------------------------------
|
|
1384
|
+
let tableParts;
|
|
1385
|
+
if (tables.length) {
|
|
1386
|
+
tableParts = {
|
|
1387
|
+
a$: {
|
|
1388
|
+
count: tables.length,
|
|
1389
|
+
},
|
|
1390
|
+
tablePart: tables.map(table => {
|
|
1391
|
+
return {
|
|
1392
|
+
a$: {
|
|
1393
|
+
'r:id': table.rel || '',
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
}),
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
for (const table of tables) {
|
|
1400
|
+
const totals_attributes = {};
|
|
1401
|
+
if (table.totals_row_count) {
|
|
1402
|
+
totals_attributes.totalsRowCount = 1;
|
|
1403
|
+
}
|
|
1404
|
+
const tableColumns = {
|
|
1405
|
+
a$: {
|
|
1406
|
+
count: (table.columns || []).length,
|
|
1407
|
+
},
|
|
1408
|
+
tableColumn: (table.columns || []).map((column, i) => {
|
|
1409
|
+
const footer = (table.footers || [])[i];
|
|
1410
|
+
return {
|
|
1411
|
+
a$: {
|
|
1412
|
+
id: i + 1,
|
|
1413
|
+
name: column || `Column${i + 1}`,
|
|
1414
|
+
totalsRowLabel: footer?.type === 'label' ? footer.value : undefined,
|
|
1415
|
+
totalsRowFunction: footer?.type === 'formula' ? 'custom' : undefined,
|
|
1416
|
+
},
|
|
1417
|
+
totalsRowFormula: footer?.type === 'formula' ? footer.value : undefined,
|
|
1418
|
+
};
|
|
1419
|
+
}),
|
|
1420
|
+
};
|
|
1421
|
+
const table_dom = {
|
|
1422
|
+
table: {
|
|
1423
|
+
a$: {
|
|
1424
|
+
xmlns: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
|
|
1425
|
+
'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',
|
|
1426
|
+
'mc:Ignorable': 'xr xr3',
|
|
1427
|
+
'xmlns:xr': 'http://schemas.microsoft.com/office/spreadsheetml/2014/revision',
|
|
1428
|
+
'xmlns:xr3': 'http://schemas.microsoft.com/office/spreadsheetml/2016/revision3',
|
|
1429
|
+
id: table.index || 0,
|
|
1430
|
+
name: table.name,
|
|
1431
|
+
displayName: table.display_name,
|
|
1432
|
+
...totals_attributes,
|
|
1433
|
+
ref: table.ref,
|
|
1434
|
+
},
|
|
1435
|
+
autoFilter: {
|
|
1436
|
+
a$: {
|
|
1437
|
+
ref: table.filterRef || table.ref,
|
|
1438
|
+
},
|
|
1439
|
+
},
|
|
1440
|
+
tableColumns,
|
|
1441
|
+
tableStyleInfo: {
|
|
1442
|
+
a$: {
|
|
1443
|
+
name: 'TableStyleMedium2',
|
|
1444
|
+
showFirstColumn: 0,
|
|
1445
|
+
showLastColumn: 0,
|
|
1446
|
+
showRowStripes: 1,
|
|
1447
|
+
showColumnStripes: 0,
|
|
1448
|
+
},
|
|
1449
|
+
},
|
|
1450
|
+
},
|
|
1451
|
+
};
|
|
1452
|
+
const xml = XMLDeclaration + this.xmlbuilder1.build(table_dom);
|
|
1453
|
+
// console.info(xml);
|
|
1454
|
+
this.zip?.Set(`xl/tables/table${table.index}.xml`, xml);
|
|
1455
|
+
}
|
|
1456
|
+
// --- conditional formats -----------------------------------------------
|
|
1457
|
+
let conditionalFormatting;
|
|
1458
|
+
if (sheet.conditional_formats?.length) {
|
|
1459
|
+
const format_list = [];
|
|
1460
|
+
let priority_index = 1;
|
|
1461
|
+
const reverse_operator_map = {};
|
|
1462
|
+
const operator_list = Object.entries(ConditionalFormatOperators).map(entry => {
|
|
1463
|
+
reverse_operator_map[entry[1]] = entry[0];
|
|
1464
|
+
return entry[1];
|
|
1465
|
+
});
|
|
1466
|
+
operator_list.sort((a, b) => b.length - a.length);
|
|
1467
|
+
for (const format of sheet.conditional_formats) {
|
|
1468
|
+
let dxf_index = 0;
|
|
1469
|
+
if (format.type !== 'gradient' && format.type !== 'data-bar') {
|
|
1470
|
+
// these are zero-based? I thought everything in there
|
|
1471
|
+
// was 1-based. [A: yes, these are indexed from 0].
|
|
1472
|
+
dxf_index = style_cache.dxf_styles.length;
|
|
1473
|
+
style_cache.dxf_styles.push(format.style);
|
|
1474
|
+
}
|
|
1475
|
+
switch (format.type) {
|
|
1476
|
+
case 'cell-match':
|
|
1477
|
+
{
|
|
1478
|
+
let operator = '';
|
|
1479
|
+
let formula = '';
|
|
1480
|
+
for (const test of operator_list) {
|
|
1481
|
+
if (new RegExp('^' + test + '\\s').test(format.expression)) {
|
|
1482
|
+
operator = reverse_operator_map[test];
|
|
1483
|
+
formula = format.expression.substring(test.length).trim();
|
|
1484
|
+
break;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
if (operator) {
|
|
1488
|
+
format_list.push({
|
|
1489
|
+
a$: { sqref: new Area(format.area.start, format.area.end).spreadsheet_label },
|
|
1490
|
+
cfRule: {
|
|
1491
|
+
a$: { type: 'cellIs', dxfId: dxf_index, operator, priority: priority_index++ },
|
|
1492
|
+
formula,
|
|
1493
|
+
}
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
break;
|
|
1498
|
+
case 'expression':
|
|
1499
|
+
format_list.push({
|
|
1500
|
+
a$: { sqref: new Area(format.area.start, format.area.end).spreadsheet_label },
|
|
1501
|
+
cfRule: {
|
|
1502
|
+
a$: { type: 'expression', dxfId: dxf_index, priority: priority_index++ },
|
|
1503
|
+
formula: format.expression,
|
|
1504
|
+
}
|
|
1505
|
+
});
|
|
1506
|
+
break;
|
|
1507
|
+
case 'duplicate-values':
|
|
1508
|
+
format_list.push({
|
|
1509
|
+
a$: { sqref: new Area(format.area.start, format.area.end).spreadsheet_label },
|
|
1510
|
+
cfRule: {
|
|
1511
|
+
a$: { type: format.unique ? 'uniqueValues' : 'duplicateValues', dxfId: dxf_index, priority: priority_index++ },
|
|
1512
|
+
}
|
|
1513
|
+
});
|
|
1514
|
+
break;
|
|
1515
|
+
case 'gradient':
|
|
1516
|
+
{
|
|
1517
|
+
const cfvo = [];
|
|
1518
|
+
const color = [];
|
|
1519
|
+
for (const stop of format.stops) {
|
|
1520
|
+
if (stop.value === 0) {
|
|
1521
|
+
cfvo.push({ a$: { type: 'min' } });
|
|
1522
|
+
}
|
|
1523
|
+
else if (stop.value === 1) {
|
|
1524
|
+
cfvo.push({ a$: { type: 'max' } });
|
|
1525
|
+
}
|
|
1526
|
+
else {
|
|
1527
|
+
cfvo.push({ a$: { type: 'percentile', val: stop.value * 100 } });
|
|
1528
|
+
}
|
|
1529
|
+
const attrs = ColorAttrs(stop.color);
|
|
1530
|
+
if (attrs) {
|
|
1531
|
+
color.push(attrs);
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
const generated = {
|
|
1535
|
+
a$: { sqref: new Area(format.area.start, format.area.end).spreadsheet_label },
|
|
1536
|
+
cfRule: {
|
|
1537
|
+
a$: { type: 'colorScale', priority: priority_index++ },
|
|
1538
|
+
colorScale: {
|
|
1539
|
+
cfvo,
|
|
1540
|
+
color,
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
};
|
|
1544
|
+
format_list.push(generated);
|
|
1545
|
+
}
|
|
1546
|
+
break;
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
if (format_list.length) {
|
|
1550
|
+
conditionalFormatting = (format_list.length > 1) ? format_list : format_list[0];
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
// --- merges ------------------------------------------------------------
|
|
1554
|
+
let mergeCells;
|
|
1555
|
+
if (merges.length) {
|
|
1556
|
+
mergeCells = {
|
|
1557
|
+
a$: { count: merges.length },
|
|
1558
|
+
mergeCell: merges.map(merge => {
|
|
1559
|
+
return {
|
|
1560
|
+
a$: { ref: merge.spreadsheet_label }
|
|
1561
|
+
};
|
|
1562
|
+
}),
|
|
1563
|
+
};
|
|
1564
|
+
}
|
|
1565
|
+
// --- hyperlinks --------------------------------------------------------
|
|
1566
|
+
let dom_hyperlinks;
|
|
1567
|
+
if (hyperlinks.length) {
|
|
1568
|
+
dom_hyperlinks = {
|
|
1569
|
+
hyperlink: hyperlinks.map(link => {
|
|
1570
|
+
return {
|
|
1571
|
+
a$: {
|
|
1572
|
+
'r:id': link.rel,
|
|
1573
|
+
ref: new Area(link.address).spreadsheet_label,
|
|
1574
|
+
'xr:uid': '{0C6B7792-7EA0-4932-BF15-D49C453C565D}',
|
|
1575
|
+
},
|
|
1576
|
+
};
|
|
1577
|
+
}),
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
// --- sparklines --------------------------------------------------------
|
|
1581
|
+
let extLst;
|
|
1582
|
+
if (sparklines.length) {
|
|
1583
|
+
const groups = {
|
|
1584
|
+
a$: {
|
|
1585
|
+
'xmlns:xm': 'http://schemas.microsoft.com/office/excel/2006/main',
|
|
1586
|
+
},
|
|
1587
|
+
'x14:sparklineGroup': sparklines.map(sparkline => {
|
|
1588
|
+
const result = this.parser.Parse(sparkline.formula);
|
|
1589
|
+
let source = '';
|
|
1590
|
+
if (result.expression
|
|
1591
|
+
&& result.expression.type === 'call'
|
|
1592
|
+
&& result.expression.args.length > 0) {
|
|
1593
|
+
const arg = result.expression.args[0];
|
|
1594
|
+
if (arg.type === 'range' || arg.type === 'address') {
|
|
1595
|
+
const start = (arg.type === 'range') ? arg.start : arg;
|
|
1596
|
+
if (!start.sheet) {
|
|
1597
|
+
if (typeof start.sheet_id !== 'undefined') {
|
|
1598
|
+
start.sheet = sheet_name_map[start.sheet_id];
|
|
1599
|
+
}
|
|
1600
|
+
else {
|
|
1601
|
+
start.sheet = sheet.name;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
source = this.parser.Render(arg);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
const color_series = {
|
|
1608
|
+
rgb: 'FF376092' // default
|
|
1609
|
+
};
|
|
1610
|
+
if (sparkline.style?.text) {
|
|
1611
|
+
if (IsHTMLColor(sparkline.style.text)) {
|
|
1612
|
+
color_series.rgb = sparkline.style.text.text;
|
|
1613
|
+
}
|
|
1614
|
+
else if (IsThemeColor(sparkline.style.text)) {
|
|
1615
|
+
color_series.rgb = undefined;
|
|
1616
|
+
color_series.theme = sparkline.style.text.theme.toString();
|
|
1617
|
+
color_series.tint = typeof sparkline.style.text.tint === 'number' ?
|
|
1618
|
+
sparkline.style.text.tint.toString() : undefined;
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
return {
|
|
1622
|
+
a$: {
|
|
1623
|
+
displayEmptyCellsAs: 'gap',
|
|
1624
|
+
displayHidden: '1',
|
|
1625
|
+
type: /column/i.test(sparkline.formula) ? 'column' : undefined,
|
|
1626
|
+
},
|
|
1627
|
+
'x14:colorSeries': { a$: { ...color_series } },
|
|
1628
|
+
'x14:sparklines': {
|
|
1629
|
+
'x14:sparkline': {
|
|
1630
|
+
'xm:f': source,
|
|
1631
|
+
'xm:sqref': new Area(sparkline.address).spreadsheet_label,
|
|
1632
|
+
},
|
|
1633
|
+
},
|
|
1634
|
+
};
|
|
1635
|
+
}),
|
|
1636
|
+
};
|
|
1637
|
+
extLst = {
|
|
1638
|
+
ext: {
|
|
1639
|
+
a$: {
|
|
1640
|
+
uri: '{05C60535-1F16-4fd2-B633-F4F36F0B64E0}',
|
|
1641
|
+
'xmlns:x14': 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main',
|
|
1642
|
+
},
|
|
1643
|
+
'x14:sparklineGroups': groups
|
|
1644
|
+
}
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
// --- charts ------------------------------------------------------------
|
|
1648
|
+
let dom_drawing;
|
|
1649
|
+
const charts = this.ParseCharts(sheet);
|
|
1650
|
+
const images = this.ParseImages(sheet);
|
|
1651
|
+
// if a sheet has one or more charts, it has a single drawing. for a
|
|
1652
|
+
// drawing, we need
|
|
1653
|
+
//
|
|
1654
|
+
// (1) entry in sheet xml
|
|
1655
|
+
// (2) drawing xml file
|
|
1656
|
+
// (3) relationship sheet -> drawing
|
|
1657
|
+
// (4) drawing rels file (for charts, later)
|
|
1658
|
+
// (5) entry in [ContentTypes]
|
|
1659
|
+
//
|
|
1660
|
+
// each chart in the drawing then needs
|
|
1661
|
+
//
|
|
1662
|
+
// (1) entry in drawing file
|
|
1663
|
+
// (2) chart xml file
|
|
1664
|
+
// (3) relationship drawing -> chart
|
|
1665
|
+
// (4) chart/colors xml file
|
|
1666
|
+
// (5) chart/style xml file
|
|
1667
|
+
// (6) chart rels file
|
|
1668
|
+
// (7) relationship chart -> colors
|
|
1669
|
+
// (8) relationship chart -> style
|
|
1670
|
+
// (9) entry in [ContentTypes]
|
|
1671
|
+
//
|
|
1672
|
+
// check: we can get away with not including colors or style, which
|
|
1673
|
+
// will revert to defaults -- let's do that for the time being if we can
|
|
1674
|
+
//
|
|
1675
|
+
// merging in images, which use the same drawing (and in a single
|
|
1676
|
+
// sheet, a single drawing holds both charts and images).
|
|
1677
|
+
if (charts.length || images.length) {
|
|
1678
|
+
const drawing = new Drawing();
|
|
1679
|
+
for (const chart of charts) {
|
|
1680
|
+
drawing.AddChart(chart.options, chart.anchor);
|
|
1681
|
+
}
|
|
1682
|
+
for (const image of images) {
|
|
1683
|
+
drawing.AddImage(image.options, image.anchor);
|
|
1684
|
+
}
|
|
1685
|
+
for (const { image } of drawing.images) {
|
|
1686
|
+
if (image.options.data) {
|
|
1687
|
+
this.zip?.SetBinary(`xl/media/image${image.index}.${image.extension}`, image.options.data, image.options.encoding);
|
|
1688
|
+
}
|
|
1689
|
+
// no media rels!
|
|
1690
|
+
}
|
|
1691
|
+
for (const { chart } of drawing.charts) {
|
|
1692
|
+
const dom = chart.toJSON();
|
|
1693
|
+
const xml = XMLDeclaration + this.xmlbuilder1.build(dom);
|
|
1694
|
+
this.zip?.Set(`xl/charts/chart${chart.index}.xml`, xml);
|
|
1695
|
+
this.WriteRels(chart.relationships, `xl/charts/_rels/chart${chart.index}.xml.rels`);
|
|
1696
|
+
}
|
|
1697
|
+
this.WriteRels(drawing.relationships, `xl/drawings/_rels/drawing${drawing.index}.xml.rels`);
|
|
1698
|
+
const xml = XMLDeclaration + this.xmlbuilder1.build(drawing.toJSON());
|
|
1699
|
+
this.zip?.Set(`xl/drawings/drawing${drawing.index}.xml`, xml);
|
|
1700
|
+
drawings.push(drawing); // for [ContentTypes]
|
|
1701
|
+
const drawing_rel = AddRel(sheet_rels, `http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing`, `../drawings/drawing${drawing.index}.xml`);
|
|
1702
|
+
// dom.worksheet.drawing = {
|
|
1703
|
+
dom_drawing = {
|
|
1704
|
+
a$: {
|
|
1705
|
+
'r:id': drawing_rel,
|
|
1706
|
+
},
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
else {
|
|
1710
|
+
// delete dom.worksheet.drawing;
|
|
1711
|
+
}
|
|
1712
|
+
// --- tab color ---------------------------------------------------------
|
|
1713
|
+
const tab_color_block = {};
|
|
1714
|
+
if (sheet.tab_color) {
|
|
1715
|
+
if (IsThemeColor(sheet.tab_color)) {
|
|
1716
|
+
tab_color_block.sheetPr = {
|
|
1717
|
+
tabColor: {
|
|
1718
|
+
a$: {
|
|
1719
|
+
theme: sheet.tab_color.theme,
|
|
1720
|
+
tint: sheet.tab_color.tint,
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
};
|
|
1724
|
+
}
|
|
1725
|
+
else if (IsHTMLColor(sheet.tab_color)) {
|
|
1726
|
+
const color = sheet.tab_color.text || '';
|
|
1727
|
+
if (/^#[0-9a-fA-F]*$/.test(color)) {
|
|
1728
|
+
tab_color_block.sheetPr = {
|
|
1729
|
+
tabColor: {
|
|
1730
|
+
a$: {
|
|
1731
|
+
rgb: `FF` + color.substring(1)
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
// --- move page margins -------------------------------------------------
|
|
1739
|
+
// const margins = dom.worksheet.pageMargins;
|
|
1740
|
+
// delete dom.worksheet.pageMargins;
|
|
1741
|
+
// dom.worksheet.pageMargins = margins;
|
|
1742
|
+
// --- end? --------------------------------------------------------------
|
|
1743
|
+
const sheetFormatPr = {
|
|
1744
|
+
a$: {
|
|
1745
|
+
'x14ac:dyDescent': 0.25,
|
|
1746
|
+
defaultRowHeight: default_row_height === 15 ? undefined : default_row_height,
|
|
1747
|
+
customHeight: default_row_height === 15 ? undefined : 1,
|
|
1748
|
+
defaultColWidth: sheet.default_column_width ? PixelsToColumnWidth(sheet.default_column_width) : undefined,
|
|
1749
|
+
},
|
|
1750
|
+
};
|
|
1751
|
+
//------------------------------------------------------------------------
|
|
1752
|
+
//
|
|
1753
|
+
// NOTE: order matters. that's why we define the layout here. we
|
|
1754
|
+
// can't just append entries to the worksheet object.
|
|
1755
|
+
//
|
|
1756
|
+
//------------------------------------------------------------------------
|
|
1757
|
+
const dom = {
|
|
1758
|
+
worksheet: {
|
|
1759
|
+
a$: { ...sheet_attributes },
|
|
1760
|
+
...tab_color_block,
|
|
1761
|
+
dimension: {
|
|
1762
|
+
a$: {
|
|
1763
|
+
ref: new Area(extent.start, extent.end).spreadsheet_label,
|
|
1764
|
+
},
|
|
1765
|
+
},
|
|
1766
|
+
sheetViews: {
|
|
1767
|
+
sheetView: {
|
|
1768
|
+
a$: {
|
|
1769
|
+
workbookViewId: 0,
|
|
1770
|
+
},
|
|
1771
|
+
},
|
|
1772
|
+
},
|
|
1773
|
+
sheetFormatPr,
|
|
1774
|
+
cols: dom_cols,
|
|
1775
|
+
sheetData: { row: sheet_rows },
|
|
1776
|
+
mergeCells,
|
|
1777
|
+
conditionalFormatting,
|
|
1778
|
+
dataValidations,
|
|
1779
|
+
hyperlinks: dom_hyperlinks,
|
|
1780
|
+
pageMargins: {
|
|
1781
|
+
a$: {
|
|
1782
|
+
left: 0.7,
|
|
1783
|
+
right: 0.7,
|
|
1784
|
+
top: 0.75,
|
|
1785
|
+
bottom: 0.75,
|
|
1786
|
+
header: 0.3,
|
|
1787
|
+
footer: 0.3,
|
|
1788
|
+
},
|
|
1789
|
+
},
|
|
1790
|
+
drawing: dom_drawing,
|
|
1791
|
+
tableParts,
|
|
1792
|
+
extLst,
|
|
1793
|
+
},
|
|
1794
|
+
};
|
|
1795
|
+
// -----------------------------------------------------------------------
|
|
1796
|
+
// it seems like chrome, at least, will maintain order. but this is
|
|
1797
|
+
// not gauranteed and we can't rely on it. the best thing to do might
|
|
1798
|
+
// be to use the renderer on blocks and then assemble the blocks ourselves.
|
|
1799
|
+
const xml = XMLDeclaration + this.xmlbuilder1.build(dom);
|
|
1800
|
+
// console.info(xml);
|
|
1801
|
+
// write this into the file
|
|
1802
|
+
this.zip?.Set(`xl/worksheets/sheet${sheet_index + 1}.xml`, xml);
|
|
1803
|
+
if (Object.keys(sheet_rels).length) {
|
|
1804
|
+
this.WriteRels(sheet_rels, `xl/worksheets/_rels/sheet${sheet_index + 1}.xml.rels`);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
// these are workbook global so after all sheets are done
|
|
1808
|
+
this.WriteSharedStrings(shared_strings);
|
|
1809
|
+
this.WriteStyleCache(style_cache);
|
|
1810
|
+
// now have to write/update
|
|
1811
|
+
//
|
|
1812
|
+
// (1) contentTypes
|
|
1813
|
+
// (2) workbook.xml
|
|
1814
|
+
// (3) workbook.xml.rels
|
|
1815
|
+
//
|
|
1816
|
+
const workbook_rels = {};
|
|
1817
|
+
AddRel(workbook_rels, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles', 'styles.xml');
|
|
1818
|
+
AddRel(workbook_rels, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', 'theme/theme1.xml');
|
|
1819
|
+
AddRel(workbook_rels, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings', 'sharedStrings.xml');
|
|
1820
|
+
const worksheet_rels_map = source.sheet_data.map((sheet, index) => AddRel(workbook_rels, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet', `worksheets/sheet${index + 1}.xml`));
|
|
1821
|
+
if (dynamic_array_metadata) {
|
|
1822
|
+
const metadata_dom = {
|
|
1823
|
+
metadata: {
|
|
1824
|
+
a$: {
|
|
1825
|
+
xmlns: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
|
|
1826
|
+
'xmlns:xda': 'http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray',
|
|
1827
|
+
},
|
|
1828
|
+
metadataTypes: {
|
|
1829
|
+
a$: {
|
|
1830
|
+
count: 1,
|
|
1831
|
+
},
|
|
1832
|
+
metadataType: {
|
|
1833
|
+
a$: {
|
|
1834
|
+
name: 'XLDAPR',
|
|
1835
|
+
minSupportedVersion: '120000',
|
|
1836
|
+
copy: 1,
|
|
1837
|
+
pasteAll: 1,
|
|
1838
|
+
pasteValues: 1,
|
|
1839
|
+
merge: 1,
|
|
1840
|
+
splitFirst: 1,
|
|
1841
|
+
rowColShift: 1,
|
|
1842
|
+
clearFormats: 1,
|
|
1843
|
+
clearComments: 1,
|
|
1844
|
+
assign: 1,
|
|
1845
|
+
coerce: 1,
|
|
1846
|
+
cellMeta: 1,
|
|
1847
|
+
},
|
|
1848
|
+
},
|
|
1849
|
+
},
|
|
1850
|
+
futureMetadata: {
|
|
1851
|
+
a$: {
|
|
1852
|
+
name: 'XLDAPR',
|
|
1853
|
+
count: 1,
|
|
1854
|
+
},
|
|
1855
|
+
bk: {
|
|
1856
|
+
extLst: {
|
|
1857
|
+
ext: {
|
|
1858
|
+
a$: {
|
|
1859
|
+
uri: '{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}',
|
|
1860
|
+
},
|
|
1861
|
+
'xda:dynamicArrayProperties': {
|
|
1862
|
+
a$: {
|
|
1863
|
+
fDynamic: 1,
|
|
1864
|
+
fCollapsed: `0`,
|
|
1865
|
+
},
|
|
1866
|
+
},
|
|
1867
|
+
},
|
|
1868
|
+
},
|
|
1869
|
+
},
|
|
1870
|
+
},
|
|
1871
|
+
cellMetadata: {
|
|
1872
|
+
a$: { count: 1 },
|
|
1873
|
+
bk: {
|
|
1874
|
+
rc: {
|
|
1875
|
+
a$: {
|
|
1876
|
+
t: 1,
|
|
1877
|
+
v: `0`,
|
|
1878
|
+
}
|
|
1879
|
+
},
|
|
1880
|
+
},
|
|
1881
|
+
},
|
|
1882
|
+
},
|
|
1883
|
+
};
|
|
1884
|
+
const metadata_xml = XMLDeclaration + this.xmlbuilder1.build(metadata_dom);
|
|
1885
|
+
// console.info(metadata_xml);
|
|
1886
|
+
this.zip?.Set(`xl/metadata.xml`, metadata_xml);
|
|
1887
|
+
// add rel
|
|
1888
|
+
AddRel(workbook_rels, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata', 'metadata.xml');
|
|
1889
|
+
}
|
|
1890
|
+
this.WriteRels(workbook_rels, `xl/_rels/workbook.xml.rels`);
|
|
1891
|
+
const definedNames = source.named?.length ? {
|
|
1892
|
+
definedName: (source.named || []).map(entry => {
|
|
1893
|
+
let scope = undefined;
|
|
1894
|
+
if (entry.scope) {
|
|
1895
|
+
const test = entry.scope.toLowerCase();
|
|
1896
|
+
for (const [index, sheet] of source.sheet_data.entries()) {
|
|
1897
|
+
if (sheet.name?.toLowerCase() === test) {
|
|
1898
|
+
scope = index.toString();
|
|
1899
|
+
break;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
return {
|
|
1904
|
+
a$: { name: entry.name, localSheetId: scope },
|
|
1905
|
+
t$: entry.expression,
|
|
1906
|
+
};
|
|
1907
|
+
}),
|
|
1908
|
+
} : undefined;
|
|
1909
|
+
const workbook_dom = {
|
|
1910
|
+
workbook: {
|
|
1911
|
+
a$: {
|
|
1912
|
+
'xmlns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
|
|
1913
|
+
'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
|
|
1914
|
+
'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',
|
|
1915
|
+
'mc:Ignorable': 'x15 xr xr6 xr10 xr2',
|
|
1916
|
+
'xmlns:x15': 'http://schemas.microsoft.com/office/spreadsheetml/2010/11/main',
|
|
1917
|
+
'xmlns:xr': 'http://schemas.microsoft.com/office/spreadsheetml/2014/revision',
|
|
1918
|
+
'xmlns:xr6': 'http://schemas.microsoft.com/office/spreadsheetml/2016/revision6',
|
|
1919
|
+
'xmlns:xr10': 'http://schemas.microsoft.com/office/spreadsheetml/2016/revision10',
|
|
1920
|
+
'xmlns:xr2': 'http://schemas.microsoft.com/office/spreadsheetml/2015/revision2',
|
|
1921
|
+
},
|
|
1922
|
+
workbookPr: {
|
|
1923
|
+
a$: {
|
|
1924
|
+
defaultThemeVersion: '166925',
|
|
1925
|
+
},
|
|
1926
|
+
},
|
|
1927
|
+
bookViews: {
|
|
1928
|
+
workbookView: {
|
|
1929
|
+
a$: {
|
|
1930
|
+
activeTab: (active_sheet || 0),
|
|
1931
|
+
},
|
|
1932
|
+
},
|
|
1933
|
+
},
|
|
1934
|
+
sheets: {
|
|
1935
|
+
sheet: source.sheet_data.map((sheet, index) => ({
|
|
1936
|
+
a$: {
|
|
1937
|
+
name: sheet.name || `Sheet${index + 1}`,
|
|
1938
|
+
sheetId: index + 1,
|
|
1939
|
+
'r:id': worksheet_rels_map[index],
|
|
1940
|
+
state: (sheet.visible === false) ? 'hidden' : undefined,
|
|
1941
|
+
}
|
|
1942
|
+
})),
|
|
1943
|
+
},
|
|
1944
|
+
definedNames,
|
|
1945
|
+
},
|
|
1946
|
+
};
|
|
1947
|
+
const workbook_xml = XMLDeclaration + this.xmlbuilder1.build(workbook_dom);
|
|
1948
|
+
// console.info(workbook_xml);
|
|
1949
|
+
this.zip?.Set(`xl/workbook.xml`, workbook_xml);
|
|
1950
|
+
// const extensions: Array<{ Extension: string, ContentType: string }> = [];
|
|
1951
|
+
const extensions = {};
|
|
1952
|
+
for (const drawing of drawings) {
|
|
1953
|
+
for (const image of drawing.images) {
|
|
1954
|
+
switch (image.image.extension) {
|
|
1955
|
+
case 'gif':
|
|
1956
|
+
case 'png':
|
|
1957
|
+
case 'jpeg':
|
|
1958
|
+
extensions[image.image.extension] = 'image/' + image.image.extension;
|
|
1959
|
+
break;
|
|
1960
|
+
case 'svg':
|
|
1961
|
+
extensions['svg'] = 'image/svg+xml';
|
|
1962
|
+
break;
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
const content_types_dom = {
|
|
1967
|
+
Types: {
|
|
1968
|
+
a$: {
|
|
1969
|
+
'xmlns': 'http://schemas.openxmlformats.org/package/2006/content-types',
|
|
1970
|
+
},
|
|
1971
|
+
Default: [
|
|
1972
|
+
{ a$: { Extension: 'rels', ContentType: 'application/vnd.openxmlformats-package.relationships+xml' } },
|
|
1973
|
+
{ a$: { Extension: 'xml', ContentType: 'application/xml' } },
|
|
1974
|
+
...Object.keys(extensions).map(key => ({
|
|
1975
|
+
a$: { Extension: key, ContentType: extensions[key] },
|
|
1976
|
+
})),
|
|
1977
|
+
],
|
|
1978
|
+
Override: [
|
|
1979
|
+
{ a$: { PartName: '/xl/workbook.xml', ContentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml' } },
|
|
1980
|
+
// sheets
|
|
1981
|
+
...source.sheet_data.map((sheet, index) => {
|
|
1982
|
+
return { a$: {
|
|
1983
|
+
ContentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml',
|
|
1984
|
+
PartName: `/xl/worksheets/sheet${index + 1}.xml`,
|
|
1985
|
+
} };
|
|
1986
|
+
}),
|
|
1987
|
+
// charts and drawings
|
|
1988
|
+
...drawings.reduce((a, drawing) => {
|
|
1989
|
+
return a.concat([
|
|
1990
|
+
...drawing.charts.map(chart => {
|
|
1991
|
+
return { a$: {
|
|
1992
|
+
ContentType: 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml',
|
|
1993
|
+
PartName: `/xl/charts/chart${chart.chart.index}.xml`,
|
|
1994
|
+
} };
|
|
1995
|
+
}),
|
|
1996
|
+
{ a$: {
|
|
1997
|
+
ContentType: 'application/vnd.openxmlformats-officedocument.drawing+xml',
|
|
1998
|
+
PartName: `/xl/drawings/drawing${drawing.index}.xml`,
|
|
1999
|
+
} },
|
|
2000
|
+
]);
|
|
2001
|
+
}, []),
|
|
2002
|
+
{ a$: { PartName: '/xl/theme/theme1.xml', ContentType: 'application/vnd.openxmlformats-officedocument.theme+xml' } },
|
|
2003
|
+
{ a$: { PartName: '/xl/styles.xml', ContentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml' } },
|
|
2004
|
+
{ a$: { PartName: '/xl/sharedStrings.xml', ContentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml' } },
|
|
2005
|
+
// metadata
|
|
2006
|
+
...(dynamic_array_metadata ? [
|
|
2007
|
+
{ a$: { PartName: '/xl/metadata.xml', ContentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml' } },
|
|
2008
|
+
] : []),
|
|
2009
|
+
// tables
|
|
2010
|
+
...global_tables.map(table => {
|
|
2011
|
+
return { a$: {
|
|
2012
|
+
ContentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml',
|
|
2013
|
+
PartName: `/xl/tables/table${table.index || 0}.xml`,
|
|
2014
|
+
} };
|
|
2015
|
+
}),
|
|
2016
|
+
{ a$: { PartName: '/docProps/core.xml', ContentType: 'application/vnd.openxmlformats-package.core-properties+xml' } },
|
|
2017
|
+
{ a$: { PartName: '/docProps/app.xml', ContentType: 'application/vnd.openxmlformats-officedocument.extended-properties+xml' } },
|
|
2018
|
+
],
|
|
2019
|
+
},
|
|
2020
|
+
};
|
|
2021
|
+
const content_types_xml = XMLDeclaration + this.xmlbuilder1.build(content_types_dom);
|
|
2022
|
+
// console.info(content_types_xml);
|
|
2023
|
+
this.zip?.Set(`[Content_Types].xml`, content_types_xml);
|
|
2024
|
+
}
|
|
2025
|
+
ArrayBuffer() {
|
|
2026
|
+
if (!this.zip) {
|
|
2027
|
+
throw new Error('missing zip');
|
|
2028
|
+
}
|
|
2029
|
+
return this.zip.ArrayBuffer();
|
|
2030
|
+
}
|
|
2031
|
+
Blob() {
|
|
2032
|
+
if (!this.zip) {
|
|
2033
|
+
throw new Error('missing zip');
|
|
2034
|
+
}
|
|
2035
|
+
const buffer = this.zip.ArrayBuffer();
|
|
2036
|
+
return new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
//# sourceMappingURL=export.js.map
|