worksheet.js 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. "use strict";
  2. function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
  3. function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
  4. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  5. function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
  6. function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
  7. function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
  8. function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
  9. function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
  10. function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
  11. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  12. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  13. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  14. var _ = require('../utils/under-dash');
  15. var colCache = require('../utils/col-cache');
  16. var Range = require('./range');
  17. var Row = require('./row');
  18. var Column = require('./column');
  19. var Enums = require('./enums');
  20. var Image = require('./image');
  21. var Table = require('./table');
  22. var DataValidations = require('./data-validations');
  23. var Encryptor = require('../utils/encryptor'); // Worksheet requirements
  24. // Operate as sheet inside workbook or standalone
  25. // Load and Save from file and stream
  26. // Access/Add/Delete individual cells
  27. // Manage column widths and row heights
  28. var Worksheet = /*#__PURE__*/function () {
  29. function Worksheet(options) {
  30. _classCallCheck(this, Worksheet);
  31. options = options || {}; // in a workbook, each sheet will have a number
  32. this.id = options.id;
  33. this.orderNo = options.orderNo; // and a name
  34. this.name = options.name || "Sheet".concat(this.id); // add a state
  35. this.state = options.state || 'visible'; // rows allows access organised by row. Sparse array of arrays indexed by row-1, col
  36. // Note: _rows is zero based. Must subtract 1 to go from cell.row to index
  37. this._rows = []; // column definitions
  38. this._columns = null; // column keys (addRow convenience): key ==> this._collumns index
  39. this._keys = {}; // keep record of all merges
  40. this._merges = {}; // record of all row and column pageBreaks
  41. this.rowBreaks = [];
  42. this._workbook = options.workbook; // for tabColor, default row height, outline levels, etc
  43. this.properties = Object.assign({}, {
  44. defaultRowHeight: 15,
  45. dyDescent: 55,
  46. outlineLevelCol: 0,
  47. outlineLevelRow: 0
  48. }, options.properties); // for all things printing
  49. this.pageSetup = Object.assign({}, {
  50. margins: {
  51. left: 0.7,
  52. right: 0.7,
  53. top: 0.75,
  54. bottom: 0.75,
  55. header: 0.3,
  56. footer: 0.3
  57. },
  58. orientation: 'portrait',
  59. horizontalDpi: 4294967295,
  60. verticalDpi: 4294967295,
  61. fitToPage: !!(options.pageSetup && (options.pageSetup.fitToWidth || options.pageSetup.fitToHeight) && !options.pageSetup.scale),
  62. pageOrder: 'downThenOver',
  63. blackAndWhite: false,
  64. draft: false,
  65. cellComments: 'None',
  66. errors: 'displayed',
  67. scale: 100,
  68. fitToWidth: 1,
  69. fitToHeight: 1,
  70. paperSize: undefined,
  71. showRowColHeaders: false,
  72. showGridLines: false,
  73. firstPageNumber: undefined,
  74. horizontalCentered: false,
  75. verticalCentered: false,
  76. rowBreaks: null,
  77. colBreaks: null
  78. }, options.pageSetup);
  79. this.headerFooter = Object.assign({}, {
  80. differentFirst: false,
  81. differentOddEven: false,
  82. oddHeader: null,
  83. oddFooter: null,
  84. evenHeader: null,
  85. evenFooter: null,
  86. firstHeader: null,
  87. firstFooter: null
  88. }, options.headerFooter);
  89. this.dataValidations = new DataValidations(); // for freezepanes, split, zoom, gridlines, etc
  90. this.views = options.views || [];
  91. this.autoFilter = options.autoFilter || null; // for images, etc
  92. this._media = []; // worksheet protection
  93. this.sheetProtection = null; // for tables
  94. this.tables = {};
  95. this.conditionalFormattings = [];
  96. }
  97. _createClass(Worksheet, [{
  98. key: "destroy",
  99. // when you're done with this worksheet, call this to remove from workbook
  100. value: function destroy() {
  101. this._workbook.removeWorksheetEx(this);
  102. } // Get the bounding range of the cells in this worksheet
  103. }, {
  104. key: "getColumnKey",
  105. value: function getColumnKey(key) {
  106. return this._keys[key];
  107. }
  108. }, {
  109. key: "setColumnKey",
  110. value: function setColumnKey(key, value) {
  111. this._keys[key] = value;
  112. }
  113. }, {
  114. key: "deleteColumnKey",
  115. value: function deleteColumnKey(key) {
  116. delete this._keys[key];
  117. }
  118. }, {
  119. key: "eachColumnKey",
  120. value: function eachColumnKey(f) {
  121. _.each(this._keys, f);
  122. } // get a single column by col number. If it doesn't exist, create it and any gaps before it
  123. }, {
  124. key: "getColumn",
  125. value: function getColumn(c) {
  126. if (typeof c === 'string') {
  127. // if it matches a key'd column, return that
  128. var col = this._keys[c];
  129. if (col) return col; // otherwise, assume letter
  130. c = colCache.l2n(c);
  131. }
  132. if (!this._columns) {
  133. this._columns = [];
  134. }
  135. if (c > this._columns.length) {
  136. var n = this._columns.length + 1;
  137. while (n <= c) {
  138. this._columns.push(new Column(this, n++));
  139. }
  140. }
  141. return this._columns[c - 1];
  142. }
  143. }, {
  144. key: "spliceColumns",
  145. value: function spliceColumns(start, count) {
  146. var _this = this;
  147. var rows = this._rows;
  148. var nRows = rows.length;
  149. for (var _len = arguments.length, inserts = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
  150. inserts[_key - 2] = arguments[_key];
  151. }
  152. if (inserts.length > 0) {
  153. var _loop = function _loop(i) {
  154. var rowArguments = [start, count]; // eslint-disable-next-line no-loop-func
  155. inserts.forEach(function (insert) {
  156. rowArguments.push(insert[i] || null);
  157. });
  158. var row = _this.getRow(i + 1); // eslint-disable-next-line prefer-spread
  159. row.splice.apply(row, rowArguments);
  160. };
  161. // must iterate over all rows whether they exist yet or not
  162. for (var i = 0; i < nRows; i++) {
  163. _loop(i);
  164. }
  165. } else {
  166. // nothing to insert, so just splice all rows
  167. this._rows.forEach(function (r) {
  168. if (r) {
  169. r.splice(start, count);
  170. }
  171. });
  172. } // splice column definitions
  173. var nExpand = inserts.length - count;
  174. var nKeep = start + count;
  175. var nEnd = this._columns.length;
  176. if (nExpand < 0) {
  177. for (var _i = start + inserts.length; _i <= nEnd; _i++) {
  178. this.getColumn(_i).defn = this.getColumn(_i - nExpand).defn;
  179. }
  180. } else if (nExpand > 0) {
  181. for (var _i2 = nEnd; _i2 >= nKeep; _i2--) {
  182. this.getColumn(_i2 + nExpand).defn = this.getColumn(_i2).defn;
  183. }
  184. }
  185. for (var _i3 = start; _i3 < start + inserts.length; _i3++) {
  186. this.getColumn(_i3).defn = null;
  187. } // account for defined names
  188. this.workbook.definedNames.spliceColumns(this.name, start, count, inserts.length);
  189. }
  190. }, {
  191. key: "_commitRow",
  192. // =========================================================================
  193. // Rows
  194. value: function _commitRow() {// nop - allows streaming reader to fill a document
  195. }
  196. }, {
  197. key: "findRow",
  198. // find a row (if exists) by row number
  199. value: function findRow(r) {
  200. return this._rows[r - 1];
  201. } // find multiple rows (if exists) by row number
  202. }, {
  203. key: "findRows",
  204. value: function findRows(start, length) {
  205. return this._rows.slice(start - 1, start - 1 + length);
  206. }
  207. }, {
  208. key: "getRow",
  209. // get a row by row number.
  210. value: function getRow(r) {
  211. var row = this._rows[r - 1];
  212. if (!row) {
  213. row = this._rows[r - 1] = new Row(this, r);
  214. }
  215. return row;
  216. } // get multiple rows by row number.
  217. }, {
  218. key: "getRows",
  219. value: function getRows(start, length) {
  220. if (length < 1) return undefined;
  221. var rows = [];
  222. for (var i = start; i < start + length; i++) {
  223. rows.push(this.getRow(i));
  224. }
  225. return rows;
  226. }
  227. }, {
  228. key: "addRow",
  229. value: function addRow(value) {
  230. var style = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'n';
  231. var rowNo = this._nextRow;
  232. var row = this.getRow(rowNo);
  233. row.values = value;
  234. this._setStyleOption(rowNo, style[0] === 'i' ? style : 'n');
  235. return row;
  236. }
  237. }, {
  238. key: "addRows",
  239. value: function addRows(value) {
  240. var _this2 = this;
  241. var style = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'n';
  242. var rows = [];
  243. value.forEach(function (row) {
  244. rows.push(_this2.addRow(row, style));
  245. });
  246. return rows;
  247. }
  248. }, {
  249. key: "insertRow",
  250. value: function insertRow(pos, value) {
  251. var style = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'n';
  252. this.spliceRows(pos, 0, value);
  253. this._setStyleOption(pos, style);
  254. return this.getRow(pos);
  255. }
  256. }, {
  257. key: "insertRows",
  258. value: function insertRows(pos, values) {
  259. var style = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'n';
  260. this.spliceRows.apply(this, [pos, 0].concat(_toConsumableArray(values)));
  261. if (style !== 'n') {
  262. // copy over the styles
  263. for (var i = 0; i < values.length; i++) {
  264. if (style[0] === 'o' && this.findRow(values.length + pos + i) !== undefined) {
  265. this._copyStyle(values.length + pos + i, pos + i, style[1] === '+');
  266. } else if (style[0] === 'i' && this.findRow(pos - 1) !== undefined) {
  267. this._copyStyle(pos - 1, pos + i, style[1] === '+');
  268. }
  269. }
  270. }
  271. return this.getRows(pos, values.length);
  272. } // set row at position to same style as of either pervious row (option 'i') or next row (option 'o')
  273. }, {
  274. key: "_setStyleOption",
  275. value: function _setStyleOption(pos) {
  276. var style = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'n';
  277. if (style[0] === 'o' && this.findRow(pos + 1) !== undefined) {
  278. this._copyStyle(pos + 1, pos, style[1] === '+');
  279. } else if (style[0] === 'i' && this.findRow(pos - 1) !== undefined) {
  280. this._copyStyle(pos - 1, pos, style[1] === '+');
  281. }
  282. }
  283. }, {
  284. key: "_copyStyle",
  285. value: function _copyStyle(src, dest) {
  286. var styleEmpty = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  287. var rSrc = this.getRow(src);
  288. var rDst = this.getRow(dest);
  289. rDst.style = Object.freeze(_objectSpread({}, rSrc.style)); // eslint-disable-next-line no-loop-func
  290. rSrc.eachCell({
  291. includeEmpty: styleEmpty
  292. }, function (cell, colNumber) {
  293. rDst.getCell(colNumber).style = Object.freeze(_objectSpread({}, cell.style));
  294. });
  295. rDst.height = rSrc.height;
  296. }
  297. }, {
  298. key: "duplicateRow",
  299. value: function duplicateRow(rowNum, count) {
  300. var _this3 = this;
  301. var insert = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  302. // create count duplicates of rowNum
  303. // either inserting new or overwriting existing rows
  304. var rSrc = this._rows[rowNum - 1];
  305. var inserts = new Array(count).fill(rSrc.values);
  306. this.spliceRows.apply(this, [rowNum + 1, insert ? 0 : count].concat(_toConsumableArray(inserts))); // now copy styles...
  307. var _loop2 = function _loop2(i) {
  308. var rDst = _this3._rows[rowNum + i];
  309. rDst.style = rSrc.style;
  310. rDst.height = rSrc.height; // eslint-disable-next-line no-loop-func
  311. rSrc.eachCell({
  312. includeEmpty: true
  313. }, function (cell, colNumber) {
  314. rDst.getCell(colNumber).style = cell.style;
  315. });
  316. };
  317. for (var i = 0; i < count; i++) {
  318. _loop2(i);
  319. }
  320. }
  321. }, {
  322. key: "spliceRows",
  323. value: function spliceRows(start, count) {
  324. var _this4 = this;
  325. // same problem as row.splice, except worse.
  326. var nKeep = start + count;
  327. for (var _len2 = arguments.length, inserts = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
  328. inserts[_key2 - 2] = arguments[_key2];
  329. }
  330. var nInserts = inserts.length;
  331. var nExpand = nInserts - count;
  332. var nEnd = this._rows.length;
  333. var i;
  334. var rSrc;
  335. if (nExpand < 0) {
  336. // remove rows
  337. for (i = nKeep; i <= nEnd; i++) {
  338. rSrc = this._rows[i - 1];
  339. if (rSrc) {
  340. (function () {
  341. var rDst = _this4.getRow(i + nExpand);
  342. rDst.values = rSrc.values;
  343. rDst.style = rSrc.style;
  344. rDst.height = rSrc.height; // eslint-disable-next-line no-loop-func
  345. rSrc.eachCell({
  346. includeEmpty: true
  347. }, function (cell, colNumber) {
  348. rDst.getCell(colNumber).style = cell.style;
  349. });
  350. _this4._rows[i - 1] = undefined;
  351. })();
  352. } else {
  353. this._rows[i + nExpand - 1] = undefined;
  354. }
  355. }
  356. } else if (nExpand > 0) {
  357. // insert new cells
  358. for (i = nEnd; i >= nKeep; i--) {
  359. rSrc = this._rows[i - 1];
  360. if (rSrc) {
  361. (function () {
  362. var rDst = _this4.getRow(i + nExpand);
  363. rDst.values = rSrc.values;
  364. rDst.style = rSrc.style;
  365. rDst.height = rSrc.height; // eslint-disable-next-line no-loop-func
  366. rSrc.eachCell({
  367. includeEmpty: true
  368. }, function (cell, colNumber) {
  369. rDst.getCell(colNumber).style = cell.style; // remerge cells accounting for insert offset
  370. if (cell._value.constructor.name === 'MergeValue') {
  371. var cellToBeMerged = _this4.getRow(cell._row._number + nInserts).getCell(colNumber);
  372. var prevMaster = cell._value._master;
  373. var newMaster = _this4.getRow(prevMaster._row._number + nInserts).getCell(prevMaster._column._number);
  374. cellToBeMerged.merge(newMaster);
  375. }
  376. });
  377. })();
  378. } else {
  379. this._rows[i + nExpand - 1] = undefined;
  380. }
  381. }
  382. } // now copy over the new values
  383. for (i = 0; i < nInserts; i++) {
  384. var rDst = this.getRow(start + i);
  385. rDst.style = {};
  386. rDst.values = inserts[i];
  387. } // account for defined names
  388. this.workbook.definedNames.spliceRows(this.name, start, count, nInserts);
  389. } // iterate over every row in the worksheet, including maybe empty rows
  390. }, {
  391. key: "eachRow",
  392. value: function eachRow(options, iteratee) {
  393. if (!iteratee) {
  394. iteratee = options;
  395. options = undefined;
  396. }
  397. if (options && options.includeEmpty) {
  398. var n = this._rows.length;
  399. for (var i = 1; i <= n; i++) {
  400. iteratee(this.getRow(i), i);
  401. }
  402. } else {
  403. this._rows.forEach(function (row) {
  404. if (row && row.hasValues) {
  405. iteratee(row, row.number);
  406. }
  407. });
  408. }
  409. } // return all rows as sparse array
  410. }, {
  411. key: "getSheetValues",
  412. value: function getSheetValues() {
  413. var rows = [];
  414. this._rows.forEach(function (row) {
  415. if (row) {
  416. rows[row.number] = row.values;
  417. }
  418. });
  419. return rows;
  420. } // =========================================================================
  421. // Cells
  422. // returns the cell at [r,c] or address given by r. If not found, return undefined
  423. }, {
  424. key: "findCell",
  425. value: function findCell(r, c) {
  426. var address = colCache.getAddress(r, c);
  427. var row = this._rows[address.row - 1];
  428. return row ? row.findCell(address.col) : undefined;
  429. } // return the cell at [r,c] or address given by r. If not found, create a new one.
  430. }, {
  431. key: "getCell",
  432. value: function getCell(r, c) {
  433. var address = colCache.getAddress(r, c);
  434. var row = this.getRow(address.row);
  435. return row.getCellEx(address);
  436. } // =========================================================================
  437. // Merge
  438. // convert the range defined by ['tl:br'], [tl,br] or [t,l,b,r] into a single 'merged' cell
  439. }, {
  440. key: "mergeCells",
  441. value: function mergeCells() {
  442. for (var _len3 = arguments.length, cells = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
  443. cells[_key3] = arguments[_key3];
  444. }
  445. var dimensions = new Range(cells);
  446. this._mergeCellsInternal(dimensions);
  447. }
  448. }, {
  449. key: "mergeCellsWithoutStyle",
  450. value: function mergeCellsWithoutStyle() {
  451. for (var _len4 = arguments.length, cells = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
  452. cells[_key4] = arguments[_key4];
  453. }
  454. var dimensions = new Range(cells);
  455. this._mergeCellsInternal(dimensions, true);
  456. }
  457. }, {
  458. key: "_mergeCellsInternal",
  459. value: function _mergeCellsInternal(dimensions, ignoreStyle) {
  460. // check cells aren't already merged
  461. _.each(this._merges, function (merge) {
  462. if (merge.intersects(dimensions)) {
  463. throw new Error('Cannot merge already merged cells');
  464. }
  465. }); // apply merge
  466. var master = this.getCell(dimensions.top, dimensions.left);
  467. for (var i = dimensions.top; i <= dimensions.bottom; i++) {
  468. for (var j = dimensions.left; j <= dimensions.right; j++) {
  469. // merge all but the master cell
  470. if (i > dimensions.top || j > dimensions.left) {
  471. this.getCell(i, j).merge(master, ignoreStyle);
  472. }
  473. }
  474. } // index merge
  475. this._merges[master.address] = dimensions;
  476. }
  477. }, {
  478. key: "_unMergeMaster",
  479. value: function _unMergeMaster(master) {
  480. // master is always top left of a rectangle
  481. var merge = this._merges[master.address];
  482. if (merge) {
  483. for (var i = merge.top; i <= merge.bottom; i++) {
  484. for (var j = merge.left; j <= merge.right; j++) {
  485. this.getCell(i, j).unmerge();
  486. }
  487. }
  488. delete this._merges[master.address];
  489. }
  490. }
  491. }, {
  492. key: "unMergeCells",
  493. // scan the range defined by ['tl:br'], [tl,br] or [t,l,b,r] and if any cell is part of a merge,
  494. // un-merge the group. Note this function can affect multiple merges and merge-blocks are
  495. // atomic - either they're all merged or all un-merged.
  496. value: function unMergeCells() {
  497. for (var _len5 = arguments.length, cells = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
  498. cells[_key5] = arguments[_key5];
  499. }
  500. var dimensions = new Range(cells); // find any cells in that range and unmerge them
  501. for (var i = dimensions.top; i <= dimensions.bottom; i++) {
  502. for (var j = dimensions.left; j <= dimensions.right; j++) {
  503. var cell = this.findCell(i, j);
  504. if (cell) {
  505. if (cell.type === Enums.ValueType.Merge) {
  506. // this cell merges to another master
  507. this._unMergeMaster(cell.master);
  508. } else if (this._merges[cell.address]) {
  509. // this cell is a master
  510. this._unMergeMaster(cell);
  511. }
  512. }
  513. }
  514. }
  515. } // ===========================================================================
  516. // Shared/Array Formula
  517. }, {
  518. key: "fillFormula",
  519. value: function fillFormula(range, formula, results) {
  520. var shareType = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'shared';
  521. // Define formula for top-left cell and share to rest
  522. var decoded = colCache.decode(range);
  523. var top = decoded.top,
  524. left = decoded.left,
  525. bottom = decoded.bottom,
  526. right = decoded.right;
  527. var width = right - left + 1;
  528. var masterAddress = colCache.encodeAddress(top, left);
  529. var isShared = shareType === 'shared'; // work out result accessor
  530. var getResult;
  531. if (typeof results === 'function') {
  532. getResult = results;
  533. } else if (Array.isArray(results)) {
  534. if (Array.isArray(results[0])) {
  535. getResult = function getResult(row, col) {
  536. return results[row - top][col - left];
  537. };
  538. } else {
  539. // eslint-disable-next-line no-mixed-operators
  540. getResult = function getResult(row, col) {
  541. return results[(row - top) * width + (col - left)];
  542. };
  543. }
  544. } else {
  545. getResult = function getResult() {
  546. return undefined;
  547. };
  548. }
  549. var first = true;
  550. for (var r = top; r <= bottom; r++) {
  551. for (var c = left; c <= right; c++) {
  552. if (first) {
  553. this.getCell(r, c).value = {
  554. shareType: shareType,
  555. formula: formula,
  556. ref: range,
  557. result: getResult(r, c)
  558. };
  559. first = false;
  560. } else {
  561. this.getCell(r, c).value = isShared ? {
  562. sharedFormula: masterAddress,
  563. result: getResult(r, c)
  564. } : getResult(r, c);
  565. }
  566. }
  567. }
  568. } // =========================================================================
  569. // Images
  570. }, {
  571. key: "addImage",
  572. value: function addImage(imageId, range) {
  573. var model = {
  574. type: 'image',
  575. imageId: imageId,
  576. range: range
  577. };
  578. this._media.push(new Image(this, model));
  579. }
  580. }, {
  581. key: "getImages",
  582. value: function getImages() {
  583. return this._media.filter(function (m) {
  584. return m.type === 'image';
  585. });
  586. }
  587. }, {
  588. key: "addBackgroundImage",
  589. value: function addBackgroundImage(imageId) {
  590. var model = {
  591. type: 'background',
  592. imageId: imageId
  593. };
  594. this._media.push(new Image(this, model));
  595. }
  596. }, {
  597. key: "getBackgroundImageId",
  598. value: function getBackgroundImageId() {
  599. var image = this._media.find(function (m) {
  600. return m.type === 'background';
  601. });
  602. return image && image.imageId;
  603. } // =========================================================================
  604. // Worksheet Protection
  605. }, {
  606. key: "protect",
  607. value: function protect(password, options) {
  608. var _this5 = this;
  609. // TODO: make this function truly async
  610. // perhaps marshal to worker thread or something
  611. return new Promise(function (resolve) {
  612. _this5.sheetProtection = {
  613. sheet: true
  614. };
  615. if (options && 'spinCount' in options) {
  616. // force spinCount to be integer >= 0
  617. options.spinCount = Number.isFinite(options.spinCount) ? Math.round(Math.max(0, options.spinCount)) : 100000;
  618. }
  619. if (password) {
  620. _this5.sheetProtection.algorithmName = 'SHA-512';
  621. _this5.sheetProtection.saltValue = Encryptor.randomBytes(16).toString('base64');
  622. _this5.sheetProtection.spinCount = options && 'spinCount' in options ? options.spinCount : 100000; // allow user specified spinCount
  623. _this5.sheetProtection.hashValue = Encryptor.convertPasswordToHash(password, 'SHA512', _this5.sheetProtection.saltValue, _this5.sheetProtection.spinCount);
  624. }
  625. if (options) {
  626. _this5.sheetProtection = Object.assign(_this5.sheetProtection, options);
  627. if (!password && 'spinCount' in options) {
  628. delete _this5.sheetProtection.spinCount;
  629. }
  630. }
  631. resolve();
  632. });
  633. }
  634. }, {
  635. key: "unprotect",
  636. value: function unprotect() {
  637. this.sheetProtection = null;
  638. } // =========================================================================
  639. // Tables
  640. }, {
  641. key: "addTable",
  642. value: function addTable(model) {
  643. var table = new Table(this, model);
  644. this.tables[model.name] = table;
  645. return table;
  646. }
  647. }, {
  648. key: "getTable",
  649. value: function getTable(name) {
  650. return this.tables[name];
  651. }
  652. }, {
  653. key: "removeTable",
  654. value: function removeTable(name) {
  655. delete this.tables[name];
  656. }
  657. }, {
  658. key: "getTables",
  659. value: function getTables() {
  660. return Object.values(this.tables);
  661. } // ===========================================================================
  662. // Conditional Formatting
  663. }, {
  664. key: "addConditionalFormatting",
  665. value: function addConditionalFormatting(cf) {
  666. this.conditionalFormattings.push(cf);
  667. }
  668. }, {
  669. key: "removeConditionalFormatting",
  670. value: function removeConditionalFormatting(filter) {
  671. if (typeof filter === 'number') {
  672. this.conditionalFormattings.splice(filter, 1);
  673. } else if (filter instanceof Function) {
  674. this.conditionalFormattings = this.conditionalFormattings.filter(filter);
  675. } else {
  676. this.conditionalFormattings = [];
  677. }
  678. } // ===========================================================================
  679. // Deprecated
  680. }, {
  681. key: "_parseRows",
  682. value: function _parseRows(model) {
  683. var _this6 = this;
  684. this._rows = [];
  685. model.rows.forEach(function (rowModel) {
  686. var row = new Row(_this6, rowModel.number);
  687. _this6._rows[row.number - 1] = row;
  688. row.model = rowModel;
  689. });
  690. }
  691. }, {
  692. key: "_parseMergeCells",
  693. value: function _parseMergeCells(model) {
  694. var _this7 = this;
  695. _.each(model.mergeCells, function (merge) {
  696. // Do not merge styles when importing an Excel file
  697. // since each cell may have different styles intentionally.
  698. _this7.mergeCellsWithoutStyle(merge);
  699. });
  700. }
  701. }, {
  702. key: "workbook",
  703. get: function get() {
  704. return this._workbook;
  705. }
  706. }, {
  707. key: "dimensions",
  708. get: function get() {
  709. var dimensions = new Range();
  710. this._rows.forEach(function (row) {
  711. if (row) {
  712. var rowDims = row.dimensions;
  713. if (rowDims) {
  714. dimensions.expand(row.number, rowDims.min, row.number, rowDims.max);
  715. }
  716. }
  717. });
  718. return dimensions;
  719. } // =========================================================================
  720. // Columns
  721. // get the current columns array.
  722. }, {
  723. key: "columns",
  724. get: function get() {
  725. return this._columns;
  726. } // set the columns from an array of column definitions.
  727. // Note: any headers defined will overwrite existing values.
  728. ,
  729. set: function set(value) {
  730. var _this8 = this;
  731. // calculate max header row count
  732. this._headerRowCount = value.reduce(function (pv, cv) {
  733. var headerCount = cv.header && 1 || cv.headers && cv.headers.length || 0;
  734. return Math.max(pv, headerCount);
  735. }, 0); // construct Column objects
  736. var count = 1;
  737. var columns = this._columns = [];
  738. value.forEach(function (defn) {
  739. var column = new Column(_this8, count++, false);
  740. columns.push(column);
  741. column.defn = defn;
  742. });
  743. }
  744. }, {
  745. key: "lastColumn",
  746. get: function get() {
  747. return this.getColumn(this.columnCount);
  748. }
  749. }, {
  750. key: "columnCount",
  751. get: function get() {
  752. var maxCount = 0;
  753. this.eachRow(function (row) {
  754. maxCount = Math.max(maxCount, row.cellCount);
  755. });
  756. return maxCount;
  757. }
  758. }, {
  759. key: "actualColumnCount",
  760. get: function get() {
  761. // performance nightmare - for each row, counts all the columns used
  762. var counts = [];
  763. var count = 0;
  764. this.eachRow(function (row) {
  765. row.eachCell(function (_ref) {
  766. var col = _ref.col;
  767. if (!counts[col]) {
  768. counts[col] = true;
  769. count++;
  770. }
  771. });
  772. });
  773. return count;
  774. }
  775. }, {
  776. key: "_lastRowNumber",
  777. get: function get() {
  778. // need to cope with results of splice
  779. var rows = this._rows;
  780. var n = rows.length;
  781. while (n > 0 && rows[n - 1] === undefined) {
  782. n--;
  783. }
  784. return n;
  785. }
  786. }, {
  787. key: "_nextRow",
  788. get: function get() {
  789. return this._lastRowNumber + 1;
  790. }
  791. }, {
  792. key: "lastRow",
  793. get: function get() {
  794. if (this._rows.length) {
  795. return this._rows[this._rows.length - 1];
  796. }
  797. return undefined;
  798. }
  799. }, {
  800. key: "rowCount",
  801. get: function get() {
  802. return this._lastRowNumber;
  803. }
  804. }, {
  805. key: "actualRowCount",
  806. get: function get() {
  807. // counts actual rows that have actual data
  808. var count = 0;
  809. this.eachRow(function () {
  810. count++;
  811. });
  812. return count;
  813. }
  814. }, {
  815. key: "hasMerges",
  816. get: function get() {
  817. // return true if this._merges has a merge object
  818. return _.some(this._merges, Boolean);
  819. }
  820. }, {
  821. key: "tabColor",
  822. get: function get() {
  823. // eslint-disable-next-line no-console
  824. console.trace('worksheet.tabColor property is now deprecated. Please use worksheet.properties.tabColor');
  825. return this.properties.tabColor;
  826. },
  827. set: function set(value) {
  828. // eslint-disable-next-line no-console
  829. console.trace('worksheet.tabColor property is now deprecated. Please use worksheet.properties.tabColor');
  830. this.properties.tabColor = value;
  831. } // ===========================================================================
  832. // Model
  833. }, {
  834. key: "model",
  835. get: function get() {
  836. var model = {
  837. id: this.id,
  838. name: this.name,
  839. dataValidations: this.dataValidations.model,
  840. properties: this.properties,
  841. state: this.state,
  842. pageSetup: this.pageSetup,
  843. headerFooter: this.headerFooter,
  844. rowBreaks: this.rowBreaks,
  845. views: this.views,
  846. autoFilter: this.autoFilter,
  847. media: this._media.map(function (medium) {
  848. return medium.model;
  849. }),
  850. sheetProtection: this.sheetProtection,
  851. tables: Object.values(this.tables).map(function (table) {
  852. return table.model;
  853. }),
  854. conditionalFormattings: this.conditionalFormattings
  855. }; // =================================================
  856. // columns
  857. model.cols = Column.toModel(this.columns); // ==========================================================
  858. // Rows
  859. var rows = model.rows = [];
  860. var dimensions = model.dimensions = new Range();
  861. this._rows.forEach(function (row) {
  862. var rowModel = row && row.model;
  863. if (rowModel) {
  864. dimensions.expand(rowModel.number, rowModel.min, rowModel.number, rowModel.max);
  865. rows.push(rowModel);
  866. }
  867. }); // ==========================================================
  868. // Merges
  869. model.merges = [];
  870. _.each(this._merges, function (merge) {
  871. model.merges.push(merge.range);
  872. });
  873. return model;
  874. },
  875. set: function set(value) {
  876. var _this9 = this;
  877. this.name = value.name;
  878. this._columns = Column.fromModel(this, value.cols);
  879. this._parseRows(value);
  880. this._parseMergeCells(value);
  881. this.dataValidations = new DataValidations(value.dataValidations);
  882. this.properties = value.properties;
  883. this.pageSetup = value.pageSetup;
  884. this.headerFooter = value.headerFooter;
  885. this.views = value.views;
  886. this.autoFilter = value.autoFilter;
  887. this._media = value.media.map(function (medium) {
  888. return new Image(_this9, medium);
  889. });
  890. this.sheetProtection = value.sheetProtection;
  891. this.tables = value.tables.reduce(function (tables, table) {
  892. var t = new Table();
  893. t.model = table;
  894. tables[table.name] = t;
  895. return tables;
  896. }, {});
  897. this.conditionalFormattings = value.conditionalFormattings;
  898. }
  899. }]);
  900. return Worksheet;
  901. }();
  902. module.exports = Worksheet;
  903. //# sourceMappingURL=worksheet.js.map