mirror of
https://github.com/dream-num/univer.git
synced 2026-10-31 02:43:44 +08:00
fix(sheet): sheet name quote (#4198)
Co-authored-by: GitHub Actions <actions@github.com>
This commit is contained in:
co-authored by
GitHub Actions
parent
b413d6809e
commit
f42c01a2ed
@@ -156,3 +156,137 @@ test('diff facade sheet hooks', async () => {
|
||||
const screenshot = await page.locator(SHEET_MAIN_CANVAS_ID).screenshot();
|
||||
await expect(screenshot).toMatchSnapshot(filename, { maxDiffPixels: 5 });
|
||||
});
|
||||
|
||||
test('diff set force string cell', async () => {
|
||||
const browser = await chromium.launch({
|
||||
headless: !!isCI, // Set to false to see the browser window
|
||||
});
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1280, height: 1280 },
|
||||
deviceScaleFactor: 2, // Set your desired DPR
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultStyleSheet());
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.evaluate(async () => {
|
||||
const activeWorkbook = window.univerAPI.getActiveWorkbook();
|
||||
const activeSheet = activeWorkbook.getActiveSheet();
|
||||
|
||||
const sheetId = activeSheet.getSheetId();
|
||||
const unitId = activeWorkbook.getId();
|
||||
|
||||
await window.univerAPI.executeCommand('sheet.operation.set-selections', {
|
||||
selections: [
|
||||
{
|
||||
range: {
|
||||
startRow: 0,
|
||||
startColumn: 7,
|
||||
endRow: 0,
|
||||
endColumn: 7,
|
||||
rangeType: 0,
|
||||
unitId,
|
||||
sheetId,
|
||||
},
|
||||
primary: {
|
||||
actualRow: 0,
|
||||
actualColumn: 7,
|
||||
isMerged: false,
|
||||
isMergedMainCell: false,
|
||||
startRow: 0,
|
||||
startColumn: 7,
|
||||
endRow: 0,
|
||||
endColumn: 7,
|
||||
},
|
||||
style: {
|
||||
strokeWidth: 1,
|
||||
stroke: '#274fee',
|
||||
fill: 'rgba(39,79,238,0.07)',
|
||||
widgets: {},
|
||||
widgetSize: 6,
|
||||
widgetStrokeWidth: 1,
|
||||
widgetStroke: '#ffffff',
|
||||
autofillSize: 6,
|
||||
autofillStrokeWidth: 1,
|
||||
autofillStroke: '#ffffff',
|
||||
rowHeaderFill: 'rgba(39,79,238,0.07)',
|
||||
rowHeaderStroke: '#274fee',
|
||||
rowHeaderStrokeWidth: 1,
|
||||
columnHeaderFill: 'rgba(39,79,238,0.07)',
|
||||
columnHeaderStroke: '#274fee',
|
||||
columnHeaderStrokeWidth: 1,
|
||||
expandCornerSize: 40,
|
||||
},
|
||||
},
|
||||
],
|
||||
unitId,
|
||||
subUnitId: sheetId,
|
||||
type: 2,
|
||||
});
|
||||
|
||||
activeWorkbook.startEditing();
|
||||
await window.univerAPI.getActiveDocument().appendText("'1");
|
||||
activeWorkbook.endEditing(true);
|
||||
});
|
||||
|
||||
const filename = generateSnapshotName('set-force-string-cell');
|
||||
const screenshot = await page.locator(SHEET_MAIN_CANVAS_ID).screenshot();
|
||||
await expect(screenshot).toMatchSnapshot(filename, { maxDiffPixels: 5 });
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
test('diff set text format number cell', async () => {
|
||||
const browser = await chromium.launch({
|
||||
headless: !!isCI, // Set to false to see the browser window
|
||||
});
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1280, height: 1280 },
|
||||
deviceScaleFactor: 2, // Set your desired DPR
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultStyleSheet());
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.evaluate(async () => {
|
||||
await window.univerAPI.executeCommand('sheet.command.numfmt.set.numfmt', {
|
||||
values: [
|
||||
{
|
||||
row: 0,
|
||||
col: 7,
|
||||
pattern: '@@@',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await window.univerAPI.getActiveWorkbook().getActiveSheet().getRange('H1').setValue(2);
|
||||
|
||||
await window.univerAPI.getActiveWorkbook().getActiveSheet().getRange('I1').setValue(3);
|
||||
|
||||
await window.univerAPI.executeCommand('sheet.command.numfmt.set.numfmt', {
|
||||
values: [
|
||||
{
|
||||
row: 0,
|
||||
col: 8,
|
||||
pattern: '@@@',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
const filename = generateSnapshotName('set-text-format-number-cell');
|
||||
const screenshot = await page.locator(SHEET_MAIN_CANVAS_ID).screenshot();
|
||||
await expect(screenshot).toMatchSnapshot(filename, { maxDiffPixels: 5 });
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 294 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 295 KiB |
@@ -1456,7 +1456,18 @@ export class LexerTreeBuilder extends Disposable {
|
||||
} else {
|
||||
const nextCurrentString = formulaStringArray[cur + 1];
|
||||
if (nextCurrentString && nextCurrentString === matchToken.SINGLE_QUOTATION) {
|
||||
// handle 'Sheet'1'!A1
|
||||
|
||||
// Add the first single quotation
|
||||
this._pushSegment(currentString);
|
||||
this._addSequenceArray(sequenceArray, currentString, cur);
|
||||
cur++;
|
||||
|
||||
// Add the second single quotation
|
||||
this._pushSegment(nextCurrentString);
|
||||
this._addSequenceArray(sequenceArray, nextCurrentString, cur);
|
||||
cur++;
|
||||
continue;
|
||||
} else {
|
||||
this._closeSingleQuotation();
|
||||
}
|
||||
|
||||
@@ -101,6 +101,19 @@ describe('Test Reference', () => {
|
||||
});
|
||||
|
||||
it('serializeRangeToRefString', () => {
|
||||
expect(
|
||||
serializeRangeToRefString({
|
||||
range: {
|
||||
startColumn: 0,
|
||||
endColumn: 10,
|
||||
startRow: 5,
|
||||
endRow: 10,
|
||||
rangeType: RANGE_TYPE.COLUMN,
|
||||
},
|
||||
sheetName: '',
|
||||
unitId: '',
|
||||
})
|
||||
).toEqual('A:K');
|
||||
expect(
|
||||
serializeRangeToRefString({
|
||||
range: {
|
||||
@@ -140,6 +153,45 @@ describe('Test Reference', () => {
|
||||
unitId: 'workbook-1',
|
||||
})
|
||||
).toEqual("'[workbook-1]sheet1'!16:16");
|
||||
expect(
|
||||
serializeRangeToRefString({
|
||||
range: {
|
||||
startColumn: Number.NaN,
|
||||
endColumn: Number.NaN,
|
||||
startRow: 15,
|
||||
endRow: 15,
|
||||
rangeType: RANGE_TYPE.ROW,
|
||||
},
|
||||
sheetName: "sheet'1",
|
||||
unitId: '',
|
||||
})
|
||||
).toEqual("'sheet''1'!16:16");
|
||||
expect(
|
||||
serializeRangeToRefString({
|
||||
range: {
|
||||
startColumn: Number.NaN,
|
||||
endColumn: Number.NaN,
|
||||
startRow: 15,
|
||||
endRow: 15,
|
||||
rangeType: RANGE_TYPE.ROW,
|
||||
},
|
||||
sheetName: "sheet''1",
|
||||
unitId: '',
|
||||
})
|
||||
).toEqual("'sheet''''1'!16:16");
|
||||
expect(
|
||||
serializeRangeToRefString({
|
||||
range: {
|
||||
startColumn: Number.NaN,
|
||||
endColumn: Number.NaN,
|
||||
startRow: 15,
|
||||
endRow: 15,
|
||||
rangeType: RANGE_TYPE.ROW,
|
||||
},
|
||||
sheetName: "sheet'1",
|
||||
unitId: 'workbook-1',
|
||||
})
|
||||
).toEqual("'[workbook-1]sheet''1'!16:16");
|
||||
});
|
||||
|
||||
it('deserializeRangeWithSheet', () => {
|
||||
@@ -259,7 +311,7 @@ describe('Test Reference', () => {
|
||||
'12a',
|
||||
'💩a',
|
||||
'❤️b',
|
||||
"Sheet'",
|
||||
"Sheet'1",
|
||||
'!Sheet',
|
||||
'!Sheet',
|
||||
'Sheet1(副本)',
|
||||
@@ -305,11 +357,40 @@ describe('Test Reference', () => {
|
||||
unitId: '',
|
||||
});
|
||||
|
||||
// with single quote
|
||||
expect(handleRefStringInfo("'sheet''1'!A1")).toStrictEqual({
|
||||
refBody: 'A1',
|
||||
sheetName: "sheet'1",
|
||||
unitId: '',
|
||||
});
|
||||
|
||||
// with double quote
|
||||
expect(handleRefStringInfo("'sheet''''1'!A1")).toStrictEqual({
|
||||
refBody: 'A1',
|
||||
sheetName: "sheet''1",
|
||||
unitId: '',
|
||||
});
|
||||
|
||||
expect(handleRefStringInfo("'[Book-1.xlsx]Sheet1'!$A$4")).toStrictEqual({
|
||||
refBody: '$A$4',
|
||||
sheetName: 'Sheet1',
|
||||
unitId: 'Book-1.xlsx',
|
||||
});
|
||||
|
||||
// with single quote
|
||||
expect(handleRefStringInfo("'[Book''1.xlsx]Sheet1'!$A$4")).toStrictEqual({
|
||||
refBody: '$A$4',
|
||||
sheetName: 'Sheet1',
|
||||
unitId: "Book'1.xlsx",
|
||||
});
|
||||
|
||||
// with double quote
|
||||
expect(handleRefStringInfo("'[Book''''1.xlsx]Sheet1'!$A$4")).toStrictEqual({
|
||||
refBody: '$A$4',
|
||||
sheetName: 'Sheet1',
|
||||
unitId: "Book''1.xlsx",
|
||||
});
|
||||
|
||||
expect(handleRefStringInfo("'[Book-1.xlsx]sheet-1'!$A$4")).toStrictEqual({
|
||||
refBody: '$A$4',
|
||||
sheetName: 'sheet-1',
|
||||
|
||||
@@ -153,10 +153,7 @@ export function serializeRange(range: IRange): string {
|
||||
* @param range
|
||||
*/
|
||||
export function serializeRangeWithSheet(sheetName: string, range: IRange): string {
|
||||
if (needsQuoting(sheetName)) {
|
||||
return `'${sheetName}'!${serializeRange(range)}`;
|
||||
}
|
||||
return `${sheetName}!${serializeRange(range)}`;
|
||||
return `${addQuotesBothSides(sheetName)}!${serializeRange(range)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,7 +164,7 @@ export function serializeRangeWithSheet(sheetName: string, range: IRange): strin
|
||||
*/
|
||||
export function serializeRangeWithSpreadsheet(unit: string, sheetName: string, range: IRange): string {
|
||||
if (needsQuoting(unit) || needsQuoting(sheetName)) {
|
||||
return `'[${unit}]${sheetName}'!${serializeRange(range)}`;
|
||||
return `'[${quoteSheetName(unit)}]${quoteSheetName(sheetName)}'!${serializeRange(range)}`;
|
||||
}
|
||||
|
||||
return `[${unit}]${sheetName}!${serializeRange(range)}`;
|
||||
@@ -206,7 +203,7 @@ export function handleRefStringInfo(refString: string) {
|
||||
|
||||
if (unitIdMatch != null) {
|
||||
unitId = unitIdMatch[0].trim();
|
||||
unitId = unitId.slice(1, unitId.length - 1);
|
||||
unitId = unquoteSheetName(unitId.slice(1, unitId.length - 1));
|
||||
refString = refString.replace(UNIT_NAME_REGEX_PRECOMPILING, '');
|
||||
}
|
||||
|
||||
@@ -218,6 +215,8 @@ export function handleRefStringInfo(refString: string) {
|
||||
if (sheetName[0] === "'" && sheetName[sheetName.length - 1] === "'") {
|
||||
sheetName = sheetName.substring(1, sheetName.length - 1);
|
||||
}
|
||||
|
||||
sheetName = unquoteSheetName(sheetName);
|
||||
refBody = refString.substring(sheetNameIndex + 1);
|
||||
} else {
|
||||
refBody = refString;
|
||||
@@ -426,6 +425,31 @@ export function needsQuoting(name: string) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add quotes to the sheet name
|
||||
*/
|
||||
export function addQuotesBothSides(name: string) {
|
||||
return needsQuoting(name) ? `'${quoteSheetName(name)}'` : name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single quote before the single quote
|
||||
* @param name
|
||||
* @returns Quoted name
|
||||
*/
|
||||
function quoteSheetName(name: string) {
|
||||
return name.replace(/'/g, "''");
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace double single quotes with single quotes
|
||||
* @param name
|
||||
* @returns Unquoted name
|
||||
*/
|
||||
function unquoteSheetName(name: string) {
|
||||
return name.replace(/''/g, "'");
|
||||
}
|
||||
|
||||
function isA1Notation(name: string) {
|
||||
const match = name.match(/[1-9][0-9]{0,6}/);
|
||||
// Excel has a limit on the number of rows and columns: targetRow > 1048576 || targetColumn > 16384, Univer has no limit
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { ErrorType } from '../../../../basics/error-type';
|
||||
import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object';
|
||||
import { ErrorValueObject } from '../../../../engine/value-object/base-value-object';
|
||||
import {
|
||||
BooleanValueObject,
|
||||
NumberValueObject,
|
||||
StringValueObject,
|
||||
} from '../../../../engine/value-object/primitive-object';
|
||||
import { getObjectValue } from '../../../__tests__/create-function-test-bed';
|
||||
import { FUNCTION_NAMES_LOOKUP } from '../../function-names';
|
||||
import { Address } from '../index';
|
||||
import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object';
|
||||
import { getObjectValue } from '../../../__tests__/create-function-test-bed';
|
||||
|
||||
describe('Test address', () => {
|
||||
const testFunction = new Address(FUNCTION_NAMES_LOOKUP.ADDRESS);
|
||||
@@ -65,6 +65,10 @@ describe('Test address', () => {
|
||||
expect(calculate(2, 3, 1, false, '[Book1]Sheet1')).toBe("'[Book1]Sheet1'!R2C3");
|
||||
});
|
||||
|
||||
it('Absolute reference to sheet name with single quote', async () => {
|
||||
expect(calculate(1, 1, 1, true, "Sheet'1")).toBe("'Sheet''1'!$A$1");
|
||||
});
|
||||
|
||||
it('Absolute reference to another worksheet', async () => {
|
||||
expect(calculate(2, 3, 1, false, 'EXCEL SHEET')).toBe("'EXCEL SHEET'!R2C3");
|
||||
});
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AbsoluteRefType, type IRange } from '@univerjs/core';
|
||||
import type { ArrayValueObject } from '../../../engine/value-object/array-value-object';
|
||||
|
||||
import { AbsoluteRefType, type IRange } from '@univerjs/core';
|
||||
import { ErrorType } from '../../../basics/error-type';
|
||||
import { expandArrayValueObject } from '../../../engine/utils/array-object';
|
||||
import { serializeRangeToR1C1 } from '../../../engine/utils/r1c1-reference';
|
||||
import { needsQuoting, serializeRange } from '../../../engine/utils/reference';
|
||||
import { addQuotesBothSides, serializeRange } from '../../../engine/utils/reference';
|
||||
import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object';
|
||||
import { BooleanValueObject, NumberValueObject, StringValueObject } from '../../../engine/value-object/primitive-object';
|
||||
import { BaseFunction } from '../../base-function';
|
||||
import type { ArrayValueObject } from '../../../engine/value-object/array-value-object';
|
||||
import { expandArrayValueObject } from '../../../engine/utils/array-object';
|
||||
|
||||
export class Address extends BaseFunction {
|
||||
override minParams = 2;
|
||||
@@ -132,7 +132,7 @@ export class Address extends BaseFunction {
|
||||
const absType = transformAbsoluteRefType(absNumberValue);
|
||||
const a1Value = this.getZeroOrOneByOneDefault(a1);
|
||||
const sheetTextValue = `${sheetText.getValue()}`;
|
||||
const sheetName = needsQuoting(sheetTextValue) ? `'${sheetTextValue}'` : sheetTextValue;
|
||||
const sheetName = addQuotesBothSides(sheetTextValue);
|
||||
|
||||
const range: IRange = {
|
||||
startRow: row,
|
||||
|
||||
@@ -27,8 +27,6 @@ export interface IFUniverSheetsFormulaMixin {
|
||||
* @returns {IDisposable} The disposable instance.
|
||||
*/
|
||||
registerFunction(config: IRegisterFunctionParams): IDisposable;
|
||||
|
||||
// TODO@Dushusir: this API should be implemented on FFormula.
|
||||
}
|
||||
|
||||
export class FUniverSheetsFormulaMixin extends FUniver implements IFUniverSheetsFormulaMixin {
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Workbook } from '@univerjs/core';
|
||||
import type { IRenderContext, IRenderModule } from '@univerjs/engine-render';
|
||||
import { Disposable, Inject, isRealNum, LocaleService } from '@univerjs/core';
|
||||
import { FormulaDataModel } from '@univerjs/engine-formula';
|
||||
import { DEFAULT_TEXT_FORMAT } from '@univerjs/engine-numfmt';
|
||||
import { INumfmtService } from '@univerjs/sheets';
|
||||
import { CellAlertManagerService, CellAlertType, HoverManagerService } from '@univerjs/sheets-ui';
|
||||
import { IZenZoneService } from '@univerjs/ui';
|
||||
import { debounceTime } from 'rxjs';
|
||||
|
||||
const ALERT_KEY = 'SHEET_NUMFMT_ALERT';
|
||||
|
||||
export class NumfmtAlertRenderController extends Disposable implements IRenderModule {
|
||||
constructor(
|
||||
private readonly _context: IRenderContext<Workbook>,
|
||||
@Inject(HoverManagerService) private readonly _hoverManagerService: HoverManagerService,
|
||||
@Inject(CellAlertManagerService) private readonly _cellAlertManagerService: CellAlertManagerService,
|
||||
@Inject(LocaleService) private readonly _localeService: LocaleService,
|
||||
@Inject(FormulaDataModel) private readonly _formulaDataModel: FormulaDataModel,
|
||||
@IZenZoneService private readonly _zenZoneService: IZenZoneService,
|
||||
@Inject(INumfmtService) private _numfmtService: INumfmtService
|
||||
) {
|
||||
super();
|
||||
this._init();
|
||||
}
|
||||
|
||||
private _init() {
|
||||
this._initCellAlertPopup();
|
||||
this._initZenService();
|
||||
}
|
||||
|
||||
private _initCellAlertPopup() {
|
||||
this.disposeWithMe(this._hoverManagerService.currentCell$.pipe(debounceTime(100)).subscribe((cellPos) => {
|
||||
if (cellPos) {
|
||||
const location = cellPos.location;
|
||||
const workbook = this._context.unit;
|
||||
const worksheet = workbook.getActiveSheet();
|
||||
if (!worksheet) return;
|
||||
|
||||
const unitId = location.unitId;
|
||||
const sheetId = location.subUnitId;
|
||||
let numfmtValue;
|
||||
|
||||
const cellData = worksheet.getCell(location.row, location.col);
|
||||
|
||||
if (cellData?.s) {
|
||||
const style = workbook.getStyles().get(cellData.s);
|
||||
if (style?.n) {
|
||||
numfmtValue = style.n;
|
||||
}
|
||||
}
|
||||
|
||||
if (!numfmtValue) {
|
||||
numfmtValue = this._numfmtService.getValue(unitId, sheetId, location.row, location.col);
|
||||
}
|
||||
|
||||
if (!numfmtValue) {
|
||||
this._hideAlert();
|
||||
return;
|
||||
}
|
||||
|
||||
// Preventing blank object
|
||||
if (numfmtValue.pattern === DEFAULT_TEXT_FORMAT && cellData?.v && isRealNum(cellData.v)) {
|
||||
const currentAlert = this._cellAlertManagerService.currentAlert.get(ALERT_KEY);
|
||||
const currentLoc = currentAlert?.alert?.location;
|
||||
if (
|
||||
currentLoc &&
|
||||
currentLoc.row === location.row &&
|
||||
currentLoc.col === location.col &&
|
||||
currentLoc.subUnitId === location.subUnitId &&
|
||||
currentLoc.unitId === location.unitId
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._cellAlertManagerService.showAlert({
|
||||
type: CellAlertType.ERROR,
|
||||
title: this._localeService.t('info.error'),
|
||||
message: this._localeService.t('info.forceStringInfo'),
|
||||
location,
|
||||
width: 200,
|
||||
height: 74,
|
||||
key: ALERT_KEY,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._hideAlert();
|
||||
}));
|
||||
}
|
||||
|
||||
private _initZenService() {
|
||||
this.disposeWithMe(this._zenZoneService.visible$.subscribe((visible) => {
|
||||
if (visible) {
|
||||
this._hideAlert();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private _hideAlert() {
|
||||
this._cellAlertManagerService.removeAlert(ALERT_KEY);
|
||||
}
|
||||
}
|
||||
@@ -169,7 +169,8 @@ export class NumfmtEditorController extends Disposable {
|
||||
return next(value);
|
||||
}
|
||||
|
||||
if (currentNumfmtValue?.pattern === DEFAULT_TEXT_FORMAT) {
|
||||
// if the cell is text format or force string, do not convert the value
|
||||
if (currentNumfmtValue?.pattern === DEFAULT_TEXT_FORMAT || value.t === CellValueType.FORCE_STRING) {
|
||||
return next(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,12 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Dependency } from '@univerjs/core';
|
||||
import type { IUniverSheetsNumfmtUIConfig } from './controllers/config.schema';
|
||||
import { DependentOn, IConfigService, Inject, Injector, merge, Plugin, registerDependencies, touchDependencies, UniverInstanceType } from '@univerjs/core';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt';
|
||||
import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui';
|
||||
import { UI_PLUGIN_CONFIG_KEY } from '@univerjs/ui';
|
||||
import { defaultPluginConfig } from './controllers/config.schema';
|
||||
import { NumfmtAlertRenderController } from './controllers/numfmt-alert-render.controller';
|
||||
import { SheetNumfmtUIController } from './controllers/numfmt.controller';
|
||||
import { NumfmtEditorController } from './controllers/numfmt.editor.controller';
|
||||
import { NumfmtMenuController } from './controllers/numfmt.menu.controller';
|
||||
@@ -35,7 +38,8 @@ export class UniverSheetsNumfmtUIPlugin extends Plugin {
|
||||
constructor(
|
||||
private readonly _config: Partial<IUniverSheetsNumfmtUIConfig> = defaultPluginConfig,
|
||||
@Inject(Injector) override readonly _injector: Injector,
|
||||
@IConfigService private readonly _configService: IConfigService
|
||||
@IConfigService private readonly _configService: IConfigService,
|
||||
@IRenderManagerService private readonly _renderManagerService: IRenderManagerService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -62,10 +66,21 @@ export class UniverSheetsNumfmtUIPlugin extends Plugin {
|
||||
}
|
||||
|
||||
override onRendered(): void {
|
||||
this._registerRenderModules();
|
||||
touchDependencies(this._injector, [
|
||||
[SheetNumfmtUIController],
|
||||
[NumfmtEditorController],
|
||||
[NumfmtMenuController],
|
||||
]);
|
||||
}
|
||||
|
||||
private _registerRenderModules(): void {
|
||||
const modules: Dependency[] = [
|
||||
[NumfmtAlertRenderController],
|
||||
];
|
||||
|
||||
modules.forEach((m) => {
|
||||
this.disposeWithMe(this._renderManagerService.registerRenderModule(UniverInstanceType.UNIVER_SHEET, m));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@univerjs/core": "workspace:*",
|
||||
"@univerjs/engine-numfmt": "workspace:*",
|
||||
"@univerjs/sheets": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
ICommandService,
|
||||
Inject,
|
||||
InterceptorEffectEnum,
|
||||
isRealNum,
|
||||
IUniverInstanceService,
|
||||
LocaleService,
|
||||
ObjectMatrix,
|
||||
@@ -33,6 +34,7 @@ import {
|
||||
ThemeService,
|
||||
UniverInstanceType,
|
||||
} from '@univerjs/core';
|
||||
import { DEFAULT_TEXT_FORMAT } from '@univerjs/engine-numfmt';
|
||||
import { InterceptCellContentPriority, INTERCEPTOR_POINT, INumfmtService, SetNumfmtMutation, SetRangeValuesMutation, SheetInterceptorService } from '@univerjs/sheets';
|
||||
import { of, skip, switchMap } from 'rxjs';
|
||||
import { getPatternPreviewIgnoreGeneral } from '../utils/pattern';
|
||||
@@ -52,6 +54,13 @@ export class SheetsNumfmtCellContentController extends Disposable {
|
||||
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
private _initInterceptorCellContent() {
|
||||
const TEXT_FORMAT_MARK = {
|
||||
tl: {
|
||||
size: 6,
|
||||
color: '#409f11',
|
||||
},
|
||||
};
|
||||
|
||||
const renderCache = new ObjectMatrix<{ result: ICellData; parameters: string | number }>();
|
||||
this.disposeWithMe(this._sheetInterceptorService.intercept(INTERCEPTOR_POINT.CELL_CONTENT, {
|
||||
effect: InterceptorEffectEnum.Value | InterceptorEffectEnum.Style,
|
||||
@@ -64,11 +73,6 @@ export class SheetsNumfmtCellContentController extends Disposable {
|
||||
return next(cell);
|
||||
}
|
||||
|
||||
// just handle number
|
||||
if (originCellValue.t !== CellValueType.NUMBER || originCellValue.v == null || Number.isNaN(originCellValue.v)) {
|
||||
return next(cell);
|
||||
}
|
||||
|
||||
if (cell?.s) {
|
||||
const style = location.workbook.getStyles().get(cell.s);
|
||||
if (style?.n) {
|
||||
@@ -79,10 +83,27 @@ export class SheetsNumfmtCellContentController extends Disposable {
|
||||
if (!numfmtValue) {
|
||||
numfmtValue = this._numfmtService.getValue(unitId, sheetId, location.row, location.col);
|
||||
}
|
||||
|
||||
if (!numfmtValue) {
|
||||
return next(cell);
|
||||
}
|
||||
|
||||
// Add error marker to text format number
|
||||
if (numfmtValue.pattern === DEFAULT_TEXT_FORMAT && originCellValue.v && isRealNum(originCellValue.v)) {
|
||||
return next({
|
||||
...cell,
|
||||
markers: {
|
||||
...cell?.markers,
|
||||
...TEXT_FORMAT_MARK,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// just handle number
|
||||
if (originCellValue.t !== CellValueType.NUMBER || originCellValue.v == null || Number.isNaN(originCellValue.v)) {
|
||||
return next(cell);
|
||||
}
|
||||
|
||||
let numfmtRes: string = '';
|
||||
const cache = renderCache.getValue(location.row, location.col);
|
||||
if (cache && cache.parameters === `${originCellValue.v}_${numfmtValue.pattern}`) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import type { Workbook } from '@univerjs/core';
|
||||
import type { IRenderContext, IRenderModule } from '@univerjs/engine-render';
|
||||
import { CellValueType, Disposable, Inject, isRealNum, LocaleService } from '@univerjs/core';
|
||||
import { IZenZoneService } from '@univerjs/ui';
|
||||
import { CellAlertManagerService, CellAlertType } from '../services/cell-alert-manager.service';
|
||||
import { HoverManagerService } from '../services/hover-manager.service';
|
||||
|
||||
@@ -27,7 +28,8 @@ export class ForceStringAlertRenderController extends Disposable implements IRen
|
||||
private readonly _context: IRenderContext<Workbook>,
|
||||
@Inject(HoverManagerService) private readonly _hoverManagerService: HoverManagerService,
|
||||
@Inject(CellAlertManagerService) private readonly _cellAlertManagerService: CellAlertManagerService,
|
||||
@Inject(LocaleService) private readonly _localeService: LocaleService
|
||||
@Inject(LocaleService) private readonly _localeService: LocaleService,
|
||||
@IZenZoneService private readonly _zenZoneService: IZenZoneService
|
||||
) {
|
||||
super();
|
||||
this._init();
|
||||
@@ -35,6 +37,7 @@ export class ForceStringAlertRenderController extends Disposable implements IRen
|
||||
|
||||
private _init() {
|
||||
this._initCellAlertPopup();
|
||||
this._initZenService();
|
||||
}
|
||||
|
||||
private _initCellAlertPopup() {
|
||||
@@ -73,7 +76,19 @@ export class ForceStringAlertRenderController extends Disposable implements IRen
|
||||
}
|
||||
}
|
||||
|
||||
this._cellAlertManagerService.removeAlert(ALERT_KEY);
|
||||
this._hideAlert();
|
||||
}));
|
||||
}
|
||||
|
||||
private _initZenService() {
|
||||
this.disposeWithMe(this._zenZoneService.visible$.subscribe((visible) => {
|
||||
if (visible) {
|
||||
this._hideAlert();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private _hideAlert() {
|
||||
this._cellAlertManagerService.removeAlert(ALERT_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +193,10 @@ export class BasicWorksheetController extends Disposable implements IDisposable
|
||||
SetNumfmtMutation,
|
||||
ReorderRangeMutation,
|
||||
EmptyMutation,
|
||||
SetRowHiddenMutation, // formula SUBTOTAL
|
||||
SetRowVisibleMutation,
|
||||
SetColHiddenMutation,
|
||||
SetColVisibleMutation,
|
||||
] as IMutation<object>[]).forEach((mutation) => {
|
||||
this._commandService.registerCommand(mutation);
|
||||
this._dataSyncPrimaryController?.registerSyncingMutations(mutation);
|
||||
@@ -240,8 +244,6 @@ export class BasicWorksheetController extends Disposable implements IDisposable
|
||||
SetBorderPositionCommand,
|
||||
SetBorderStyleCommand,
|
||||
SetColHiddenCommand,
|
||||
SetColHiddenMutation,
|
||||
SetColVisibleMutation,
|
||||
SetColWidthCommand,
|
||||
SetColDataCommand,
|
||||
SetColDataMutation,
|
||||
@@ -252,8 +254,6 @@ export class BasicWorksheetController extends Disposable implements IDisposable
|
||||
SetRangeValuesCommand,
|
||||
SetRowHeightCommand,
|
||||
SetRowHiddenCommand,
|
||||
SetRowHiddenMutation,
|
||||
SetRowVisibleMutation,
|
||||
SetRowDataCommand,
|
||||
SetRowDataMutation,
|
||||
SetSelectedColsVisibleCommand,
|
||||
|
||||
Generated
+3
@@ -2686,6 +2686,9 @@ importers:
|
||||
'@univerjs/core':
|
||||
specifier: workspace:*
|
||||
version: link:../core
|
||||
'@univerjs/engine-numfmt':
|
||||
specifier: workspace:*
|
||||
version: link:../engine-numfmt
|
||||
'@univerjs/sheets':
|
||||
specifier: workspace:*
|
||||
version: link:../sheets
|
||||
|
||||
Reference in New Issue
Block a user