Skip to content

Commit

Permalink
[se] Added processing of links to the current file when opening and w…
Browse files Browse the repository at this point in the history
…riting formulas
  • Loading branch information
DimitryOrlov committed Jan 16, 2025
1 parent 32f2766 commit 102f684
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 11 deletions.
32 changes: 28 additions & 4 deletions cell/model/FormulaObjects/parserFormula.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}

Expand Down
21 changes: 19 additions & 2 deletions cell/model/Workbook.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -23532,14 +23538,16 @@
}
} else if (oExternalLink) {
res = oExternalLink;
} else if (sameFile) {
res += locale ? index : "[0]";
}
return res;
};

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];
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions common/editorscommon.js
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
60 changes: 55 additions & 5 deletions tests/cell/spreadsheet-calculation/ExternalReference.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 102f684

Please sign in to comment.