Skip to content

Commit

Permalink
feat(sheet): update code
Browse files Browse the repository at this point in the history
  • Loading branch information
VicKun4937 committed Dec 28, 2024
1 parent 7526596 commit ca69841
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 110 deletions.
2 changes: 1 addition & 1 deletion packages/sheets/src/facade/f-range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,6 @@ export class FRange extends FBase {
unitId: this.getUnitId(),
subUnitId: this._worksheet.getSheetId(),
};
this._injector.get(SheetRangeThemeService).registerRangeThemeStyles(themeName, rangeInfo);
this._injector.get(SheetRangeThemeService).registerRangeThemeStyle(themeName, rangeInfo);
}
}
3 changes: 1 addition & 2 deletions packages/sheets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ export { createTopMatrixFromMatrix, createTopMatrixFromRanges, findAllRectangle,
export { type IUniverSheetsConfig } from './controllers/config.schema';
export { MAX_CELL_PER_SHEET_KEY } from './controllers/config/config';
export { BorderStyleManagerService, type IBorderInfo } from './services/border-style-manager.service';
export { type IRangeThemeStyleItem, RangeThemeStyle } from './services/theme-range/range-theme-util';
export { SheetRangeThemeService } from './services/theme-range/range-theme-service';
export { SheetRangeThemeService } from './services/range-theme-service';
export * from './services/permission/permission-point';
export { WorksheetPermissionService } from './services/permission/worksheet-permission/worksheet-permission.service';
export { WorkbookPermissionService } from './services/permission/workbook-permission/workbook-permission.service';
Expand Down
223 changes: 223 additions & 0 deletions packages/sheets/src/model/range-theme-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/**
* 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 { ICellDataForSheetInterceptor, IRange, Nullable } from '@univerjs/core';
import type { IRangeThemeStyleItem } from './range-theme-util';
import { Disposable, generateRandomId, Inject, InterceptorEffectEnum, IResourceManagerService, RTree, UniverInstanceType } from '@univerjs/core';
import { INTERCEPTOR_POINT } from '../services/sheet-interceptor/interceptor-const';
import { SheetInterceptorService } from '../services/sheet-interceptor/sheet-interceptor.service';
import { RangeThemeStyle } from './range-theme-util';
import defaultRangeThemeStyle from './range-themes/default';

export interface IRangeThemeRangeInfo {
range: IRange;
unitId: string;
subUnitId: string;
}

export interface IRangeThemeStyleRule {
rangeInfo: IRangeThemeRangeInfo;
themeName: string;
}

const SHEET_RANGE_THEME_MODEL_PLUGIN = 'SHEET_RANGE_THEME_MODEL_PLUGIN';

export class SheetRangeThemeModel extends Disposable {
private _rangeThemeStyleMap: Map<string, Map<string, RangeThemeStyle>> = new Map();
private _rangeThemeStyleRuleMap: Map<string, Map<string, IRangeThemeStyleRule>> = new Map();
private _rTreeCollection: Map<string, RTree> = new Map();
private _defaultRangeThemeMap: Map<string, RangeThemeStyle> = new Map();
constructor(
@Inject(SheetInterceptorService) private _sheetInterceptorService: SheetInterceptorService,
@Inject(IResourceManagerService) private _resourceManagerService: IResourceManagerService
) {
super();
this._registerIntercept();
this.registerDefaultRangeTheme(defaultRangeThemeStyle);
this._initSnapshot();
}

private _ensureRangeThemeStyleMap(unitId: string) {
if (!this._rangeThemeStyleMap.has(unitId)) {
this._rangeThemeStyleMap.set(unitId, new Map());
}
return this._rangeThemeStyleMap.get(unitId)!;
}

private _ensureRangeThemeStyleRuleMap(unitId: string) {
if (!this._rangeThemeStyleRuleMap.has(unitId)) {
this._rangeThemeStyleRuleMap.set(unitId, new Map());
}
return this._rangeThemeStyleRuleMap.get(unitId)!;
}

private _ensureRTreeCollection(unitId: string) {
if (!this._rTreeCollection.has(unitId)) {
this._rTreeCollection.set(unitId, new RTree());
}
return this._rTreeCollection.get(unitId)!;
}

/**
* Register range theme styles
* @param {string} themeName
* @param {IRangeThemeRangeInfo} rangeInfo
*/
registerRangeThemeRule(themeName: string, rangeInfo: IRangeThemeRangeInfo): void {
const { unitId, subUnitId, range } = rangeInfo;
const id = generateRandomId();
const ruleMap = this._ensureRangeThemeStyleRuleMap(unitId);
const rTreeCollection = this._ensureRTreeCollection(unitId);
ruleMap.set(id, { rangeInfo, themeName });
rTreeCollection.insert({ unitId, sheetId: subUnitId, range, id });
}

registerDefaultRangeTheme(rangeThemeStyle: RangeThemeStyle): void {
this._defaultRangeThemeMap.set(rangeThemeStyle.getName(), rangeThemeStyle);
}

registerRangeThemeStyle(unitId: string, rangeThemeStyle: RangeThemeStyle): void {
this._ensureRangeThemeStyleMap(unitId).set(rangeThemeStyle.getName(), rangeThemeStyle);
}

getALLRegisteredTheme(): string[] {
return Array.from(this._rangeThemeStyleMap.keys());
}

getRangeThemeStyle(unitId: string, name: string): RangeThemeStyle {
if (this._defaultRangeThemeMap.has(name)) {
return this._defaultRangeThemeMap.get(name)!;
}
return this._ensureRangeThemeStyleMap(unitId).get(name)!;
}

public getCellStyle(unitId: string, subUnitId: string, row: number, col: number): Nullable<IRangeThemeStyleItem> {
const range = { startRow: row, startColumn: col, endRow: row, endColumn: col };
const rTreeCollection = this._ensureRTreeCollection(unitId);
const themes = Array.from(rTreeCollection.bulkSearch([{ unitId, sheetId: subUnitId, range }]));
if (themes[0]) {
const themeRuleMap = this._ensureRangeThemeStyleRuleMap(unitId);
const themeRule = themeRuleMap.get(themes[0] as string);
if (themeRule) {
const { rangeInfo, themeName } = themeRule;
const offsetRow = row - rangeInfo.range.startRow;
const offsetCol = col - rangeInfo.range.startColumn;
const theme = this.getRangeThemeStyle(unitId, themeName);
return theme.getStyle(offsetRow, offsetCol);
}
}
return undefined;
}

private _registerIntercept(): void {
this.disposeWithMe(this._sheetInterceptorService.intercept(INTERCEPTOR_POINT.CELL_CONTENT, {
effect: InterceptorEffectEnum.Style,
handler: (cell, context, next) => {
const { row, col, unitId, subUnitId } = context;
const style = this.getCellStyle(unitId, subUnitId, row, col);

if (style) {
const newCell: ICellDataForSheetInterceptor = { ...cell };
newCell.s = style;
return next(newCell);
}

return next(cell);
},
}));
}

toJson(unitId: string) {
const ruleMap = this._ensureRangeThemeStyleRuleMap(unitId);
const rangeThemeStyleRuleMap: Record<string, IRangeThemeStyleRule> = {};
ruleMap.forEach((value, key) => {
rangeThemeStyleRuleMap[key] = value;
});

const rangeThemeStyleMap = this._ensureRangeThemeStyleMap(unitId);
const rangeThemeStyleMapJson: Record<string, Record<string, string>> = {};
rangeThemeStyleMap.forEach((value, key) => {
rangeThemeStyleMapJson[key] = value.toJSON();
});

return JSON.stringify({
rangeThemeStyleRuleMap,
rangeThemeStyleMapJson,
});
}

fromJSON(json: string) {
const { rangeThemeStyleRuleMap, rangeThemeStyleMapJson } = JSON.parse(json);
Object.keys(rangeThemeStyleRuleMap).forEach((key) => {
this._ensureRangeThemeStyleRuleMap(key).clear();
this._ensureRTreeCollection(key).clear();
const ruleMap = rangeThemeStyleRuleMap[key];
Object.keys(ruleMap).forEach((ruleKey) => {
const rule = ruleMap[ruleKey];
this.registerRangeThemeRule(rule.themeName, rule.rangeInfo);
const rTreeCollection = this._ensureRTreeCollection(key);
rTreeCollection.insert({ unitId: key, sheetId: rule.rangeInfo.subUnitId, range: rule.rangeInfo.range, id: ruleKey });
});
});

Object.keys(rangeThemeStyleMapJson).forEach((key) => {
const styleMap = rangeThemeStyleMapJson[key];
const style = new RangeThemeStyle(styleMap.name);
style.fromJSON(styleMap);
this._ensureRangeThemeStyleMap(key).set(style.getName(), style);
});
}

deleteUnitId(unitId: string) {
this._rangeThemeStyleMap.delete(unitId);
this._rangeThemeStyleRuleMap.delete(unitId);
this._rTreeCollection.delete(unitId);
}

private _initSnapshot(): void {
this.disposeWithMe(this._resourceManagerService.registerPluginResource({
toJson: (unitId: string) => {
return this.toJson(unitId);
},
parseJson: (json: string) => {
if (!json) {
return {};
}
try {
return JSON.parse(json);
// eslint-disable-next-line unused-imports/no-unused-vars
} catch (error) {
return {};
}
},
businesses: [UniverInstanceType.UNIVER_SHEET],
pluginName: SHEET_RANGE_THEME_MODEL_PLUGIN,
onLoad: (_unitId, resources) => {
this.fromJSON(resources);
},
onUnLoad: (unitId) => {
this.deleteUnitId(unitId);
},
}));
}

override dispose(): void {
super.dispose();
this._rangeThemeStyleMap.clear();
this._rangeThemeStyleRuleMap.clear();
this._rTreeCollection.clear();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,32 @@ export class RangeThemeStyle {
return this.wholeStyle;
}
}

toJSON(): Record<string, string> {
return {
name: this._name,
wholeStyle: JSON.stringify(this.wholeStyle),
headerRowStyle: JSON.stringify(this.headerRowStyle),
headerColumnStyle: JSON.stringify(this.headerColumnStyle),
firstRowStyle: JSON.stringify(this.firstRowStyle),
secondRowStyle: JSON.stringify(this.secondRowStyle),
lastRowStyle: JSON.stringify(this.lastRowStyle),
firstColumnStyle: JSON.stringify(this.firstColumnStyle),
secondColumnStyle: JSON.stringify(this.secondColumnStyle),
lastColumnStyle: JSON.stringify(this.lastColumnStyle),
};
}

fromJSON(json: Record<string, string>): void {
this.wholeStyle = JSON.parse(json.wholeStyle);
this.headerRowStyle = JSON.parse(json.headerRowStyle);
this.headerColumnStyle = JSON.parse(json.headerColumnStyle);
this.firstRowStyle = JSON.parse(json.firstRowStyle);
this.secondRowStyle = JSON.parse(json.secondRowStyle);
this.lastRowStyle = JSON.parse(json.lastRowStyle);
this.firstColumnStyle = JSON.parse(json.firstColumnStyle);
this.secondColumnStyle = JSON.parse(json.secondColumnStyle);
this.lastColumnStyle = JSON.parse(json.lastColumnStyle);
}
}

40 changes: 40 additions & 0 deletions packages/sheets/src/services/range-theme-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* 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 { IRangeThemeRangeInfo } from '../model/range-theme-model';
import type { RangeThemeStyle } from '../model/range-theme-util';
import { Disposable, Inject } from '@univerjs/core';
import { SheetRangeThemeModel } from '../model/range-theme-model';

export class SheetRangeThemeService extends Disposable {
constructor(
@Inject(SheetRangeThemeModel) private _sheetRangeThemeModel: SheetRangeThemeModel
) {
super();
}

registerRangeTheme(unitId: string, rangeThemeStyle: RangeThemeStyle): void {
this._sheetRangeThemeModel.registerRangeThemeStyle(unitId, rangeThemeStyle);
}

getALLRegisterThemes(): string[] {
return this._sheetRangeThemeModel.getALLRegisteredTheme();
}

registerRangeThemeStyle(themeName: string, rangeInfo: IRangeThemeRangeInfo): void {
this._sheetRangeThemeModel.registerRangeThemeRule(themeName, rangeInfo);
}
}
Loading

0 comments on commit ca69841

Please sign in to comment.