bdc7ab67586b2f7071264d0bfa47660f81d85bbbd60139e26ff8acdb552f7b9a867caf0d29e6b2d49c8b4adb9557ed2c29f412a55355f795575abbc3811f82 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. 'use strict';
  2. exports.__esModule = true;
  3. var _createClass = function () { 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  4. var _coords = require('./../cell/coords');
  5. var _coords2 = _interopRequireDefault(_coords);
  6. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  7. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  8. /**
  9. * A cell range is a set of exactly two CellCoords (that can be the same or different)
  10. *
  11. * @class CellRange
  12. */
  13. var CellRange = function () {
  14. /**
  15. * @param {CellCoords} highlight Used to draw bold border around a cell where selection was
  16. * started and to edit the cell when you press Enter
  17. * @param {CellCoords} from Usually the same as highlight, but in Excel there is distinction - one can change
  18. * highlight within a selection
  19. * @param {CellCoords} to End selection
  20. */
  21. function CellRange(highlight, from, to) {
  22. _classCallCheck(this, CellRange);
  23. this.highlight = highlight;
  24. this.from = from;
  25. this.to = to;
  26. }
  27. /**
  28. * Checks if given coords are valid in context of a given Walkontable instance
  29. *
  30. * @param {Walkontable} wotInstance
  31. * @returns {Boolean}
  32. */
  33. _createClass(CellRange, [{
  34. key: 'isValid',
  35. value: function isValid(wotInstance) {
  36. return this.from.isValid(wotInstance) && this.to.isValid(wotInstance);
  37. }
  38. /**
  39. * Checks if this cell range is restricted to one cell
  40. *
  41. * @returns {Boolean}
  42. */
  43. }, {
  44. key: 'isSingle',
  45. value: function isSingle() {
  46. return this.from.row === this.to.row && this.from.col === this.to.col;
  47. }
  48. /**
  49. * Returns selected range height (in number of rows)
  50. *
  51. * @returns {Number}
  52. */
  53. }, {
  54. key: 'getHeight',
  55. value: function getHeight() {
  56. return Math.max(this.from.row, this.to.row) - Math.min(this.from.row, this.to.row) + 1;
  57. }
  58. /**
  59. * Returns selected range width (in number of columns)
  60. *
  61. * @returns {Number}
  62. */
  63. }, {
  64. key: 'getWidth',
  65. value: function getWidth() {
  66. return Math.max(this.from.col, this.to.col) - Math.min(this.from.col, this.to.col) + 1;
  67. }
  68. /**
  69. * Checks if given cell coords is within `from` and `to` cell coords of this range
  70. *
  71. * @param {CellCoords} cellCoords
  72. * @returns {Boolean}
  73. */
  74. }, {
  75. key: 'includes',
  76. value: function includes(cellCoords) {
  77. var row = cellCoords.row,
  78. col = cellCoords.col;
  79. var topLeft = this.getTopLeftCorner();
  80. var bottomRight = this.getBottomRightCorner();
  81. return topLeft.row <= row && bottomRight.row >= row && topLeft.col <= col && bottomRight.col >= col;
  82. }
  83. /**
  84. * Checks if given range is within of this range
  85. *
  86. * @param {CellRange} testedRange
  87. * @returns {Boolean}
  88. */
  89. }, {
  90. key: 'includesRange',
  91. value: function includesRange(testedRange) {
  92. return this.includes(testedRange.getTopLeftCorner()) && this.includes(testedRange.getBottomRightCorner());
  93. }
  94. /**
  95. * Checks if given range is equal to this range
  96. *
  97. * @param {CellRange} testedRange
  98. * @returns {Boolean}
  99. */
  100. }, {
  101. key: 'isEqual',
  102. value: function isEqual(testedRange) {
  103. return Math.min(this.from.row, this.to.row) == Math.min(testedRange.from.row, testedRange.to.row) && Math.max(this.from.row, this.to.row) == Math.max(testedRange.from.row, testedRange.to.row) && Math.min(this.from.col, this.to.col) == Math.min(testedRange.from.col, testedRange.to.col) && Math.max(this.from.col, this.to.col) == Math.max(testedRange.from.col, testedRange.to.col);
  104. }
  105. /**
  106. * Checks if tested range overlaps with the range.
  107. * Range A is considered to to be overlapping with range B if intersection of A and B or B and A is not empty.
  108. *
  109. * @param {CellRange} testedRange
  110. * @returns {Boolean}
  111. */
  112. }, {
  113. key: 'overlaps',
  114. value: function overlaps(testedRange) {
  115. return testedRange.isSouthEastOf(this.getTopLeftCorner()) && testedRange.isNorthWestOf(this.getBottomRightCorner());
  116. }
  117. /**
  118. * @param {CellRange} testedCoords
  119. * @returns {Boolean}
  120. */
  121. }, {
  122. key: 'isSouthEastOf',
  123. value: function isSouthEastOf(testedCoords) {
  124. return this.getTopLeftCorner().isSouthEastOf(testedCoords) || this.getBottomRightCorner().isSouthEastOf(testedCoords);
  125. }
  126. /**
  127. * @param {CellRange} testedCoords
  128. * @returns {Boolean}
  129. */
  130. }, {
  131. key: 'isNorthWestOf',
  132. value: function isNorthWestOf(testedCoords) {
  133. return this.getTopLeftCorner().isNorthWestOf(testedCoords) || this.getBottomRightCorner().isNorthWestOf(testedCoords);
  134. }
  135. /**
  136. * Adds a cell to a range (only if exceeds corners of the range). Returns information if range was expanded
  137. *
  138. * @param {CellCoords} cellCoords
  139. * @returns {Boolean}
  140. */
  141. }, {
  142. key: 'expand',
  143. value: function expand(cellCoords) {
  144. var topLeft = this.getTopLeftCorner();
  145. var bottomRight = this.getBottomRightCorner();
  146. if (cellCoords.row < topLeft.row || cellCoords.col < topLeft.col || cellCoords.row > bottomRight.row || cellCoords.col > bottomRight.col) {
  147. this.from = new _coords2.default(Math.min(topLeft.row, cellCoords.row), Math.min(topLeft.col, cellCoords.col));
  148. this.to = new _coords2.default(Math.max(bottomRight.row, cellCoords.row), Math.max(bottomRight.col, cellCoords.col));
  149. return true;
  150. }
  151. return false;
  152. }
  153. /**
  154. * @param {CellRange} expandingRange
  155. * @returns {Boolean}
  156. */
  157. }, {
  158. key: 'expandByRange',
  159. value: function expandByRange(expandingRange) {
  160. if (this.includesRange(expandingRange) || !this.overlaps(expandingRange)) {
  161. return false;
  162. }
  163. var topLeft = this.getTopLeftCorner();
  164. var bottomRight = this.getBottomRightCorner();
  165. var topRight = this.getTopRightCorner();
  166. var bottomLeft = this.getBottomLeftCorner();
  167. var expandingTopLeft = expandingRange.getTopLeftCorner();
  168. var expandingBottomRight = expandingRange.getBottomRightCorner();
  169. var resultTopRow = Math.min(topLeft.row, expandingTopLeft.row);
  170. var resultTopCol = Math.min(topLeft.col, expandingTopLeft.col);
  171. var resultBottomRow = Math.max(bottomRight.row, expandingBottomRight.row);
  172. var resultBottomCol = Math.max(bottomRight.col, expandingBottomRight.col);
  173. var finalFrom = new _coords2.default(resultTopRow, resultTopCol),
  174. finalTo = new _coords2.default(resultBottomRow, resultBottomCol);
  175. var isCorner = new CellRange(finalFrom, finalFrom, finalTo).isCorner(this.from, expandingRange),
  176. onlyMerge = expandingRange.isEqual(new CellRange(finalFrom, finalFrom, finalTo));
  177. if (isCorner && !onlyMerge) {
  178. if (this.from.col > finalFrom.col) {
  179. finalFrom.col = resultBottomCol;
  180. finalTo.col = resultTopCol;
  181. }
  182. if (this.from.row > finalFrom.row) {
  183. finalFrom.row = resultBottomRow;
  184. finalTo.row = resultTopRow;
  185. }
  186. }
  187. this.from = finalFrom;
  188. this.to = finalTo;
  189. return true;
  190. }
  191. /**
  192. * @returns {String}
  193. */
  194. }, {
  195. key: 'getDirection',
  196. value: function getDirection() {
  197. if (this.from.isNorthWestOf(this.to)) {
  198. // NorthWest - SouthEast
  199. return 'NW-SE';
  200. } else if (this.from.isNorthEastOf(this.to)) {
  201. // NorthEast - SouthWest
  202. return 'NE-SW';
  203. } else if (this.from.isSouthEastOf(this.to)) {
  204. // SouthEast - NorthWest
  205. return 'SE-NW';
  206. } else if (this.from.isSouthWestOf(this.to)) {
  207. // SouthWest - NorthEast
  208. return 'SW-NE';
  209. }
  210. }
  211. /**
  212. * @param {String} direction
  213. */
  214. }, {
  215. key: 'setDirection',
  216. value: function setDirection(direction) {
  217. switch (direction) {
  218. case 'NW-SE':
  219. var _ref = [this.getTopLeftCorner(), this.getBottomRightCorner()];
  220. this.from = _ref[0];
  221. this.to = _ref[1];
  222. break;
  223. case 'NE-SW':
  224. var _ref2 = [this.getTopRightCorner(), this.getBottomLeftCorner()];
  225. this.from = _ref2[0];
  226. this.to = _ref2[1];
  227. break;
  228. case 'SE-NW':
  229. var _ref3 = [this.getBottomRightCorner(), this.getTopLeftCorner()];
  230. this.from = _ref3[0];
  231. this.to = _ref3[1];
  232. break;
  233. case 'SW-NE':
  234. var _ref4 = [this.getBottomLeftCorner(), this.getTopRightCorner()];
  235. this.from = _ref4[0];
  236. this.to = _ref4[1];
  237. break;
  238. default:
  239. break;
  240. }
  241. }
  242. /**
  243. * Get top left corner of this range
  244. *
  245. * @returns {CellCoords}
  246. */
  247. }, {
  248. key: 'getTopLeftCorner',
  249. value: function getTopLeftCorner() {
  250. return new _coords2.default(Math.min(this.from.row, this.to.row), Math.min(this.from.col, this.to.col));
  251. }
  252. /**
  253. * Get bottom right corner of this range
  254. *
  255. * @returns {CellCoords}
  256. */
  257. }, {
  258. key: 'getBottomRightCorner',
  259. value: function getBottomRightCorner() {
  260. return new _coords2.default(Math.max(this.from.row, this.to.row), Math.max(this.from.col, this.to.col));
  261. }
  262. /**
  263. * Get top right corner of this range
  264. *
  265. * @returns {CellCoords}
  266. */
  267. }, {
  268. key: 'getTopRightCorner',
  269. value: function getTopRightCorner() {
  270. return new _coords2.default(Math.min(this.from.row, this.to.row), Math.max(this.from.col, this.to.col));
  271. }
  272. /**
  273. * Get bottom left corner of this range
  274. *
  275. * @returns {CellCoords}
  276. */
  277. }, {
  278. key: 'getBottomLeftCorner',
  279. value: function getBottomLeftCorner() {
  280. return new _coords2.default(Math.max(this.from.row, this.to.row), Math.min(this.from.col, this.to.col));
  281. }
  282. /**
  283. * @param {CellCoords} coords
  284. * @param {CellRange} expandedRange
  285. * @returns {*}
  286. */
  287. }, {
  288. key: 'isCorner',
  289. value: function isCorner(coords, expandedRange) {
  290. if (expandedRange) {
  291. if (expandedRange.includes(coords)) {
  292. if (this.getTopLeftCorner().isEqual(new _coords2.default(expandedRange.from.row, expandedRange.from.col)) || this.getTopRightCorner().isEqual(new _coords2.default(expandedRange.from.row, expandedRange.to.col)) || this.getBottomLeftCorner().isEqual(new _coords2.default(expandedRange.to.row, expandedRange.from.col)) || this.getBottomRightCorner().isEqual(new _coords2.default(expandedRange.to.row, expandedRange.to.col))) {
  293. return true;
  294. }
  295. }
  296. }
  297. return coords.isEqual(this.getTopLeftCorner()) || coords.isEqual(this.getTopRightCorner()) || coords.isEqual(this.getBottomLeftCorner()) || coords.isEqual(this.getBottomRightCorner());
  298. }
  299. /**
  300. * @param {CellCoords} coords
  301. * @param {CellRange} expandedRange
  302. * @returns {CellCoords}
  303. */
  304. }, {
  305. key: 'getOppositeCorner',
  306. value: function getOppositeCorner(coords, expandedRange) {
  307. if (!(coords instanceof _coords2.default)) {
  308. return false;
  309. }
  310. if (expandedRange) {
  311. if (expandedRange.includes(coords)) {
  312. if (this.getTopLeftCorner().isEqual(new _coords2.default(expandedRange.from.row, expandedRange.from.col))) {
  313. return this.getBottomRightCorner();
  314. }
  315. if (this.getTopRightCorner().isEqual(new _coords2.default(expandedRange.from.row, expandedRange.to.col))) {
  316. return this.getBottomLeftCorner();
  317. }
  318. if (this.getBottomLeftCorner().isEqual(new _coords2.default(expandedRange.to.row, expandedRange.from.col))) {
  319. return this.getTopRightCorner();
  320. }
  321. if (this.getBottomRightCorner().isEqual(new _coords2.default(expandedRange.to.row, expandedRange.to.col))) {
  322. return this.getTopLeftCorner();
  323. }
  324. }
  325. }
  326. if (coords.isEqual(this.getBottomRightCorner())) {
  327. return this.getTopLeftCorner();
  328. } else if (coords.isEqual(this.getTopLeftCorner())) {
  329. return this.getBottomRightCorner();
  330. } else if (coords.isEqual(this.getTopRightCorner())) {
  331. return this.getBottomLeftCorner();
  332. } else if (coords.isEqual(this.getBottomLeftCorner())) {
  333. return this.getTopRightCorner();
  334. }
  335. }
  336. /**
  337. * @param {CellRange} range
  338. * @returns {Array}
  339. */
  340. }, {
  341. key: 'getBordersSharedWith',
  342. value: function getBordersSharedWith(range) {
  343. if (!this.includesRange(range)) {
  344. return [];
  345. }
  346. var thisBorders = {
  347. top: Math.min(this.from.row, this.to.row),
  348. bottom: Math.max(this.from.row, this.to.row),
  349. left: Math.min(this.from.col, this.to.col),
  350. right: Math.max(this.from.col, this.to.col)
  351. };
  352. var rangeBorders = {
  353. top: Math.min(range.from.row, range.to.row),
  354. bottom: Math.max(range.from.row, range.to.row),
  355. left: Math.min(range.from.col, range.to.col),
  356. right: Math.max(range.from.col, range.to.col)
  357. };
  358. var result = [];
  359. if (thisBorders.top == rangeBorders.top) {
  360. result.push('top');
  361. }
  362. if (thisBorders.right == rangeBorders.right) {
  363. result.push('right');
  364. }
  365. if (thisBorders.bottom == rangeBorders.bottom) {
  366. result.push('bottom');
  367. }
  368. if (thisBorders.left == rangeBorders.left) {
  369. result.push('left');
  370. }
  371. return result;
  372. }
  373. /**
  374. * Get inner selected cell coords defined by this range
  375. *
  376. * @returns {Array}
  377. */
  378. }, {
  379. key: 'getInner',
  380. value: function getInner() {
  381. var topLeft = this.getTopLeftCorner();
  382. var bottomRight = this.getBottomRightCorner();
  383. var out = [];
  384. for (var r = topLeft.row; r <= bottomRight.row; r++) {
  385. for (var c = topLeft.col; c <= bottomRight.col; c++) {
  386. if (!(this.from.row === r && this.from.col === c) && !(this.to.row === r && this.to.col === c)) {
  387. out.push(new _coords2.default(r, c));
  388. }
  389. }
  390. }
  391. return out;
  392. }
  393. /**
  394. * Get all selected cell coords defined by this range
  395. *
  396. * @returns {Array}
  397. */
  398. }, {
  399. key: 'getAll',
  400. value: function getAll() {
  401. var topLeft = this.getTopLeftCorner();
  402. var bottomRight = this.getBottomRightCorner();
  403. var out = [];
  404. for (var r = topLeft.row; r <= bottomRight.row; r++) {
  405. for (var c = topLeft.col; c <= bottomRight.col; c++) {
  406. if (topLeft.row === r && topLeft.col === c) {
  407. out.push(topLeft);
  408. } else if (bottomRight.row === r && bottomRight.col === c) {
  409. out.push(bottomRight);
  410. } else {
  411. out.push(new _coords2.default(r, c));
  412. }
  413. }
  414. }
  415. return out;
  416. }
  417. /**
  418. * Runs a callback function against all cells in the range. You can break the iteration by returning
  419. * `false` in the callback function
  420. *
  421. * @param callback {Function}
  422. */
  423. }, {
  424. key: 'forAll',
  425. value: function forAll(callback) {
  426. var topLeft = this.getTopLeftCorner();
  427. var bottomRight = this.getBottomRightCorner();
  428. for (var r = topLeft.row; r <= bottomRight.row; r++) {
  429. for (var c = topLeft.col; c <= bottomRight.col; c++) {
  430. var breakIteration = callback(r, c);
  431. if (breakIteration === false) {
  432. return;
  433. }
  434. }
  435. }
  436. }
  437. }]);
  438. return CellRange;
  439. }();
  440. exports.default = CellRange;