column.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. 'use strict';
  2. const _ = require('../utils/under-dash');
  3. const Enums = require('./enums');
  4. const colCache = require('../utils/col-cache');
  5. const DEFAULT_COLUMN_WIDTH = 9;
  6. // Column defines the column properties for 1 column.
  7. // This includes header rows, widths, key, (style), etc.
  8. // Worksheet will condense the columns as appropriate during serialization
  9. class Column {
  10. constructor(worksheet, number, defn) {
  11. this._worksheet = worksheet;
  12. this._number = number;
  13. if (defn !== false) {
  14. // sometimes defn will follow
  15. this.defn = defn;
  16. }
  17. }
  18. get number() {
  19. return this._number;
  20. }
  21. get worksheet() {
  22. return this._worksheet;
  23. }
  24. get letter() {
  25. return colCache.n2l(this._number);
  26. }
  27. get isCustomWidth() {
  28. return this.width !== undefined && this.width !== DEFAULT_COLUMN_WIDTH;
  29. }
  30. get defn() {
  31. return {
  32. header: this._header,
  33. key: this.key,
  34. width: this.width,
  35. style: this.style,
  36. hidden: this.hidden,
  37. outlineLevel: this.outlineLevel,
  38. };
  39. }
  40. set defn(value) {
  41. if (value) {
  42. this.key = value.key;
  43. this.width = value.width !== undefined ? value.width : DEFAULT_COLUMN_WIDTH;
  44. this.outlineLevel = value.outlineLevel;
  45. if (value.style) {
  46. this.style = value.style;
  47. } else {
  48. this.style = {};
  49. }
  50. // headers must be set after style
  51. this.header = value.header;
  52. this._hidden = !!value.hidden;
  53. } else {
  54. delete this._header;
  55. delete this._key;
  56. delete this.width;
  57. this.style = {};
  58. this.outlineLevel = 0;
  59. }
  60. }
  61. get headers() {
  62. return this._header && this._header instanceof Array ? this._header : [this._header];
  63. }
  64. get header() {
  65. return this._header;
  66. }
  67. set header(value) {
  68. if (value !== undefined) {
  69. this._header = value;
  70. this.headers.forEach((text, index) => {
  71. this._worksheet.getCell(index + 1, this.number).value = text;
  72. });
  73. } else {
  74. this._header = undefined;
  75. }
  76. }
  77. get key() {
  78. return this._key;
  79. }
  80. set key(value) {
  81. const column = this._key && this._worksheet.getColumnKey(this._key);
  82. if (column === this) {
  83. this._worksheet.deleteColumnKey(this._key);
  84. }
  85. this._key = value;
  86. if (value) {
  87. this._worksheet.setColumnKey(this._key, this);
  88. }
  89. }
  90. get hidden() {
  91. return !!this._hidden;
  92. }
  93. set hidden(value) {
  94. this._hidden = value;
  95. }
  96. get outlineLevel() {
  97. return this._outlineLevel || 0;
  98. }
  99. set outlineLevel(value) {
  100. this._outlineLevel = value;
  101. }
  102. get collapsed() {
  103. return !!(
  104. this._outlineLevel && this._outlineLevel >= this._worksheet.properties.outlineLevelCol
  105. );
  106. }
  107. toString() {
  108. return JSON.stringify({
  109. key: this.key,
  110. width: this.width,
  111. headers: this.headers.length ? this.headers : undefined,
  112. });
  113. }
  114. equivalentTo(other) {
  115. return (
  116. this.width === other.width &&
  117. this.hidden === other.hidden &&
  118. this.outlineLevel === other.outlineLevel &&
  119. _.isEqual(this.style, other.style)
  120. );
  121. }
  122. get isDefault() {
  123. if (this.isCustomWidth) {
  124. return false;
  125. }
  126. if (this.hidden) {
  127. return false;
  128. }
  129. if (this.outlineLevel) {
  130. return false;
  131. }
  132. const s = this.style;
  133. if (s && (s.font || s.numFmt || s.alignment || s.border || s.fill || s.protection)) {
  134. return false;
  135. }
  136. return true;
  137. }
  138. get headerCount() {
  139. return this.headers.length;
  140. }
  141. eachCell(options, iteratee) {
  142. const colNumber = this.number;
  143. if (!iteratee) {
  144. iteratee = options;
  145. options = null;
  146. }
  147. this._worksheet.eachRow(options, (row, rowNumber) => {
  148. iteratee(row.getCell(colNumber), rowNumber);
  149. });
  150. }
  151. get values() {
  152. const v = [];
  153. this.eachCell((cell, rowNumber) => {
  154. if (cell && cell.type !== Enums.ValueType.Null) {
  155. v[rowNumber] = cell.value;
  156. }
  157. });
  158. return v;
  159. }
  160. set values(v) {
  161. if (!v) {
  162. return;
  163. }
  164. const colNumber = this.number;
  165. let offset = 0;
  166. if (v.hasOwnProperty('0')) {
  167. // assume contiguous array, start at row 1
  168. offset = 1;
  169. }
  170. v.forEach((value, index) => {
  171. this._worksheet.getCell(index + offset, colNumber).value = value;
  172. });
  173. }
  174. // =========================================================================
  175. // styles
  176. _applyStyle(name, value) {
  177. this.style[name] = value;
  178. this.eachCell(cell => {
  179. cell[name] = value;
  180. });
  181. return value;
  182. }
  183. get numFmt() {
  184. return this.style.numFmt;
  185. }
  186. set numFmt(value) {
  187. this._applyStyle('numFmt', value);
  188. }
  189. get font() {
  190. return this.style.font;
  191. }
  192. set font(value) {
  193. this._applyStyle('font', value);
  194. }
  195. get alignment() {
  196. return this.style.alignment;
  197. }
  198. set alignment(value) {
  199. this._applyStyle('alignment', value);
  200. }
  201. get protection() {
  202. return this.style.protection;
  203. }
  204. set protection(value) {
  205. this._applyStyle('protection', value);
  206. }
  207. get border() {
  208. return this.style.border;
  209. }
  210. set border(value) {
  211. this._applyStyle('border', value);
  212. }
  213. get fill() {
  214. return this.style.fill;
  215. }
  216. set fill(value) {
  217. this._applyStyle('fill', value);
  218. }
  219. // =============================================================================
  220. // static functions
  221. static toModel(columns) {
  222. // Convert array of Column into compressed list cols
  223. const cols = [];
  224. let col = null;
  225. if (columns) {
  226. columns.forEach((column, index) => {
  227. if (column.isDefault) {
  228. if (col) {
  229. col = null;
  230. }
  231. } else if (!col || !column.equivalentTo(col)) {
  232. col = {
  233. min: index + 1,
  234. max: index + 1,
  235. width: column.width !== undefined ? column.width : DEFAULT_COLUMN_WIDTH,
  236. style: column.style,
  237. isCustomWidth: column.isCustomWidth,
  238. hidden: column.hidden,
  239. outlineLevel: column.outlineLevel,
  240. collapsed: column.collapsed,
  241. };
  242. cols.push(col);
  243. } else {
  244. col.max = index + 1;
  245. }
  246. });
  247. }
  248. return cols.length ? cols : undefined;
  249. }
  250. static fromModel(worksheet, cols) {
  251. cols = cols || [];
  252. const columns = [];
  253. let count = 1;
  254. let index = 0;
  255. /**
  256. * sort cols by min
  257. * If it is not sorted, the subsequent column configuration will be overwritten
  258. * */
  259. cols = cols.sort(function(pre, next) {
  260. return pre.min - next.min;
  261. });
  262. while (index < cols.length) {
  263. const col = cols[index++];
  264. while (count < col.min) {
  265. columns.push(new Column(worksheet, count++));
  266. }
  267. while (count <= col.max) {
  268. columns.push(new Column(worksheet, count++, col));
  269. }
  270. }
  271. return columns.length ? columns : null;
  272. }
  273. }
  274. module.exports = Column;