| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- 'use strict';
- const _ = require('../utils/under-dash');
- const colCache = require('../utils/col-cache');
- const CellMatrix = require('../utils/cell-matrix');
- const Range = require('./range');
- const rangeRegexp = /[$](\w+)[$](\d+)(:[$](\w+)[$](\d+))?/;
- class DefinedNames {
- constructor() {
- this.matrixMap = {};
- }
- getMatrix(name) {
- const matrix = this.matrixMap[name] || (this.matrixMap[name] = new CellMatrix());
- return matrix;
- }
- // add a name to a cell. locStr in the form SheetName!$col$row or SheetName!$c1$r1:$c2:$r2
- add(locStr, name) {
- const location = colCache.decodeEx(locStr);
- this.addEx(location, name);
- }
- addEx(location, name) {
- const matrix = this.getMatrix(name);
- if (location.top) {
- for (let col = location.left; col <= location.right; col++) {
- for (let row = location.top; row <= location.bottom; row++) {
- const address = {
- sheetName: location.sheetName,
- address: colCache.n2l(col) + row,
- row,
- col,
- };
- matrix.addCellEx(address);
- }
- }
- } else {
- matrix.addCellEx(location);
- }
- }
- remove(locStr, name) {
- const location = colCache.decodeEx(locStr);
- this.removeEx(location, name);
- }
- removeEx(location, name) {
- const matrix = this.getMatrix(name);
- matrix.removeCellEx(location);
- }
- removeAllNames(location) {
- _.each(this.matrixMap, matrix => {
- matrix.removeCellEx(location);
- });
- }
- forEach(callback) {
- _.each(this.matrixMap, (matrix, name) => {
- matrix.forEach(cell => {
- callback(name, cell);
- });
- });
- }
- // get all the names of a cell
- getNames(addressStr) {
- return this.getNamesEx(colCache.decodeEx(addressStr));
- }
- getNamesEx(address) {
- return _.map(this.matrixMap, (matrix, name) => matrix.findCellEx(address) && name).filter(
- Boolean
- );
- }
- _explore(matrix, cell) {
- cell.mark = false;
- const {sheetName} = cell;
- const range = new Range(cell.row, cell.col, cell.row, cell.col, sheetName);
- let x;
- let y;
- // grow vertical - only one col to worry about
- function vGrow(yy, edge) {
- const c = matrix.findCellAt(sheetName, yy, cell.col);
- if (!c || !c.mark) {
- return false;
- }
- range[edge] = yy;
- c.mark = false;
- return true;
- }
- for (y = cell.row - 1; vGrow(y, 'top'); y--);
- for (y = cell.row + 1; vGrow(y, 'bottom'); y++);
- // grow horizontal - ensure all rows can grow
- function hGrow(xx, edge) {
- const cells = [];
- for (y = range.top; y <= range.bottom; y++) {
- const c = matrix.findCellAt(sheetName, y, xx);
- if (c && c.mark) {
- cells.push(c);
- } else {
- return false;
- }
- }
- range[edge] = xx;
- for (let i = 0; i < cells.length; i++) {
- cells[i].mark = false;
- }
- return true;
- }
- for (x = cell.col - 1; hGrow(x, 'left'); x--);
- for (x = cell.col + 1; hGrow(x, 'right'); x++);
- return range;
- }
- getRanges(name, matrix) {
- matrix = matrix || this.matrixMap[name];
- if (!matrix) {
- return {name, ranges: []};
- }
- // mark and sweep!
- matrix.forEach(cell => {
- cell.mark = true;
- });
- const ranges = matrix
- .map(cell => cell.mark && this._explore(matrix, cell))
- .filter(Boolean)
- .map(range => range.$shortRange);
- return {
- name,
- ranges,
- };
- }
- normaliseMatrix(matrix, sheetName) {
- // some of the cells might have shifted on specified sheet
- // need to reassign rows, cols
- matrix.forEachInSheet(sheetName, (cell, row, col) => {
- if (cell) {
- if (cell.row !== row || cell.col !== col) {
- cell.row = row;
- cell.col = col;
- cell.address = colCache.n2l(col) + row;
- }
- }
- });
- }
- spliceRows(sheetName, start, numDelete, numInsert) {
- _.each(this.matrixMap, matrix => {
- matrix.spliceRows(sheetName, start, numDelete, numInsert);
- this.normaliseMatrix(matrix, sheetName);
- });
- }
- spliceColumns(sheetName, start, numDelete, numInsert) {
- _.each(this.matrixMap, matrix => {
- matrix.spliceColumns(sheetName, start, numDelete, numInsert);
- this.normaliseMatrix(matrix, sheetName);
- });
- }
- get model() {
- // To get names per cell - just iterate over all names finding cells if they exist
- return _.map(this.matrixMap, (matrix, name) => this.getRanges(name, matrix)).filter(
- definedName => definedName.ranges.length
- );
- }
- set model(value) {
- // value is [ { name, ranges }, ... ]
- const matrixMap = (this.matrixMap = {});
- value.forEach(definedName => {
- const matrix = (matrixMap[definedName.name] = new CellMatrix());
- definedName.ranges.forEach(rangeStr => {
- if (rangeRegexp.test(rangeStr.split('!').pop() || '')) {
- matrix.addCell(rangeStr);
- }
- });
- });
- }
- }
- module.exports = DefinedNames;
|