@visactor/vtable-sheet 1.20.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/components/vtable-sheet.d.ts +78 -0
- package/cjs/components/vtable-sheet.js +474 -0
- package/cjs/components/vtable-sheet.js.map +1 -0
- package/cjs/core/WorkSheet.d.ts +69 -0
- package/cjs/core/WorkSheet.js +298 -0
- package/cjs/core/WorkSheet.js.map +1 -0
- package/cjs/core/table-plugins.d.ts +3 -0
- package/cjs/core/table-plugins.js +171 -0
- package/cjs/core/table-plugins.js.map +1 -0
- package/cjs/event/event-manager.d.ts +29 -0
- package/cjs/event/event-manager.js +71 -0
- package/cjs/event/event-manager.js.map +1 -0
- package/cjs/event/event-target.d.ts +12 -0
- package/cjs/event/event-target.js +50 -0
- package/cjs/event/event-target.js.map +1 -0
- package/cjs/formula/cell-highlight-manager.d.ts +29 -0
- package/cjs/formula/cell-highlight-manager.js +141 -0
- package/cjs/formula/cell-highlight-manager.js.map +1 -0
- package/cjs/formula/formula-autocomplete.d.ts +39 -0
- package/cjs/formula/formula-autocomplete.js +239 -0
- package/cjs/formula/formula-autocomplete.js.map +1 -0
- package/cjs/formula/formula-editor.d.ts +21 -0
- package/cjs/formula/formula-editor.js +162 -0
- package/cjs/formula/formula-editor.js.map +1 -0
- package/cjs/formula/formula-helper.d.ts +8 -0
- package/cjs/formula/formula-helper.js +66 -0
- package/cjs/formula/formula-helper.js.map +1 -0
- package/cjs/formula/formula-range-selector.d.ts +19 -0
- package/cjs/formula/formula-range-selector.js +201 -0
- package/cjs/formula/formula-range-selector.js.map +1 -0
- package/cjs/formula/formula-throttle.d.ts +10 -0
- package/cjs/formula/formula-throttle.js +39 -0
- package/cjs/formula/formula-throttle.js.map +1 -0
- package/cjs/formula/formula-ui-manager.d.ts +19 -0
- package/cjs/formula/formula-ui-manager.js +226 -0
- package/cjs/formula/formula-ui-manager.js.map +1 -0
- package/cjs/formula/index.d.ts +5 -0
- package/cjs/formula/index.js +23 -0
- package/cjs/formula/index.js.map +1 -0
- package/cjs/index.d.ts +6 -0
- package/cjs/index.js +50 -0
- package/cjs/index.js.map +1 -0
- package/cjs/managers/formula-manager.d.ts +82 -0
- package/cjs/managers/formula-manager.js +445 -0
- package/cjs/managers/formula-manager.js.map +1 -0
- package/cjs/managers/menu-manager.d.ts +12 -0
- package/cjs/managers/menu-manager.js +89 -0
- package/cjs/managers/menu-manager.js.map +1 -0
- package/cjs/managers/sheet-manager.d.ts +21 -0
- package/cjs/managers/sheet-manager.js +74 -0
- package/cjs/managers/sheet-manager.js.map +1 -0
- package/cjs/managers/tab-drag-manager.d.ts +24 -0
- package/cjs/managers/tab-drag-manager.js +121 -0
- package/cjs/managers/tab-drag-manager.js.map +1 -0
- package/cjs/sheet-helper.d.ts +16 -0
- package/cjs/sheet-helper.js +64 -0
- package/cjs/sheet-helper.js.map +1 -0
- package/cjs/styles/common.d.ts +1 -0
- package/cjs/styles/common.js +17 -0
- package/cjs/styles/common.js.map +1 -0
- package/cjs/styles/formula-autocomplete.d.ts +1 -0
- package/cjs/styles/formula-autocomplete.js +17 -0
- package/cjs/styles/formula-autocomplete.js.map +1 -0
- package/cjs/styles/formula-bar.d.ts +1 -0
- package/cjs/styles/formula-bar.js +17 -0
- package/cjs/styles/formula-bar.js.map +1 -0
- package/cjs/styles/menu.d.ts +1 -0
- package/cjs/styles/menu.js +17 -0
- package/cjs/styles/menu.js.map +1 -0
- package/cjs/styles/sheet-tab.d.ts +1 -0
- package/cjs/styles/sheet-tab.js +17 -0
- package/cjs/styles/sheet-tab.js.map +1 -0
- package/cjs/styles/sheet.d.ts +1 -0
- package/cjs/styles/sheet.js +17 -0
- package/cjs/styles/sheet.js.map +1 -0
- package/cjs/styles/style-manager.d.ts +1 -0
- package/cjs/styles/style-manager.js +15 -0
- package/cjs/styles/style-manager.js.map +1 -0
- package/cjs/test/formula-complete.test.d.ts +1 -0
- package/cjs/test/formula-complete.test.js +42 -0
- package/cjs/test/formula-complete.test.js.map +1 -0
- package/cjs/tools/env.d.ts +20 -0
- package/cjs/tools/env.js +59 -0
- package/cjs/tools/env.js.map +1 -0
- package/cjs/tools/index.d.ts +3 -0
- package/cjs/tools/index.js +16 -0
- package/cjs/tools/index.js.map +1 -0
- package/cjs/tools/ui/snackbar.d.ts +1 -0
- package/cjs/tools/ui/snackbar.js +20 -0
- package/cjs/tools/ui/snackbar.js.map +1 -0
- package/cjs/ts-types/base.d.ts +44 -0
- package/cjs/ts-types/base.js +14 -0
- package/cjs/ts-types/base.js.map +1 -0
- package/cjs/ts-types/event.d.ts +79 -0
- package/cjs/ts-types/event.js +6 -0
- package/cjs/ts-types/event.js.map +1 -0
- package/cjs/ts-types/events.d.ts +1 -0
- package/cjs/ts-types/events.js +3 -0
- package/cjs/ts-types/events.js.map +1 -0
- package/cjs/ts-types/filter.d.ts +58 -0
- package/cjs/ts-types/filter.js +16 -0
- package/cjs/ts-types/filter.js.map +1 -0
- package/cjs/ts-types/formula.d.ts +51 -0
- package/cjs/ts-types/formula.js +6 -0
- package/cjs/ts-types/formula.js.map +1 -0
- package/cjs/ts-types/index.d.ts +67 -0
- package/cjs/ts-types/index.js +37 -0
- package/cjs/ts-types/index.js.map +1 -0
- package/cjs/ts-types/sheet.d.ts +45 -0
- package/cjs/ts-types/sheet.js +6 -0
- package/cjs/ts-types/sheet.js.map +1 -0
- package/cjs/vtable.d.ts +1 -0
- package/cjs/vtable.js +35 -0
- package/cjs/vtable.js.map +1 -0
- package/dist/vtable-sheet.js +114494 -0
- package/dist/vtable-sheet.min.js +853 -0
- package/es/components/vtable-sheet.d.ts +78 -0
- package/es/components/vtable-sheet.js +462 -0
- package/es/components/vtable-sheet.js.map +1 -0
- package/es/core/WorkSheet.d.ts +69 -0
- package/es/core/WorkSheet.js +298 -0
- package/es/core/WorkSheet.js.map +1 -0
- package/es/core/table-plugins.d.ts +3 -0
- package/es/core/table-plugins.js +164 -0
- package/es/core/table-plugins.js.map +1 -0
- package/es/event/event-manager.d.ts +29 -0
- package/es/event/event-manager.js +63 -0
- package/es/event/event-manager.js.map +1 -0
- package/es/event/event-target.d.ts +12 -0
- package/es/event/event-target.js +42 -0
- package/es/event/event-target.js.map +1 -0
- package/es/formula/cell-highlight-manager.d.ts +29 -0
- package/es/formula/cell-highlight-manager.js +133 -0
- package/es/formula/cell-highlight-manager.js.map +1 -0
- package/es/formula/formula-autocomplete.d.ts +39 -0
- package/es/formula/formula-autocomplete.js +231 -0
- package/es/formula/formula-autocomplete.js.map +1 -0
- package/es/formula/formula-editor.d.ts +21 -0
- package/es/formula/formula-editor.js +135 -0
- package/es/formula/formula-editor.js.map +1 -0
- package/es/formula/formula-helper.d.ts +8 -0
- package/es/formula/formula-helper.js +60 -0
- package/es/formula/formula-helper.js.map +1 -0
- package/es/formula/formula-range-selector.d.ts +19 -0
- package/es/formula/formula-range-selector.js +195 -0
- package/es/formula/formula-range-selector.js.map +1 -0
- package/es/formula/formula-throttle.d.ts +10 -0
- package/es/formula/formula-throttle.js +31 -0
- package/es/formula/formula-throttle.js.map +1 -0
- package/es/formula/formula-ui-manager.d.ts +19 -0
- package/es/formula/formula-ui-manager.js +218 -0
- package/es/formula/formula-ui-manager.js.map +1 -0
- package/es/formula/index.d.ts +5 -0
- package/es/formula/index.js +10 -0
- package/es/formula/index.js.map +1 -0
- package/es/index.d.ts +6 -0
- package/es/index.js +13 -0
- package/es/index.js.map +1 -0
- package/es/managers/formula-manager.d.ts +82 -0
- package/es/managers/formula-manager.js +441 -0
- package/es/managers/formula-manager.js.map +1 -0
- package/es/managers/menu-manager.d.ts +12 -0
- package/es/managers/menu-manager.js +81 -0
- package/es/managers/menu-manager.js.map +1 -0
- package/es/managers/sheet-manager.d.ts +21 -0
- package/es/managers/sheet-manager.js +66 -0
- package/es/managers/sheet-manager.js.map +1 -0
- package/es/managers/tab-drag-manager.d.ts +24 -0
- package/es/managers/tab-drag-manager.js +113 -0
- package/es/managers/tab-drag-manager.js.map +1 -0
- package/es/sheet-helper.d.ts +16 -0
- package/es/sheet-helper.js +54 -0
- package/es/sheet-helper.js.map +1 -0
- package/es/styles/common.d.ts +1 -0
- package/es/styles/common.js +9 -0
- package/es/styles/common.js.map +1 -0
- package/es/styles/formula-autocomplete.d.ts +1 -0
- package/es/styles/formula-autocomplete.js +9 -0
- package/es/styles/formula-autocomplete.js.map +1 -0
- package/es/styles/formula-bar.d.ts +1 -0
- package/es/styles/formula-bar.js +9 -0
- package/es/styles/formula-bar.js.map +1 -0
- package/es/styles/menu.d.ts +1 -0
- package/es/styles/menu.js +9 -0
- package/es/styles/menu.js.map +1 -0
- package/es/styles/sheet-tab.d.ts +1 -0
- package/es/styles/sheet-tab.js +9 -0
- package/es/styles/sheet-tab.js.map +1 -0
- package/es/styles/sheet.d.ts +1 -0
- package/es/styles/sheet.js +9 -0
- package/es/styles/sheet.js.map +1 -0
- package/es/styles/style-manager.d.ts +1 -0
- package/es/styles/style-manager.js +17 -0
- package/es/styles/style-manager.js.map +1 -0
- package/es/test/formula-complete.test.d.ts +1 -0
- package/es/test/formula-complete.test.js +36 -0
- package/es/test/formula-complete.test.js.map +1 -0
- package/es/tools/env.d.ts +20 -0
- package/es/tools/env.js +53 -0
- package/es/tools/env.js.map +1 -0
- package/es/tools/index.d.ts +3 -0
- package/es/tools/index.js +9 -0
- package/es/tools/index.js.map +1 -0
- package/es/tools/ui/snackbar.d.ts +1 -0
- package/es/tools/ui/snackbar.js +14 -0
- package/es/tools/ui/snackbar.js.map +1 -0
- package/es/ts-types/base.d.ts +44 -0
- package/es/ts-types/base.js +14 -0
- package/es/ts-types/base.js.map +1 -0
- package/es/ts-types/event.d.ts +79 -0
- package/es/ts-types/event.js +2 -0
- package/es/ts-types/event.js.map +1 -0
- package/es/ts-types/events.d.ts +1 -0
- package/es/ts-types/events.js +3 -0
- package/es/ts-types/events.js.map +1 -0
- package/es/ts-types/filter.d.ts +58 -0
- package/es/ts-types/filter.js +16 -0
- package/es/ts-types/filter.js.map +1 -0
- package/es/ts-types/formula.d.ts +51 -0
- package/es/ts-types/formula.js +2 -0
- package/es/ts-types/formula.js.map +1 -0
- package/es/ts-types/index.d.ts +67 -0
- package/es/ts-types/index.js +14 -0
- package/es/ts-types/index.js.map +1 -0
- package/es/ts-types/sheet.d.ts +45 -0
- package/es/ts-types/sheet.js +2 -0
- package/es/ts-types/sheet.js.map +1 -0
- package/es/vtable.d.ts +1 -0
- package/es/vtable.js +2 -0
- package/es/vtable.js.map +1 -0
- package/package.json +120 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/formula/formula-helper.ts"],"names":[],"mappings":";;;AAAa,QAAA,kBAAkB,GAAG;IAChC,KAAK;IACL,SAAS;IACT,KAAK;IACL,KAAK;IACL,OAAO;IACP,QAAQ;IACR,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,KAAK;IACL,OAAO;IACP,OAAO;IACP,SAAS;IACT,KAAK;IACL,MAAM;IACN,OAAO;IACP,KAAK;IACL,KAAK;IACL,MAAM;IACN,OAAO;IACP,KAAK;IACL,MAAM;IACN,OAAO;IACP,KAAK;IACL,MAAM;IACN,QAAQ;IACR,QAAQ;CACT,CAAC;AAQF,SAAS,sBAAsB,CAAC,OAAe,EAAE,cAAsB;IACrE,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,IAAI,CAAC,GAAG,cAAc,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACxD,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;YACtB,KAAK,EAAE,CAAC;SACT;aAAM,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;YAC7B,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC,EAAE;gBACf,OAAO,CAAC,CAAC;aACV;SACF;KACF;IAED,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAQD,SAAgB,+BAA+B,CAC7C,OAAe,EACf,cAAsB;IAStB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;QAC5B,OAAO;YACL,WAAW,EAAE,KAAK;YAClB,qBAAqB,EAAE,IAAI;SAC5B,CAAC;KACH;IAID,MAAM,aAAa,GAAG,mBAAmB,CAAC;IAC1C,IAAI,KAAK,CAAC;IACV,IAAI,oBAAoB,GAAG,CAAC,CAAC,CAAC;IAG9B,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE;QACrD,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC;QAClC,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAG3D,IAAI,cAAc,GAAG,cAAc,IAAI,cAAc,GAAG,oBAAoB,EAAE;YAE5E,MAAM,eAAe,GAAG,sBAAsB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAGxE,IAAI,cAAc,GAAG,cAAc,IAAI,CAAC,eAAe,KAAK,CAAC,CAAC,IAAI,cAAc,IAAI,eAAe,CAAC,EAAE;gBACpG,OAAO;oBACL,WAAW,EAAE,IAAI;oBACjB,qBAAqB,EAAE;wBACrB,KAAK,EAAE,cAAc,GAAG,CAAC;wBACzB,GAAG,EAAE,cAAc;qBACpB;iBACF,CAAC;aACH;YAGD,IAAI,cAAc,KAAK,cAAc,GAAG,CAAC,EAAE;gBACzC,OAAO;oBACL,WAAW,EAAE,IAAI;oBACjB,qBAAqB,EAAE;wBACrB,KAAK,EAAE,cAAc,GAAG,CAAC;wBACzB,GAAG,EAAE,cAAc;qBACpB;iBACF,CAAC;aACH;YAGD,oBAAoB,GAAG,cAAc,CAAC;SACvC;KACF;IAGD,IAAI,cAAc,GAAG,CAAC,IAAI,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE;QAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YACnF,OAAO;gBACL,WAAW,EAAE,IAAI;gBACjB,qBAAqB,EAAE;oBACrB,KAAK,EAAE,cAAc;oBACrB,GAAG,EAAE,cAAc;iBACpB;aACF,CAAC;SACH;KACF;IAGD,IAAI,cAAc,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;QAC9C,OAAO;YACL,WAAW,EAAE,IAAI;YACjB,qBAAqB,EAAE;gBACrB,KAAK,EAAE,cAAc;gBACrB,GAAG,EAAE,cAAc;aACpB;SACF,CAAC;KACH;IAGD,OAAO;QACL,WAAW,EAAE,KAAK;QAClB,qBAAqB,EAAE,IAAI;KAC5B,CAAC;AACJ,CAAC;AA5FD,0EA4FC","file":"formula-helper.js","sourcesContent":["export const supportedFunctions = [\n 'SUM',\n 'AVERAGE',\n 'MAX',\n 'MIN',\n 'COUNT',\n 'COUNTA',\n 'IF',\n 'AND',\n 'OR',\n 'NOT',\n 'ROUND',\n 'FLOOR',\n 'CEILING',\n 'ABS',\n 'SQRT',\n 'POWER',\n 'MOD',\n 'INT',\n 'RAND',\n 'TODAY',\n 'NOW',\n 'YEAR',\n 'MONTH',\n 'DAY',\n 'HOUR',\n 'MINUTE',\n 'SECOND'\n];\n\n/**\n * 查找匹配的右括号\n * @param formula 公式内容\n * @param openParenIndex 左括号的位置\n * @returns 匹配的右括号位置,若未找到则返回-1\n */\nfunction findMatchingCloseParen(formula: string, openParenIndex: number): number {\n let depth = 1; // 括号深度计数\n\n for (let i = openParenIndex + 1; i < formula.length; i++) {\n if (formula[i] === '(') {\n depth++;\n } else if (formula[i] === ')') {\n depth--;\n if (depth === 0) {\n return i; // 找到匹配的右括号\n }\n }\n }\n\n return -1; // 未找到匹配的右括号\n}\n\n/**\n * 检测函数参数位置\n * @param formula 公式内容\n * @param cursorPosition 光标位置\n * @returns 是否在函数参数位置\n */\nexport function detectFunctionParameterPosition(\n formula: string,\n cursorPosition: number\n): {\n inParamMode: boolean;\n functionParamPosition: {\n start: number;\n end: number;\n } | null;\n} {\n // 基本检查\n if (!formula.startsWith('=')) {\n return {\n inParamMode: false,\n functionParamPosition: null\n };\n }\n\n // 1. 先检查是否在函数参数位置\n // 匹配所有函数调用模式:FUNCTION_NAME(\n const functionRegex = /([A-Za-z]+)\\s*\\(/g;\n let match;\n let positionBeforeCursor = -1;\n\n // 查找距离光标最近的左括号\n while ((match = functionRegex.exec(formula)) !== null) {\n const functionName = match[1].toUpperCase();\n const functionStart = match.index;\n const openParenIndex = formula.indexOf('(', functionStart);\n\n // 如果光标在函数名之后,且这个函数比之前找到的更接近光标\n if (openParenIndex < cursorPosition && openParenIndex > positionBeforeCursor) {\n // 查找对应的右括号位置\n const closeParenIndex = findMatchingCloseParen(formula, openParenIndex);\n\n // 检查光标是否在函数参数位置(在左括号之后且在右括号之前或没有找到右括号)\n if (cursorPosition > openParenIndex && (closeParenIndex === -1 || cursorPosition <= closeParenIndex)) {\n return {\n inParamMode: true,\n functionParamPosition: {\n start: openParenIndex + 1,\n end: cursorPosition\n }\n };\n }\n\n // 如果光标正好在括号后面,也认为是参数位置\n if (cursorPosition === openParenIndex + 1) {\n return {\n inParamMode: true,\n functionParamPosition: {\n start: openParenIndex + 1,\n end: cursorPosition\n }\n };\n }\n\n // 记录这个左括号位置,用于比较\n positionBeforeCursor = openParenIndex;\n }\n }\n\n // 2. 检查是否在操作符后面 - 也将此视为函数参数模式\n if (cursorPosition > 1 && cursorPosition <= formula.length) {\n const prevChar = formula[cursorPosition - 1];\n if (['+', '-', '*', '/', '=', '>', '<', '&', '|', '^', '(', ','].includes(prevChar)) {\n return {\n inParamMode: true,\n functionParamPosition: {\n start: cursorPosition,\n end: cursorPosition\n }\n };\n }\n }\n\n // 3. 检查是否在公式开始位置 - 公式开始后也视为可能需要函数输入\n if (cursorPosition === 1 && formula[0] === '=') {\n return {\n inParamMode: true,\n functionParamPosition: {\n start: cursorPosition,\n end: cursorPosition\n }\n };\n }\n\n // 默认情况,不在任何特殊位置\n return {\n inParamMode: false,\n functionParamPosition: null\n };\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FormulaManager } from '../managers/formula-manager';
|
|
2
|
+
import type { CellRange, CellValueChangedEvent } from '../ts-types';
|
|
3
|
+
export interface FunctionParamPosition {
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class FormulaRangeSelector {
|
|
8
|
+
private formulaManager;
|
|
9
|
+
constructor(formulaManager: FormulaManager);
|
|
10
|
+
selectionsToA1Notation(selections: any[], addressFromCoord: (row: number, col: number) => string): string;
|
|
11
|
+
insertA1ReferenceInFunction(formulaInput: HTMLInputElement, a1Notation: string, isCtrlAddSelection: boolean): void;
|
|
12
|
+
private findCurrentArgumentPosition;
|
|
13
|
+
handleSelectionChanged(selections: CellRange[], formulaInput: HTMLInputElement, isCtrlAddSelection: boolean, addressFromCoord: (row: number, col: number) => string): void;
|
|
14
|
+
handleCellValueChanged(event: CellValueChangedEvent): void;
|
|
15
|
+
handleSelectionChangedForRangeMode(event: any): void;
|
|
16
|
+
private hasFormulaDependents;
|
|
17
|
+
private ensureCursorVisible;
|
|
18
|
+
release(): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: !0
|
|
5
|
+
}), exports.FormulaRangeSelector = void 0;
|
|
6
|
+
|
|
7
|
+
const formula_throttle_1 = require("./formula-throttle"), formula_helper_1 = require("./formula-helper");
|
|
8
|
+
|
|
9
|
+
class FormulaRangeSelector {
|
|
10
|
+
constructor(formulaManager) {
|
|
11
|
+
this.formulaManager = formulaManager;
|
|
12
|
+
}
|
|
13
|
+
selectionsToA1Notation(selections, addressFromCoord) {
|
|
14
|
+
if (!selections || 0 === selections.length) return "";
|
|
15
|
+
const ranges = [];
|
|
16
|
+
for (const range of selections) {
|
|
17
|
+
const startAddr = addressFromCoord(range.startRow, range.startCol), endAddr = addressFromCoord(range.endRow, range.endCol);
|
|
18
|
+
range.startRow === range.endRow && range.startCol === range.endCol ? ranges.push(startAddr) : ranges.push(`${startAddr}:${endAddr}`);
|
|
19
|
+
}
|
|
20
|
+
return ranges.join(",");
|
|
21
|
+
}
|
|
22
|
+
insertA1ReferenceInFunction(formulaInput, a1Notation, isCtrlAddSelection) {
|
|
23
|
+
if (!this.formulaManager.inputIsParamMode.inParamMode) return;
|
|
24
|
+
const currentValue = formulaInput.value, cursorPos = this.formulaManager.lastKnownCursorPosInFormulaInput, argPosition = this.findCurrentArgumentPosition(currentValue, cursorPos);
|
|
25
|
+
let newValue;
|
|
26
|
+
if (argPosition) if (isCtrlAddSelection) {
|
|
27
|
+
newValue = currentValue.substring(argPosition.start, argPosition.end).trim() ? currentValue.slice(0, argPosition.end) + ("," === currentValue[argPosition.end - 1] ? " " : ", ") + a1Notation + currentValue.slice(argPosition.end) : currentValue.slice(0, argPosition.start) + a1Notation + currentValue.slice(argPosition.end);
|
|
28
|
+
} else newValue = currentValue.slice(0, argPosition.start) + a1Notation + currentValue.slice(argPosition.end); else newValue = currentValue;
|
|
29
|
+
formulaInput.value = newValue, this.formulaManager.setCellContent({
|
|
30
|
+
sheet: this.formulaManager.sheet.getActiveSheet().getKey(),
|
|
31
|
+
row: this.formulaManager.sheet.getActiveSheet().editingCell.row,
|
|
32
|
+
col: this.formulaManager.sheet.getActiveSheet().editingCell.col
|
|
33
|
+
}, newValue);
|
|
34
|
+
const newCursorPos = isCtrlAddSelection ? this.formulaManager.lastKnownCursorPosInFormulaInput + (newValue.length - currentValue.length) : argPosition ? argPosition.start + a1Notation.length : cursorPos;
|
|
35
|
+
formulaInput.setSelectionRange(newCursorPos, newCursorPos), setTimeout((() => {
|
|
36
|
+
this.ensureCursorVisible(formulaInput, newCursorPos);
|
|
37
|
+
})), this.formulaManager.inputIsParamMode.functionParamPosition = {
|
|
38
|
+
start: newCursorPos,
|
|
39
|
+
end: newCursorPos
|
|
40
|
+
};
|
|
41
|
+
const inputEvent = new Event("input", {
|
|
42
|
+
bubbles: !0
|
|
43
|
+
});
|
|
44
|
+
Object.defineProperty(inputEvent, "isFormulaInsertion", {
|
|
45
|
+
value: !0
|
|
46
|
+
}), formulaInput.dispatchEvent(inputEvent);
|
|
47
|
+
}
|
|
48
|
+
findCurrentArgumentPosition(formula, cursorPos) {
|
|
49
|
+
if (cursorPos > 1 && cursorPos <= formula.length) {
|
|
50
|
+
const prevChar = formula[cursorPos - 1];
|
|
51
|
+
if ([ "+", "-", "*", "/", "=", ">", "<", "&", "|", "^" ].includes(prevChar)) return {
|
|
52
|
+
start: cursorPos,
|
|
53
|
+
end: cursorPos
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (!formula.includes("(")) return null;
|
|
57
|
+
let lastOpenParenBeforeCursor = -1, nestLevel = 0, inQuote = !1;
|
|
58
|
+
for (let i = 0; i < cursorPos; i++) {
|
|
59
|
+
const char = formula[i];
|
|
60
|
+
'"' !== char || 0 !== i && "\\" === formula[i - 1] ? inQuote || ("(" === char ? (nestLevel++,
|
|
61
|
+
lastOpenParenBeforeCursor = i) : ")" === char && nestLevel--) : inQuote = !inQuote;
|
|
62
|
+
}
|
|
63
|
+
if (-1 === lastOpenParenBeforeCursor || nestLevel <= 0) return formula.startsWith("=") && 1 === cursorPos ? {
|
|
64
|
+
start: cursorPos,
|
|
65
|
+
end: cursorPos
|
|
66
|
+
} : null;
|
|
67
|
+
if (cursorPos === lastOpenParenBeforeCursor + 1) return {
|
|
68
|
+
start: cursorPos,
|
|
69
|
+
end: cursorPos
|
|
70
|
+
};
|
|
71
|
+
if (cursorPos > 0 && "," === formula[cursorPos - 1]) return {
|
|
72
|
+
start: cursorPos,
|
|
73
|
+
end: cursorPos
|
|
74
|
+
};
|
|
75
|
+
let argumentStart = lastOpenParenBeforeCursor + 1, argumentEnd = cursorPos;
|
|
76
|
+
nestLevel = 1, inQuote = !1;
|
|
77
|
+
for (let i = argumentStart; i < cursorPos; i++) {
|
|
78
|
+
const char = formula[i];
|
|
79
|
+
if ('"' !== char || 0 !== i && "\\" === formula[i - 1]) {
|
|
80
|
+
if (!inQuote) if ("(" === char) nestLevel++; else if (")" === char) {
|
|
81
|
+
if (nestLevel--, 0 === nestLevel) break;
|
|
82
|
+
} else "," === char && 1 === nestLevel && (argumentStart = i + 1);
|
|
83
|
+
} else inQuote = !inQuote;
|
|
84
|
+
}
|
|
85
|
+
nestLevel = 0, inQuote = !1;
|
|
86
|
+
for (let i = 0; i < cursorPos; i++) '"' !== formula[i] || 0 !== i && "\\" === formula[i - 1] ? inQuote || ("(" === formula[i] && nestLevel++,
|
|
87
|
+
")" === formula[i] && nestLevel--) : inQuote = !inQuote;
|
|
88
|
+
argumentEnd = formula.length;
|
|
89
|
+
for (let i = cursorPos; i < formula.length; i++) {
|
|
90
|
+
const char = formula[i];
|
|
91
|
+
if ('"' !== char || 0 !== i && "\\" === formula[i - 1]) {
|
|
92
|
+
if (!inQuote) if ("(" === char) nestLevel++; else if (")" === char) {
|
|
93
|
+
if (nestLevel--, 0 === nestLevel) {
|
|
94
|
+
argumentEnd = i;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
} else if ("," === char && 1 === nestLevel) {
|
|
98
|
+
argumentEnd = i;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
} else inQuote = !inQuote;
|
|
102
|
+
}
|
|
103
|
+
const paramContentBefore = formula.substring(argumentStart, cursorPos).trim(), paramContentAfter = formula.substring(cursorPos, argumentEnd).trim();
|
|
104
|
+
return "" === paramContentBefore && cursorPos === argumentStart ? {
|
|
105
|
+
start: argumentStart,
|
|
106
|
+
end: argumentStart
|
|
107
|
+
} : ("" === paramContentAfter && cursorPos < argumentEnd && (argumentEnd = cursorPos),
|
|
108
|
+
{
|
|
109
|
+
start: argumentStart,
|
|
110
|
+
end: argumentEnd
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
handleSelectionChanged(selections, formulaInput, isCtrlAddSelection, addressFromCoord) {
|
|
114
|
+
if (!this.formulaManager.inputIsParamMode.inParamMode || !selections || 0 === selections.length) return;
|
|
115
|
+
const a1Notation = this.selectionsToA1Notation(selections, addressFromCoord);
|
|
116
|
+
a1Notation && this.insertA1ReferenceInFunction(formulaInput, a1Notation, isCtrlAddSelection);
|
|
117
|
+
}
|
|
118
|
+
handleCellValueChanged(event) {
|
|
119
|
+
var _a, _b, _c;
|
|
120
|
+
const activeWorkSheet = this.formulaManager.sheet.getActiveSheet(), formulaManager = this.formulaManager.sheet.formulaManager;
|
|
121
|
+
if (activeWorkSheet && !this.formulaManager.formulaWorkingOnCell) try {
|
|
122
|
+
const newValue = event.newValue;
|
|
123
|
+
if ("string" == typeof newValue && newValue.startsWith("=") && newValue.length > 1) try {
|
|
124
|
+
const currentCellAddress = activeWorkSheet.addressFromCoord(event.row, event.col);
|
|
125
|
+
if (new RegExp(`(^|[^A-Za-z0-9])${currentCellAddress}([^A-Za-z0-9]|$)`).test(newValue)) return null === (_a = activeWorkSheet.tableInstance) || void 0 === _a || _a.changeCellValue(event.col, event.row, "#CYCLE!", !0, !1),
|
|
126
|
+
void (this.formulaManager.formulaWorkingOnCell = null);
|
|
127
|
+
formulaManager.setCellContent({
|
|
128
|
+
sheet: activeWorkSheet.getKey(),
|
|
129
|
+
row: event.row,
|
|
130
|
+
col: event.col
|
|
131
|
+
}, newValue);
|
|
132
|
+
const result = formulaManager.getCellValue({
|
|
133
|
+
sheet: activeWorkSheet.getKey(),
|
|
134
|
+
row: event.row,
|
|
135
|
+
col: event.col
|
|
136
|
+
});
|
|
137
|
+
null === (_b = activeWorkSheet.tableInstance) || void 0 === _b || _b.changeCellValue(event.col, event.row, result.value, !0, !1),
|
|
138
|
+
this.formulaManager.formulaWorkingOnCell = null;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
null === (_c = activeWorkSheet.tableInstance) || void 0 === _c || _c.changeCellValue(event.col, event.row, "#ERROR!", !0, !1),
|
|
141
|
+
this.formulaManager.formulaWorkingOnCell = null;
|
|
142
|
+
} else formulaManager.setCellContent({
|
|
143
|
+
sheet: activeWorkSheet.getKey(),
|
|
144
|
+
row: event.row,
|
|
145
|
+
col: event.col
|
|
146
|
+
}, newValue);
|
|
147
|
+
const formulaThrottle = formula_throttle_1.FormulaThrottle.getInstance();
|
|
148
|
+
if (this.hasFormulaDependents({
|
|
149
|
+
sheet: activeWorkSheet.getKey(),
|
|
150
|
+
row: event.row,
|
|
151
|
+
col: event.col
|
|
152
|
+
})) {
|
|
153
|
+
formulaManager.getCellDependents({
|
|
154
|
+
sheet: activeWorkSheet.getKey(),
|
|
155
|
+
row: event.row,
|
|
156
|
+
col: event.col
|
|
157
|
+
}).forEach((dependent => {
|
|
158
|
+
const result = formulaManager.getCellValue(dependent);
|
|
159
|
+
activeWorkSheet && activeWorkSheet.setCellValue(dependent.row, dependent.col, result.value);
|
|
160
|
+
})), formulaThrottle.immediateRebuildAndRecalculate(formulaManager);
|
|
161
|
+
} else formulaThrottle.throttledRebuildAndRecalculate(formulaManager);
|
|
162
|
+
} catch (error) {}
|
|
163
|
+
}
|
|
164
|
+
handleSelectionChangedForRangeMode(event) {
|
|
165
|
+
var _a;
|
|
166
|
+
const activeWorkSheet = this.formulaManager.sheet.getActiveSheet(), formulaWorkingOnCell = this.formulaManager.formulaWorkingOnCell, formulaManager = this.formulaManager.sheet.formulaManager;
|
|
167
|
+
if (!activeWorkSheet || !formulaWorkingOnCell) return;
|
|
168
|
+
const formulaInput = this.formulaManager.inputingElement;
|
|
169
|
+
if (!formulaInput) return;
|
|
170
|
+
if (this.formulaManager.inputIsParamMode = (0, formula_helper_1.detectFunctionParameterPosition)(formulaInput.value, this.formulaManager.lastKnownCursorPosInFormulaInput),
|
|
171
|
+
!this.formulaManager.inputIsParamMode.inParamMode) return;
|
|
172
|
+
document.activeElement !== formulaInput && formulaInput.focus();
|
|
173
|
+
const selections = activeWorkSheet.getMultipleSelections(), todoSelection = selections[selections.length - 1];
|
|
174
|
+
let isCtrlAddSelection = !1;
|
|
175
|
+
if ((null == selections ? void 0 : selections.length) > (null === (_a = formulaManager.lastSelectionRangesOfHandling) || void 0 === _a ? void 0 : _a.length) && (isCtrlAddSelection = !0),
|
|
176
|
+
formulaManager.lastSelectionRangesOfHandling = selections, !selections || 0 === selections.length) return;
|
|
177
|
+
const editCell = formulaManager.formulaWorkingOnCell, safeSelections = this.formulaManager.sheet.excludeEditCellFromSelection(todoSelection, (null == editCell ? void 0 : editCell.row) || 0, (null == editCell ? void 0 : editCell.col) || 0);
|
|
178
|
+
this.handleSelectionChanged([ safeSelections ], formulaInput, isCtrlAddSelection, ((row, col) => activeWorkSheet.addressFromCoord(row, col)));
|
|
179
|
+
}
|
|
180
|
+
hasFormulaDependents(cell) {
|
|
181
|
+
try {
|
|
182
|
+
return this.formulaManager.getCellDependents(cell).length > 0;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
return !1;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
ensureCursorVisible(input, cursorPos) {
|
|
188
|
+
const tempSpan = document.createElement("span"), inputStyle = window.getComputedStyle(input);
|
|
189
|
+
tempSpan.style.font = inputStyle.font, tempSpan.style.letterSpacing = inputStyle.letterSpacing,
|
|
190
|
+
tempSpan.style.position = "absolute", tempSpan.style.visibility = "hidden", tempSpan.style.whiteSpace = "pre",
|
|
191
|
+
tempSpan.textContent = input.value.substring(0, cursorPos), document.body.appendChild(tempSpan);
|
|
192
|
+
const cursorOffset = tempSpan.offsetWidth;
|
|
193
|
+
document.body.removeChild(tempSpan);
|
|
194
|
+
const inputScrollLeft = input.scrollLeft, inputWidth = input.clientWidth, paddingLeft = parseFloat(inputStyle.paddingLeft), paddingRight = parseFloat(inputStyle.paddingRight), visibleWidth = inputWidth - paddingLeft - paddingRight;
|
|
195
|
+
cursorOffset < inputScrollLeft + paddingLeft ? input.scrollLeft = Math.max(0, cursorOffset - paddingLeft) : cursorOffset > inputScrollLeft + visibleWidth && (input.scrollLeft = cursorOffset - visibleWidth + paddingRight);
|
|
196
|
+
}
|
|
197
|
+
release() {}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
exports.FormulaRangeSelector = FormulaRangeSelector;
|
|
201
|
+
//# sourceMappingURL=formula-range-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/formula/formula-range-selector.ts"],"names":[],"mappings":"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","file":"formula-range-selector.js","sourcesContent":["/**\n * 公式范围选择器\n * 实现Excel风格的公式输入体验:用户输入\"=sum(\"后,选择单元格范围自动插入A1引用\n */\n\nimport { FormulaThrottle } from './formula-throttle';\nimport type { FormulaManager } from '../managers/formula-manager';\nimport type { CellRange, CellValueChangedEvent, FormulaCell } from '../ts-types';\nimport { detectFunctionParameterPosition } from './formula-helper';\n\nexport interface FunctionParamPosition {\n start: number;\n end: number;\n}\n\nexport class FormulaRangeSelector {\n private formulaManager: FormulaManager;\n constructor(formulaManager: FormulaManager) {\n this.formulaManager = formulaManager;\n }\n\n /**\n * 将选择范围转换为A1格式\n * @param selections 选择范围数组\n * @param addressFromCoord 坐标转地址函数\n * @returns A1格式字符串\n */\n selectionsToA1Notation(selections: any[], addressFromCoord: (row: number, col: number) => string): string {\n if (!selections || selections.length === 0) {\n return '';\n }\n\n const ranges: string[] = [];\n\n for (const range of selections) {\n const startAddr = addressFromCoord(range.startRow, range.startCol);\n const endAddr = addressFromCoord(range.endRow, range.endCol);\n\n // 如果是单个单元格(start和end相同)\n if (range.startRow === range.endRow && range.startCol === range.endCol) {\n ranges.push(startAddr);\n } else {\n // 如果是范围,使用冒号分隔\n ranges.push(`${startAddr}:${endAddr}`);\n }\n }\n\n return ranges.join(',');\n }\n\n insertA1ReferenceInFunction(formulaInput: HTMLInputElement, a1Notation: string, isCtrlAddSelection: boolean): void {\n if (!this.formulaManager.inputIsParamMode.inParamMode) {\n return;\n }\n\n const currentValue = formulaInput.value;\n const cursorPos = this.formulaManager.lastKnownCursorPosInFormulaInput;\n\n // 找到当前光标所处的参数位置\n const argPosition = this.findCurrentArgumentPosition(currentValue, cursorPos);\n\n // 在函数参数位置插入或替换A1引用\n let newValue;\n\n if (argPosition) {\n if (isCtrlAddSelection) {\n // Ctrl模式:追加而非替换\n const currentArg = currentValue.substring(argPosition.start, argPosition.end).trim();\n\n if (currentArg) {\n // 如果当前参数不为空,追加逗号和新引用\n newValue =\n currentValue.slice(0, argPosition.end) +\n (currentValue[argPosition.end - 1] === ',' ? ' ' : ', ') +\n a1Notation +\n currentValue.slice(argPosition.end);\n } else {\n // 如果当前参数为空,直接插入新引用\n newValue = currentValue.slice(0, argPosition.start) + a1Notation + currentValue.slice(argPosition.end);\n }\n } else {\n // 替换模式:完全替换当前参数\n newValue = currentValue.slice(0, argPosition.start) + a1Notation + currentValue.slice(argPosition.end);\n }\n } else {\n // 防止newValue未定义\n newValue = currentValue;\n }\n\n formulaInput.value = newValue;\n // 首先设置公式内容\n this.formulaManager.setCellContent(\n {\n sheet: this.formulaManager.sheet.getActiveSheet().getKey(),\n row: this.formulaManager.sheet.getActiveSheet().editingCell.row,\n col: this.formulaManager.sheet.getActiveSheet().editingCell.col\n },\n newValue\n );\n // 设置光标位置到插入内容之后\n const newCursorPos = isCtrlAddSelection\n ? this.formulaManager.lastKnownCursorPosInFormulaInput + (newValue.length - currentValue.length)\n : argPosition\n ? argPosition.start + a1Notation.length\n : cursorPos;\n\n formulaInput.setSelectionRange(newCursorPos, newCursorPos);\n setTimeout(() => {\n // 确保光标位置在可视区域内\n this.ensureCursorVisible(formulaInput, newCursorPos);\n });\n // 更新函数参数位置\n this.formulaManager.inputIsParamMode.functionParamPosition = {\n start: newCursorPos,\n end: newCursorPos\n };\n\n // 触发输入事件以更新高亮\n const inputEvent = new Event('input', { bubbles: true });\n Object.defineProperty(inputEvent, 'isFormulaInsertion', { value: true });\n formulaInput.dispatchEvent(inputEvent);\n }\n /**\n * 找到光标所在的参数位置\n * @param formula 公式文本\n * @param cursorPos 光标位置\n * @returns 参数的起始和结束位置\n */\n private findCurrentArgumentPosition(formula: string, cursorPos: number): { start: number; end: number } | null {\n // 首先检查光标是否在操作符后面\n if (cursorPos > 1 && cursorPos <= formula.length) {\n const prevChar = formula[cursorPos - 1];\n if (['+', '-', '*', '/', '=', '>', '<', '&', '|', '^'].includes(prevChar)) {\n // 光标在操作符后面,将光标位置视为参数的起始和结束位置\n return {\n start: cursorPos,\n end: cursorPos\n };\n }\n }\n\n // 检查公式是否包含括号\n if (!formula.includes('(')) {\n return null;\n }\n\n // 从后向前查找最接近光标的左括号\n let lastOpenParenBeforeCursor = -1;\n let nestLevel = 0;\n let inQuote = false;\n\n // 第一阶段:找到光标所在的函数调用\n for (let i = 0; i < cursorPos; i++) {\n const char = formula[i];\n\n // 处理引号内的内容\n if (char === '\"' && (i === 0 || formula[i - 1] !== '\\\\')) {\n inQuote = !inQuote;\n continue;\n }\n\n // 如果在引号内,忽略所有特殊字符\n if (inQuote) {\n continue;\n }\n\n if (char === '(') {\n nestLevel++;\n lastOpenParenBeforeCursor = i;\n } else if (char === ')') {\n nestLevel--;\n }\n }\n\n // 如果没有找到左括号或者光标不在任何括号内\n if (lastOpenParenBeforeCursor === -1 || nestLevel <= 0) {\n // 检查是否在公式开始位置\n if (formula.startsWith('=') && cursorPos === 1) {\n return {\n start: cursorPos,\n end: cursorPos\n };\n }\n\n return null;\n }\n\n // 特殊处理:光标恰好在左括号后面\n if (cursorPos === lastOpenParenBeforeCursor + 1) {\n return {\n start: cursorPos,\n end: cursorPos\n };\n }\n\n // 特殊处理:光标在逗号后面\n if (cursorPos > 0 && formula[cursorPos - 1] === ',') {\n return {\n start: cursorPos,\n end: cursorPos\n };\n }\n\n // 找到当前参数的起始位置\n let argumentStart = lastOpenParenBeforeCursor + 1;\n let argumentEnd = cursorPos;\n\n // 重置状态\n nestLevel = 1; // 从左括号开始,嵌套级别为1\n inQuote = false;\n\n // 从找到的左括号位置向光标方向扫描,找到当前参数的起始位置\n for (let i = argumentStart; i < cursorPos; i++) {\n const char = formula[i];\n\n if (char === '\"' && (i === 0 || formula[i - 1] !== '\\\\')) {\n inQuote = !inQuote;\n continue;\n }\n if (inQuote) {\n continue;\n }\n\n if (char === '(') {\n nestLevel++;\n } else if (char === ')') {\n nestLevel--;\n if (nestLevel === 0) {\n // 如果回到了函数最外层,则这个右括号后面的内容不再是当前函数的参数\n break;\n }\n } else if (char === ',' && nestLevel === 1) {\n // 如果是当前函数层级的参数分隔符,更新参数开始位置\n argumentStart = i + 1;\n }\n }\n\n // 重置状态,准备从光标位置向后扫描\n nestLevel = 0;\n inQuote = false;\n\n // 重新计算光标位置的嵌套级别\n for (let i = 0; i < cursorPos; i++) {\n if (formula[i] === '\"' && (i === 0 || formula[i - 1] !== '\\\\')) {\n inQuote = !inQuote;\n continue;\n }\n if (inQuote) {\n continue;\n }\n\n if (formula[i] === '(') {\n nestLevel++;\n }\n if (formula[i] === ')') {\n nestLevel--;\n }\n }\n\n // 从光标位置向后查找参数结束位置\n argumentEnd = formula.length;\n for (let i = cursorPos; i < formula.length; i++) {\n const char = formula[i];\n\n if (char === '\"' && (i === 0 || formula[i - 1] !== '\\\\')) {\n inQuote = !inQuote;\n continue;\n }\n if (inQuote) {\n continue;\n }\n\n if (char === '(') {\n nestLevel++;\n } else if (char === ')') {\n nestLevel--;\n // 如果回到了当前函数的右括号\n if (nestLevel === 0) {\n argumentEnd = i;\n break;\n }\n } else if (char === ',' && nestLevel === 1) {\n // 找到下一个同级参数的分隔符\n argumentEnd = i;\n break;\n }\n }\n\n // 处理空参数的情况\n const paramContentBefore = formula.substring(argumentStart, cursorPos).trim();\n const paramContentAfter = formula.substring(cursorPos, argumentEnd).trim();\n\n if (paramContentBefore === '' && cursorPos === argumentStart) {\n // 光标在参数起始位置,且参数为空\n return {\n start: argumentStart,\n end: argumentStart\n };\n }\n\n if (paramContentAfter === '' && cursorPos < argumentEnd) {\n // 光标后面到结束位置都是空白\n argumentEnd = cursorPos;\n }\n\n return {\n start: argumentStart,\n end: argumentEnd\n };\n }\n /**\n * 处理单元格选择变化\n * @param selections 当前选择范围\n * @param formulaInput 公式输入框\n * @param addressFromCoord 坐标转地址函数\n */\n handleSelectionChanged(\n selections: CellRange[],\n formulaInput: HTMLInputElement,\n isCtrlAddSelection: boolean,\n addressFromCoord: (row: number, col: number) => string\n ): void {\n if (!this.formulaManager.inputIsParamMode.inParamMode || !selections || selections.length === 0) {\n return;\n }\n\n const a1Notation = this.selectionsToA1Notation(selections, addressFromCoord);\n if (a1Notation) {\n this.insertA1ReferenceInFunction(formulaInput, a1Notation, isCtrlAddSelection);\n }\n }\n\n /**\n * 处理单元格值变更事件\n * @param event 事件\n */\n handleCellValueChanged(event: CellValueChangedEvent): void {\n console.log('handleCellValueChanged', event);\n const activeWorkSheet = this.formulaManager.sheet.getActiveSheet();\n const formulaManager = this.formulaManager.sheet.formulaManager;\n\n if (!activeWorkSheet || this.formulaManager.formulaWorkingOnCell) {\n return;\n }\n\n try {\n // 检查新输入的值是否为公式\n const newValue = event.newValue;\n if (typeof newValue === 'string' && newValue.startsWith('=') && newValue.length > 1) {\n try {\n // 检查是否包含循环引用\n const currentCellAddress = activeWorkSheet.addressFromCoord(event.row, event.col);\n // 使用正则表达式来精确匹配单元格引用\n const cellRegex = new RegExp(`(^|[^A-Za-z0-9])${currentCellAddress}([^A-Za-z0-9]|$)`);\n if (cellRegex.test(newValue)) {\n console.warn('Circular reference detected:', newValue, 'contains', currentCellAddress);\n activeWorkSheet.tableInstance?.changeCellValue(event.col, event.row, '#CYCLE!', true, false);\n this.formulaManager.formulaWorkingOnCell = null;\n return;\n }\n\n // 首先设置公式内容\n formulaManager.setCellContent(\n {\n sheet: activeWorkSheet.getKey(),\n row: event.row,\n col: event.col\n },\n newValue\n );\n\n // 获取计算结果\n const result = formulaManager.getCellValue({\n sheet: activeWorkSheet.getKey(),\n row: event.row,\n col: event.col\n });\n // // 检查当前单元格是否正在编辑(是否在公式栏中编辑)\n // const formulaInput = this.formulaManager.inputingElement;\n // const isEditing = document.activeElement === formulaInput;\n\n // 更新单元格显示 - 如果正在编辑则显示公式,否则显示计算结果\n // activeWorkSheet.tableInstance?.changeCellValue(event.col, event.row, isEditing ? newValue : result.value);\n activeWorkSheet.tableInstance?.changeCellValue(event.col, event.row, result.value, true, false);\n this.formulaManager.formulaWorkingOnCell = null;\n } catch (error) {\n console.warn('Formula processing error:', error);\n // 显示错误状态\n activeWorkSheet.tableInstance?.changeCellValue(event.col, event.row, '#ERROR!', true, false);\n this.formulaManager.formulaWorkingOnCell = null;\n }\n } else {\n // 非公式值,同步到HyperFormula\n formulaManager.setCellContent(\n {\n sheet: activeWorkSheet.getKey(),\n row: event.row,\n col: event.col\n },\n newValue\n );\n }\n\n // 使用FormulaThrottle来优化公式重新计算\n const formulaThrottle = FormulaThrottle.getInstance();\n // 判断是否需要立即更新\n const needImmediateUpdate = this.hasFormulaDependents({\n sheet: activeWorkSheet.getKey(),\n row: event.row,\n col: event.col\n });\n if (needImmediateUpdate) {\n // 更新依赖的公式\n const dependents = formulaManager.getCellDependents({\n sheet: activeWorkSheet.getKey(),\n row: event.row,\n col: event.col\n });\n\n // 重新计算依赖该单元格的所有公式\n dependents.forEach(dependent => {\n const result = formulaManager.getCellValue(dependent);\n if (activeWorkSheet) {\n activeWorkSheet.setCellValue(dependent.row, dependent.col, result.value);\n }\n });\n // 立即执行完整重新计算\n formulaThrottle.immediateRebuildAndRecalculate(formulaManager);\n } else {\n // 使用节流方式进行公式计算\n formulaThrottle.throttledRebuildAndRecalculate(formulaManager);\n }\n\n // // 如果当前编辑的单元格就是选中的单元格,更新 fx 输入框\n // const selection = this.activeWorkSheet.getSelection();\n // if (selection && selection.startRow === event.row && selection.startCol === event.col) {\n // this.updateFormulaBar();\n // }\n } catch (error) {\n console.error('Error in handleCellValueChanged:', error);\n }\n }\n\n /**\n * 处理范围选择模式下的单元格选中事件\n */\n handleSelectionChangedForRangeMode(event: any): void {\n console.log('handleSelectionChangedForRangeMode', event);\n const activeWorkSheet = this.formulaManager.sheet.getActiveSheet();\n const formulaWorkingOnCell = this.formulaManager.formulaWorkingOnCell;\n const formulaManager = this.formulaManager.sheet.formulaManager;\n if (!activeWorkSheet || !formulaWorkingOnCell) {\n return;\n }\n\n // const formulaInput = this.formulaInput;\n const formulaInput = this.formulaManager.inputingElement;\n // if (!formulaInput || this.formulaManager.isUpdatingFromFormula) {\n // return;\n // }\n // TODO 尝试全部去掉isUpdatingFromFormula的判断和赋值\n if (!formulaInput) {\n return;\n }\n\n // 不依赖 event.type 字符串,selection-end 已在上层绑定,这里直接处理\n\n this.formulaManager.inputIsParamMode = detectFunctionParameterPosition(\n formulaInput.value,\n this.formulaManager.lastKnownCursorPosInFormulaInput\n );\n if (!this.formulaManager.inputIsParamMode.inParamMode) {\n return;\n }\n\n if (document.activeElement !== formulaInput) {\n formulaInput.focus();\n }\n\n // 获取所有选择范围(支持Ctrl/Cmd多选)\n const selections = activeWorkSheet.getMultipleSelections();\n const todoSelection = selections[selections.length - 1];\n let isCtrlAddSelection = false;\n if (selections?.length > formulaManager.lastSelectionRangesOfHandling?.length) {\n isCtrlAddSelection = true;\n }\n formulaManager.lastSelectionRangesOfHandling = selections;\n if (!selections || selections.length === 0) {\n return;\n }\n\n // 排除当前编辑单元格,避免形成自引用导致 #CYCLE!\n const editCell = formulaManager.formulaWorkingOnCell;\n // const safeSelections = selections\n // .map(selection => this.excludeEditCellFromSelection(selection, editCell?.row || 0, editCell?.col || 0))\n // .filter(selection => selection.startRow >= 0 && selection.startCol >= 0); // 过滤掉无效选择\n const safeSelections = this.formulaManager.sheet.excludeEditCellFromSelection(\n todoSelection,\n editCell?.row || 0,\n editCell?.col || 0\n );\n\n this.handleSelectionChanged([safeSelections], formulaInput, isCtrlAddSelection, (row: number, col: number) =>\n activeWorkSheet!.addressFromCoord(row, col)\n );\n\n // 写入后不再刷新公式栏,以免覆盖刚插入的引用\n }\n\n /**\n * 检查单元格是否有公式依赖\n * @param cell 单元格\n * @returns 是否有公式依赖\n */\n private hasFormulaDependents(cell: FormulaCell): boolean {\n try {\n const dependents = this.formulaManager.getCellDependents(cell);\n return dependents.length > 0;\n } catch (error) {\n console.warn('Error checking formula dependents:', error);\n return false;\n }\n }\n\n /**\n * 确保光标位置在输入框的可视区域内\n * @param input 输入框元素\n * @param cursorPos 光标位置\n */\n private ensureCursorVisible(input: HTMLInputElement, cursorPos: number): void {\n // 创建一个临时元素来计算光标位置\n const tempSpan = document.createElement('span');\n const inputStyle = window.getComputedStyle(input);\n\n // 复制输入框的样式到临时元素\n tempSpan.style.font = inputStyle.font;\n tempSpan.style.letterSpacing = inputStyle.letterSpacing;\n tempSpan.style.position = 'absolute';\n tempSpan.style.visibility = 'hidden';\n tempSpan.style.whiteSpace = 'pre';\n\n // 设置文本内容为光标位置前的文本\n tempSpan.textContent = input.value.substring(0, cursorPos);\n document.body.appendChild(tempSpan);\n\n // 计算光标位置\n const cursorOffset = tempSpan.offsetWidth;\n document.body.removeChild(tempSpan);\n\n // 计算可视区域\n const inputScrollLeft = input.scrollLeft;\n const inputWidth = input.clientWidth;\n const paddingLeft = parseFloat(inputStyle.paddingLeft);\n const paddingRight = parseFloat(inputStyle.paddingRight);\n const visibleWidth = inputWidth - paddingLeft - paddingRight;\n\n // 调整滚动位置确保光标可见\n if (cursorOffset < inputScrollLeft + paddingLeft) {\n // 光标在可视区域左侧\n input.scrollLeft = Math.max(0, cursorOffset - paddingLeft);\n } else if (cursorOffset > inputScrollLeft + visibleWidth) {\n // 光标在可视区域右侧\n input.scrollLeft = cursorOffset - visibleWidth + paddingRight;\n }\n }\n\n release(): void {\n //do nothing\n }\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FormulaManager } from '../managers/formula-manager';
|
|
2
|
+
export declare class FormulaThrottle {
|
|
3
|
+
private static instance;
|
|
4
|
+
private recalcTimer;
|
|
5
|
+
private pendingRecalc;
|
|
6
|
+
private throttleDelay;
|
|
7
|
+
static getInstance(): FormulaThrottle;
|
|
8
|
+
throttledRebuildAndRecalculate(formulaManager: FormulaManager): void;
|
|
9
|
+
immediateRebuildAndRecalculate(formulaManager: FormulaManager): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: !0
|
|
5
|
+
}), exports.FormulaThrottle = void 0;
|
|
6
|
+
|
|
7
|
+
class FormulaThrottle {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.recalcTimer = null, this.pendingRecalc = !1, this.throttleDelay = 150;
|
|
10
|
+
}
|
|
11
|
+
static getInstance() {
|
|
12
|
+
return FormulaThrottle.instance || (FormulaThrottle.instance = new FormulaThrottle),
|
|
13
|
+
FormulaThrottle.instance;
|
|
14
|
+
}
|
|
15
|
+
throttledRebuildAndRecalculate(formulaManager) {
|
|
16
|
+
if (formulaManager) if (null === this.recalcTimer) {
|
|
17
|
+
if (!this.pendingRecalc) try {
|
|
18
|
+
formulaManager.rebuildAndRecalculate();
|
|
19
|
+
} catch (e) {}
|
|
20
|
+
this.pendingRecalc = !1, this.recalcTimer = window.setTimeout((() => {
|
|
21
|
+
if (this.recalcTimer = null, this.pendingRecalc) try {
|
|
22
|
+
formulaManager.rebuildAndRecalculate(), this.pendingRecalc = !1;
|
|
23
|
+
} catch (e) {}
|
|
24
|
+
}), this.throttleDelay);
|
|
25
|
+
} else this.pendingRecalc = !0;
|
|
26
|
+
}
|
|
27
|
+
immediateRebuildAndRecalculate(formulaManager) {
|
|
28
|
+
if (formulaManager) {
|
|
29
|
+
null !== this.recalcTimer && (window.clearTimeout(this.recalcTimer), this.recalcTimer = null),
|
|
30
|
+
this.pendingRecalc = !1;
|
|
31
|
+
try {
|
|
32
|
+
formulaManager.rebuildAndRecalculate();
|
|
33
|
+
} catch (e) {}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
exports.FormulaThrottle = FormulaThrottle;
|
|
39
|
+
//# sourceMappingURL=formula-throttle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/formula/formula-throttle.ts"],"names":[],"mappings":";;;AAEA,MAAa,eAAe;IAA5B;QAEU,gBAAW,GAAkB,IAAI,CAAC;QAClC,kBAAa,GAAG,KAAK,CAAC;QACtB,kBAAa,GAAG,GAAG,CAAC;IAsE9B,CAAC;IApEC,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE;YAC7B,eAAe,CAAC,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;SAClD;QACD,OAAO,eAAe,CAAC,QAAQ,CAAC;IAClC,CAAC;IAMD,8BAA8B,CAAC,cAA8B;QAC3D,IAAI,CAAC,cAAc,EAAE;YACnB,OAAO;SACR;QAGD,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,EAAE;YAC7B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,OAAO;SACR;QAGD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;YACvB,IAAI;gBACF,cAAc,CAAC,qBAAqB,EAAE,CAAC;aACxC;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,CAAC,IAAI,CAAC,+CAA+C,EAAE,CAAC,CAAC,CAAC;aAClE;SACF;QAED,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;YACxC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,IAAI,IAAI,CAAC,aAAa,EAAE;gBACtB,IAAI;oBACF,cAAc,CAAC,qBAAqB,EAAE,CAAC;oBACvC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;iBAC5B;gBAAC,OAAO,CAAC,EAAE;oBACV,OAAO,CAAC,IAAI,CAAC,wDAAwD,EAAE,CAAC,CAAC,CAAC;iBAC3E;aACF;QACH,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACzB,CAAC;IAMD,8BAA8B,CAAC,cAA8B;QAC3D,IAAI,CAAC,cAAc,EAAE;YACnB,OAAO;SACR;QAGD,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,EAAE;YAC7B,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACtC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;SACzB;QAED,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAE3B,IAAI;YACF,cAAc,CAAC,qBAAqB,EAAE,CAAC;SACxC;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,CAAC,IAAI,CAAC,yDAAyD,EAAE,CAAC,CAAC,CAAC;SAC5E;IACH,CAAC;CACF;AA1ED,0CA0EC","file":"formula-throttle.js","sourcesContent":["import type { FormulaManager } from '../managers/formula-manager';\n\nexport class FormulaThrottle {\n private static instance: FormulaThrottle;\n private recalcTimer: number | null = null;\n private pendingRecalc = false;\n private throttleDelay = 150; // ms\n\n static getInstance(): FormulaThrottle {\n if (!FormulaThrottle.instance) {\n FormulaThrottle.instance = new FormulaThrottle();\n }\n return FormulaThrottle.instance;\n }\n\n /**\n * 节流方式调用公式重建和重新计算\n * @param formulaManager 公式管理器实例\n */\n throttledRebuildAndRecalculate(formulaManager: FormulaManager): void {\n if (!formulaManager) {\n return;\n }\n\n // 如果有定时器正在等待,直接返回\n if (this.recalcTimer !== null) {\n this.pendingRecalc = true;\n return;\n }\n\n // 如果没有待处理的重新计算,执行一次,然后设置定时器\n if (!this.pendingRecalc) {\n try {\n formulaManager.rebuildAndRecalculate();\n } catch (e) {\n console.warn('Error during formula rebuild and recalculate:', e);\n }\n }\n\n this.pendingRecalc = false;\n this.recalcTimer = window.setTimeout(() => {\n this.recalcTimer = null;\n if (this.pendingRecalc) {\n try {\n formulaManager.rebuildAndRecalculate();\n this.pendingRecalc = false;\n } catch (e) {\n console.warn('Error during formula rebuild and recalculate in timer:', e);\n }\n }\n }, this.throttleDelay);\n }\n\n /**\n * 立即执行一次计算,并取消任何待处理的计算\n * @param formulaManager 公式管理器实例\n */\n immediateRebuildAndRecalculate(formulaManager: FormulaManager): void {\n if (!formulaManager) {\n return;\n }\n\n // 清除任何待处理的计时器\n if (this.recalcTimer !== null) {\n window.clearTimeout(this.recalcTimer);\n this.recalcTimer = null;\n }\n\n this.pendingRecalc = false;\n\n try {\n formulaManager.rebuildAndRecalculate();\n } catch (e) {\n console.warn('Error during immediate formula rebuild and recalculate:', e);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type VTableSheet from '../components/vtable-sheet';
|
|
2
|
+
export declare class FormulaUIManager {
|
|
3
|
+
private sheet;
|
|
4
|
+
private formulaBarElement;
|
|
5
|
+
formulaInput: HTMLInputElement | null;
|
|
6
|
+
isFormulaBarShowingResult: boolean;
|
|
7
|
+
private isEnterKeyPressed;
|
|
8
|
+
constructor(sheet: VTableSheet);
|
|
9
|
+
createFormulaBar(): HTMLElement;
|
|
10
|
+
activateFormulaBar(): void;
|
|
11
|
+
deactivateFormulaBar(): void;
|
|
12
|
+
cancelFormulaEdit(): void;
|
|
13
|
+
confirmFormulaEdit(): void;
|
|
14
|
+
updateFormulaBar(): void;
|
|
15
|
+
private handleFormulaInput;
|
|
16
|
+
private handleFormulaKeydown;
|
|
17
|
+
clearFormula(): void;
|
|
18
|
+
release(): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: !0
|
|
5
|
+
}), exports.FormulaUIManager = void 0;
|
|
6
|
+
|
|
7
|
+
const formula_helper_1 = require("./formula-helper");
|
|
8
|
+
|
|
9
|
+
class FormulaUIManager {
|
|
10
|
+
constructor(sheet) {
|
|
11
|
+
this.formulaBarElement = null, this.formulaInput = null, this.isFormulaBarShowingResult = !1,
|
|
12
|
+
this.isEnterKeyPressed = !1, this.sheet = sheet;
|
|
13
|
+
}
|
|
14
|
+
createFormulaBar() {
|
|
15
|
+
const formulaBar = document.createElement("div");
|
|
16
|
+
formulaBar.className = "vtable-sheet-formula-bar";
|
|
17
|
+
const cellAddressBox = document.createElement("div");
|
|
18
|
+
cellAddressBox.className = "vtable-sheet-cell-address", cellAddressBox.textContent = "",
|
|
19
|
+
formulaBar.appendChild(cellAddressBox);
|
|
20
|
+
const formulaIcon = document.createElement("div");
|
|
21
|
+
formulaIcon.className = "vtable-sheet-formula-icon", formulaIcon.textContent = "fx",
|
|
22
|
+
formulaIcon.title = "插入函数", formulaBar.appendChild(formulaIcon);
|
|
23
|
+
const formulaInput = document.createElement("input");
|
|
24
|
+
this.formulaInput = formulaInput, formulaInput.className = "vtable-sheet-formula-input",
|
|
25
|
+
formulaInput.placeholder = "输入公式...";
|
|
26
|
+
[ "click", "mouseup", "keyup", "select", "input", "focus" ].forEach((eventType => {
|
|
27
|
+
formulaInput.addEventListener(eventType, (e => {
|
|
28
|
+
const cursorPos = formulaInput.selectionStart;
|
|
29
|
+
null != cursorPos && (this.sheet.formulaManager.lastKnownCursorPosInFormulaInput = cursorPos,
|
|
30
|
+
this.sheet.formulaManager.inputingElement = formulaInput);
|
|
31
|
+
}));
|
|
32
|
+
})), formulaInput.addEventListener("input", (e => this.handleFormulaInput(e))),
|
|
33
|
+
formulaInput.addEventListener("keydown", (e => this.handleFormulaKeydown(e))), formulaInput.addEventListener("focus", (() => {
|
|
34
|
+
this.activateFormulaBar();
|
|
35
|
+
const activeWorkSheet = this.sheet.getActiveSheet();
|
|
36
|
+
if (activeWorkSheet) {
|
|
37
|
+
const editingCell = activeWorkSheet.editingCell;
|
|
38
|
+
if (editingCell && !this.sheet.formulaManager.formulaWorkingOnCell) {
|
|
39
|
+
const formula = this.sheet.formulaManager.getCellFormula({
|
|
40
|
+
sheet: editingCell.sheet,
|
|
41
|
+
row: editingCell.row,
|
|
42
|
+
col: editingCell.col
|
|
43
|
+
});
|
|
44
|
+
if (formula) {
|
|
45
|
+
this.sheet.formulaManager.formulaWorkingOnCell = editingCell;
|
|
46
|
+
const displayFormula = formula.startsWith("=") ? formula : `=${formula}`;
|
|
47
|
+
formulaInput.value = displayFormula, this.sheet.formulaManager.cellHighlightManager.highlightFormulaCells(displayFormula),
|
|
48
|
+
this.sheet.formulaManager.inputIsParamMode = (0, formula_helper_1.detectFunctionParameterPosition)(formulaInput.value, this.sheet.formulaManager.lastKnownCursorPosInFormulaInput);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})), formulaInput.addEventListener("blur", (() => {
|
|
53
|
+
var _a;
|
|
54
|
+
if (this.sheet.formulaManager.formulaWorkingOnCell) return;
|
|
55
|
+
this.deactivateFormulaBar(), this.sheet.formulaManager.cellHighlightManager.clearHighlights();
|
|
56
|
+
const activeWorkSheet = this.sheet.getActiveSheet();
|
|
57
|
+
if (activeWorkSheet) {
|
|
58
|
+
const selection = activeWorkSheet.getSelection();
|
|
59
|
+
if (selection) {
|
|
60
|
+
const result = this.sheet.formulaManager.getCellValue({
|
|
61
|
+
sheet: activeWorkSheet.getKey(),
|
|
62
|
+
row: selection.startRow,
|
|
63
|
+
col: selection.startCol
|
|
64
|
+
});
|
|
65
|
+
null === (_a = activeWorkSheet.tableInstance) || void 0 === _a || _a.changeCellValue(selection.startCol, selection.startRow, result.error ? "#ERROR!" : result.value);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
})), formulaBar.appendChild(formulaInput);
|
|
69
|
+
const formulaActions = document.createElement("div");
|
|
70
|
+
formulaActions.className = "vtable-sheet-formula-actions";
|
|
71
|
+
const cancelButton = document.createElement("button");
|
|
72
|
+
cancelButton.className = "vtable-sheet-formula-button vtable-sheet-formula-cancel",
|
|
73
|
+
cancelButton.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>',
|
|
74
|
+
cancelButton.title = "取消", cancelButton.addEventListener("click", (() => this.cancelFormulaEdit())),
|
|
75
|
+
formulaActions.appendChild(cancelButton);
|
|
76
|
+
const confirmButton = document.createElement("button");
|
|
77
|
+
return confirmButton.className = "vtable-sheet-formula-button vtable-sheet-formula-confirm",
|
|
78
|
+
confirmButton.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>',
|
|
79
|
+
confirmButton.title = "确认", confirmButton.addEventListener("click", (() => this.confirmFormulaEdit())),
|
|
80
|
+
formulaActions.appendChild(confirmButton), formulaBar.appendChild(formulaActions),
|
|
81
|
+
this.formulaBarElement = formulaBar, formulaBar;
|
|
82
|
+
}
|
|
83
|
+
activateFormulaBar() {
|
|
84
|
+
const formulaBar = this.formulaBarElement;
|
|
85
|
+
formulaBar && formulaBar.classList.add("active");
|
|
86
|
+
}
|
|
87
|
+
deactivateFormulaBar() {
|
|
88
|
+
const formulaBar = this.formulaBarElement;
|
|
89
|
+
formulaBar && formulaBar.classList.remove("active"), this.sheet.formulaManager.cellHighlightManager.clearHighlights();
|
|
90
|
+
}
|
|
91
|
+
cancelFormulaEdit() {
|
|
92
|
+
this.formulaInput && this.updateFormulaBar();
|
|
93
|
+
}
|
|
94
|
+
confirmFormulaEdit() {
|
|
95
|
+
var _a;
|
|
96
|
+
const formulaInput = this.formulaInput, activeWorkSheet = this.sheet.getActiveSheet();
|
|
97
|
+
if (formulaInput && activeWorkSheet) {
|
|
98
|
+
const selection = activeWorkSheet.editingCell;
|
|
99
|
+
if (!selection) return;
|
|
100
|
+
const value = formulaInput.value;
|
|
101
|
+
if (value.startsWith("=") && value.length > 1) try {
|
|
102
|
+
const currentCellAddress = activeWorkSheet.addressFromCoord(selection.row, selection.col);
|
|
103
|
+
if (new RegExp(`(^|[^A-Za-z0-9])${currentCellAddress}([^A-Za-z0-9]|$)`).test(value)) return activeWorkSheet.setCellValue(selection.row, selection.col, "#CYCLE!"),
|
|
104
|
+
null === (_a = activeWorkSheet.tableInstance) || void 0 === _a || _a.changeCellValue(selection.col, selection.row, "#CYCLE!"),
|
|
105
|
+
formulaInput.value = "", void formulaInput.blur();
|
|
106
|
+
this.sheet.formulaManager.setCellContent({
|
|
107
|
+
sheet: activeWorkSheet.getKey(),
|
|
108
|
+
row: selection.row,
|
|
109
|
+
col: selection.col
|
|
110
|
+
}, value);
|
|
111
|
+
const result = this.sheet.formulaManager.getCellValue({
|
|
112
|
+
sheet: activeWorkSheet.getKey(),
|
|
113
|
+
row: selection.row,
|
|
114
|
+
col: selection.col
|
|
115
|
+
});
|
|
116
|
+
activeWorkSheet.setCellValue(selection.row, selection.col, result.value);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
activeWorkSheet.setCellValue(selection.row, selection.col, "#ERROR!");
|
|
119
|
+
} else activeWorkSheet.setCellValue(selection.row, selection.col, value);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
updateFormulaBar() {
|
|
123
|
+
if (!this.formulaBarElement) return;
|
|
124
|
+
const activeWorkSheet = this.sheet.getActiveSheet();
|
|
125
|
+
if (!activeWorkSheet) return void this.clearFormula();
|
|
126
|
+
const selection = activeWorkSheet.getSelection();
|
|
127
|
+
if (selection) try {
|
|
128
|
+
const rowCount = activeWorkSheet.getRowCount(), colCount = activeWorkSheet.getColumnCount();
|
|
129
|
+
if (selection.startRow < 0 || selection.startRow >= rowCount || selection.startCol < 0 || selection.startCol >= colCount) return void this.clearFormula();
|
|
130
|
+
const cellAddressBox = this.formulaBarElement.querySelector(".vtable-sheet-cell-address");
|
|
131
|
+
cellAddressBox && (cellAddressBox.textContent = activeWorkSheet.addressFromCoord(selection.startRow, selection.startCol));
|
|
132
|
+
const formulaInput = this.formulaInput;
|
|
133
|
+
if (formulaInput) {
|
|
134
|
+
if (this.sheet.formulaManager.inputIsParamMode = (0, formula_helper_1.detectFunctionParameterPosition)(formulaInput.value, this.sheet.formulaManager.lastKnownCursorPosInFormulaInput),
|
|
135
|
+
this.sheet.formulaManager.inputIsParamMode.inParamMode) return;
|
|
136
|
+
if (this.isFormulaBarShowingResult) return;
|
|
137
|
+
try {
|
|
138
|
+
const formula = this.sheet.formulaManager.getCellFormula({
|
|
139
|
+
sheet: activeWorkSheet.getKey(),
|
|
140
|
+
row: selection.startRow,
|
|
141
|
+
col: selection.startCol
|
|
142
|
+
});
|
|
143
|
+
if (formula) {
|
|
144
|
+
const displayFormula = formula.startsWith("=") ? formula : "=" + formula;
|
|
145
|
+
formulaInput.value = displayFormula;
|
|
146
|
+
} else {
|
|
147
|
+
const cellValue = activeWorkSheet.getCellValue(selection.startRow, selection.startCol);
|
|
148
|
+
formulaInput.value = null != cellValue ? String(cellValue) : "";
|
|
149
|
+
}
|
|
150
|
+
} catch (e) {
|
|
151
|
+
formulaInput.value = "";
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} catch (e) {
|
|
155
|
+
this.clearFormula();
|
|
156
|
+
} else this.clearFormula();
|
|
157
|
+
}
|
|
158
|
+
handleFormulaInput(event) {
|
|
159
|
+
var _a;
|
|
160
|
+
const activeWorkSheet = this.sheet.getActiveSheet();
|
|
161
|
+
if (!activeWorkSheet) return;
|
|
162
|
+
const editingCell = activeWorkSheet.editingCell;
|
|
163
|
+
if (!editingCell) return;
|
|
164
|
+
const input = event.target, value = input.value;
|
|
165
|
+
this.sheet.getActiveSheet().tableInstance.editorManager.editingEditor || this.sheet.getActiveSheet().tableInstance.startEditCell(editingCell.col, editingCell.row, value),
|
|
166
|
+
(null === (_a = this.sheet.getActiveSheet().tableInstance.editorManager.editingEditor) || void 0 === _a ? void 0 : _a.getInputElement) && (this.sheet.getActiveSheet().tableInstance.editorManager.editingEditor.getInputElement().value = value,
|
|
167
|
+
input.focus()), value.startsWith("=") && this.sheet.formulaManager.cellHighlightManager.highlightFormulaCells(value),
|
|
168
|
+
event.isFormulaInsertion || (this.sheet.formulaManager.inputIsParamMode = (0, formula_helper_1.detectFunctionParameterPosition)(value, this.sheet.formulaManager.lastKnownCursorPosInFormulaInput),
|
|
169
|
+
value.startsWith("=") ? (this.sheet.formulaManager.cellHighlightManager.highlightFormulaCells(value),
|
|
170
|
+
this.isFormulaBarShowingResult = !1, this.sheet.formulaManager.setCellContent({
|
|
171
|
+
sheet: activeWorkSheet.getKey(),
|
|
172
|
+
row: editingCell.row,
|
|
173
|
+
col: editingCell.col
|
|
174
|
+
}, value)) : this.sheet.formulaManager.cellHighlightManager.clearHighlights(), this.sheet.formulaManager.formulaWorkingOnCell = activeWorkSheet.editingCell);
|
|
175
|
+
}
|
|
176
|
+
handleFormulaKeydown(event) {
|
|
177
|
+
var _a, _b, _c, _d;
|
|
178
|
+
const activeWorkSheet = this.sheet.getActiveSheet();
|
|
179
|
+
if (!activeWorkSheet) return;
|
|
180
|
+
const input = event.target;
|
|
181
|
+
if ("Enter" === event.key) {
|
|
182
|
+
const editingCell = activeWorkSheet.editingCell;
|
|
183
|
+
if (!editingCell) return;
|
|
184
|
+
const value = input.value;
|
|
185
|
+
if (value.startsWith("=") && value.length > 1) try {
|
|
186
|
+
const currentCellAddress = activeWorkSheet.addressFromCoord(editingCell.row, editingCell.col);
|
|
187
|
+
if (new RegExp(`(^|[^A-Za-z0-9])${currentCellAddress}([^A-Za-z0-9]|$)`).test(value)) return activeWorkSheet.setCellValue(editingCell.row, editingCell.col, "#CYCLE!"),
|
|
188
|
+
null === (_a = activeWorkSheet.tableInstance) || void 0 === _a || _a.changeCellValue(editingCell.col, editingCell.row, "#CYCLE!"),
|
|
189
|
+
this.sheet.formulaManager.formulaWorkingOnCell = null, input.value = "", void input.blur();
|
|
190
|
+
this.sheet.formulaManager.setCellContent({
|
|
191
|
+
sheet: activeWorkSheet.getKey(),
|
|
192
|
+
row: editingCell.row,
|
|
193
|
+
col: editingCell.col
|
|
194
|
+
}, value);
|
|
195
|
+
const result = this.sheet.formulaManager.getCellValue({
|
|
196
|
+
sheet: activeWorkSheet.getKey(),
|
|
197
|
+
row: editingCell.row,
|
|
198
|
+
col: editingCell.col
|
|
199
|
+
});
|
|
200
|
+
null === (_b = activeWorkSheet.tableInstance) || void 0 === _b || _b.changeCellValue(editingCell.col, editingCell.row, result.error ? "#ERROR!" : result.value),
|
|
201
|
+
this.isFormulaBarShowingResult = !0, input.blur(), setTimeout((() => {
|
|
202
|
+
this.sheet.formulaManager.formulaWorkingOnCell = null, activeWorkSheet.tableInstance.clearSelected(),
|
|
203
|
+
this.sheet.formulaManager.cellHighlightManager.clearHighlights(), activeWorkSheet.tableInstance.selectCell(editingCell.col, editingCell.row);
|
|
204
|
+
}), 0);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
activeWorkSheet.setCellValue(editingCell.row, editingCell.col, "#ERROR!"), null === (_c = activeWorkSheet.tableInstance) || void 0 === _c || _c.changeCellValue(editingCell.col, editingCell.row, "#ERROR!"),
|
|
207
|
+
this.sheet.formulaManager.formulaWorkingOnCell = null;
|
|
208
|
+
} else activeWorkSheet.setCellValue(editingCell.row, editingCell.col, value), null === (_d = activeWorkSheet.tableInstance) || void 0 === _d || _d.changeCellValue(editingCell.col, editingCell.row, value),
|
|
209
|
+
this.sheet.formulaManager.formulaWorkingOnCell = null;
|
|
210
|
+
this.isEnterKeyPressed = !0, event.preventDefault(), event.stopPropagation();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
clearFormula() {
|
|
214
|
+
var _a;
|
|
215
|
+
const cellAddressBox = null === (_a = this.formulaBarElement) || void 0 === _a ? void 0 : _a.querySelector(".vtable-sheet-cell-address");
|
|
216
|
+
cellAddressBox && (cellAddressBox.textContent = "");
|
|
217
|
+
const formulaInput = this.formulaInput;
|
|
218
|
+
formulaInput && (formulaInput.value = "");
|
|
219
|
+
}
|
|
220
|
+
release() {
|
|
221
|
+
this.formulaBarElement = null, this.formulaInput = null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
exports.FormulaUIManager = FormulaUIManager;
|
|
226
|
+
//# sourceMappingURL=formula-ui-manager.js.map
|