@yuanliwei/exceljs 4.4.0

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.
Files changed (185) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +3024 -0
  3. package/README_zh.md +2878 -0
  4. package/excel.js +13 -0
  5. package/index.d.ts +2040 -0
  6. package/index.ts +2 -0
  7. package/lib/csv/csv.js +191 -0
  8. package/lib/csv/line-buffer.js +74 -0
  9. package/lib/csv/stream-converter.js +135 -0
  10. package/lib/doc/anchor.js +91 -0
  11. package/lib/doc/cell.js +1124 -0
  12. package/lib/doc/column.js +320 -0
  13. package/lib/doc/data/theme1.json +234 -0
  14. package/lib/doc/data-validations.js +19 -0
  15. package/lib/doc/defined-names.js +196 -0
  16. package/lib/doc/enums.js +48 -0
  17. package/lib/doc/image.js +59 -0
  18. package/lib/doc/modelcontainer.js +18 -0
  19. package/lib/doc/note.js +65 -0
  20. package/lib/doc/pivot-table.js +132 -0
  21. package/lib/doc/range.js +257 -0
  22. package/lib/doc/row.js +415 -0
  23. package/lib/doc/table.js +465 -0
  24. package/lib/doc/workbook.js +224 -0
  25. package/lib/doc/worksheet.js +949 -0
  26. package/lib/exceljs.bare.js +13 -0
  27. package/lib/exceljs.browser.js +36 -0
  28. package/lib/exceljs.nodejs.js +14 -0
  29. package/lib/stream/xlsx/hyperlink-reader.js +83 -0
  30. package/lib/stream/xlsx/sheet-comments-writer.js +121 -0
  31. package/lib/stream/xlsx/sheet-rels-writer.js +119 -0
  32. package/lib/stream/xlsx/workbook-reader.js +337 -0
  33. package/lib/stream/xlsx/workbook-writer.js +347 -0
  34. package/lib/stream/xlsx/worksheet-reader.js +374 -0
  35. package/lib/stream/xlsx/worksheet-writer.js +717 -0
  36. package/lib/utils/auto-drain.js +15 -0
  37. package/lib/utils/browser-buffer-decode.js +14 -0
  38. package/lib/utils/browser-buffer-encode.js +15 -0
  39. package/lib/utils/cell-matrix.js +165 -0
  40. package/lib/utils/col-cache.js +287 -0
  41. package/lib/utils/copy-style.js +43 -0
  42. package/lib/utils/encryptor.js +55 -0
  43. package/lib/utils/iterate-stream.js +48 -0
  44. package/lib/utils/parse-sax.js +30 -0
  45. package/lib/utils/shared-formula.js +44 -0
  46. package/lib/utils/shared-strings.js +35 -0
  47. package/lib/utils/stream-base64.js +72 -0
  48. package/lib/utils/stream-buf.js +364 -0
  49. package/lib/utils/string-buf.js +82 -0
  50. package/lib/utils/string-builder.js +35 -0
  51. package/lib/utils/stuttered-pipe.js +67 -0
  52. package/lib/utils/typed-stack.js +24 -0
  53. package/lib/utils/under-dash.js +184 -0
  54. package/lib/utils/utils.js +205 -0
  55. package/lib/utils/xml-stream.js +169 -0
  56. package/lib/utils/zip-stream.js +87 -0
  57. package/lib/xlsx/.rels +11 -0
  58. package/lib/xlsx/calcChain.xml +6 -0
  59. package/lib/xlsx/core.xml +7 -0
  60. package/lib/xlsx/defaultnumformats.js +153 -0
  61. package/lib/xlsx/rel-type.js +20 -0
  62. package/lib/xlsx/styles.xml +41 -0
  63. package/lib/xlsx/workbook.xml +16 -0
  64. package/lib/xlsx/xform/base-xform.js +145 -0
  65. package/lib/xlsx/xform/book/defined-name-xform.js +91 -0
  66. package/lib/xlsx/xform/book/sheet-xform.js +34 -0
  67. package/lib/xlsx/xform/book/workbook-calc-properties-xform.js +26 -0
  68. package/lib/xlsx/xform/book/workbook-pivot-cache-xform.js +29 -0
  69. package/lib/xlsx/xform/book/workbook-properties-xform.js +29 -0
  70. package/lib/xlsx/xform/book/workbook-view-xform.js +53 -0
  71. package/lib/xlsx/xform/book/workbook-xform.js +259 -0
  72. package/lib/xlsx/xform/comment/comment-xform.js +105 -0
  73. package/lib/xlsx/xform/comment/comments-xform.js +82 -0
  74. package/lib/xlsx/xform/comment/style/vml-position-xform.js +39 -0
  75. package/lib/xlsx/xform/comment/style/vml-protection-xform.js +36 -0
  76. package/lib/xlsx/xform/comment/vml-anchor-xform.js +60 -0
  77. package/lib/xlsx/xform/comment/vml-client-data-xform.js +95 -0
  78. package/lib/xlsx/xform/comment/vml-notes-xform.js +107 -0
  79. package/lib/xlsx/xform/comment/vml-shape-xform.js +95 -0
  80. package/lib/xlsx/xform/comment/vml-textbox-xform.js +64 -0
  81. package/lib/xlsx/xform/composite-xform.js +56 -0
  82. package/lib/xlsx/xform/core/app-heading-pairs-xform.js +32 -0
  83. package/lib/xlsx/xform/core/app-titles-of-parts-xform.js +28 -0
  84. package/lib/xlsx/xform/core/app-xform.js +100 -0
  85. package/lib/xlsx/xform/core/content-types-xform.js +135 -0
  86. package/lib/xlsx/xform/core/core-xform.js +136 -0
  87. package/lib/xlsx/xform/core/relationship-xform.js +25 -0
  88. package/lib/xlsx/xform/core/relationships-xform.js +73 -0
  89. package/lib/xlsx/xform/drawing/base-cell-anchor-xform.js +48 -0
  90. package/lib/xlsx/xform/drawing/blip-fill-xform.js +71 -0
  91. package/lib/xlsx/xform/drawing/blip-xform.js +42 -0
  92. package/lib/xlsx/xform/drawing/c-nv-pic-pr-xform.js +38 -0
  93. package/lib/xlsx/xform/drawing/c-nv-pr-xform.js +68 -0
  94. package/lib/xlsx/xform/drawing/cell-position-xform.js +77 -0
  95. package/lib/xlsx/xform/drawing/drawing-xform.js +109 -0
  96. package/lib/xlsx/xform/drawing/ext-lst-xform.js +43 -0
  97. package/lib/xlsx/xform/drawing/ext-xform.js +44 -0
  98. package/lib/xlsx/xform/drawing/hlink-click-xform.js +41 -0
  99. package/lib/xlsx/xform/drawing/nv-pic-pr-xform.js +65 -0
  100. package/lib/xlsx/xform/drawing/one-cell-anchor-xform.js +63 -0
  101. package/lib/xlsx/xform/drawing/pic-xform.js +77 -0
  102. package/lib/xlsx/xform/drawing/sp-pr.js +17 -0
  103. package/lib/xlsx/xform/drawing/two-cell-anchor-xform.js +62 -0
  104. package/lib/xlsx/xform/list-xform.js +95 -0
  105. package/lib/xlsx/xform/pivot-table/cache-field.js +43 -0
  106. package/lib/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +77 -0
  107. package/lib/xlsx/xform/pivot-table/pivot-cache-records-xform.js +103 -0
  108. package/lib/xlsx/xform/pivot-table/pivot-table-xform.js +189 -0
  109. package/lib/xlsx/xform/sheet/auto-filter-xform.js +38 -0
  110. package/lib/xlsx/xform/sheet/cell-xform.js +498 -0
  111. package/lib/xlsx/xform/sheet/cf/cf-rule-xform.js +301 -0
  112. package/lib/xlsx/xform/sheet/cf/cfvo-xform.js +27 -0
  113. package/lib/xlsx/xform/sheet/cf/color-scale-xform.js +45 -0
  114. package/lib/xlsx/xform/sheet/cf/conditional-formatting-xform.js +48 -0
  115. package/lib/xlsx/xform/sheet/cf/conditional-formattings-xform.js +92 -0
  116. package/lib/xlsx/xform/sheet/cf/databar-xform.js +49 -0
  117. package/lib/xlsx/xform/sheet/cf/ext-lst-ref-xform.js +87 -0
  118. package/lib/xlsx/xform/sheet/cf/formula-xform.js +25 -0
  119. package/lib/xlsx/xform/sheet/cf/icon-set-xform.js +47 -0
  120. package/lib/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.js +27 -0
  121. package/lib/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js +98 -0
  122. package/lib/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.js +43 -0
  123. package/lib/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.js +62 -0
  124. package/lib/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.js +50 -0
  125. package/lib/xlsx/xform/sheet/cf-ext/databar-ext-xform.js +98 -0
  126. package/lib/xlsx/xform/sheet/cf-ext/f-ext-xform.js +25 -0
  127. package/lib/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.js +73 -0
  128. package/lib/xlsx/xform/sheet/cf-ext/sqref-ext-xform.js +25 -0
  129. package/lib/xlsx/xform/sheet/col-xform.js +86 -0
  130. package/lib/xlsx/xform/sheet/data-validations-xform.js +257 -0
  131. package/lib/xlsx/xform/sheet/dimension-xform.js +29 -0
  132. package/lib/xlsx/xform/sheet/drawing-xform.js +33 -0
  133. package/lib/xlsx/xform/sheet/ext-lst-xform.js +86 -0
  134. package/lib/xlsx/xform/sheet/header-footer-xform.js +146 -0
  135. package/lib/xlsx/xform/sheet/hyperlink-xform.js +54 -0
  136. package/lib/xlsx/xform/sheet/merge-cell-xform.js +27 -0
  137. package/lib/xlsx/xform/sheet/merges.js +56 -0
  138. package/lib/xlsx/xform/sheet/outline-properties-xform.js +43 -0
  139. package/lib/xlsx/xform/sheet/page-breaks-xform.js +27 -0
  140. package/lib/xlsx/xform/sheet/page-margins-xform.js +49 -0
  141. package/lib/xlsx/xform/sheet/page-setup-properties-xform.js +35 -0
  142. package/lib/xlsx/xform/sheet/page-setup-xform.js +103 -0
  143. package/lib/xlsx/xform/sheet/picture-xform.js +33 -0
  144. package/lib/xlsx/xform/sheet/print-options-xform.js +49 -0
  145. package/lib/xlsx/xform/sheet/row-breaks-xform.js +39 -0
  146. package/lib/xlsx/xform/sheet/row-xform.js +142 -0
  147. package/lib/xlsx/xform/sheet/sheet-format-properties-xform.js +55 -0
  148. package/lib/xlsx/xform/sheet/sheet-properties-xform.js +90 -0
  149. package/lib/xlsx/xform/sheet/sheet-protection-xform.js +89 -0
  150. package/lib/xlsx/xform/sheet/sheet-view-xform.js +202 -0
  151. package/lib/xlsx/xform/sheet/table-part-xform.js +33 -0
  152. package/lib/xlsx/xform/sheet/worksheet-xform.js +548 -0
  153. package/lib/xlsx/xform/simple/boolean-xform.js +31 -0
  154. package/lib/xlsx/xform/simple/date-xform.js +66 -0
  155. package/lib/xlsx/xform/simple/float-xform.js +51 -0
  156. package/lib/xlsx/xform/simple/integer-xform.js +57 -0
  157. package/lib/xlsx/xform/simple/string-xform.js +51 -0
  158. package/lib/xlsx/xform/static-xform.js +64 -0
  159. package/lib/xlsx/xform/strings/phonetic-text-xform.js +98 -0
  160. package/lib/xlsx/xform/strings/rich-text-xform.js +101 -0
  161. package/lib/xlsx/xform/strings/shared-string-xform.js +102 -0
  162. package/lib/xlsx/xform/strings/shared-strings-xform.js +127 -0
  163. package/lib/xlsx/xform/strings/text-xform.js +44 -0
  164. package/lib/xlsx/xform/style/alignment-xform.js +172 -0
  165. package/lib/xlsx/xform/style/border-xform.js +207 -0
  166. package/lib/xlsx/xform/style/color-xform.js +63 -0
  167. package/lib/xlsx/xform/style/dxf-xform.js +111 -0
  168. package/lib/xlsx/xform/style/fill-xform.js +364 -0
  169. package/lib/xlsx/xform/style/font-xform.js +102 -0
  170. package/lib/xlsx/xform/style/numfmt-xform.js +63 -0
  171. package/lib/xlsx/xform/style/protection-xform.js +60 -0
  172. package/lib/xlsx/xform/style/style-xform.js +125 -0
  173. package/lib/xlsx/xform/style/styles-xform.js +527 -0
  174. package/lib/xlsx/xform/style/underline-xform.js +47 -0
  175. package/lib/xlsx/xform/table/auto-filter-xform.js +81 -0
  176. package/lib/xlsx/xform/table/custom-filter-xform.js +33 -0
  177. package/lib/xlsx/xform/table/filter-column-xform.js +96 -0
  178. package/lib/xlsx/xform/table/filter-xform.js +31 -0
  179. package/lib/xlsx/xform/table/table-column-xform.js +44 -0
  180. package/lib/xlsx/xform/table/table-style-info-xform.js +41 -0
  181. package/lib/xlsx/xform/table/table-xform.js +131 -0
  182. package/lib/xlsx/xlsx.js +774 -0
  183. package/lib/xlsx/xml/theme1.js +3 -0
  184. package/lib/xlsx/xml/theme1.xml +318 -0
  185. package/package.json +149 -0
@@ -0,0 +1,259 @@
1
+ const _ = require('../../../utils/under-dash');
2
+
3
+ const colCache = require('../../../utils/col-cache');
4
+ const XmlStream = require('../../../utils/xml-stream');
5
+
6
+ const BaseXform = require('../base-xform');
7
+ const StaticXform = require('../static-xform');
8
+ const ListXform = require('../list-xform');
9
+ const DefinedNameXform = require('./defined-name-xform');
10
+ const SheetXform = require('./sheet-xform');
11
+ const WorkbookViewXform = require('./workbook-view-xform');
12
+ const WorkbookPropertiesXform = require('./workbook-properties-xform');
13
+ const WorkbookCalcPropertiesXform = require('./workbook-calc-properties-xform');
14
+ const WorkbookPivotCacheXform = require('./workbook-pivot-cache-xform');
15
+
16
+ class WorkbookXform extends BaseXform {
17
+ constructor() {
18
+ super();
19
+
20
+ this.map = {
21
+ fileVersion: WorkbookXform.STATIC_XFORMS.fileVersion,
22
+ workbookPr: new WorkbookPropertiesXform(),
23
+ bookViews: new ListXform({
24
+ tag: 'bookViews',
25
+ count: false,
26
+ childXform: new WorkbookViewXform(),
27
+ }),
28
+ sheets: new ListXform({tag: 'sheets', count: false, childXform: new SheetXform()}),
29
+ definedNames: new ListXform({
30
+ tag: 'definedNames',
31
+ count: false,
32
+ childXform: new DefinedNameXform(),
33
+ }),
34
+ calcPr: new WorkbookCalcPropertiesXform(),
35
+ pivotCaches: new ListXform({
36
+ tag: 'pivotCaches',
37
+ count: false,
38
+ childXform: new WorkbookPivotCacheXform(),
39
+ }),
40
+ };
41
+ }
42
+
43
+ prepare(model) {
44
+ model.sheets = model.worksheets;
45
+
46
+ // collate all the print areas from all of the sheets and add them to the defined names
47
+ const printAreas = [];
48
+ let index = 0; // sheets is sparse array - calc index manually
49
+ model.sheets.forEach(sheet => {
50
+ if (sheet.pageSetup && sheet.pageSetup.printArea) {
51
+ sheet.pageSetup.printArea.split('&&').forEach(printArea => {
52
+ const printAreaComponents = printArea.split(':');
53
+ const definedName = {
54
+ name: '_xlnm.Print_Area',
55
+ ranges: [`'${sheet.name}'!$${printAreaComponents[0]}:$${printAreaComponents[1]}`],
56
+ localSheetId: index,
57
+ };
58
+ printAreas.push(definedName);
59
+ });
60
+ }
61
+
62
+ if (sheet.pageSetup && (sheet.pageSetup.printTitlesRow || sheet.pageSetup.printTitlesColumn)) {
63
+ const ranges = [];
64
+
65
+ if (sheet.pageSetup.printTitlesColumn) {
66
+ const titlesColumns = sheet.pageSetup.printTitlesColumn.split(':');
67
+ ranges.push(`'${sheet.name}'!$${titlesColumns[0]}:$${titlesColumns[1]}`);
68
+ }
69
+
70
+ if (sheet.pageSetup.printTitlesRow) {
71
+ const titlesRows = sheet.pageSetup.printTitlesRow.split(':');
72
+ ranges.push(`'${sheet.name}'!$${titlesRows[0]}:$${titlesRows[1]}`);
73
+ }
74
+
75
+ const definedName = {
76
+ name: '_xlnm.Print_Titles',
77
+ ranges,
78
+ localSheetId: index,
79
+ };
80
+
81
+ printAreas.push(definedName);
82
+ }
83
+ index++;
84
+ });
85
+ if (printAreas.length) {
86
+ model.definedNames = model.definedNames.concat(printAreas);
87
+ }
88
+
89
+ (model.media || []).forEach((medium, i) => {
90
+ // assign name
91
+ medium.name = medium.type + (i + 1);
92
+ });
93
+ }
94
+
95
+ render(xmlStream, model) {
96
+ xmlStream.openXml(XmlStream.StdDocAttributes);
97
+ xmlStream.openNode('workbook', WorkbookXform.WORKBOOK_ATTRIBUTES);
98
+
99
+ this.map.fileVersion.render(xmlStream);
100
+ this.map.workbookPr.render(xmlStream, model.properties);
101
+ this.map.bookViews.render(xmlStream, model.views);
102
+ this.map.sheets.render(xmlStream, model.sheets);
103
+ this.map.definedNames.render(xmlStream, model.definedNames);
104
+ this.map.calcPr.render(xmlStream, model.calcProperties);
105
+ this.map.pivotCaches.render(xmlStream, model.pivotTables);
106
+
107
+ xmlStream.closeNode();
108
+ }
109
+
110
+ parseOpen(node) {
111
+ if (this.parser) {
112
+ this.parser.parseOpen(node);
113
+ return true;
114
+ }
115
+ switch (node.name) {
116
+ case 'workbook':
117
+ return true;
118
+ default:
119
+ this.parser = this.map[node.name];
120
+ if (this.parser) {
121
+ this.parser.parseOpen(node);
122
+ }
123
+ return true;
124
+ }
125
+ }
126
+
127
+ parseText(text) {
128
+ if (this.parser) {
129
+ this.parser.parseText(text);
130
+ }
131
+ }
132
+
133
+ parseClose(name) {
134
+ if (this.parser) {
135
+ if (!this.parser.parseClose(name)) {
136
+ this.parser = undefined;
137
+ }
138
+ return true;
139
+ }
140
+ switch (name) {
141
+ case 'workbook':
142
+ this.model = {
143
+ sheets: this.map.sheets.model,
144
+ properties: this.map.workbookPr.model || {},
145
+ views: this.map.bookViews.model,
146
+ calcProperties: {},
147
+ };
148
+ if (this.map.definedNames.model) {
149
+ this.model.definedNames = this.map.definedNames.model;
150
+ }
151
+
152
+ return false;
153
+ default:
154
+ // not quite sure how we get here!
155
+ return true;
156
+ }
157
+ }
158
+
159
+ reconcile(model) {
160
+ const rels = (model.workbookRels || []).reduce((map, rel) => {
161
+ map[rel.Id] = rel;
162
+ return map;
163
+ }, {});
164
+
165
+ // reconcile sheet ids, rIds and names
166
+ const worksheets = [];
167
+ let worksheet;
168
+ let index = 0;
169
+
170
+ (model.sheets || []).forEach(sheet => {
171
+ const rel = rels[sheet.rId];
172
+ if (!rel) {
173
+ return;
174
+ }
175
+ // if rel.Target start with `[space]/xl/` or `/xl/` , then it will be replaced with `''` and spliced behind `xl/`,
176
+ // otherwise it will be spliced directly behind `xl/`. i.g.
177
+ worksheet = model.worksheetHash[`xl/${rel.Target.replace(/^(\s|\/xl\/)+/, '')}`];
178
+ // If there are "chartsheets" in the file, rel.Target will
179
+ // come out as chartsheets/sheet1.xml or similar here, and
180
+ // that won't be in model.worksheetHash.
181
+ // As we don't have the infrastructure to support chartsheets,
182
+ // we will ignore them for now:
183
+ if (worksheet) {
184
+ worksheet.name = sheet.name;
185
+ worksheet.id = sheet.id;
186
+ worksheet.state = sheet.state;
187
+ worksheets[index++] = worksheet;
188
+ }
189
+ });
190
+
191
+ // reconcile print areas
192
+ const definedNames = [];
193
+ _.each(model.definedNames, definedName => {
194
+ if (definedName.name === '_xlnm.Print_Area') {
195
+ worksheet = worksheets[definedName.localSheetId];
196
+ if (worksheet) {
197
+ if (!worksheet.pageSetup) {
198
+ worksheet.pageSetup = {};
199
+ }
200
+ const range = colCache.decodeEx(definedName.ranges[0]);
201
+ worksheet.pageSetup.printArea = worksheet.pageSetup.printArea
202
+ ? `${worksheet.pageSetup.printArea}&&${range.dimensions}`
203
+ : range.dimensions;
204
+ }
205
+ } else if (definedName.name === '_xlnm.Print_Titles') {
206
+ worksheet = worksheets[definedName.localSheetId];
207
+ if (worksheet) {
208
+ if (!worksheet.pageSetup) {
209
+ worksheet.pageSetup = {};
210
+ }
211
+
212
+ const rangeString = definedName.ranges.join(',');
213
+
214
+ const dollarRegex = /\$/g;
215
+
216
+ const rowRangeRegex = /\$\d+:\$\d+/;
217
+ const rowRangeMatches = rangeString.match(rowRangeRegex);
218
+
219
+ if (rowRangeMatches && rowRangeMatches.length) {
220
+ const range = rowRangeMatches[0];
221
+ worksheet.pageSetup.printTitlesRow = range.replace(dollarRegex, '');
222
+ }
223
+
224
+ const columnRangeRegex = /\$[A-Z]+:\$[A-Z]+/;
225
+ const columnRangeMatches = rangeString.match(columnRangeRegex);
226
+
227
+ if (columnRangeMatches && columnRangeMatches.length) {
228
+ const range = columnRangeMatches[0];
229
+ worksheet.pageSetup.printTitlesColumn = range.replace(dollarRegex, '');
230
+ }
231
+ }
232
+ } else {
233
+ definedNames.push(definedName);
234
+ }
235
+ });
236
+ model.definedNames = definedNames;
237
+
238
+ // used by sheets to build their image models
239
+ model.media.forEach((media, i) => {
240
+ media.index = i;
241
+ });
242
+ }
243
+ }
244
+
245
+ WorkbookXform.WORKBOOK_ATTRIBUTES = {
246
+ xmlns: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
247
+ 'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
248
+ 'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',
249
+ 'mc:Ignorable': 'x15',
250
+ 'xmlns:x15': 'http://schemas.microsoft.com/office/spreadsheetml/2010/11/main',
251
+ };
252
+ WorkbookXform.STATIC_XFORMS = {
253
+ fileVersion: new StaticXform({
254
+ tag: 'fileVersion',
255
+ $: {appName: 'xl', lastEdited: 5, lowestEdited: 5, rupBuild: 9303},
256
+ }),
257
+ };
258
+
259
+ module.exports = WorkbookXform;
@@ -0,0 +1,105 @@
1
+ const RichTextXform = require('../strings/rich-text-xform');
2
+ const utils = require('../../../utils/utils');
3
+ const BaseXform = require('../base-xform');
4
+
5
+ /**
6
+ <comment ref="B1" authorId="0">
7
+ <text>
8
+ <r>
9
+ <rPr>
10
+ <b/>
11
+ <sz val="9"/>
12
+ <rFont val="宋体"/>
13
+ <charset val="134"/>
14
+ </rPr>
15
+ <t>51422:</t>
16
+ </r>
17
+ <r>
18
+ <rPr>
19
+ <sz val="9"/>
20
+ <rFont val="宋体"/>
21
+ <charset val="134"/>
22
+ </rPr>
23
+ <t xml:space="preserve">&#10;test</t>
24
+ </r>
25
+ </text>
26
+ </comment>
27
+ */
28
+
29
+ const CommentXform = (module.exports = function(model) {
30
+ this.model = model;
31
+ });
32
+
33
+ utils.inherits(CommentXform, BaseXform, {
34
+ get tag() {
35
+ return 'r';
36
+ },
37
+
38
+ get richTextXform() {
39
+ if (!this._richTextXform) {
40
+ this._richTextXform = new RichTextXform();
41
+ }
42
+ return this._richTextXform;
43
+ },
44
+
45
+ render(xmlStream, model) {
46
+ model = model || this.model;
47
+
48
+ xmlStream.openNode('comment', {
49
+ ref: model.ref,
50
+ authorId: 0,
51
+ });
52
+ xmlStream.openNode('text');
53
+ if (model && model.note && model.note.texts) {
54
+ model.note.texts.forEach(text => {
55
+ this.richTextXform.render(xmlStream, text);
56
+ });
57
+ }
58
+ xmlStream.closeNode();
59
+ xmlStream.closeNode();
60
+ },
61
+
62
+ parseOpen(node) {
63
+ if (this.parser) {
64
+ this.parser.parseOpen(node);
65
+ return true;
66
+ }
67
+ switch (node.name) {
68
+ case 'comment':
69
+ this.model = {
70
+ type: 'note',
71
+ note: {
72
+ texts: [],
73
+ },
74
+ ...node.attributes,
75
+ };
76
+ return true;
77
+ case 'r':
78
+ this.parser = this.richTextXform;
79
+ this.parser.parseOpen(node);
80
+ return true;
81
+ default:
82
+ return false;
83
+ }
84
+ },
85
+ parseText(text) {
86
+ if (this.parser) {
87
+ this.parser.parseText(text);
88
+ }
89
+ },
90
+ parseClose(name) {
91
+ switch (name) {
92
+ case 'comment':
93
+ return false;
94
+ case 'r':
95
+ this.model.note.texts.push(this.parser.model);
96
+ this.parser = undefined;
97
+ return true;
98
+ default:
99
+ if (this.parser) {
100
+ this.parser.parseClose(name);
101
+ }
102
+ return true;
103
+ }
104
+ },
105
+ });
@@ -0,0 +1,82 @@
1
+ const XmlStream = require('../../../utils/xml-stream');
2
+ const utils = require('../../../utils/utils');
3
+ const BaseXform = require('../base-xform');
4
+
5
+ const CommentXform = require('./comment-xform');
6
+
7
+ const CommentsXform = (module.exports = function() {
8
+ this.map = {
9
+ comment: new CommentXform(),
10
+ };
11
+ });
12
+
13
+ utils.inherits(
14
+ CommentsXform,
15
+ BaseXform,
16
+ {
17
+ COMMENTS_ATTRIBUTES: {
18
+ xmlns: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
19
+ },
20
+ },
21
+ {
22
+ render(xmlStream, model) {
23
+ model = model || this.model;
24
+ xmlStream.openXml(XmlStream.StdDocAttributes);
25
+ xmlStream.openNode('comments', CommentsXform.COMMENTS_ATTRIBUTES);
26
+
27
+ // authors
28
+ // TODO: support authors properly
29
+ xmlStream.openNode('authors');
30
+ xmlStream.leafNode('author', null, 'Author');
31
+ xmlStream.closeNode();
32
+
33
+ // comments
34
+ xmlStream.openNode('commentList');
35
+ model.comments.forEach(comment => {
36
+ this.map.comment.render(xmlStream, comment);
37
+ });
38
+ xmlStream.closeNode();
39
+ xmlStream.closeNode();
40
+ },
41
+
42
+ parseOpen(node) {
43
+ if (this.parser) {
44
+ this.parser.parseOpen(node);
45
+ return true;
46
+ }
47
+ switch (node.name) {
48
+ case 'commentList':
49
+ this.model = {
50
+ comments: [],
51
+ };
52
+ return true;
53
+ case 'comment':
54
+ this.parser = this.map.comment;
55
+ this.parser.parseOpen(node);
56
+ return true;
57
+ default:
58
+ return false;
59
+ }
60
+ },
61
+ parseText(text) {
62
+ if (this.parser) {
63
+ this.parser.parseText(text);
64
+ }
65
+ },
66
+ parseClose(name) {
67
+ switch (name) {
68
+ case 'commentList':
69
+ return false;
70
+ case 'comment':
71
+ this.model.comments.push(this.parser.model);
72
+ this.parser = undefined;
73
+ return true;
74
+ default:
75
+ if (this.parser) {
76
+ this.parser.parseClose(name);
77
+ }
78
+ return true;
79
+ }
80
+ },
81
+ }
82
+ );
@@ -0,0 +1,39 @@
1
+ const BaseXform = require('../../base-xform');
2
+
3
+ class VmlPositionXform extends BaseXform {
4
+ constructor(model) {
5
+ super();
6
+ this._model = model;
7
+ }
8
+
9
+ get tag() {
10
+ return this._model && this._model.tag;
11
+ }
12
+
13
+ render(xmlStream, model, type) {
14
+ if (model === type[2]) {
15
+ xmlStream.leafNode(this.tag);
16
+ } else if (this.tag === 'x:SizeWithCells' && model === type[1]) {
17
+ xmlStream.leafNode(this.tag);
18
+ }
19
+ }
20
+
21
+ parseOpen(node) {
22
+ switch (node.name) {
23
+ case this.tag:
24
+ this.model = {};
25
+ this.model[this.tag] = true;
26
+ return true;
27
+ default:
28
+ return false;
29
+ }
30
+ }
31
+
32
+ parseText() {}
33
+
34
+ parseClose() {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ module.exports = VmlPositionXform;
@@ -0,0 +1,36 @@
1
+ const BaseXform = require('../../base-xform');
2
+
3
+ class VmlProtectionXform extends BaseXform {
4
+ constructor(model) {
5
+ super();
6
+ this._model = model;
7
+ }
8
+
9
+ get tag() {
10
+ return this._model && this._model.tag;
11
+ }
12
+
13
+ render(xmlStream, model) {
14
+ xmlStream.leafNode(this.tag, null, model);
15
+ }
16
+
17
+ parseOpen(node) {
18
+ switch (node.name) {
19
+ case this.tag:
20
+ this.text = '';
21
+ return true;
22
+ default:
23
+ return false;
24
+ }
25
+ }
26
+
27
+ parseText(text) {
28
+ this.text = text;
29
+ }
30
+
31
+ parseClose() {
32
+ return false;
33
+ }
34
+ }
35
+
36
+ module.exports = VmlProtectionXform;
@@ -0,0 +1,60 @@
1
+ const BaseXform = require('../base-xform');
2
+
3
+ // render the triangle in the cell for the comment
4
+ class VmlAnchorXform extends BaseXform {
5
+ get tag() {
6
+ return 'x:Anchor';
7
+ }
8
+
9
+ getAnchorRect(anchor) {
10
+ const l = Math.floor(anchor.left);
11
+ const lf = Math.floor((anchor.left - l) * 68);
12
+ const t = Math.floor(anchor.top);
13
+ const tf = Math.floor((anchor.top - t) * 18);
14
+ const r = Math.floor(anchor.right);
15
+ const rf = Math.floor((anchor.right - r) * 68);
16
+ const b = Math.floor(anchor.bottom);
17
+ const bf = Math.floor((anchor.bottom - b) * 18);
18
+ return [l, lf, t, tf, r, rf, b, bf];
19
+ }
20
+
21
+ getDefaultRect(ref) {
22
+ const l = ref.col;
23
+ const lf = 6;
24
+ const t = Math.max(ref.row - 2, 0);
25
+ const tf = 14;
26
+ const r = l + 2;
27
+ const rf = 2;
28
+ const b = t + 4;
29
+ const bf = 16;
30
+ return [l, lf, t, tf, r, rf, b, bf];
31
+ }
32
+
33
+ render(xmlStream, model) {
34
+ const rect = model.anchor
35
+ ? this.getAnchorRect(model.anchor)
36
+ : this.getDefaultRect(model.refAddress);
37
+
38
+ xmlStream.leafNode('x:Anchor', null, rect.join(', '));
39
+ }
40
+
41
+ parseOpen(node) {
42
+ switch (node.name) {
43
+ case this.tag:
44
+ this.text = '';
45
+ return true;
46
+ default:
47
+ return false;
48
+ }
49
+ }
50
+
51
+ parseText(text) {
52
+ this.text = text;
53
+ }
54
+
55
+ parseClose() {
56
+ return false;
57
+ }
58
+ }
59
+
60
+ module.exports = VmlAnchorXform;
@@ -0,0 +1,95 @@
1
+ const BaseXform = require('../base-xform');
2
+
3
+ const VmlAnchorXform = require('./vml-anchor-xform');
4
+ const VmlProtectionXform = require('./style/vml-protection-xform');
5
+ const VmlPositionXform = require('./style/vml-position-xform');
6
+
7
+ const POSITION_TYPE = ['twoCells', 'oneCells', 'absolute'];
8
+
9
+ class VmlClientDataXform extends BaseXform {
10
+ constructor() {
11
+ super();
12
+ this.map = {
13
+ 'x:Anchor': new VmlAnchorXform(),
14
+ 'x:Locked': new VmlProtectionXform({tag: 'x:Locked'}),
15
+ 'x:LockText': new VmlProtectionXform({tag: 'x:LockText'}),
16
+ 'x:SizeWithCells': new VmlPositionXform({tag: 'x:SizeWithCells'}),
17
+ 'x:MoveWithCells': new VmlPositionXform({tag: 'x:MoveWithCells'}),
18
+ };
19
+ }
20
+
21
+ get tag() {
22
+ return 'x:ClientData';
23
+ }
24
+
25
+ render(xmlStream, model) {
26
+ const {protection, editAs} = model.note;
27
+ xmlStream.openNode(this.tag, {ObjectType: 'Note'});
28
+ this.map['x:MoveWithCells'].render(xmlStream, editAs, POSITION_TYPE);
29
+ this.map['x:SizeWithCells'].render(xmlStream, editAs, POSITION_TYPE);
30
+ this.map['x:Anchor'].render(xmlStream, model);
31
+ this.map['x:Locked'].render(xmlStream, protection.locked);
32
+ xmlStream.leafNode('x:AutoFill', null, 'False');
33
+ this.map['x:LockText'].render(xmlStream, protection.lockText);
34
+ xmlStream.leafNode('x:Row', null, model.refAddress.row - 1);
35
+ xmlStream.leafNode('x:Column', null, model.refAddress.col - 1);
36
+ xmlStream.closeNode();
37
+ }
38
+
39
+ parseOpen(node) {
40
+ switch (node.name) {
41
+ case this.tag:
42
+ this.reset();
43
+ this.model = {
44
+ anchor: [],
45
+ protection: {},
46
+ editAs: '',
47
+ };
48
+ break;
49
+ default:
50
+ this.parser = this.map[node.name];
51
+ if (this.parser) {
52
+ this.parser.parseOpen(node);
53
+ }
54
+ break;
55
+ }
56
+ return true;
57
+ }
58
+
59
+ parseText(text) {
60
+ if (this.parser) {
61
+ this.parser.parseText(text);
62
+ }
63
+ }
64
+
65
+ parseClose(name) {
66
+ if (this.parser) {
67
+ if (!this.parser.parseClose(name)) {
68
+ this.parser = undefined;
69
+ }
70
+ return true;
71
+ }
72
+ switch (name) {
73
+ case this.tag:
74
+ this.normalizeModel();
75
+ return false;
76
+ default:
77
+ return true;
78
+ }
79
+ }
80
+
81
+ normalizeModel() {
82
+ const position = Object.assign(
83
+ {},
84
+ this.map['x:MoveWithCells'].model,
85
+ this.map['x:SizeWithCells'].model
86
+ );
87
+ const len = Object.keys(position).length;
88
+ this.model.editAs = POSITION_TYPE[len];
89
+ this.model.anchor = this.map['x:Anchor'].text;
90
+ this.model.protection.locked = this.map['x:Locked'].text;
91
+ this.model.protection.lockText = this.map['x:LockText'].text;
92
+ }
93
+ }
94
+
95
+ module.exports = VmlClientDataXform;