From 102f6847a510a94200c412e919304b7f3972db77 Mon Sep 17 00:00:00 2001 From: Dmitriy Orlov Date: Thu, 16 Jan 2025 15:46:46 +0600 Subject: [PATCH] [se] Added processing of links to the current file when opening and writing formulas --- cell/model/FormulaObjects/parserFormula.js | 32 ++++++++-- cell/model/Workbook.js | 21 ++++++- common/editorscommon.js | 9 +++ .../ExternalReference.js | 60 +++++++++++++++++-- 4 files changed, 111 insertions(+), 11 deletions(-) diff --git a/cell/model/FormulaObjects/parserFormula.js b/cell/model/FormulaObjects/parserFormula.js index fce5546a8b..c1abf26bd9 100644 --- a/cell/model/FormulaObjects/parserFormula.js +++ b/cell/model/FormulaObjects/parserFormula.js @@ -8093,7 +8093,7 @@ function parserFormula( formula, parent, _ws ) { let sheetName = _3DRefTmp[1]; // _3DRefTmp[4] - shortlink info - let isExternalRefExist, externalLink, receivedLink, externalName, isShortLink, externalProps; + let isExternalRefExist, externalLink, receivedLink, externalName, isShortLink, externalProps, isCurrentFile, currentFileDefname; if (_3DRefTmp[4]) { externalProps = t.wb && t.wb.externalReferenceHelper && t.wb.externalReferenceHelper.check3dRef(_3DRefTmp, local); } else { @@ -8112,13 +8112,15 @@ function parserFormula( formula, parent, _ws ) { externalName = externalProps.externalName; receivedLink = externalProps.receivedLink; isShortLink = externalProps.isShortLink; + isCurrentFile = externalProps.isCurrentFile; + currentFileDefname = externalProps.currentFileDefname; } if (externalProps && !sheetName) { sheetName = externalProps.sheetName ? externalProps.sheetName : externalName; } - if (externalLink) { + if (externalLink && !isCurrentFile) { if (local) { externalLink = t.wb.getExternalLinkIndexByName(externalLink); if (externalLink === null) { @@ -8149,7 +8151,7 @@ function parserFormula( formula, parent, _ws ) { // if we refer to defname that doesn't exist, but the ER itself exists, then we refer to the first existing worksheet // since we don't know the name of the sheet in the short link and defname doesn't exist wsF = t.wb.getExternalWorksheet(externalLink, sheetName, true /* getFirtsSheet */); - + // todo in future versions it's necessary to check the internal defname and refer to it when opening the file with [0] eLink. // todo Research needed. this is special case when externalLink equal [0] and it refers to the current file if (!wsF) { @@ -8163,7 +8165,29 @@ function parserFormula( formula, parent, _ws ) { wsT = wsF; } else { - wsF = t.wb.getWorksheetByName(sheetName/*_3DRefTmp[1]*/); + // isCurrentFileCheck + let currentDefname, sheet; + if (isCurrentFile && currentFileDefname /*&& !local*/) { + // looking for defname from this sheet + currentDefname = t.wb.getDefinesNames(currentFileDefname); + if (!currentDefname) { + // todo it's not entirely clear what needs to be returned in the absence of defname - an error or cName + // parseResult.setError(c_oAscError.ID.FrmlWrongReferences); + // if (!ignoreErrors) { + // t.outStack = []; + // return false; + // } + + sheet = t.wb.getActiveWs(); + wsF = t.wb.getWorksheetByName(sheet.getName()); + } else { + let exclamationMarkIndex = currentDefname.ref && currentDefname.ref.lastIndexOf("!"); + sheet = currentDefname.ref.slice(0, exclamationMarkIndex); + wsF = t.wb.getWorksheetByName(sheet); + } + } + + wsF = wsF ? wsF : t.wb.getWorksheetByName(sheetName/*_3DRefTmp[1]*/); wsT = (null !== _3DRefTmp[2]) ? t.wb.getWorksheetByName(_3DRefTmp[2]) : wsF; } diff --git a/cell/model/Workbook.js b/cell/model/Workbook.js index c6a66b2bdf..52aae8ad7a 100644 --- a/cell/model/Workbook.js +++ b/cell/model/Workbook.js @@ -23514,6 +23514,12 @@ CExternalReferenceHelper.prototype.getExternalLinkStr = function (nExternalLinkIndex, locale, isShortLink) { let index = nExternalLinkIndex; + let sameFile; + let fileName = window["Asc"]["editor"].DocInfo && window["Asc"]["editor"].DocInfo.get_Title(); + if (index === fileName) { + sameFile = true; + } + let wbModel = this.wb; let oExternalLink = nExternalLinkIndex && wbModel && wbModel.getExternalLinkByIndex(index - 1, true); @@ -23532,6 +23538,8 @@ } } else if (oExternalLink) { res = oExternalLink; + } else if (sameFile) { + res += locale ? index : "[0]"; } return res; }; @@ -23539,7 +23547,7 @@ CExternalReferenceHelper.prototype.check3dRef = function (_3DRefTmp, local) { let t = this; let externalLink = _3DRefTmp[3]; - let externalDefName, externalSheetName, receivedDefName, receivedLink, isShortLink; + let externalDefName, externalSheetName, receivedDefName, receivedLink, isShortLink, isCurrentFile; // this argument contain shortLink object with full formula and two parts of it let receivedShortLink = _3DRefTmp[4]; @@ -23549,6 +23557,7 @@ receivedLink = receivedShortLink.externalLink; externalSheetName = receivedShortLink.externalLink; receivedDefName = receivedShortLink.defname; + isCurrentFile = receivedShortLink.currentFile; } // This check of short links is performed only when opening/reading, manual input is processed differently @@ -23632,7 +23641,15 @@ } } - return {sheetName: sheetName, externalLink: externalLink, receivedLink: receivedLink, externalName: externalName, isShortLink: isShortLink}; + return { + sheetName: sheetName, + externalLink: externalLink, + receivedLink: receivedLink, + externalName: externalName, + isShortLink: isShortLink, + isCurrentFile: isCurrentFile, + currentFileDefname: isCurrentFile ? receivedDefName : null + }; }; // Export diff --git a/common/editorscommon.js b/common/editorscommon.js index be3e3ca86d..456e0fe915 100644 --- a/common/editorscommon.js +++ b/common/editorscommon.js @@ -3475,10 +3475,19 @@ } } + /* current file check */ + let currentFileName = window["Asc"]["editor"].DocInfo && window["Asc"]["editor"].DocInfo.get_Title(); + // let currentFileDefname; + /* shortlink return obj {fullstring, externalLink, defname} */ let shortLink = isExternalShortLink(subSTR) || (local && !external && isExternalShortLinkLocal(subSTR)); if (shortLink) { + if ((shortLink.externalLink && shortLink.externalLink === currentFileName) || external === "0") { + external = null; + shortLink.currentFile = true; + } + this.pCurrPos += shortLink.fullString.length + externalLength; this.operand_str = shortLink.defname; return [true, null, null, external, shortLink]; diff --git a/tests/cell/spreadsheet-calculation/ExternalReference.js b/tests/cell/spreadsheet-calculation/ExternalReference.js index 2a0b81051d..ce8d84e33b 100644 --- a/tests/cell/spreadsheet-calculation/ExternalReference.js +++ b/tests/cell/spreadsheet-calculation/ExternalReference.js @@ -996,6 +996,7 @@ $(function () { QUnit.test("Test: \"Check short links\"", function (assert) { // create ext link // check parser formula - simulate reading a string like [linkIndex] + "SheetName" + "!" + "ReferenceTo" + let fileName = window["Asc"]["editor"].DocInfo && window["Asc"]["editor"].DocInfo.get_Title(); let fullLinkLocal = "'[book.xlsx]Sheet1'!A1", fullLinkDefnameLocal = "'[book.xlsx]Sheet1'!_s1", fullLink = "'[1]Sheet1'!A1", @@ -1033,6 +1034,10 @@ $(function () { // defNames.wb[this.Name].getRef(); // wb.externalReferences[0].addDefName() + // add defname to current workbook([0] tests) + wb.dependencyFormulas.addDefName("currentDef", "Sheet2!$A$1:$B$2"); + wb.createWorksheet(0, "Sheet2"); + // local = false. Read/open file with formulas. Try to parse string to external ref similiar as read the file oParser = new parserFormula(fullLink, cellWithFormula, ws); assert.ok(oParser.parse(false/*isLocal*/, null, parseResult), "Full link. isLocal = false. " + fullLink); @@ -1074,14 +1079,59 @@ $(function () { oParser = new parserFormula("SUM('[1]'!_s1,2,3)", cellWithFormula, ws); assert.ok(oParser.parse(false, null, parseResult) === false, "SUM('[1]'!_s1,2,3). isLocal = false"); - // for bug 72385. eR in file === [0] - oParser = new parserFormula("[0]!_s1", cellWithFormula, ws); - assert.ok(oParser.parse(false, null, parseResult) === false, "[0]!_s1. isLocal = false"); + /* Links to current file check. Formula in file have format "[0]!defname" */ + oParser = new parserFormula("[0]!currentDef", cellWithFormula, ws); + assert.ok(oParser.parse(false, null, parseResult), "[0]!currentDef. isLocal = false. Link to existing defname in current wb"); + elemInStack = oParser.outStack && oParser.outStack[0]; + if (elemInStack && (elemInStack.type === AscCommonExcel.cElementType.name3D)) { + assert.strictEqual(elemInStack.value, "currentDef"); + assert.ok(elemInStack.ws); + assert.strictEqual(elemInStack.ws && elemInStack.ws.sName, "Sheet2", "Defname location"); + assert.ok(wb.getDefinesNames(elemInStack.value), "Defname exist on second sheet"); + } + + oParser = new parserFormula("SUM([0]!currentDef,2,3,4)", cellWithFormula, ws); + assert.ok(oParser.parse(false, null, parseResult), "SUM([0]!currentDef,2,3,4). isLocal = false. Link to existing defname in current wb inside the formula"); + + oParser = new parserFormula("[0]!_nonExistentDefname", cellWithFormula, ws); + assert.ok(oParser.parse(false, null, parseResult), "[0]!_nonExistentDefname. isLocal = false. Link to non-existent defname in current wb"); + elemInStack = oParser.outStack && oParser.outStack[0]; + if (elemInStack && (elemInStack.type === AscCommonExcel.cElementType.name3D)) { + assert.strictEqual(elemInStack.value, "_nonExistentDefname"); + assert.ok(elemInStack.ws); + assert.strictEqual(elemInStack.ws && elemInStack.ws.sName, wb.getActiveWs() && wb.getActiveWs().getName(), "Location for WS in cName3D by default"); + assert.ok(!wb.getDefinesNames(elemInStack.value), "Defname doesn't exist"); + } - oParser = new parserFormula("SUM([0]!_s1,2,3,4)", cellWithFormula, ws); - assert.ok(oParser.parse(false, null, parseResult) === false, "SUM([0]!_s1,2,3,4). isLocal = false"); + oParser = new parserFormula("SUM([0]!_nonExistentDefname,2,3,4)", cellWithFormula, ws); + assert.ok(oParser.parse(false, null, parseResult), "SUM([0]!_nonExistentDefname,2,3,4). isLocal = false. Link to non-existent defname in current wb inside the formula"); // local = true. Manual input. Try parse string to external ref similiar as writing a string manually + /* Links to current file check. Formula is typed as "filename.xlsx!defname" */ + oParser = new parserFormula(fileName + "!currentDef", cellWithFormula, ws); + assert.ok(oParser.parse(true, null, parseResult), fileName +"!currentDef. isLocal = true. Link to existing defname in current wb"); + elemInStack = oParser.outStack && oParser.outStack[0]; + if (elemInStack && (elemInStack.type === AscCommonExcel.cElementType.name3D)) { + assert.strictEqual(elemInStack.value, "currentDef"); + assert.ok(elemInStack.ws); + assert.ok(elemInStack.shortLink); + assert.strictEqual(elemInStack.externalLink, fileName); + assert.strictEqual(elemInStack.ws && elemInStack.ws.sName, "Sheet2", "Defname location"); + assert.ok(wb.getDefinesNames(elemInStack.value), "Defname exist on the second sheet"); + } + + oParser = new parserFormula(fileName + "!_nonExistentDefname", cellWithFormula, ws); + assert.ok(oParser.parse(true, null, parseResult), fileName +"!_nonExistentDefname. isLocal = true. Link to non-existent defname in current wb"); + elemInStack = oParser.outStack && oParser.outStack[0]; + if (elemInStack && (elemInStack.type === AscCommonExcel.cElementType.name3D)) { + assert.strictEqual(elemInStack.value, "_nonExistentDefname"); + assert.ok(elemInStack.ws); + assert.ok(elemInStack.shortLink); + assert.strictEqual(elemInStack.externalLink, fileName); + assert.strictEqual(elemInStack.ws && elemInStack.ws.sName, wb.getActiveWs() && wb.getActiveWs().getName(), "Location for WS in cName3D by default"); + assert.ok(!wb.getDefinesNames(elemInStack.value), "Defname doesn't exist"); + } + oParser = new parserFormula(fullLinkLocal, cellWithFormula, ws); assert.ok(oParser.parse(true/*isLocal*/, null, parseResult), "Full link. isLocal = true. " + fullLinkLocal);