diff --git a/cell/model/FormulaObjects/parserFormula.js b/cell/model/FormulaObjects/parserFormula.js index 092d0c2dc7..e0019d30ec 100644 --- a/cell/model/FormulaObjects/parserFormula.js +++ b/cell/model/FormulaObjects/parserFormula.js @@ -2347,7 +2347,7 @@ parserHelp.setDigitSeparator(AscCommon.g_oDefaultCultureInfo.NumberDecimalSepara } else if (null != this.reservedColumnIndex) { if (this.isDynamic && isLocal && this.reservedColumnIndex === AscCommon.FormulaTablePartInfo.thisRow) { tblStr += "[" + "@" + "]"; - } else if (this.isDynamic) { + } else /*if (this.isDynamic)*/ { tblStr += "[" + this._buildLocalTableString(this.reservedColumnIndex, isLocal) + "]"; } } else if (this.hdtIndexes || this.hdtcstartIndex || this.hdtcendIndex) { @@ -2422,6 +2422,14 @@ parserHelp.setDigitSeparator(AscCommon.g_oDefaultCultureInfo.NumberDecimalSepara this.isDynamic = true; } + let openBracketIndex = startCol.indexOf("["); + if (openBracketIndex !== -1) { + let closeBracketIndex = startCol.lastIndexOf("]"); + if (closeBracketIndex !== -1) { + startCol = startCol.slice(openBracketIndex + 1, closeBracketIndex); + } + } + this.oneColumnIndex = this.wb.getTableIndexColumnByName(this.tableName, this.isDynamic ? startCol.slice(1) : startCol); bRes = !!this.oneColumnIndex; } else if (val['columnRange']) { @@ -8278,7 +8286,7 @@ function parserFormula( formula, parent, _ws ) { if (local || (local === false && digitDelim === false)) { // local and digitDelim with value false using only for copypaste mode. t.ca = isRecursiveFormula(found_operand, t); } - } else if (_tableTMP = parserHelp.isTable.call(ph, t.Formula, ph.pCurrPos, local)) { + } else if (_tableTMP = parserHelp.isTable.call(ph, t.Formula, ph.pCurrPos, local, t)) { found_operand = cStrucTable.prototype.createFromVal(_tableTMP, t.wb, t.ws, tablesMap); //todo undo delete column diff --git a/common/editorscommon.js b/common/editorscommon.js index 553eee90f2..e331ffcef2 100644 --- a/common/editorscommon.js +++ b/common/editorscommon.js @@ -1491,14 +1491,14 @@ function build_rx_table_cur() { - var loc_all = cStrucTableLocalColumns['a'], + let loc_all = cStrucTableLocalColumns['a'], loc_headers = cStrucTableLocalColumns['h'], loc_data = cStrucTableLocalColumns['d'], loc_totals = cStrucTableLocalColumns['t'], loc_this_row = cStrucTableLocalColumns['tr'], structured_tables_headata = new XRegExp('(?:\\[\\#' + loc_headers + '\\]\\' + FormulaSeparators.functionArgumentSeparator + '\\[\\#' + loc_data + '\\])'), structured_tables_datals = new XRegExp('(?:\\[\\#' + loc_data + '\\]\\' + FormulaSeparators.functionArgumentSeparator + '\\[\\#' + loc_totals + '\\])'), - structured_tables_userColumn = new XRegExp('(?:\'\\[|\'\\]|[^[\\]])+'), + structured_tables_userColumn = new XRegExp('\\s*\\[{0,1}(?:\'\\[|\'\\]|[^[\\]])+\\]{0,1}\\s*'), structured_tables_reservedColumn = new XRegExp('\\#(?:' + loc_all + '|' + loc_headers + '|' + loc_totals + '|' + loc_data + /*'|' + loc_this_row + */')'), structured_tables_thisRow = new XRegExp('(?:\\#(?:' + loc_this_row +')|(?:\\@))'); @@ -1524,7 +1524,7 @@ let argsSeparator = FormulaSeparators.functionArgumentSeparator; return XRegExp.build('^(?{{tableName}})\\[(?{{columnName}})?\\]', { "tableName": new XRegExp("^(:?[" + str_namedRanges + "][" + str_namedRanges + "\\d.]*)"), - "columnName": XRegExp.build('(?{{reservedColumn}}|{{thisRow}})|(?{{userColumn}})|(?{{userColumnRange}})|(?{{hdtcc}})', { + "columnName": XRegExp.build('(?{{hdtcc}})|(?{{reservedColumn}}|{{thisRow}})|(?{{userColumn}})|(?{{userColumnRange}})', { "userColumn": structured_tables_userColumn, "reservedColumn": structured_tables_reservedColumn, "thisRow": structured_tables_thisRow, @@ -3869,19 +3869,44 @@ return true; } }; - parserHelper.prototype.isTable = function (formula, start_pos, local) + parserHelper.prototype.isTable = function (formula, start_pos, local, parserFormula) { if (this instanceof parserHelper) { this._reset(); } - let subSTR = formula.substring(start_pos), - match = XRegExp.exec(subSTR, local ? rx_table_local : rx_table); + let subSTR = formula.substring(start_pos); + /* + short notation can be used inside table cells + short entry - an entry without table name, but with the same syntax + */ + let tableIntersection; + if (local && subSTR[0] === "[" && parserFormula.parent && parserFormula.ws && parserFormula.ws.TableParts) { + let col = parserFormula.parent.nCol; + let row = parserFormula.parent.nRow; + // go through each existing table and check intersection by col row + for (let i = 0; i < parserFormula.ws.TableParts.length; i++) { + let table = parserFormula.ws.TableParts[i]; + let tableRef = table.Ref; + if (!tableRef.contains(col, row)) { + continue; + } + tableIntersection = table; + break; + } + + if (tableIntersection) { + // add the table name to the beginning of the line for correct checking further + subSTR = tableIntersection.DisplayName + subSTR; + } + } + + const match = XRegExp.exec(subSTR, local ? rx_table_local : rx_table); if (match != null && match["tableName"]) { - this.operand_str = match[0]; - this.pCurrPos += match[0].length; + this.operand_str = tableIntersection ? "[" + match.columnName1 + "]" : match[0]; + this.pCurrPos += tableIntersection ? match.columnName1.length + 2 : match[0].length; return match; } diff --git a/tests/cell/spreadsheet-calculation/SheetStructureTests.js b/tests/cell/spreadsheet-calculation/SheetStructureTests.js index dcb3d36414..4a66ee5825 100644 --- a/tests/cell/spreadsheet-calculation/SheetStructureTests.js +++ b/tests/cell/spreadsheet-calculation/SheetStructureTests.js @@ -2843,8 +2843,8 @@ $(function () { resCell = ws.getRange4(101, 70); resCell.setValue("=" + tableName +"[#All]"); - assert.strictEqual(resCell.getValueForEdit(), "=" + tableName, "Value for edit in cell after Table[#All] is typed"); - assert.strictEqual(resCell.getFormula(), tableName, "Formula in cell after Table[#All] is typed"); + assert.strictEqual(resCell.getValueForEdit(), "=" + tableName + "[#All]", "Value for edit in cell after Table[#All] is typed"); + assert.strictEqual(resCell.getFormula(), tableName + "[#All]", "Formula in cell after Table[#All] is typed"); // calc res check @@ -2883,8 +2883,8 @@ $(function () { resCell = ws.getRange4(101, 80); resCell.setValue("=" + tableName +"[#Data]"); - assert.strictEqual(resCell.getValueForEdit(), "=" + tableName, "Value for edit in cell after Table[#Data] is typed"); - assert.strictEqual(resCell.getFormula(), tableName, "Formula in cell after Table[#Data] is typed"); + assert.strictEqual(resCell.getValueForEdit(), "=" + tableName +"[#Data]", "Value for edit in cell after Table[#Data] is typed"); + assert.strictEqual(resCell.getFormula(), tableName +"[#Data]", "Formula in cell after Table[#Data] is typed"); // calc res check @@ -3021,6 +3021,40 @@ $(function () { assert.strictEqual(resCell.getValueForEdit(), "=" + tableName + "[[#Data],[#Headers]]", "Value for edit in cell after Table[[#Data],[#Headers]] is typed"); assert.strictEqual(resCell.getFormula(), tableName + "[[#Data],[#Headers]]", "Formula in cell after Table[[#Data],[#Headers]] is typed"); + // for bug 46174 + // calc res check + cellWithFormula = new AscCommonExcel.CCellWithFormula(ws, 104, 0); + oParser = new AscCommonExcel.parserFormula("[[Column1]]", cellWithFormula, ws); + assert.ok(oParser.parse(true)); + array = oParser.calculate(); + assert.strictEqual(array.getValueByRowCol(0, 0).getValue(), 1, 'Short notation. Result of [[Column1]][0,0] inside table'); + assert.strictEqual(array.getValueByRowCol(1, 0).getValue(), 1, 'Short notation. Result of [[Column1]][1,0] inside table'); + assert.strictEqual(array.getValueByRowCol(2, 0).getValue(), 1, 'Short notation. Result of [[Column1]][2,0] inside table'); + assert.strictEqual(array.getValueByRowCol(3, 0).getValue(), 1, 'Short notation. Result of [[Column1]][3,0] inside table'); + + cellWithFormula = new AscCommonExcel.CCellWithFormula(ws, 105, 0); + oParser = new AscCommonExcel.parserFormula("[[Column1]]", cellWithFormula, ws); + assert.ok(!oParser.parse(true)); + array = oParser.calculate(); + assert.strictEqual(array.type, AscCommonExcel.cElementType.error, 'Short notation. Result of [[Column1]] outside table'); + + cellWithFormula = new AscCommonExcel.CCellWithFormula(ws, 101, 20); + oParser = new AscCommonExcel.parserFormula(tableName + "[[Column1]]", cellWithFormula, ws); + assert.ok(oParser.parse()); + array = oParser.calculate(); + assert.strictEqual(array.getValueByRowCol(0, 0).getValue(), 1, 'Result of [[Column1]][0,0]'); + assert.strictEqual(array.getValueByRowCol(1, 0).getValue(), 1, 'Result of [[Column1]][1,0]'); + assert.strictEqual(array.getValueByRowCol(2, 0).getValue(), 1, 'Result of [[Column1]][2,0]'); + assert.strictEqual(array.getValueByRowCol(3, 0).getValue(), 1, 'Result of [[Column1]][3,0]'); + + // value for edit and formula in cell check + resCell = ws.getRange4(101, 20); + resCell.setValue("=" + tableName +"[[Column1]]"); + + assert.strictEqual(resCell.getValueForEdit(), "=" + tableName + "[Column1]", "Value for edit in cell after Table[[Column1]] is typed"); + assert.strictEqual(resCell.getFormula(), tableName + "[Column1]", "Formula in cell after Table[[Column1]] is typed"); + + clearData(0, 99, 0, 105); }); @@ -3040,7 +3074,6 @@ $(function () { let tables = wsView.model.autoFilters.getTablesIntersectionRange(new Asc.Range(0, 100, 0, 100)); assert.strictEqual(tables.length, 1, "compare tables length"); - debugger let table = tables[0]; let tableName = table.DisplayName; // due to the fact that other tables are used in file, get the name of the one we need by this way wsView.af_changeFormatTableInfo(tableName, Asc.c_oAscChangeTableStyleInfo.rowTotal, true); @@ -3062,8 +3095,8 @@ $(function () { resCell = ws.getRange4(101, 70); resCell.setValue("=" + tableName +"[#All]"); - assert.strictEqual(resCell.getValueForEdit(), "=" + tableName, "Value for edit in cell after Table[#All] is typed"); - assert.strictEqual(resCell.getFormula(), tableName, "Formula in cell after Table[#All] is typed"); + assert.strictEqual(resCell.getValueForEdit(), "=" + tableName + "[#All]", "Value for edit in cell after Table[#All] is typed"); + assert.strictEqual(resCell.getFormula(), tableName + "[#All]", "Formula in cell after Table[#All] is typed"); /* column header check */